summaryrefslogtreecommitdiff
path: root/src/engine/lightmap.cpp
diff options
context:
space:
mode:
authorxolatile2025-08-04 22:53:42 +0200
committerxolatile2025-08-04 22:53:42 +0200
commitd309df4ce4d8ad0ed995a8e1c4267412a7782021 (patch)
tree999ca8d785ecc1681e5eb7538ce2e6a18d244fa5 /src/engine/lightmap.cpp
parent29d613d9cb65a0faa7e3f80e75bea0b6d910cb9a (diff)
downloadxolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.xz
xolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.zst
Bunch of small changes...
Diffstat (limited to 'src/engine/lightmap.cpp')
-rw-r--r--src/engine/lightmap.cpp4485
1 files changed, 2156 insertions, 2329 deletions
diff --git a/src/engine/lightmap.cpp b/src/engine/lightmap.cpp
index b4090e2..959782e 100644
--- a/src/engine/lightmap.cpp
+++ b/src/engine/lightmap.cpp
@@ -8,59 +8,59 @@ struct lightmaptask;
struct lightmapworker
{
- uchar *buf;
- int bufstart, bufused;
- lightmapinfo *firstlightmap, *lastlightmap, *curlightmaps;
- cube *c;
- cubeext *ext;
- uchar *colorbuf;
- bvec *raybuf;
- uchar *ambient, *blur;
- vec *colordata, *raydata;
- int type, bpp, w, h, orient, rotate;
- VSlot *vslot;
- Slot *slot;
- vector<const extentity *> lights;
- ShadowRayCache *shadowraycache;
- BlendMapCache *blendmapcache;
- bool needspace, doneworking;
- SDL_cond *spacecond;
- SDL_Thread *thread;
-
- lightmapworker();
- ~lightmapworker();
-
- void reset();
- bool setupthread();
- void cleanupthread();
-
- static int work(void *data);
+ uchar *buf;
+ int bufstart, bufused;
+ lightmapinfo *firstlightmap, *lastlightmap, *curlightmaps;
+ cube *c;
+ cubeext *ext;
+ uchar *colorbuf;
+ bvec *raybuf;
+ uchar *ambient, *blur;
+ vec *colordata, *raydata;
+ int type, bpp, w, h, orient, rotate;
+ VSlot *vslot;
+ Slot *slot;
+ vector<const extentity *> lights;
+ ShadowRayCache *shadowraycache;
+ BlendMapCache *blendmapcache;
+ bool needspace, doneworking;
+ SDL_cond *spacecond;
+ SDL_Thread *thread;
+
+ lightmapworker();
+ ~lightmapworker();
+
+ void reset();
+ bool setupthread();
+ void cleanupthread();
+
+ static int work(void *data);
};
struct lightmapinfo
{
- lightmapinfo *next;
- cube *c;
- uchar *colorbuf;
- bvec *raybuf;
- bool packed;
- int type, w, h, bpp, bufsize, surface, layers;
+ lightmapinfo *next;
+ cube *c;
+ uchar *colorbuf;
+ bvec *raybuf;
+ bool packed;
+ int type, w, h, bpp, bufsize, surface, layers;
};
struct lightmaptask
{
- ivec o;
- int size, usefaces, progress;
- cube *c;
- cubeext *ext;
- lightmapinfo *lightmaps;
- lightmapworker *worker;
+ ivec o;
+ int size, usefaces, progress;
+ cube *c;
+ cubeext *ext;
+ lightmapinfo *lightmaps;
+ lightmapworker *worker;
};
struct lightmapext
{
- cube *c;
- cubeext *ext;
+ cube *c;
+ cubeext *ext;
};
static vector<lightmapworker *> lightmapworkers;
@@ -79,24 +79,24 @@ VARR(lighterror, 1, 8, 16);
VARR(bumperror, 1, 3, 16);
VARR(lightlod, 0, 0, 10);
bvec ambientcolor(0x19, 0x19, 0x19), skylightcolor(0, 0, 0);
-HVARFR(ambient, 1, 0x191919, 0xFFFFFF,
+HVARFR(ambient, 1, 0x191919, 0xFFFFFF,
{
- if(ambient <= 255) ambient |= (ambient<<8) | (ambient<<16);
- ambientcolor = bvec((ambient>>16)&0xFF, (ambient>>8)&0xFF, ambient&0xFF);
+ if(ambient <= 255) ambient |= (ambient<<8) | (ambient<<16);
+ ambientcolor = bvec((ambient>>16)&0xFF, (ambient>>8)&0xFF, ambient&0xFF);
});
-HVARFR(skylight, 0, 0, 0xFFFFFF,
+HVARFR(skylight, 0, 0, 0xFFFFFF,
{
- if(skylight <= 255) skylight |= (skylight<<8) | (skylight<<16);
- skylightcolor = bvec((skylight>>16)&0xFF, (skylight>>8)&0xFF, skylight&0xFF);
+ if(skylight <= 255) skylight |= (skylight<<8) | (skylight<<16);
+ skylightcolor = bvec((skylight>>16)&0xFF, (skylight>>8)&0xFF, skylight&0xFF);
});
extern void setupsunlight();
bvec sunlightcolor(0, 0, 0);
HVARFR(sunlight, 0, 0, 0xFFFFFF,
{
- if(sunlight <= 255) sunlight |= (sunlight<<8) | (sunlight<<16);
- sunlightcolor = bvec((sunlight>>16)&0xFF, (sunlight>>8)&0xFF, sunlight&0xFF);
- setupsunlight();
+ if(sunlight <= 255) sunlight |= (sunlight<<8) | (sunlight<<16);
+ sunlightcolor = bvec((sunlight>>16)&0xFF, (sunlight>>8)&0xFF, sunlight&0xFF);
+ setupsunlight();
});
FVARFR(sunlightscale, 0, 1, 16, setupsunlight());
vec sunlightdir(0, 0, 1);
@@ -104,25 +104,25 @@ extern void setsunlightdir();
VARFR(sunlightyaw, 0, 0, 360, setsunlightdir());
VARFR(sunlightpitch, -90, 90, 90, setsunlightdir());
-void setsunlightdir()
-{
- sunlightdir = vec(sunlightyaw*RAD, sunlightpitch*RAD);
- loopk(3) if(fabs(sunlightdir[k]) < 1e-5f) sunlightdir[k] = 0;
- sunlightdir.normalize();
- setupsunlight();
+void setsunlightdir()
+{
+ sunlightdir = vec(sunlightyaw*RAD, sunlightpitch*RAD);
+ loopk(3) if(fabs(sunlightdir[k]) < 1e-5f) sunlightdir[k] = 0;
+ sunlightdir.normalize();
+ setupsunlight();
}
entity sunlightent;
void setupsunlight()
{
- memclear(sunlightent);
- sunlightent.type = ET_LIGHT;
- sunlightent.attr1 = 0;
- sunlightent.attr2 = int(sunlightcolor.x*sunlightscale);
- sunlightent.attr3 = int(sunlightcolor.y*sunlightscale);
- sunlightent.attr4 = int(sunlightcolor.z*sunlightscale);
- float dist = min(min(sunlightdir.x ? 1/fabs(sunlightdir.x) : 1e16f, sunlightdir.y ? 1/fabs(sunlightdir.y) : 1e16f), sunlightdir.z ? 1/fabs(sunlightdir.z) : 1e16f);
- sunlightent.o = vec(sunlightdir).mul(dist*worldsize).add(vec(worldsize/2, worldsize/2, worldsize/2));
+ memclear(sunlightent);
+ sunlightent.type = ET_LIGHT;
+ sunlightent.attr1 = 0;
+ sunlightent.attr2 = int(sunlightcolor.x*sunlightscale);
+ sunlightent.attr3 = int(sunlightcolor.y*sunlightscale);
+ sunlightent.attr4 = int(sunlightcolor.z*sunlightscale);
+ float dist = min(min(sunlightdir.x ? 1/fabs(sunlightdir.x) : 1e16f, sunlightdir.y ? 1/fabs(sunlightdir.y) : 1e16f), sunlightdir.z ? 1/fabs(sunlightdir.z) : 1e16f);
+ sunlightent.o = vec(sunlightdir).mul(dist*worldsize).add(vec(worldsize/2, worldsize/2, worldsize/2));
}
VARR(skytexturelight, 0, 1, 1);
@@ -130,97 +130,97 @@ extern int useskytexture;
static const surfaceinfo brightsurfaces[6] =
{
- brightsurface,
- brightsurface,
- brightsurface,
- brightsurface,
- brightsurface,
- brightsurface
+ brightsurface,
+ brightsurface,
+ brightsurface,
+ brightsurface,
+ brightsurface,
+ brightsurface
};
void brightencube(cube &c)
{
- if(!c.ext) newcubeext(c, 0, false);
- memcpy(c.ext->surfaces, brightsurfaces, sizeof(brightsurfaces));
+ if(!c.ext) newcubeext(c, 0, false);
+ memcpy(c.ext->surfaces, brightsurfaces, sizeof(brightsurfaces));
}
void setsurfaces(cube &c, const surfaceinfo *surfs, const vertinfo *verts, int numverts)
{
- if(!c.ext || c.ext->maxverts < numverts) newcubeext(c, numverts, false);
- memcpy(c.ext->surfaces, surfs, sizeof(c.ext->surfaces));
- memcpy(c.ext->verts(), verts, numverts*sizeof(vertinfo));
+ if(!c.ext || c.ext->maxverts < numverts) newcubeext(c, numverts, false);
+ memcpy(c.ext->surfaces, surfs, sizeof(c.ext->surfaces));
+ memcpy(c.ext->verts(), verts, numverts*sizeof(vertinfo));
}
void setsurface(cube &c, int orient, const surfaceinfo &src, const vertinfo *srcverts, int numsrcverts)
{
- int dstoffset = 0;
- if(!c.ext) newcubeext(c, numsrcverts, true);
- else
- {
- int numbefore = 0, beforeoffset = 0;
- loopi(orient)
- {
- surfaceinfo &surf = c.ext->surfaces[i];
- int numverts = surf.totalverts();
- if(!numverts) continue;
- numbefore += numverts;
- beforeoffset = surf.verts + numverts;
- }
- int numafter = 0, afteroffset = c.ext->maxverts;
- for(int i = 5; i > orient; i--)
- {
- surfaceinfo &surf = c.ext->surfaces[i];
- int numverts = surf.totalverts();
- if(!numverts) continue;
- numafter += numverts;
- afteroffset = surf.verts;
- }
- if(afteroffset - beforeoffset >= numsrcverts) dstoffset = beforeoffset;
- else
- {
- cubeext *ext = c.ext;
- if(numbefore + numsrcverts + numafter > c.ext->maxverts)
- {
- ext = growcubeext(c.ext, numbefore + numsrcverts + numafter);
- memcpy(ext->surfaces, c.ext->surfaces, sizeof(ext->surfaces));
- }
- int offset = 0;
- if(numbefore == beforeoffset)
- {
- if(numbefore && c.ext != ext) memcpy(ext->verts(), c.ext->verts(), numbefore*sizeof(vertinfo));
- offset = numbefore;
- }
- else loopi(orient)
- {
- surfaceinfo &surf = ext->surfaces[i];
- int numverts = surf.totalverts();
- if(!numverts) continue;
- memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
- surf.verts = offset;
- offset += numverts;
- }
- dstoffset = offset;
- offset += numsrcverts;
- if(numafter && offset > afteroffset)
- {
- offset += numafter;
- for(int i = 5; i > orient; i--)
- {
- surfaceinfo &surf = ext->surfaces[i];
- int numverts = surf.totalverts();
- if(!numverts) continue;
- offset -= numverts;
- memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
- surf.verts = offset;
- }
- }
- if(c.ext != ext) setcubeext(c, ext);
- }
- }
- surfaceinfo &dst = c.ext->surfaces[orient];
- dst = src;
- dst.verts = dstoffset;
- if(srcverts) memcpy(c.ext->verts() + dstoffset, srcverts, numsrcverts*sizeof(vertinfo));
+ int dstoffset = 0;
+ if(!c.ext) newcubeext(c, numsrcverts, true);
+ else
+ {
+ int numbefore = 0, beforeoffset = 0;
+ loopi(orient)
+ {
+ surfaceinfo &surf = c.ext->surfaces[i];
+ int numverts = surf.totalverts();
+ if(!numverts) continue;
+ numbefore += numverts;
+ beforeoffset = surf.verts + numverts;
+ }
+ int numafter = 0, afteroffset = c.ext->maxverts;
+ for(int i = 5; i > orient; i--)
+ {
+ surfaceinfo &surf = c.ext->surfaces[i];
+ int numverts = surf.totalverts();
+ if(!numverts) continue;
+ numafter += numverts;
+ afteroffset = surf.verts;
+ }
+ if(afteroffset - beforeoffset >= numsrcverts) dstoffset = beforeoffset;
+ else
+ {
+ cubeext *ext = c.ext;
+ if(numbefore + numsrcverts + numafter > c.ext->maxverts)
+ {
+ ext = growcubeext(c.ext, numbefore + numsrcverts + numafter);
+ memcpy(ext->surfaces, c.ext->surfaces, sizeof(ext->surfaces));
+ }
+ int offset = 0;
+ if(numbefore == beforeoffset)
+ {
+ if(numbefore && c.ext != ext) memcpy(ext->verts(), c.ext->verts(), numbefore*sizeof(vertinfo));
+ offset = numbefore;
+ }
+ else loopi(orient)
+ {
+ surfaceinfo &surf = ext->surfaces[i];
+ int numverts = surf.totalverts();
+ if(!numverts) continue;
+ memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
+ surf.verts = offset;
+ offset += numverts;
+ }
+ dstoffset = offset;
+ offset += numsrcverts;
+ if(numafter && offset > afteroffset)
+ {
+ offset += numafter;
+ for(int i = 5; i > orient; i--)
+ {
+ surfaceinfo &surf = ext->surfaces[i];
+ int numverts = surf.totalverts();
+ if(!numverts) continue;
+ offset -= numverts;
+ memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
+ surf.verts = offset;
+ }
+ }
+ if(c.ext != ext) setcubeext(c, ext);
+ }
+ }
+ surfaceinfo &dst = c.ext->surfaces[orient];
+ dst = src;
+ dst.verts = dstoffset;
+ if(srcverts) memcpy(c.ext->verts() + dstoffset, srcverts, numsrcverts*sizeof(vertinfo));
}
// quality parameters, set by the calclight arg
@@ -238,38 +238,38 @@ volatile bool check_calclight_progress = false;
void check_calclight_canceled()
{
- if(interceptkey(SDLK_ESCAPE))
- {
- calclight_canceled = true;
- loopv(lightmapworkers) lightmapworkers[i]->doneworking = true;
- }
- if(!calclight_canceled) check_calclight_progress = false;
+ if(interceptkey(SDLK_ESCAPE))
+ {
+ calclight_canceled = true;
+ loopv(lightmapworkers) lightmapworkers[i]->doneworking = true;
+ }
+ if(!calclight_canceled) check_calclight_progress = false;
}
void show_calclight_progress()
{
- float bar1 = float(progress) / float(allocnodes);
- defformatstring(text1, "%d%% using %d textures", int(bar1 * 100), lightmaps.length());
-
- if(LM_PACKW <= hwtexsize && !progresstex)
- {
- glGenTextures(1, &progresstex);
- createtexture(progresstex, LM_PACKW, LM_PACKH, NULL, 3, 1, GL_RGB);
- }
-
- // only update once a sec (4 * 250 ms ticks) to not kill performance
- if(progresstex && !calclight_canceled && progresslightmap >= 0 && !(progresstexticks++ % 4))
- {
- if(tasklock) SDL_LockMutex(tasklock);
- LightMap &lm = lightmaps[progresslightmap];
- uchar *data = lm.data;
- int bpp = lm.bpp;
- if(tasklock) SDL_UnlockMutex(tasklock);
- glBindTexture(GL_TEXTURE_2D, progresstex);
- glPixelStorei(GL_UNPACK_ALIGNMENT, texalign(data, LM_PACKW, bpp));
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LM_PACKW, LM_PACKH, bpp > 3 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
- }
- renderprogress(bar1, text1, progresstexticks ? progresstex : 0);
+ float bar1 = float(progress) / float(allocnodes);
+ defformatstring(text1, "%d%% using %d textures", int(bar1 * 100), lightmaps.length());
+
+ if(LM_PACKW <= hwtexsize && !progresstex)
+ {
+ glGenTextures(1, &progresstex);
+ createtexture(progresstex, LM_PACKW, LM_PACKH, NULL, 3, 1, GL_RGB);
+ }
+
+ // only update once a sec (4 * 250 ms ticks) to not kill performance
+ if(progresstex && !calclight_canceled && progresslightmap >= 0 && !(progresstexticks++ % 4))
+ {
+ if(tasklock) SDL_LockMutex(tasklock);
+ LightMap &lm = lightmaps[progresslightmap];
+ uchar *data = lm.data;
+ int bpp = lm.bpp;
+ if(tasklock) SDL_UnlockMutex(tasklock);
+ glBindTexture(GL_TEXTURE_2D, progresstex);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, texalign(data, LM_PACKW, bpp));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LM_PACKW, LM_PACKH, bpp > 3 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, data);
+ }
+ renderprogress(bar1, text1, progresstexticks ? progresstex : 0);
}
#define CHECK_PROGRESS_LOCKED(exit, before, after) CHECK_CALCLIGHT_PROGRESS_LOCKED(exit, show_calclight_progress, before, after)
@@ -277,398 +277,398 @@ void show_calclight_progress()
bool PackNode::insert(ushort &tx, ushort &ty, ushort tw, ushort th)
{
- if((available < tw && available < th) || w < tw || h < th)
- return false;
- if(child1)
- {
- bool inserted = child1->insert(tx, ty, tw, th) ||
- child2->insert(tx, ty, tw, th);
- available = max(child1->available, child2->available);
- if(!available) clear();
- return inserted;
- }
- if(w == tw && h == th)
- {
- available = 0;
- tx = x;
- ty = y;
- return true;
- }
-
- if(w - tw > h - th)
- {
- child1 = new PackNode(x, y, tw, h);
- child2 = new PackNode(x + tw, y, w - tw, h);
- }
- else
- {
- child1 = new PackNode(x, y, w, th);
- child2 = new PackNode(x, y + th, w, h - th);
- }
-
- bool inserted = child1->insert(tx, ty, tw, th);
- available = max(child1->available, child2->available);
- return inserted;
+ if((available < tw && available < th) || w < tw || h < th)
+ return false;
+ if(child1)
+ {
+ bool inserted = child1->insert(tx, ty, tw, th) ||
+ child2->insert(tx, ty, tw, th);
+ available = max(child1->available, child2->available);
+ if(!available) clear();
+ return inserted;
+ }
+ if(w == tw && h == th)
+ {
+ available = 0;
+ tx = x;
+ ty = y;
+ return true;
+ }
+
+ if(w - tw > h - th)
+ {
+ child1 = new PackNode(x, y, tw, h);
+ child2 = new PackNode(x + tw, y, w - tw, h);
+ }
+ else
+ {
+ child1 = new PackNode(x, y, w, th);
+ child2 = new PackNode(x, y + th, w, h - th);
+ }
+
+ bool inserted = child1->insert(tx, ty, tw, th);
+ available = max(child1->available, child2->available);
+ return inserted;
}
bool LightMap::insert(ushort &tx, ushort &ty, uchar *src, ushort tw, ushort th)
{
- if((type&LM_TYPE) != LM_BUMPMAP1 && !packroot.insert(tx, ty, tw, th))
- return false;
+ if((type&LM_TYPE) != LM_BUMPMAP1 && !packroot.insert(tx, ty, tw, th))
+ return false;
- copy(tx, ty, src, tw, th);
- return true;
+ copy(tx, ty, src, tw, th);
+ return true;
}
void LightMap::copy(ushort tx, ushort ty, uchar *src, ushort tw, ushort th)
{
- uchar *dst = data + bpp * tx + ty * bpp * LM_PACKW;
- loopi(th)
- {
- memcpy(dst, src, bpp * tw);
- dst += bpp * LM_PACKW;
- src += bpp * tw;
- }
- ++lightmaps;
- lumels += tw * th;
+ uchar *dst = data + bpp * tx + ty * bpp * LM_PACKW;
+ loopi(th)
+ {
+ memcpy(dst, src, bpp * tw);
+ dst += bpp * LM_PACKW;
+ src += bpp * tw;
+ }
+ ++lightmaps;
+ lumels += tw * th;
}
static void insertunlit(int i)
{
- LightMap &l = lightmaps[i];
- if((l.type&LM_TYPE) == LM_BUMPMAP1)
- {
- l.unlitx = l.unlity = -1;
- return;
- }
- ushort x, y;
- uchar unlit[4] = { ambientcolor[0], ambientcolor[1], ambientcolor[2], 255 };
- if(l.insert(x, y, unlit, 1, 1))
- {
- if((l.type&LM_TYPE) == LM_BUMPMAP0)
- {
- bvec front(128, 128, 255);
- ASSERT(lightmaps[i+1].insert(x, y, front.v, 1, 1));
- }
- l.unlitx = x;
- l.unlity = y;
- }
+ LightMap &l = lightmaps[i];
+ if((l.type&LM_TYPE) == LM_BUMPMAP1)
+ {
+ l.unlitx = l.unlity = -1;
+ return;
+ }
+ ushort x, y;
+ uchar unlit[4] = { ambientcolor[0], ambientcolor[1], ambientcolor[2], 255 };
+ if(l.insert(x, y, unlit, 1, 1))
+ {
+ if((l.type&LM_TYPE) == LM_BUMPMAP0)
+ {
+ bvec front(128, 128, 255);
+ ASSERT(lightmaps[i+1].insert(x, y, front.v, 1, 1));
+ }
+ l.unlitx = x;
+ l.unlity = y;
+ }
}
struct layoutinfo
{
- ushort x, y, lmid;
- uchar w, h;
+ ushort x, y, lmid;
+ uchar w, h;
};
static void insertlightmap(lightmapinfo &li, layoutinfo &si)
{
- loopv(lightmaps)
- {
- if(lightmaps[i].type == li.type && lightmaps[i].insert(si.x, si.y, li.colorbuf, si.w, si.h))
- {
- si.lmid = i + LMID_RESERVED;
- if((li.type&LM_TYPE) == LM_BUMPMAP0) ASSERT(lightmaps[i+1].insert(si.x, si.y, (uchar *)li.raybuf, si.w, si.h));
- return;
- }
- }
-
- progresslightmap = lightmaps.length();
-
- si.lmid = lightmaps.length() + LMID_RESERVED;
- LightMap &l = lightmaps.add();
- l.type = li.type;
- l.bpp = li.bpp;
- l.data = new uchar[li.bpp*LM_PACKW*LM_PACKH];
- memset(l.data, 0, li.bpp*LM_PACKW*LM_PACKH);
- ASSERT(l.insert(si.x, si.y, li.colorbuf, si.w, si.h));
- if((li.type&LM_TYPE) == LM_BUMPMAP0)
- {
- LightMap &r = lightmaps.add();
- r.type = LM_BUMPMAP1 | (li.type&~LM_TYPE);
- r.bpp = 3;
- r.data = new uchar[3*LM_PACKW*LM_PACKH];
- memset(r.data, 0, 3*LM_PACKW*LM_PACKH);
- ASSERT(r.insert(si.x, si.y, (uchar *)li.raybuf, si.w, si.h));
- }
+ loopv(lightmaps)
+ {
+ if(lightmaps[i].type == li.type && lightmaps[i].insert(si.x, si.y, li.colorbuf, si.w, si.h))
+ {
+ si.lmid = i + LMID_RESERVED;
+ if((li.type&LM_TYPE) == LM_BUMPMAP0) ASSERT(lightmaps[i+1].insert(si.x, si.y, (uchar *)li.raybuf, si.w, si.h));
+ return;
+ }
+ }
+
+ progresslightmap = lightmaps.length();
+
+ si.lmid = lightmaps.length() + LMID_RESERVED;
+ LightMap &l = lightmaps.add();
+ l.type = li.type;
+ l.bpp = li.bpp;
+ l.data = new uchar[li.bpp*LM_PACKW*LM_PACKH];
+ memset(l.data, 0, li.bpp*LM_PACKW*LM_PACKH);
+ ASSERT(l.insert(si.x, si.y, li.colorbuf, si.w, si.h));
+ if((li.type&LM_TYPE) == LM_BUMPMAP0)
+ {
+ LightMap &r = lightmaps.add();
+ r.type = LM_BUMPMAP1 | (li.type&~LM_TYPE);
+ r.bpp = 3;
+ r.data = new uchar[3*LM_PACKW*LM_PACKH];
+ memset(r.data, 0, 3*LM_PACKW*LM_PACKH);
+ ASSERT(r.insert(si.x, si.y, (uchar *)li.raybuf, si.w, si.h));
+ }
}
static void copylightmap(lightmapinfo &li, layoutinfo &si)
{
- lightmaps[si.lmid-LMID_RESERVED].copy(si.x, si.y, li.colorbuf, si.w, si.h);
- if((li.type&LM_TYPE)==LM_BUMPMAP0 && lightmaps.inrange(si.lmid+1-LMID_RESERVED))
- lightmaps[si.lmid+1-LMID_RESERVED].copy(si.x, si.y, (uchar *)li.raybuf, si.w, si.h);
+ lightmaps[si.lmid-LMID_RESERVED].copy(si.x, si.y, li.colorbuf, si.w, si.h);
+ if((li.type&LM_TYPE)==LM_BUMPMAP0 && lightmaps.inrange(si.lmid+1-LMID_RESERVED))
+ lightmaps[si.lmid+1-LMID_RESERVED].copy(si.x, si.y, (uchar *)li.raybuf, si.w, si.h);
}
static inline bool htcmp(const lightmapinfo &k, const layoutinfo &v)
{
- int kw = k.w, kh = k.h;
- if(kw != v.w || kh != v.h) return false;
- LightMap &vlm = lightmaps[v.lmid - LMID_RESERVED];
- int ktype = k.type;
- if(ktype != vlm.type) return false;
- int kbpp = k.bpp;
- const uchar *kcolor = k.colorbuf, *vcolor = vlm.data + kbpp*(v.x + v.y*LM_PACKW);
- loopi(kh)
- {
- if(memcmp(kcolor, vcolor, kbpp*kw)) return false;
- kcolor += kbpp*kw;
- vcolor += kbpp*LM_PACKW;
- }
- if((ktype&LM_TYPE) != LM_BUMPMAP0) return true;
- const bvec *kdir = k.raybuf, *vdir = (const bvec *)lightmaps[v.lmid+1 - LMID_RESERVED].data + (v.x + v.y*LM_PACKW);
- loopi(kh)
- {
- if(memcmp(kdir, vdir, kw*sizeof(bvec))) return false;
- kdir += kw;
- vdir += LM_PACKW;
- }
- return true;
-}
-
+ int kw = k.w, kh = k.h;
+ if(kw != v.w || kh != v.h) return false;
+ LightMap &vlm = lightmaps[v.lmid - LMID_RESERVED];
+ int ktype = k.type;
+ if(ktype != vlm.type) return false;
+ int kbpp = k.bpp;
+ const uchar *kcolor = k.colorbuf, *vcolor = vlm.data + kbpp*(v.x + v.y*LM_PACKW);
+ loopi(kh)
+ {
+ if(memcmp(kcolor, vcolor, kbpp*kw)) return false;
+ kcolor += kbpp*kw;
+ vcolor += kbpp*LM_PACKW;
+ }
+ if((ktype&LM_TYPE) != LM_BUMPMAP0) return true;
+ const bvec *kdir = k.raybuf, *vdir = (const bvec *)lightmaps[v.lmid+1 - LMID_RESERVED].data + (v.x + v.y*LM_PACKW);
+ loopi(kh)
+ {
+ if(memcmp(kdir, vdir, kw*sizeof(bvec))) return false;
+ kdir += kw;
+ vdir += LM_PACKW;
+ }
+ return true;
+}
+
static inline uint hthash(const lightmapinfo &k)
{
- int kw = k.w, kh = k.h, kbpp = k.bpp;
- uint hash = kw + (kh<<8);
- const uchar *color = k.colorbuf;
- loopi(kw*kh)
- {
- hash ^= color[0] + (color[1] << 4) + (color[2] << 8);
- color += kbpp;
- }
- return hash;
+ int kw = k.w, kh = k.h, kbpp = k.bpp;
+ uint hash = kw + (kh<<8);
+ const uchar *color = k.colorbuf;
+ loopi(kw*kh)
+ {
+ hash ^= color[0] + (color[1] << 4) + (color[2] << 8);
+ color += kbpp;
+ }
+ return hash;
}
static hashset<layoutinfo> compressed;
VAR(lightcompress, 0, 3, 6);
-static bool packlightmap(lightmapinfo &l, layoutinfo &surface)
-{
- surface.w = l.w;
- surface.h = l.h;
- if((int)l.w <= lightcompress && (int)l.h <= lightcompress)
- {
- layoutinfo *val = compressed.access(l);
- if(!val)
- {
- insertlightmap(l, surface);
- compressed[l] = surface;
- }
- else
- {
- surface.x = val->x;
- surface.y = val->y;
- surface.lmid = val->lmid;
- return false;
- }
- }
- else insertlightmap(l, surface);
- return true;
+static bool packlightmap(lightmapinfo &l, layoutinfo &surface)
+{
+ surface.w = l.w;
+ surface.h = l.h;
+ if((int)l.w <= lightcompress && (int)l.h <= lightcompress)
+ {
+ layoutinfo *val = compressed.access(l);
+ if(!val)
+ {
+ insertlightmap(l, surface);
+ compressed[l] = surface;
+ }
+ else
+ {
+ surface.x = val->x;
+ surface.y = val->y;
+ surface.lmid = val->lmid;
+ return false;
+ }
+ }
+ else insertlightmap(l, surface);
+ return true;
}
static void updatelightmap(const layoutinfo &surface)
{
- if(max(LM_PACKW, LM_PACKH) > hwtexsize || !lightmaps.inrange(surface.lmid-LMID_RESERVED)) return;
-
- LightMap &lm = lightmaps[surface.lmid-LMID_RESERVED];
- if(lm.tex < 0)
- {
- lm.offsetx = lm.offsety = 0;
- lm.tex = lightmaptexs.length();
- LightMapTexture &tex = lightmaptexs.add();
- tex.type = lm.type;
- tex.w = LM_PACKW;
- tex.h = LM_PACKH;
- tex.unlitx = lm.unlitx;
- tex.unlity = lm.unlity;
- glGenTextures(1, &tex.id);
- createtexture(tex.id, tex.w, tex.h, NULL, 3, 1, tex.type&LM_ALPHA ? GL_RGBA : GL_RGB);
- if((lm.type&LM_TYPE)==LM_BUMPMAP0 && lightmaps.inrange(surface.lmid+1-LMID_RESERVED))
- {
- LightMap &lm2 = lightmaps[surface.lmid+1-LMID_RESERVED];
- lm2.offsetx = lm2.offsety = 0;
- lm2.tex = lightmaptexs.length();
- LightMapTexture &tex2 = lightmaptexs.add();
- tex2.type = (lm.type&~LM_TYPE) | LM_BUMPMAP0;
- tex2.w = LM_PACKW;
- tex2.h = LM_PACKH;
- tex2.unlitx = lm2.unlitx;
- tex2.unlity = lm2.unlity;
- glGenTextures(1, &tex2.id);
- createtexture(tex2.id, tex2.w, tex2.h, NULL, 3, 1, GL_RGB);
- }
- }
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, LM_PACKW);
-
- glBindTexture(GL_TEXTURE_2D, lightmaptexs[lm.tex].id);
- glTexSubImage2D(GL_TEXTURE_2D, 0, lm.offsetx + surface.x, lm.offsety + surface.y, surface.w, surface.h, lm.type&LM_ALPHA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, &lm.data[(surface.y*LM_PACKW + surface.x)*lm.bpp]);
- if((lm.type&LM_TYPE)==LM_BUMPMAP0 && lightmaps.inrange(surface.lmid+1-LMID_RESERVED))
- {
- LightMap &lm2 = lightmaps[surface.lmid+1-LMID_RESERVED];
- glBindTexture(GL_TEXTURE_2D, lightmaptexs[lm2.tex].id);
- glTexSubImage2D(GL_TEXTURE_2D, 0, lm2.offsetx + surface.x, lm2.offsety + surface.y, surface.w, surface.h, GL_RGB, GL_UNSIGNED_BYTE, &lm2.data[(surface.y*LM_PACKW + surface.x)*3]);
- }
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-}
-
-
+ if(max(LM_PACKW, LM_PACKH) > hwtexsize || !lightmaps.inrange(surface.lmid-LMID_RESERVED)) return;
+
+ LightMap &lm = lightmaps[surface.lmid-LMID_RESERVED];
+ if(lm.tex < 0)
+ {
+ lm.offsetx = lm.offsety = 0;
+ lm.tex = lightmaptexs.length();
+ LightMapTexture &tex = lightmaptexs.add();
+ tex.type = lm.type;
+ tex.w = LM_PACKW;
+ tex.h = LM_PACKH;
+ tex.unlitx = lm.unlitx;
+ tex.unlity = lm.unlity;
+ glGenTextures(1, &tex.id);
+ createtexture(tex.id, tex.w, tex.h, NULL, 3, 1, tex.type&LM_ALPHA ? GL_RGBA : GL_RGB);
+ if((lm.type&LM_TYPE)==LM_BUMPMAP0 && lightmaps.inrange(surface.lmid+1-LMID_RESERVED))
+ {
+ LightMap &lm2 = lightmaps[surface.lmid+1-LMID_RESERVED];
+ lm2.offsetx = lm2.offsety = 0;
+ lm2.tex = lightmaptexs.length();
+ LightMapTexture &tex2 = lightmaptexs.add();
+ tex2.type = (lm.type&~LM_TYPE) | LM_BUMPMAP0;
+ tex2.w = LM_PACKW;
+ tex2.h = LM_PACKH;
+ tex2.unlitx = lm2.unlitx;
+ tex2.unlity = lm2.unlity;
+ glGenTextures(1, &tex2.id);
+ createtexture(tex2.id, tex2.w, tex2.h, NULL, 3, 1, GL_RGB);
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, LM_PACKW);
+
+ glBindTexture(GL_TEXTURE_2D, lightmaptexs[lm.tex].id);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, lm.offsetx + surface.x, lm.offsety + surface.y, surface.w, surface.h, lm.type&LM_ALPHA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, &lm.data[(surface.y*LM_PACKW + surface.x)*lm.bpp]);
+ if((lm.type&LM_TYPE)==LM_BUMPMAP0 && lightmaps.inrange(surface.lmid+1-LMID_RESERVED))
+ {
+ LightMap &lm2 = lightmaps[surface.lmid+1-LMID_RESERVED];
+ glBindTexture(GL_TEXTURE_2D, lightmaptexs[lm2.tex].id);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, lm2.offsetx + surface.x, lm2.offsety + surface.y, surface.w, surface.h, GL_RGB, GL_UNSIGNED_BYTE, &lm2.data[(surface.y*LM_PACKW + surface.x)*3]);
+ }
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+}
+
+
static uint generatelumel(lightmapworker *w, const float tolerance, uint lightmask, const vector<const extentity *> &lights, const vec &target, const vec &normal, vec &sample, int x, int y)
{
- vec avgray(0, 0, 0);
- float r = 0, g = 0, b = 0;
- uint lightused = 0;
- loopv(lights)
- {
- if(lightmask&(1<<i)) continue;
- const extentity &light = *lights[i];
- vec ray = target;
- ray.sub(light.o);
- float mag = ray.magnitude();
- if(!mag) continue;
- float attenuation = 1;
- if(light.attr1)
- {
- attenuation -= mag / float(light.attr1);
- if(attenuation <= 0) continue;
- }
- ray.mul(1.0f / mag);
- float angle = -ray.dot(normal);
- if(angle <= 0) continue;
- if(light.attached && light.attached->type==ET_SPOTLIGHT)
- {
- vec spot = vec(light.attached->o).sub(light.o).normalize();
- float maxatten = sincos360[clamp(int(light.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
- if(spotatten <= 0) continue;
- attenuation *= spotatten;
- }
- if(lmshadows && mag)
- {
- float dist = shadowray(w->shadowraycache, light.o, ray, mag - tolerance, RAY_SHADOW | (lmshadows > 1 ? RAY_ALPHAPOLY : 0));
- if(dist < mag - tolerance) continue;
- }
- lightused |= 1<<i;
- float intensity;
- switch(w->type&LM_TYPE)
- {
- case LM_BUMPMAP0:
- intensity = attenuation;
- avgray.add(ray.mul(-attenuation));
- break;
- default:
- intensity = angle * attenuation;
- break;
- }
- r += intensity * float(light.attr2);
- g += intensity * float(light.attr3);
- b += intensity * float(light.attr4);
- }
- if(sunlight)
- {
- float angle = sunlightdir.dot(normal);
- if(angle > 0 &&
- (!lmshadows ||
- shadowray(w->shadowraycache, vec(sunlightdir).mul(tolerance).add(target), sunlightdir, 1e16f, RAY_SHADOW | (lmshadows > 1 ? RAY_ALPHAPOLY : 0) | (skytexturelight ? RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0) : 0)) > 1e15f))
- {
- float intensity;
- switch(w->type&LM_TYPE)
- {
- case LM_BUMPMAP0:
- intensity = 1;
- avgray.add(sunlightdir);
- break;
- default:
- intensity = angle;
- break;
- }
- r += intensity * (sunlightcolor.x*sunlightscale);
- g += intensity * (sunlightcolor.y*sunlightscale);
- b += intensity * (sunlightcolor.z*sunlightscale);
- }
- }
- switch(w->type&LM_TYPE)
- {
- case LM_BUMPMAP0:
- if(avgray.iszero()) break;
- // transform to tangent space
- extern const vec orientation_tangent[8][3];
- extern const vec orientation_bitangent[8][3];
- vec S(orientation_tangent[w->rotate][dimension(w->orient)]),
- T(orientation_bitangent[w->rotate][dimension(w->orient)]);
- normal.orthonormalize(S, T);
- avgray.normalize();
- w->raydata[y*w->w+x].add(vec(S.dot(avgray)/S.magnitude(), T.dot(avgray)/T.magnitude(), normal.dot(avgray)));
- break;
- }
- sample.x = min(255.0f, max(r, float(ambientcolor[0])));
- sample.y = min(255.0f, max(g, float(ambientcolor[1])));
- sample.z = min(255.0f, max(b, float(ambientcolor[2])));
- return lightused;
+ vec avgray(0, 0, 0);
+ float r = 0, g = 0, b = 0;
+ uint lightused = 0;
+ loopv(lights)
+ {
+ if(lightmask&(1<<i)) continue;
+ const extentity &light = *lights[i];
+ vec ray = target;
+ ray.sub(light.o);
+ float mag = ray.magnitude();
+ if(!mag) continue;
+ float attenuation = 1;
+ if(light.attr1)
+ {
+ attenuation -= mag / float(light.attr1);
+ if(attenuation <= 0) continue;
+ }
+ ray.mul(1.0f / mag);
+ float angle = -ray.dot(normal);
+ if(angle <= 0) continue;
+ if(light.attached && light.attached->type==ET_SPOTLIGHT)
+ {
+ vec spot = vec(light.attached->o).sub(light.o).normalize();
+ float maxatten = sincos360[clamp(int(light.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
+ if(spotatten <= 0) continue;
+ attenuation *= spotatten;
+ }
+ if(lmshadows && mag)
+ {
+ float dist = shadowray(w->shadowraycache, light.o, ray, mag - tolerance, RAY_SHADOW | (lmshadows > 1 ? RAY_ALPHAPOLY : 0));
+ if(dist < mag - tolerance) continue;
+ }
+ lightused |= 1<<i;
+ float intensity;
+ switch(w->type&LM_TYPE)
+ {
+ case LM_BUMPMAP0:
+ intensity = attenuation;
+ avgray.add(ray.mul(-attenuation));
+ break;
+ default:
+ intensity = angle * attenuation;
+ break;
+ }
+ r += intensity * float(light.attr2);
+ g += intensity * float(light.attr3);
+ b += intensity * float(light.attr4);
+ }
+ if(sunlight)
+ {
+ float angle = sunlightdir.dot(normal);
+ if(angle > 0 &&
+ (!lmshadows ||
+ shadowray(w->shadowraycache, vec(sunlightdir).mul(tolerance).add(target), sunlightdir, 1e16f, RAY_SHADOW | (lmshadows > 1 ? RAY_ALPHAPOLY : 0) | (skytexturelight ? RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0) : 0)) > 1e15f))
+ {
+ float intensity;
+ switch(w->type&LM_TYPE)
+ {
+ case LM_BUMPMAP0:
+ intensity = 1;
+ avgray.add(sunlightdir);
+ break;
+ default:
+ intensity = angle;
+ break;
+ }
+ r += intensity * (sunlightcolor.x*sunlightscale);
+ g += intensity * (sunlightcolor.y*sunlightscale);
+ b += intensity * (sunlightcolor.z*sunlightscale);
+ }
+ }
+ switch(w->type&LM_TYPE)
+ {
+ case LM_BUMPMAP0:
+ if(avgray.iszero()) break;
+ // transform to tangent space
+ extern const vec orientation_tangent[8][3];
+ extern const vec orientation_bitangent[8][3];
+ vec S(orientation_tangent[w->rotate][dimension(w->orient)]),
+ T(orientation_bitangent[w->rotate][dimension(w->orient)]);
+ normal.orthonormalize(S, T);
+ avgray.normalize();
+ w->raydata[y*w->w+x].add(vec(S.dot(avgray)/S.magnitude(), T.dot(avgray)/T.magnitude(), normal.dot(avgray)));
+ break;
+ }
+ sample.x = min(255.0f, max(r, float(ambientcolor[0])));
+ sample.y = min(255.0f, max(g, float(ambientcolor[1])));
+ sample.z = min(255.0f, max(b, float(ambientcolor[2])));
+ return lightused;
}
static bool lumelsample(const vec &sample, int aasample, int stride)
{
- if(sample.x >= int(ambientcolor[0])+1 || sample.y >= int(ambientcolor[1])+1 || sample.z >= int(ambientcolor[2])+1) return true;
+ if(sample.x >= int(ambientcolor[0])+1 || sample.y >= int(ambientcolor[1])+1 || sample.z >= int(ambientcolor[2])+1) return true;
#define NCHECK(n) \
- if((n).x >= int(ambientcolor[0])+1 || (n).y >= int(ambientcolor[1])+1 || (n).z >= int(ambientcolor[2])+1) \
- return true;
- const vec *n = &sample - stride - aasample;
- NCHECK(n[0]); NCHECK(n[aasample]); NCHECK(n[2*aasample]);
- n += stride;
- NCHECK(n[0]); NCHECK(n[2*aasample]);
- n += stride;
- NCHECK(n[0]); NCHECK(n[aasample]); NCHECK(n[2*aasample]);
- return false;
+ if((n).x >= int(ambientcolor[0])+1 || (n).y >= int(ambientcolor[1])+1 || (n).z >= int(ambientcolor[2])+1) \
+ return true;
+ const vec *n = &sample - stride - aasample;
+ NCHECK(n[0]); NCHECK(n[aasample]); NCHECK(n[2*aasample]);
+ n += stride;
+ NCHECK(n[0]); NCHECK(n[2*aasample]);
+ n += stride;
+ NCHECK(n[0]); NCHECK(n[aasample]); NCHECK(n[2*aasample]);
+ return false;
}
static void calcskylight(lightmapworker *w, const vec &o, const vec &normal, float tolerance, uchar *skylight, int flags = RAY_ALPHAPOLY, extentity *t = NULL)
{
- static const vec rays[17] =
- {
- vec(cosf(21*RAD)*cosf(50*RAD), sinf(21*RAD)*cosf(50*RAD), sinf(50*RAD)),
- vec(cosf(111*RAD)*cosf(50*RAD), sinf(111*RAD)*cosf(50*RAD), sinf(50*RAD)),
- vec(cosf(201*RAD)*cosf(50*RAD), sinf(201*RAD)*cosf(50*RAD), sinf(50*RAD)),
- vec(cosf(291*RAD)*cosf(50*RAD), sinf(291*RAD)*cosf(50*RAD), sinf(50*RAD)),
-
- vec(cosf(66*RAD)*cosf(70*RAD), sinf(66*RAD)*cosf(70*RAD), sinf(70*RAD)),
- vec(cosf(156*RAD)*cosf(70*RAD), sinf(156*RAD)*cosf(70*RAD), sinf(70*RAD)),
- vec(cosf(246*RAD)*cosf(70*RAD), sinf(246*RAD)*cosf(70*RAD), sinf(70*RAD)),
- vec(cosf(336*RAD)*cosf(70*RAD), sinf(336*RAD)*cosf(70*RAD), sinf(70*RAD)),
-
- vec(0, 0, 1),
-
- vec(cosf(43*RAD)*cosf(60*RAD), sinf(43*RAD)*cosf(60*RAD), sinf(60*RAD)),
- vec(cosf(133*RAD)*cosf(60*RAD), sinf(133*RAD)*cosf(60*RAD), sinf(60*RAD)),
- vec(cosf(223*RAD)*cosf(60*RAD), sinf(223*RAD)*cosf(60*RAD), sinf(60*RAD)),
- vec(cosf(313*RAD)*cosf(60*RAD), sinf(313*RAD)*cosf(60*RAD), sinf(60*RAD)),
-
- vec(cosf(88*RAD)*cosf(80*RAD), sinf(88*RAD)*cosf(80*RAD), sinf(80*RAD)),
- vec(cosf(178*RAD)*cosf(80*RAD), sinf(178*RAD)*cosf(80*RAD), sinf(80*RAD)),
- vec(cosf(268*RAD)*cosf(80*RAD), sinf(268*RAD)*cosf(80*RAD), sinf(80*RAD)),
- vec(cosf(358*RAD)*cosf(80*RAD), sinf(358*RAD)*cosf(80*RAD), sinf(80*RAD)),
-
- };
- flags |= RAY_SHADOW;
- if(skytexturelight) flags |= RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0);
- int hit = 0;
- if(w) loopi(17)
- {
- if(normal.dot(rays[i])>=0 && shadowray(w->shadowraycache, vec(rays[i]).mul(tolerance).add(o), rays[i], 1e16f, flags, t)>1e15f) hit++;
- }
- else loopi(17)
- {
- if(normal.dot(rays[i])>=0 && shadowray(vec(rays[i]).mul(tolerance).add(o), rays[i], 1e16f, flags, t)>1e15f) hit++;
- }
-
- loopk(3) skylight[k] = uchar(ambientcolor[k] + (max(skylightcolor[k], ambientcolor[k]) - ambientcolor[k])*hit/17.0f);
+ static const vec rays[17] =
+ {
+ vec(cosf(21*RAD)*cosf(50*RAD), sinf(21*RAD)*cosf(50*RAD), sinf(50*RAD)),
+ vec(cosf(111*RAD)*cosf(50*RAD), sinf(111*RAD)*cosf(50*RAD), sinf(50*RAD)),
+ vec(cosf(201*RAD)*cosf(50*RAD), sinf(201*RAD)*cosf(50*RAD), sinf(50*RAD)),
+ vec(cosf(291*RAD)*cosf(50*RAD), sinf(291*RAD)*cosf(50*RAD), sinf(50*RAD)),
+
+ vec(cosf(66*RAD)*cosf(70*RAD), sinf(66*RAD)*cosf(70*RAD), sinf(70*RAD)),
+ vec(cosf(156*RAD)*cosf(70*RAD), sinf(156*RAD)*cosf(70*RAD), sinf(70*RAD)),
+ vec(cosf(246*RAD)*cosf(70*RAD), sinf(246*RAD)*cosf(70*RAD), sinf(70*RAD)),
+ vec(cosf(336*RAD)*cosf(70*RAD), sinf(336*RAD)*cosf(70*RAD), sinf(70*RAD)),
+
+ vec(0, 0, 1),
+
+ vec(cosf(43*RAD)*cosf(60*RAD), sinf(43*RAD)*cosf(60*RAD), sinf(60*RAD)),
+ vec(cosf(133*RAD)*cosf(60*RAD), sinf(133*RAD)*cosf(60*RAD), sinf(60*RAD)),
+ vec(cosf(223*RAD)*cosf(60*RAD), sinf(223*RAD)*cosf(60*RAD), sinf(60*RAD)),
+ vec(cosf(313*RAD)*cosf(60*RAD), sinf(313*RAD)*cosf(60*RAD), sinf(60*RAD)),
+
+ vec(cosf(88*RAD)*cosf(80*RAD), sinf(88*RAD)*cosf(80*RAD), sinf(80*RAD)),
+ vec(cosf(178*RAD)*cosf(80*RAD), sinf(178*RAD)*cosf(80*RAD), sinf(80*RAD)),
+ vec(cosf(268*RAD)*cosf(80*RAD), sinf(268*RAD)*cosf(80*RAD), sinf(80*RAD)),
+ vec(cosf(358*RAD)*cosf(80*RAD), sinf(358*RAD)*cosf(80*RAD), sinf(80*RAD)),
+
+ };
+ flags |= RAY_SHADOW;
+ if(skytexturelight) flags |= RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0);
+ int hit = 0;
+ if(w) loopi(17)
+ {
+ if(normal.dot(rays[i])>=0 && shadowray(w->shadowraycache, vec(rays[i]).mul(tolerance).add(o), rays[i], 1e16f, flags, t)>1e15f) hit++;
+ }
+ else loopi(17)
+ {
+ if(normal.dot(rays[i])>=0 && shadowray(vec(rays[i]).mul(tolerance).add(o), rays[i], 1e16f, flags, t)>1e15f) hit++;
+ }
+
+ loopk(3) skylight[k] = uchar(ambientcolor[k] + (max(skylightcolor[k], ambientcolor[k]) - ambientcolor[k])*hit/17.0f);
}
static inline bool hasskylight()
{
- return skylightcolor[0]>ambientcolor[0] || skylightcolor[1]>ambientcolor[1] || skylightcolor[2]>ambientcolor[2];
+ return skylightcolor[0]>ambientcolor[0] || skylightcolor[1]>ambientcolor[1] || skylightcolor[2]>ambientcolor[2];
}
VARR(blurlms, 0, 0, 2);
@@ -676,45 +676,45 @@ VARR(blurskylight, 0, 0, 2);
static inline void generatealpha(lightmapworker *w, float tolerance, const vec &pos, uchar &alpha)
{
- alpha = lookupblendmap(w->blendmapcache, pos);
- if(w->slot->layermask)
- {
- static const int sdim[] = { 1, 0, 0 }, tdim[] = { 2, 2, 1 };
- int dim = dimension(w->orient);
- float k = 8.0f/w->vslot->scale,
- s = (pos[sdim[dim]] * k - w->vslot->offset.y) / w->slot->layermaskscale,
- t = (pos[tdim[dim]] * (dim <= 1 ? -k : k) - w->vslot->offset.y) / w->slot->layermaskscale;
- const texrotation &r = texrotations[w->rotate];
- if(r.swapxy) swap(s, t);
- if(r.flipx) s = -s;
- if(r.flipy) t = -t;
- const ImageData &mask = *w->slot->layermask;
- int mx = int(floor(s))%mask.w, my = int(floor(t))%mask.h;
- if(mx < 0) mx += mask.w;
- if(my < 0) my += mask.h;
- uchar maskval = mask.data[mask.bpp*(mx + 1) - 1 + mask.pitch*my];
- switch(w->slot->layermaskmode)
- {
- case 2: alpha = min(alpha, maskval); break;
- case 3: alpha = max(alpha, maskval); break;
- case 4: alpha = min(alpha, uchar(0xFF - maskval)); break;
- case 5: alpha = max(alpha, uchar(0xFF - maskval)); break;
- default: alpha = maskval; break;
- }
- }
-}
-
+ alpha = lookupblendmap(w->blendmapcache, pos);
+ if(w->slot->layermask)
+ {
+ static const int sdim[] = { 1, 0, 0 }, tdim[] = { 2, 2, 1 };
+ int dim = dimension(w->orient);
+ float k = 8.0f/w->vslot->scale,
+ s = (pos[sdim[dim]] * k - w->vslot->offset.y) / w->slot->layermaskscale,
+ t = (pos[tdim[dim]] * (dim <= 1 ? -k : k) - w->vslot->offset.y) / w->slot->layermaskscale;
+ const texrotation &r = texrotations[w->rotate];
+ if(r.swapxy) swap(s, t);
+ if(r.flipx) s = -s;
+ if(r.flipy) t = -t;
+ const ImageData &mask = *w->slot->layermask;
+ int mx = int(floor(s))%mask.w, my = int(floor(t))%mask.h;
+ if(mx < 0) mx += mask.w;
+ if(my < 0) my += mask.h;
+ uchar maskval = mask.data[mask.bpp*(mx + 1) - 1 + mask.pitch*my];
+ switch(w->slot->layermaskmode)
+ {
+ case 2: alpha = min(alpha, maskval); break;
+ case 3: alpha = max(alpha, maskval); break;
+ case 4: alpha = min(alpha, uchar(0xFF - maskval)); break;
+ case 5: alpha = max(alpha, uchar(0xFF - maskval)); break;
+ default: alpha = maskval; break;
+ }
+ }
+}
+
VAR(edgetolerance, 1, 4, 64);
VAR(adaptivesample, 0, 2, 2);
enum
{
- NO_SURFACE = 0,
- SURFACE_AMBIENT_BOTTOM,
- SURFACE_AMBIENT_TOP,
- SURFACE_LIGHTMAP_BOTTOM,
- SURFACE_LIGHTMAP_TOP,
- SURFACE_LIGHTMAP_BLEND
+ NO_SURFACE = 0,
+ SURFACE_AMBIENT_BOTTOM,
+ SURFACE_AMBIENT_TOP,
+ SURFACE_LIGHTMAP_BOTTOM,
+ SURFACE_LIGHTMAP_TOP,
+ SURFACE_LIGHTMAP_BLEND
};
#define SURFACE_AMBIENT SURFACE_AMBIENT_BOTTOM
@@ -722,316 +722,316 @@ enum
static bool generatelightmap(lightmapworker *w, float lpu, const lerpvert *lv, int numv, vec origin1, const vec &xstep1, const vec &ystep1, vec origin2, const vec &xstep2, const vec &ystep2, float side0, float sidestep)
{
- static const float aacoords[8][2] =
- {
- {0.0f, 0.0f},
- {-0.5f, -0.5f},
- {0.0f, -0.5f},
- {-0.5f, 0.0f},
-
- {0.3f, -0.6f},
- {0.6f, 0.3f},
- {-0.3f, 0.6f},
- {-0.6f, -0.3f},
- };
- float tolerance = 0.5 / lpu;
- uint lightmask = 0, lightused = 0;
- vec offsets1[8], offsets2[8];
- loopi(8)
- {
- offsets1[i] = vec(xstep1).mul(aacoords[i][0]).add(vec(ystep1).mul(aacoords[i][1]));
- offsets2[i] = vec(xstep2).mul(aacoords[i][0]).add(vec(ystep2).mul(aacoords[i][1]));
- }
- if((w->type&LM_TYPE) == LM_BUMPMAP0) memclear(w->raydata, (LM_MAXW + 4)*(LM_MAXH + 4));
-
- origin1.sub(vec(ystep1).add(xstep1).mul(blurlms));
- origin2.sub(vec(ystep2).add(xstep2).mul(blurlms));
-
- int aasample = min(1 << lmaa, 4);
- int stride = aasample*(w->w+1);
- vec *sample = w->colordata;
- uchar *skylight = w->ambient;
- lerpbounds start, end;
- initlerpbounds(-blurlms, -blurlms, lv, numv, start, end);
- float sidex = side0 + blurlms*sidestep;
- for(int y = 0; y < w->h; ++y, sidex += sidestep)
- {
- vec normal, nstep;
- lerpnormal(-blurlms, y - blurlms, lv, numv, start, end, normal, nstep);
-
- for(int x = 0; x < w->w; ++x, normal.add(nstep), skylight += w->bpp)
- {
+ static const float aacoords[8][2] =
+ {
+ {0.0f, 0.0f},
+ {-0.5f, -0.5f},
+ {0.0f, -0.5f},
+ {-0.5f, 0.0f},
+
+ {0.3f, -0.6f},
+ {0.6f, 0.3f},
+ {-0.3f, 0.6f},
+ {-0.6f, -0.3f},
+ };
+ float tolerance = 0.5 / lpu;
+ uint lightmask = 0, lightused = 0;
+ vec offsets1[8], offsets2[8];
+ loopi(8)
+ {
+ offsets1[i] = vec(xstep1).mul(aacoords[i][0]).add(vec(ystep1).mul(aacoords[i][1]));
+ offsets2[i] = vec(xstep2).mul(aacoords[i][0]).add(vec(ystep2).mul(aacoords[i][1]));
+ }
+ if((w->type&LM_TYPE) == LM_BUMPMAP0) memclear(w->raydata, (LM_MAXW + 4)*(LM_MAXH + 4));
+
+ origin1.sub(vec(ystep1).add(xstep1).mul(blurlms));
+ origin2.sub(vec(ystep2).add(xstep2).mul(blurlms));
+
+ int aasample = min(1 << lmaa, 4);
+ int stride = aasample*(w->w+1);
+ vec *sample = w->colordata;
+ uchar *skylight = w->ambient;
+ lerpbounds start, end;
+ initlerpbounds(-blurlms, -blurlms, lv, numv, start, end);
+ float sidex = side0 + blurlms*sidestep;
+ for(int y = 0; y < w->h; ++y, sidex += sidestep)
+ {
+ vec normal, nstep;
+ lerpnormal(-blurlms, y - blurlms, lv, numv, start, end, normal, nstep);
+
+ for(int x = 0; x < w->w; ++x, normal.add(nstep), skylight += w->bpp)
+ {
#define EDGE_TOLERANCE(x, y) \
- (x < blurlms \
- || x+1 > w->w - blurlms \
- || y < blurlms \
- || y+1 > w->h - blurlms \
- ? edgetolerance : 1)
- float t = EDGE_TOLERANCE(x, y) * tolerance;
- vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
- lightused |= generatelumel(w, t, 0, w->lights, u, vec(normal).normalize(), *sample, x, y);
- if(hasskylight())
- {
- if((w->type&LM_TYPE)==LM_BUMPMAP0 || !adaptivesample || sample->x<skylightcolor[0] || sample->y<skylightcolor[1] || sample->z<skylightcolor[2])
- calcskylight(w, u, normal, t, skylight, lmshadows > 1 ? RAY_ALPHAPOLY : 0);
- else loopk(3) skylight[k] = max(skylightcolor[k], ambientcolor[k]);
- }
- else loopk(3) skylight[k] = ambientcolor[k];
- if(w->type&LM_ALPHA) generatealpha(w, t, u, skylight[3]);
- sample += aasample;
- }
- sample += aasample;
- }
- if(adaptivesample > 1 && min(w->w, w->h) >= 2) lightmask = ~lightused;
- sample = w->colordata;
- initlerpbounds(-blurlms, -blurlms, lv, numv, start, end);
- sidex = side0 + blurlms*sidestep;
- for(int y = 0; y < w->h; ++y, sidex += sidestep)
- {
- vec normal, nstep;
- lerpnormal(-blurlms, y - blurlms, lv, numv, start, end, normal, nstep);
-
- for(int x = 0; x < w->w; ++x, normal.add(nstep))
- {
- vec &center = *sample++;
- if(adaptivesample && x > 0 && x+1 < w->w && y > 0 && y+1 < w->h && !lumelsample(center, aasample, stride))
- loopi(aasample-1) *sample++ = center;
- else
- {
+ (x < blurlms \
+ || x+1 > w->w - blurlms \
+ || y < blurlms \
+ || y+1 > w->h - blurlms \
+ ? edgetolerance : 1)
+ float t = EDGE_TOLERANCE(x, y) * tolerance;
+ vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
+ lightused |= generatelumel(w, t, 0, w->lights, u, vec(normal).normalize(), *sample, x, y);
+ if(hasskylight())
+ {
+ if((w->type&LM_TYPE)==LM_BUMPMAP0 || !adaptivesample || sample->x<skylightcolor[0] || sample->y<skylightcolor[1] || sample->z<skylightcolor[2])
+ calcskylight(w, u, normal, t, skylight, lmshadows > 1 ? RAY_ALPHAPOLY : 0);
+ else loopk(3) skylight[k] = max(skylightcolor[k], ambientcolor[k]);
+ }
+ else loopk(3) skylight[k] = ambientcolor[k];
+ if(w->type&LM_ALPHA) generatealpha(w, t, u, skylight[3]);
+ sample += aasample;
+ }
+ sample += aasample;
+ }
+ if(adaptivesample > 1 && min(w->w, w->h) >= 2) lightmask = ~lightused;
+ sample = w->colordata;
+ initlerpbounds(-blurlms, -blurlms, lv, numv, start, end);
+ sidex = side0 + blurlms*sidestep;
+ for(int y = 0; y < w->h; ++y, sidex += sidestep)
+ {
+ vec normal, nstep;
+ lerpnormal(-blurlms, y - blurlms, lv, numv, start, end, normal, nstep);
+
+ for(int x = 0; x < w->w; ++x, normal.add(nstep))
+ {
+ vec &center = *sample++;
+ if(adaptivesample && x > 0 && x+1 < w->w && y > 0 && y+1 < w->h && !lumelsample(center, aasample, stride))
+ loopi(aasample-1) *sample++ = center;
+ else
+ {
#define AA_EDGE_TOLERANCE(x, y, i) EDGE_TOLERANCE(x + aacoords[i][0], y + aacoords[i][1])
- vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
- const vec *offsets = x < sidex ? offsets1 : offsets2;
- vec n = vec(normal).normalize();
- loopi(aasample-1)
- generatelumel(w, AA_EDGE_TOLERANCE(x, y, i+1) * tolerance, lightmask, w->lights, vec(u).add(offsets[i+1]), n, *sample++, x, y);
- if(lmaa == 3)
- {
- loopi(4)
- {
- vec s;
- generatelumel(w, AA_EDGE_TOLERANCE(x, y, i+4) * tolerance, lightmask, w->lights, vec(u).add(offsets[i+4]), n, s, x, y);
- center.add(s);
- }
- center.div(5);
- }
- }
- }
- if(aasample > 1)
- {
- vec u = w->w < sidex ? vec(xstep1).mul(w->w).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(w->w).add(vec(ystep2).mul(y)).add(origin2);
- const vec *offsets = w->w < sidex ? offsets1 : offsets2;
- vec n = vec(normal).normalize();
- generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[1]), n, sample[1], w->w-1, y);
- if(aasample > 2)
- generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[3]), n, sample[3], w->w-1, y);
- }
- sample += aasample;
- }
-
- if(aasample > 1)
- {
- vec normal, nstep;
- lerpnormal(-blurlms, w->h - blurlms, lv, numv, start, end, normal, nstep);
-
- for(int x = 0; x <= w->w; ++x, normal.add(nstep))
- {
- vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(w->h)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(w->h)).add(origin2);
- const vec *offsets = x < sidex ? offsets1 : offsets2;
- vec n = vec(normal).normalize();
- generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[1]), n, sample[1], min(x, w->w-1), w->h-1);
- if(aasample > 2)
- generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[2]), n, sample[2], min(x, w->w-1), w->h-1);
- sample += aasample;
- }
- }
- return true;
-}
-
+ vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
+ const vec *offsets = x < sidex ? offsets1 : offsets2;
+ vec n = vec(normal).normalize();
+ loopi(aasample-1)
+ generatelumel(w, AA_EDGE_TOLERANCE(x, y, i+1) * tolerance, lightmask, w->lights, vec(u).add(offsets[i+1]), n, *sample++, x, y);
+ if(lmaa == 3)
+ {
+ loopi(4)
+ {
+ vec s;
+ generatelumel(w, AA_EDGE_TOLERANCE(x, y, i+4) * tolerance, lightmask, w->lights, vec(u).add(offsets[i+4]), n, s, x, y);
+ center.add(s);
+ }
+ center.div(5);
+ }
+ }
+ }
+ if(aasample > 1)
+ {
+ vec u = w->w < sidex ? vec(xstep1).mul(w->w).add(vec(ystep1).mul(y)).add(origin1) : vec(xstep2).mul(w->w).add(vec(ystep2).mul(y)).add(origin2);
+ const vec *offsets = w->w < sidex ? offsets1 : offsets2;
+ vec n = vec(normal).normalize();
+ generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[1]), n, sample[1], w->w-1, y);
+ if(aasample > 2)
+ generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[3]), n, sample[3], w->w-1, y);
+ }
+ sample += aasample;
+ }
+
+ if(aasample > 1)
+ {
+ vec normal, nstep;
+ lerpnormal(-blurlms, w->h - blurlms, lv, numv, start, end, normal, nstep);
+
+ for(int x = 0; x <= w->w; ++x, normal.add(nstep))
+ {
+ vec u = x < sidex ? vec(xstep1).mul(x).add(vec(ystep1).mul(w->h)).add(origin1) : vec(xstep2).mul(x).add(vec(ystep2).mul(w->h)).add(origin2);
+ const vec *offsets = x < sidex ? offsets1 : offsets2;
+ vec n = vec(normal).normalize();
+ generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[1]), n, sample[1], min(x, w->w-1), w->h-1);
+ if(aasample > 2)
+ generatelumel(w, edgetolerance * tolerance, lightmask, w->lights, vec(u).add(offsets[2]), n, sample[2], min(x, w->w-1), w->h-1);
+ sample += aasample;
+ }
+ }
+ return true;
+}
+
static int finishlightmap(lightmapworker *w)
-{
- if(hasskylight() && blurskylight && (w->w>1 || w->h>1))
- {
- blurtexture(blurskylight, w->bpp, w->w, w->h, w->blur, w->ambient);
- swap(w->blur, w->ambient);
- }
- vec *sample = w->colordata;
- int aasample = min(1 << lmaa, 4), stride = aasample*(w->w+1);
- float weight = 1.0f / (1.0f + 4.0f*lmaa),
- cweight = weight * (lmaa == 3 ? 5.0f : 1.0f);
- uchar *skylight = w->ambient;
- vec *ray = w->raydata;
- uchar *dstcolor = blurlms && (w->w > 1 || w->h > 1) ? w->blur : w->colorbuf;
- uchar mincolor[4] = { 255, 255, 255, 255 }, maxcolor[4] = { 0, 0, 0, 0 };
- bvec *dstray = blurlms && (w->w > 1 || w->h > 1) ? (bvec *)w->raydata : w->raybuf;
- bvec minray(255, 255, 255), maxray(0, 0, 0);
- loop(y, w->h)
- {
- loop(x, w->w)
- {
- vec l(0, 0, 0);
- const vec &center = *sample++;
- loopi(aasample-1) l.add(*sample++);
- if(aasample > 1)
- {
- l.add(sample[1]);
- if(aasample > 2) l.add(sample[3]);
- }
- vec *next = sample + stride - aasample;
- if(aasample > 1)
- {
- l.add(next[1]);
- if(aasample > 2) l.add(next[2]);
- l.add(next[aasample+1]);
- }
-
- int r = int(center.x*cweight + l.x*weight),
- g = int(center.y*cweight + l.y*weight),
- b = int(center.z*cweight + l.z*weight),
- ar = skylight[0], ag = skylight[1], ab = skylight[2];
- dstcolor[0] = max(ar, r);
- dstcolor[1] = max(ag, g);
- dstcolor[2] = max(ab, b);
- loopk(3)
- {
- mincolor[k] = min(mincolor[k], dstcolor[k]);
- maxcolor[k] = max(maxcolor[k], dstcolor[k]);
- }
- if(w->type&LM_ALPHA)
- {
- dstcolor[3] = skylight[3];
- mincolor[3] = min(mincolor[3], dstcolor[3]);
- maxcolor[3] = max(maxcolor[3], dstcolor[3]);
- }
- if((w->type&LM_TYPE) == LM_BUMPMAP0)
- {
- if(ray->iszero()) dstray[0] = bvec(128, 128, 255);
- else
- {
- // bias the normals towards the amount of ambient/skylight in the lumel
- // this is necessary to prevent the light values in shaders from dropping too far below the skylight (to the ambient) if N.L is small
- ray->normalize();
- int l = max(r, max(g, b)), a = max(ar, max(ag, ab));
- ray->mul(max(l-a, 0));
- ray->z += a;
- dstray[0] = bvec(ray->normalize());
- }
- loopk(3)
- {
- minray[k] = min(minray[k], dstray[0][k]);
- maxray[k] = max(maxray[k], dstray[0][k]);
- }
- ray++;
- dstray++;
- }
- dstcolor += w->bpp;
- skylight += w->bpp;
- }
- sample += aasample;
- }
- if(int(maxcolor[0]) - int(mincolor[0]) <= lighterror &&
- int(maxcolor[1]) - int(mincolor[1]) <= lighterror &&
- int(maxcolor[2]) - int(mincolor[2]) <= lighterror &&
- mincolor[3] >= maxcolor[3])
- {
- uchar color[3];
- loopk(3) color[k] = (int(maxcolor[k]) + int(mincolor[k])) / 2;
- if(color[0] <= int(ambientcolor[0]) + lighterror &&
- color[1] <= int(ambientcolor[1]) + lighterror &&
- color[2] <= int(ambientcolor[2]) + lighterror &&
- (maxcolor[3]==0 || mincolor[3]==255))
- return mincolor[3]==255 ? SURFACE_AMBIENT_TOP : SURFACE_AMBIENT_BOTTOM;
- if((w->type&LM_TYPE) != LM_BUMPMAP0 ||
- (int(maxray.x) - int(minray.x) <= bumperror &&
- int(maxray.y) - int(minray.z) <= bumperror &&
- int(maxray.z) - int(minray.z) <= bumperror))
-
- {
- memcpy(w->colorbuf, color, 3);
- if(w->type&LM_ALPHA) w->colorbuf[3] = mincolor[3];
- if((w->type&LM_TYPE) == LM_BUMPMAP0)
- {
- loopk(3) w->raybuf[0][k] = uchar((int(maxray[k])+int(minray[k]))/2);
- }
- w->lastlightmap->w = w->w = 1;
- w->lastlightmap->h = w->h = 1;
- }
- }
- if(blurlms && (w->w>1 || w->h>1))
- {
- blurtexture(blurlms, w->bpp, w->w, w->h, w->colorbuf, w->blur, blurlms);
- if((w->type&LM_TYPE) == LM_BUMPMAP0) blurnormals(blurlms, w->w, w->h, w->raybuf, (const bvec *)w->raydata, blurlms);
- w->lastlightmap->w = (w->w -= 2*blurlms);
- w->lastlightmap->h = (w->h -= 2*blurlms);
- }
- if(mincolor[3]==255) return SURFACE_LIGHTMAP_TOP;
- else if(maxcolor[3]==0) return SURFACE_LIGHTMAP_BOTTOM;
- else return SURFACE_LIGHTMAP_BLEND;
+{
+ if(hasskylight() && blurskylight && (w->w>1 || w->h>1))
+ {
+ blurtexture(blurskylight, w->bpp, w->w, w->h, w->blur, w->ambient);
+ swap(w->blur, w->ambient);
+ }
+ vec *sample = w->colordata;
+ int aasample = min(1 << lmaa, 4), stride = aasample*(w->w+1);
+ float weight = 1.0f / (1.0f + 4.0f*lmaa),
+ cweight = weight * (lmaa == 3 ? 5.0f : 1.0f);
+ uchar *skylight = w->ambient;
+ vec *ray = w->raydata;
+ uchar *dstcolor = blurlms && (w->w > 1 || w->h > 1) ? w->blur : w->colorbuf;
+ uchar mincolor[4] = { 255, 255, 255, 255 }, maxcolor[4] = { 0, 0, 0, 0 };
+ bvec *dstray = blurlms && (w->w > 1 || w->h > 1) ? (bvec *)w->raydata : w->raybuf;
+ bvec minray(255, 255, 255), maxray(0, 0, 0);
+ loop(y, w->h)
+ {
+ loop(x, w->w)
+ {
+ vec l(0, 0, 0);
+ const vec &center = *sample++;
+ loopi(aasample-1) l.add(*sample++);
+ if(aasample > 1)
+ {
+ l.add(sample[1]);
+ if(aasample > 2) l.add(sample[3]);
+ }
+ vec *next = sample + stride - aasample;
+ if(aasample > 1)
+ {
+ l.add(next[1]);
+ if(aasample > 2) l.add(next[2]);
+ l.add(next[aasample+1]);
+ }
+
+ int r = int(center.x*cweight + l.x*weight),
+ g = int(center.y*cweight + l.y*weight),
+ b = int(center.z*cweight + l.z*weight),
+ ar = skylight[0], ag = skylight[1], ab = skylight[2];
+ dstcolor[0] = max(ar, r);
+ dstcolor[1] = max(ag, g);
+ dstcolor[2] = max(ab, b);
+ loopk(3)
+ {
+ mincolor[k] = min(mincolor[k], dstcolor[k]);
+ maxcolor[k] = max(maxcolor[k], dstcolor[k]);
+ }
+ if(w->type&LM_ALPHA)
+ {
+ dstcolor[3] = skylight[3];
+ mincolor[3] = min(mincolor[3], dstcolor[3]);
+ maxcolor[3] = max(maxcolor[3], dstcolor[3]);
+ }
+ if((w->type&LM_TYPE) == LM_BUMPMAP0)
+ {
+ if(ray->iszero()) dstray[0] = bvec(128, 128, 255);
+ else
+ {
+ // bias the normals towards the amount of ambient/skylight in the lumel
+ // this is necessary to prevent the light values in shaders from dropping too far below the skylight (to the ambient) if N.L is small
+ ray->normalize();
+ int l = max(r, max(g, b)), a = max(ar, max(ag, ab));
+ ray->mul(max(l-a, 0));
+ ray->z += a;
+ dstray[0] = bvec(ray->normalize());
+ }
+ loopk(3)
+ {
+ minray[k] = min(minray[k], dstray[0][k]);
+ maxray[k] = max(maxray[k], dstray[0][k]);
+ }
+ ray++;
+ dstray++;
+ }
+ dstcolor += w->bpp;
+ skylight += w->bpp;
+ }
+ sample += aasample;
+ }
+ if(int(maxcolor[0]) - int(mincolor[0]) <= lighterror &&
+ int(maxcolor[1]) - int(mincolor[1]) <= lighterror &&
+ int(maxcolor[2]) - int(mincolor[2]) <= lighterror &&
+ mincolor[3] >= maxcolor[3])
+ {
+ uchar color[3];
+ loopk(3) color[k] = (int(maxcolor[k]) + int(mincolor[k])) / 2;
+ if(color[0] <= int(ambientcolor[0]) + lighterror &&
+ color[1] <= int(ambientcolor[1]) + lighterror &&
+ color[2] <= int(ambientcolor[2]) + lighterror &&
+ (maxcolor[3]==0 || mincolor[3]==255))
+ return mincolor[3]==255 ? SURFACE_AMBIENT_TOP : SURFACE_AMBIENT_BOTTOM;
+ if((w->type&LM_TYPE) != LM_BUMPMAP0 ||
+ (int(maxray.x) - int(minray.x) <= bumperror &&
+ int(maxray.y) - int(minray.z) <= bumperror &&
+ int(maxray.z) - int(minray.z) <= bumperror))
+
+ {
+ memcpy(w->colorbuf, color, 3);
+ if(w->type&LM_ALPHA) w->colorbuf[3] = mincolor[3];
+ if((w->type&LM_TYPE) == LM_BUMPMAP0)
+ {
+ loopk(3) w->raybuf[0][k] = uchar((int(maxray[k])+int(minray[k]))/2);
+ }
+ w->lastlightmap->w = w->w = 1;
+ w->lastlightmap->h = w->h = 1;
+ }
+ }
+ if(blurlms && (w->w>1 || w->h>1))
+ {
+ blurtexture(blurlms, w->bpp, w->w, w->h, w->colorbuf, w->blur, blurlms);
+ if((w->type&LM_TYPE) == LM_BUMPMAP0) blurnormals(blurlms, w->w, w->h, w->raybuf, (const bvec *)w->raydata, blurlms);
+ w->lastlightmap->w = (w->w -= 2*blurlms);
+ w->lastlightmap->h = (w->h -= 2*blurlms);
+ }
+ if(mincolor[3]==255) return SURFACE_LIGHTMAP_TOP;
+ else if(maxcolor[3]==0) return SURFACE_LIGHTMAP_BOTTOM;
+ else return SURFACE_LIGHTMAP_BLEND;
}
static int previewlightmapalpha(lightmapworker *w, float lpu, const vec &origin1, const vec &xstep1, const vec &ystep1, const vec &origin2, const vec &xstep2, const vec &ystep2, float side0, float sidestep)
{
- extern int fullbrightlevel;
- float tolerance = 0.5 / lpu;
- uchar *dst = w->colorbuf;
- uchar minalpha = 255, maxalpha = 0;
- float sidex = side0;
- for(int y = 0; y < w->h; ++y, sidex += sidestep)
- {
- for(int x = 0; x < w->w; ++x, dst += 4)
- {
- vec u = x < sidex ?
- vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) :
- vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
- loopk(3) dst[k] = fullbrightlevel;
- generatealpha(w, tolerance, u, dst[3]);
- minalpha = min(minalpha, dst[3]);
- maxalpha = max(maxalpha, dst[3]);
- }
- }
- if(minalpha==255) return SURFACE_AMBIENT_TOP;
- if(maxalpha==0) return SURFACE_AMBIENT_BOTTOM;
- if(minalpha==maxalpha) w->w = w->h = 1;
- if((w->type&LM_TYPE) == LM_BUMPMAP0) loopi(w->w*w->h) w->raybuf[i] = bvec(128, 128, 255);
- return SURFACE_LIGHTMAP_BLEND;
-}
+ extern int fullbrightlevel;
+ float tolerance = 0.5 / lpu;
+ uchar *dst = w->colorbuf;
+ uchar minalpha = 255, maxalpha = 0;
+ float sidex = side0;
+ for(int y = 0; y < w->h; ++y, sidex += sidestep)
+ {
+ for(int x = 0; x < w->w; ++x, dst += 4)
+ {
+ vec u = x < sidex ?
+ vec(xstep1).mul(x).add(vec(ystep1).mul(y)).add(origin1) :
+ vec(xstep2).mul(x).add(vec(ystep2).mul(y)).add(origin2);
+ loopk(3) dst[k] = fullbrightlevel;
+ generatealpha(w, tolerance, u, dst[3]);
+ minalpha = min(minalpha, dst[3]);
+ maxalpha = max(maxalpha, dst[3]);
+ }
+ }
+ if(minalpha==255) return SURFACE_AMBIENT_TOP;
+ if(maxalpha==0) return SURFACE_AMBIENT_BOTTOM;
+ if(minalpha==maxalpha) w->w = w->h = 1;
+ if((w->type&LM_TYPE) == LM_BUMPMAP0) loopi(w->w*w->h) w->raybuf[i] = bvec(128, 128, 255);
+ return SURFACE_LIGHTMAP_BLEND;
+}
static void clearsurfaces(cube *c)
{
- loopi(8)
- {
- if(c[i].ext)
- {
- loopj(6)
- {
- surfaceinfo &surf = c[i].ext->surfaces[j];
- if(!surf.used()) continue;
- surf.clear();
- int numverts = surf.numverts&MAXFACEVERTS;
- if(numverts)
- {
- if(!(c[i].merged&(1<<j))) { surf.numverts &= ~MAXFACEVERTS; continue; }
-
- vertinfo *verts = c[i].ext->verts() + surf.verts;
- loopk(numverts)
- {
- vertinfo &v = verts[k];
- v.u = 0;
- v.v = 0;
- v.norm = 0;
- }
- }
- }
- }
- if(c[i].children) clearsurfaces(c[i].children);
- }
+ loopi(8)
+ {
+ if(c[i].ext)
+ {
+ loopj(6)
+ {
+ surfaceinfo &surf = c[i].ext->surfaces[j];
+ if(!surf.used()) continue;
+ surf.clear();
+ int numverts = surf.numverts&MAXFACEVERTS;
+ if(numverts)
+ {
+ if(!(c[i].merged&(1<<j))) { surf.numverts &= ~MAXFACEVERTS; continue; }
+
+ vertinfo *verts = c[i].ext->verts() + surf.verts;
+ loopk(numverts)
+ {
+ vertinfo &v = verts[k];
+ v.u = 0;
+ v.v = 0;
+ v.norm = 0;
+ }
+ }
+ }
+ }
+ if(c[i].children) clearsurfaces(c[i].children);
+ }
}
#define LIGHTCACHESIZE 1024
static struct lightcacheentry
{
- int x, y;
- vector<int> lights;
+ int x, y;
+ vector<int> lights;
} lightcache[LIGHTCACHESIZE];
#define LIGHTCACHEHASH(x, y) (((((x)^(y))<<5) + (((x)^(y))>>5)) & (LIGHTCACHESIZE - 1))
@@ -1040,1015 +1040,1015 @@ VARF(lightcachesize, 4, 6, 12, clearlightcache());
void clearlightcache(int id)
{
- if(id >= 0)
- {
- const extentity &light = *entities::getents()[id];
- int radius = light.attr1;
- if(radius)
- {
- for(int x = int(max(light.o.x-radius, 0.0f))>>lightcachesize, ex = int(min(light.o.x+radius, worldsize-1.0f))>>lightcachesize; x <= ex; x++)
- for(int y = int(max(light.o.y-radius, 0.0f))>>lightcachesize, ey = int(min(light.o.y+radius, worldsize-1.0f))>>lightcachesize; y <= ey; y++)
- {
- lightcacheentry &lce = lightcache[LIGHTCACHEHASH(x, y)];
- if(lce.x != x || lce.y != y) continue;
- lce.x = -1;
- lce.lights.setsize(0);
- }
- return;
- }
- }
-
- for(lightcacheentry *lce = lightcache; lce < &lightcache[LIGHTCACHESIZE]; lce++)
- {
- lce->x = -1;
- lce->lights.setsize(0);
- }
+ if(id >= 0)
+ {
+ const extentity &light = *entities::getents()[id];
+ int radius = light.attr1;
+ if(radius)
+ {
+ for(int x = int(max(light.o.x-radius, 0.0f))>>lightcachesize, ex = int(min(light.o.x+radius, worldsize-1.0f))>>lightcachesize; x <= ex; x++)
+ for(int y = int(max(light.o.y-radius, 0.0f))>>lightcachesize, ey = int(min(light.o.y+radius, worldsize-1.0f))>>lightcachesize; y <= ey; y++)
+ {
+ lightcacheentry &lce = lightcache[LIGHTCACHEHASH(x, y)];
+ if(lce.x != x || lce.y != y) continue;
+ lce.x = -1;
+ lce.lights.setsize(0);
+ }
+ return;
+ }
+ }
+
+ for(lightcacheentry *lce = lightcache; lce < &lightcache[LIGHTCACHESIZE]; lce++)
+ {
+ lce->x = -1;
+ lce->lights.setsize(0);
+ }
}
const vector<int> &checklightcache(int x, int y)
{
- x >>= lightcachesize;
- y >>= lightcachesize;
- lightcacheentry &lce = lightcache[LIGHTCACHEHASH(x, y)];
- if(lce.x == x && lce.y == y) return lce.lights;
-
- lce.lights.setsize(0);
- int csize = 1<<lightcachesize, cx = x<<lightcachesize, cy = y<<lightcachesize;
- const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
- const extentity &light = *ents[i];
- switch(light.type)
- {
- case ET_LIGHT:
- {
- int radius = light.attr1;
- if(radius > 0)
- {
- if(light.o.x + radius < cx || light.o.x - radius > cx + csize ||
- light.o.y + radius < cy || light.o.y - radius > cy + csize)
- continue;
- }
- break;
- }
- default: continue;
- }
- lce.lights.add(i);
- }
-
- lce.x = x;
- lce.y = y;
- return lce.lights;
+ x >>= lightcachesize;
+ y >>= lightcachesize;
+ lightcacheentry &lce = lightcache[LIGHTCACHEHASH(x, y)];
+ if(lce.x == x && lce.y == y) return lce.lights;
+
+ lce.lights.setsize(0);
+ int csize = 1<<lightcachesize, cx = x<<lightcachesize, cy = y<<lightcachesize;
+ const vector<extentity *> &ents = entities::getents();
+ loopv(ents)
+ {
+ const extentity &light = *ents[i];
+ switch(light.type)
+ {
+ case ET_LIGHT:
+ {
+ int radius = light.attr1;
+ if(radius > 0)
+ {
+ if(light.o.x + radius < cx || light.o.x - radius > cx + csize ||
+ light.o.y + radius < cy || light.o.y - radius > cy + csize)
+ continue;
+ }
+ break;
+ }
+ default: continue;
+ }
+ lce.lights.add(i);
+ }
+
+ lce.x = x;
+ lce.y = y;
+ return lce.lights;
}
static inline void addlight(lightmapworker *w, const extentity &light, int cx, int cy, int cz, int size, const vec *v, const vec *n, int numv)
{
- int radius = light.attr1;
- if(radius > 0)
- {
- if(light.o.x + radius < cx || light.o.x - radius > cx + size ||
- light.o.y + radius < cy || light.o.y - radius > cy + size ||
- light.o.z + radius < cz || light.o.z - radius > cz + size)
- return;
- }
-
- loopi(4)
- {
- vec p(light.o);
- p.sub(v[i]);
- float dist = p.dot(n[i]);
- if(dist >= 0 && (!radius || dist < radius))
- {
- w->lights.add(&light);
- break;
- }
- }
-}
+ int radius = light.attr1;
+ if(radius > 0)
+ {
+ if(light.o.x + radius < cx || light.o.x - radius > cx + size ||
+ light.o.y + radius < cy || light.o.y - radius > cy + size ||
+ light.o.z + radius < cz || light.o.z - radius > cz + size)
+ return;
+ }
+
+ loopi(4)
+ {
+ vec p(light.o);
+ p.sub(v[i]);
+ float dist = p.dot(n[i]);
+ if(dist >= 0 && (!radius || dist < radius))
+ {
+ w->lights.add(&light);
+ break;
+ }
+ }
+}
static bool findlights(lightmapworker *w, int cx, int cy, int cz, int size, const vec *v, const vec *n, int numv, const Slot &slot, const VSlot &vslot)
{
- w->lights.setsize(0);
- const vector<extentity *> &ents = entities::getents();
- static volatile bool usinglightcache = false;
- if(size <= 1<<lightcachesize && (!lightlock || !usinglightcache))
- {
- if(lightlock) { SDL_LockMutex(lightlock); usinglightcache = true; }
- const vector<int> &lights = checklightcache(cx, cy);
- loopv(lights)
- {
- const extentity &light = *ents[lights[i]];
- switch(light.type)
- {
- case ET_LIGHT: addlight(w, light, cx, cy, cz, size, v, n, numv); break;
- }
- }
- if(lightlock) { usinglightcache = false; SDL_UnlockMutex(lightlock); }
- }
- else loopv(ents)
- {
- const extentity &light = *ents[i];
- switch(light.type)
- {
- case ET_LIGHT: addlight(w, light, cx, cy, cz, size, v, n, numv); break;
- }
- }
- if(vslot.layer && (setblendmaporigin(w->blendmapcache, ivec(cx, cy, cz), size) || slot.layermask)) return true;
- return w->lights.length() || hasskylight() || sunlight;
+ w->lights.setsize(0);
+ const vector<extentity *> &ents = entities::getents();
+ static volatile bool usinglightcache = false;
+ if(size <= 1<<lightcachesize && (!lightlock || !usinglightcache))
+ {
+ if(lightlock) { SDL_LockMutex(lightlock); usinglightcache = true; }
+ const vector<int> &lights = checklightcache(cx, cy);
+ loopv(lights)
+ {
+ const extentity &light = *ents[lights[i]];
+ switch(light.type)
+ {
+ case ET_LIGHT: addlight(w, light, cx, cy, cz, size, v, n, numv); break;
+ }
+ }
+ if(lightlock) { usinglightcache = false; SDL_UnlockMutex(lightlock); }
+ }
+ else loopv(ents)
+ {
+ const extentity &light = *ents[i];
+ switch(light.type)
+ {
+ case ET_LIGHT: addlight(w, light, cx, cy, cz, size, v, n, numv); break;
+ }
+ }
+ if(vslot.layer && (setblendmaporigin(w->blendmapcache, ivec(cx, cy, cz), size) || slot.layermask)) return true;
+ return w->lights.length() || hasskylight() || sunlight;
}
static int packlightmaps(lightmapworker *w = NULL)
{
- int numpacked = 0;
- for(; packidx < lightmaptasks[0].length(); packidx++, numpacked++)
- {
- lightmaptask &t = lightmaptasks[0][packidx];
- if(!t.lightmaps) break;
- if(t.ext && t.c->ext != t.ext)
- {
- lightmapext &e = lightmapexts.add();
- e.c = t.c;
- e.ext = t.ext;
- }
- progress = t.progress;
- lightmapinfo *l = t.lightmaps;
- if(l == (lightmapinfo *)-1) continue;
- int space = 0;
- for(; l && l->c == t.c; l = l->next)
- {
- l->packed = true;
- space += l->bufsize;
- if(l->surface < 0 || !t.ext) continue;
- surfaceinfo &surf = t.ext->surfaces[l->surface];
- layoutinfo layout;
- packlightmap(*l, layout);
- int numverts = surf.numverts&MAXFACEVERTS;
- vertinfo *verts = t.ext->verts() + surf.verts;
- if(l->layers&LAYER_DUP)
- {
- if(l->type&LM_ALPHA) surf.lmid[0] = layout.lmid;
- else { surf.lmid[1] = layout.lmid; verts += numverts; }
- }
- else
- {
- if(l->layers&LAYER_TOP) surf.lmid[0] = layout.lmid;
- if(l->layers&LAYER_BOTTOM) surf.lmid[1] = layout.lmid;
- }
- ushort offsetx = layout.x*((USHRT_MAX+1)/LM_PACKW), offsety = layout.y*((USHRT_MAX+1)/LM_PACKH);
- loopk(numverts)
- {
- vertinfo &v = verts[k];
- v.u += offsetx;
- v.v += offsety;
- }
- }
- if(t.worker == w)
- {
- w->bufused -= space;
- w->bufstart = (w->bufstart + space)%LIGHTMAPBUFSIZE;
- w->firstlightmap = l;
- if(!l)
- {
- w->lastlightmap = NULL;
- w->bufstart = w->bufused = 0;
- }
- }
- if(t.worker->needspace) SDL_CondSignal(t.worker->spacecond);
- }
- return numpacked;
+ int numpacked = 0;
+ for(; packidx < lightmaptasks[0].length(); packidx++, numpacked++)
+ {
+ lightmaptask &t = lightmaptasks[0][packidx];
+ if(!t.lightmaps) break;
+ if(t.ext && t.c->ext != t.ext)
+ {
+ lightmapext &e = lightmapexts.add();
+ e.c = t.c;
+ e.ext = t.ext;
+ }
+ progress = t.progress;
+ lightmapinfo *l = t.lightmaps;
+ if(l == (lightmapinfo *)-1) continue;
+ int space = 0;
+ for(; l && l->c == t.c; l = l->next)
+ {
+ l->packed = true;
+ space += l->bufsize;
+ if(l->surface < 0 || !t.ext) continue;
+ surfaceinfo &surf = t.ext->surfaces[l->surface];
+ layoutinfo layout;
+ packlightmap(*l, layout);
+ int numverts = surf.numverts&MAXFACEVERTS;
+ vertinfo *verts = t.ext->verts() + surf.verts;
+ if(l->layers&LAYER_DUP)
+ {
+ if(l->type&LM_ALPHA) surf.lmid[0] = layout.lmid;
+ else { surf.lmid[1] = layout.lmid; verts += numverts; }
+ }
+ else
+ {
+ if(l->layers&LAYER_TOP) surf.lmid[0] = layout.lmid;
+ if(l->layers&LAYER_BOTTOM) surf.lmid[1] = layout.lmid;
+ }
+ ushort offsetx = layout.x*((USHRT_MAX+1)/LM_PACKW), offsety = layout.y*((USHRT_MAX+1)/LM_PACKH);
+ loopk(numverts)
+ {
+ vertinfo &v = verts[k];
+ v.u += offsetx;
+ v.v += offsety;
+ }
+ }
+ if(t.worker == w)
+ {
+ w->bufused -= space;
+ w->bufstart = (w->bufstart + space)%LIGHTMAPBUFSIZE;
+ w->firstlightmap = l;
+ if(!l)
+ {
+ w->lastlightmap = NULL;
+ w->bufstart = w->bufused = 0;
+ }
+ }
+ if(t.worker->needspace) SDL_CondSignal(t.worker->spacecond);
+ }
+ return numpacked;
}
static lightmapinfo *alloclightmap(lightmapworker *w)
{
- int needspace1 = sizeof(lightmapinfo) + w->w*w->h*w->bpp,
- needspace2 = (w->type&LM_TYPE) == LM_BUMPMAP0 ? w->w*w->h*3 : 0,
- needspace = needspace1 + needspace2,
- bufend = (w->bufstart + w->bufused)%LIGHTMAPBUFSIZE,
- availspace = LIGHTMAPBUFSIZE - w->bufused,
- availspace1 = min(availspace, LIGHTMAPBUFSIZE - bufend),
- availspace2 = min(availspace, w->bufstart);
- if(availspace < needspace || (max(availspace1, availspace2) < needspace && (availspace1 < needspace1 || availspace2 < needspace2)))
- {
- if(tasklock) SDL_LockMutex(tasklock);
- while(!w->doneworking)
- {
- lightmapinfo *l = w->firstlightmap;
- for(; l && l->packed; l = l->next)
- {
- w->bufused -= l->bufsize;
- w->bufstart = (w->bufstart + l->bufsize)%LIGHTMAPBUFSIZE;
- }
- w->firstlightmap = l;
- if(!l)
- {
- w->lastlightmap = NULL;
- w->bufstart = w->bufused = 0;
- }
- bufend = (w->bufstart + w->bufused)%LIGHTMAPBUFSIZE;
- availspace = LIGHTMAPBUFSIZE - w->bufused;
- availspace1 = min(availspace, LIGHTMAPBUFSIZE - bufend);
- availspace2 = min(availspace, w->bufstart);
- if(availspace >= needspace && (max(availspace1, availspace2) >= needspace || (availspace1 >= needspace1 && availspace2 >= needspace2))) break;
- if(packlightmaps(w)) continue;
- if(!w->spacecond || !tasklock) break;
- w->needspace = true;
- SDL_CondWait(w->spacecond, tasklock);
- w->needspace = false;
- }
- if(tasklock) SDL_UnlockMutex(tasklock);
- }
- int usedspace = needspace;
- lightmapinfo *l = NULL;
- if(availspace1 >= needspace1)
- {
- l = (lightmapinfo *)&w->buf[bufend];
- w->colorbuf = (uchar *)(l + 1);
- if((w->type&LM_TYPE) != LM_BUMPMAP0) w->raybuf = NULL;
- else if(availspace1 >= needspace) w->raybuf = (bvec *)&w->buf[bufend + needspace1];
- else
- {
- w->raybuf = (bvec *)w->buf;
- usedspace += availspace1 - needspace1;
- }
- }
- else if(availspace2 >= needspace)
- {
- usedspace += availspace1;
- l = (lightmapinfo *)w->buf;
- w->colorbuf = (uchar *)(l + 1);
- w->raybuf = (w->type&LM_TYPE) == LM_BUMPMAP0 ? (bvec *)&w->buf[needspace1] : NULL;
- }
- else return NULL;
- w->bufused += usedspace;
- l->next = NULL;
- l->c = w->c;
- l->type = w->type;
- l->w = w->w;
- l->h = w->h;
- l->bpp = w->bpp;
- l->colorbuf = w->colorbuf;
- l->raybuf = w->raybuf;
- l->packed = false;
- l->bufsize = usedspace;
- l->surface = -1;
- l->layers = 0;
- if(!w->firstlightmap) w->firstlightmap = l;
- if(w->lastlightmap) w->lastlightmap->next = l;
- w->lastlightmap = l;
- if(!w->curlightmaps) w->curlightmaps = l;
- return l;
+ int needspace1 = sizeof(lightmapinfo) + w->w*w->h*w->bpp,
+ needspace2 = (w->type&LM_TYPE) == LM_BUMPMAP0 ? w->w*w->h*3 : 0,
+ needspace = needspace1 + needspace2,
+ bufend = (w->bufstart + w->bufused)%LIGHTMAPBUFSIZE,
+ availspace = LIGHTMAPBUFSIZE - w->bufused,
+ availspace1 = min(availspace, LIGHTMAPBUFSIZE - bufend),
+ availspace2 = min(availspace, w->bufstart);
+ if(availspace < needspace || (max(availspace1, availspace2) < needspace && (availspace1 < needspace1 || availspace2 < needspace2)))
+ {
+ if(tasklock) SDL_LockMutex(tasklock);
+ while(!w->doneworking)
+ {
+ lightmapinfo *l = w->firstlightmap;
+ for(; l && l->packed; l = l->next)
+ {
+ w->bufused -= l->bufsize;
+ w->bufstart = (w->bufstart + l->bufsize)%LIGHTMAPBUFSIZE;
+ }
+ w->firstlightmap = l;
+ if(!l)
+ {
+ w->lastlightmap = NULL;
+ w->bufstart = w->bufused = 0;
+ }
+ bufend = (w->bufstart + w->bufused)%LIGHTMAPBUFSIZE;
+ availspace = LIGHTMAPBUFSIZE - w->bufused;
+ availspace1 = min(availspace, LIGHTMAPBUFSIZE - bufend);
+ availspace2 = min(availspace, w->bufstart);
+ if(availspace >= needspace && (max(availspace1, availspace2) >= needspace || (availspace1 >= needspace1 && availspace2 >= needspace2))) break;
+ if(packlightmaps(w)) continue;
+ if(!w->spacecond || !tasklock) break;
+ w->needspace = true;
+ SDL_CondWait(w->spacecond, tasklock);
+ w->needspace = false;
+ }
+ if(tasklock) SDL_UnlockMutex(tasklock);
+ }
+ int usedspace = needspace;
+ lightmapinfo *l = NULL;
+ if(availspace1 >= needspace1)
+ {
+ l = (lightmapinfo *)&w->buf[bufend];
+ w->colorbuf = (uchar *)(l + 1);
+ if((w->type&LM_TYPE) != LM_BUMPMAP0) w->raybuf = NULL;
+ else if(availspace1 >= needspace) w->raybuf = (bvec *)&w->buf[bufend + needspace1];
+ else
+ {
+ w->raybuf = (bvec *)w->buf;
+ usedspace += availspace1 - needspace1;
+ }
+ }
+ else if(availspace2 >= needspace)
+ {
+ usedspace += availspace1;
+ l = (lightmapinfo *)w->buf;
+ w->colorbuf = (uchar *)(l + 1);
+ w->raybuf = (w->type&LM_TYPE) == LM_BUMPMAP0 ? (bvec *)&w->buf[needspace1] : NULL;
+ }
+ else return NULL;
+ w->bufused += usedspace;
+ l->next = NULL;
+ l->c = w->c;
+ l->type = w->type;
+ l->w = w->w;
+ l->h = w->h;
+ l->bpp = w->bpp;
+ l->colorbuf = w->colorbuf;
+ l->raybuf = w->raybuf;
+ l->packed = false;
+ l->bufsize = usedspace;
+ l->surface = -1;
+ l->layers = 0;
+ if(!w->firstlightmap) w->firstlightmap = l;
+ if(w->lastlightmap) w->lastlightmap->next = l;
+ w->lastlightmap = l;
+ if(!w->curlightmaps) w->curlightmaps = l;
+ return l;
}
static void freelightmap(lightmapworker *w)
{
- lightmapinfo *l = w->lastlightmap;
- if(!l || l->surface >= 0) return;
- if(w->firstlightmap == w->lastlightmap)
- {
- w->firstlightmap = w->lastlightmap = w->curlightmaps = NULL;
- w->bufstart = w->bufused = 0;
- }
- else
- {
- w->bufused -= l->bufsize - sizeof(lightmapinfo);
- l->bufsize = sizeof(lightmapinfo);
- l->packed = true;
- }
- if(w->curlightmaps == l) w->curlightmaps = NULL;
+ lightmapinfo *l = w->lastlightmap;
+ if(!l || l->surface >= 0) return;
+ if(w->firstlightmap == w->lastlightmap)
+ {
+ w->firstlightmap = w->lastlightmap = w->curlightmaps = NULL;
+ w->bufstart = w->bufused = 0;
+ }
+ else
+ {
+ w->bufused -= l->bufsize - sizeof(lightmapinfo);
+ l->bufsize = sizeof(lightmapinfo);
+ l->packed = true;
+ }
+ if(w->curlightmaps == l) w->curlightmaps = NULL;
}
static int setupsurface(lightmapworker *w, plane planes[2], int numplanes, const vec *p, const vec *n, int numverts, vertinfo *litverts, bool preview = false)
{
- vec u, v, t;
- vec2 c[MAXFACEVERTS];
-
- u = vec(p[2]).sub(p[0]).normalize();
- v.cross(planes[0], u);
- c[0] = vec2(0, 0);
- if(numplanes >= 2) t.cross(planes[1], u); else t = v;
- vec r1 = vec(p[1]).sub(p[0]);
- c[1] = vec2(r1.dot(u), min(r1.dot(v), 0.0f));
- c[2] = vec2(vec(p[2]).sub(p[0]).dot(u), 0);
- for(int i = 3; i < numverts; i++)
- {
- vec r = vec(p[i]).sub(p[0]);
- c[i] = vec2(r.dot(u), max(r.dot(t), 0.0f));
- }
-
- float carea = 1e16f;
- vec2 cx(0, 0), cy(0, 0), co(0, 0), cmin(0, 0), cmax(0, 0);
- loopi(numverts)
- {
- vec2 px = vec2(c[i+1 < numverts ? i+1 : 0]).sub(c[i]);
- float len = px.squaredlen();
- if(!len) continue;
- px.mul(1/sqrtf(len));
- vec2 py(-px.y, px.x), pmin(0, 0), pmax(0, 0);
- if(numplanes >= 2 && (i == 0 || i >= 3)) px.neg();
- loopj(numverts)
- {
- vec2 rj = vec2(c[j]).sub(c[i]), pj(rj.dot(px), rj.dot(py));
- pmin.x = min(pmin.x, pj.x);
- pmin.y = min(pmin.y, pj.y);
- pmax.x = max(pmax.x, pj.x);
- pmax.y = max(pmax.y, pj.y);
- }
- float area = (pmax.x-pmin.x)*(pmax.y-pmin.y);
- if(area < carea) { carea = area; cx = px; cy = py; co = c[i]; cmin = pmin; cmax = pmax; }
- }
-
- int scale = int(min(cmax.x - cmin.x, cmax.y - cmin.y));
- float lpu = 16.0f / float(lightlod && scale < (1 << lightlod) ? max(lightprecision / 2, 1) : lightprecision);
- int lw = clamp(int(ceil((cmax.x - cmin.x + 1)*lpu)), LM_MINW, LM_MAXW), lh = clamp(int(ceil((cmax.y - cmin.y + 1)*lpu)), LM_MINH, LM_MAXH);
- w->w = lw;
- w->h = lh;
- if(!preview)
- {
- w->w += 2*blurlms;
- w->h += 2*blurlms;
- }
- if(!alloclightmap(w)) return NO_SURFACE;
-
- vec2 cscale = vec2(cmax).sub(cmin).div(vec2(lw-1, lh-1)),
- comin = vec2(cx).mul(cmin.x).add(vec2(cy).mul(cmin.y)).add(co);
- loopi(numverts)
- {
- vec2 ri = vec2(c[i]).sub(comin);
- c[i] = vec2(ri.dot(cx)/cscale.x, ri.dot(cy)/cscale.y);
- }
-
- vec xstep1 = vec(v).mul(cx.y).add(vec(u).mul(cx.x)).mul(cscale.x),
- ystep1 = vec(v).mul(cy.y).add(vec(u).mul(cy.x)).mul(cscale.y),
- origin1 = vec(v).mul(comin.y).add(vec(u).mul(comin.x)).add(p[0]),
- xstep2 = xstep1, ystep2 = ystep1, origin2 = origin1;
- float side0 = LM_MAXW + 1, sidestep = 0;
- if(numplanes >= 2)
- {
- xstep2 = vec(t).mul(cx.y).add(vec(u).mul(cx.x)).mul(cscale.x);
- ystep2 = vec(t).mul(cy.y).add(vec(u).mul(cy.x)).mul(cscale.y);
- origin2 = vec(t).mul(comin.y).add(vec(u).mul(comin.x)).add(p[0]);
- if(cx.y) { side0 = comin.y/-(cx.y*cscale.x); sidestep = cy.y*cscale.y/-(cx.y*cscale.x); }
- else if(cy.y) { side0 = ceil(comin.y/-(cy.y*cscale.y))*(LM_MAXW + 1); sidestep = -(LM_MAXW + 1); if(cy.y < 0) { side0 = (LM_MAXW + 1) - side0; sidestep = -sidestep; } }
- else side0 = comin.y <= 0 ? LM_MAXW + 1 : -1;
- }
-
- int surftype = NO_SURFACE;
- if(preview)
- {
- surftype = previewlightmapalpha(w, lpu, origin1, xstep1, ystep1, origin2, xstep2, ystep2, side0, sidestep);
- }
- else
- {
- lerpvert lv[MAXFACEVERTS];
- int numv = numverts;
- calclerpverts(c, n, lv, numv);
-
- if(!generatelightmap(w, lpu, lv, numv, origin1, xstep1, ystep1, origin2, xstep2, ystep2, side0, sidestep)) return NO_SURFACE;
- surftype = finishlightmap(w);
- }
- if(surftype<SURFACE_LIGHTMAP) return surftype;
-
- vec2 texscale(float(USHRT_MAX+1)/LM_PACKW, float(USHRT_MAX+1)/LM_PACKH);
- if(lw != w->w) texscale.x *= float(w->w - 1) / (lw - 1);
- if(lh != w->h) texscale.y *= float(w->h - 1) / (lh - 1);
- loopk(numverts)
- {
- litverts[k].u = ushort(floor(clamp(c[k].x*texscale.x, 0.0f, float(USHRT_MAX))));
- litverts[k].v = ushort(floor(clamp(c[k].y*texscale.y, 0.0f, float(USHRT_MAX))));
- }
- return surftype;
+ vec u, v, t;
+ vec2 c[MAXFACEVERTS];
+
+ u = vec(p[2]).sub(p[0]).normalize();
+ v.cross(planes[0], u);
+ c[0] = vec2(0, 0);
+ if(numplanes >= 2) t.cross(planes[1], u); else t = v;
+ vec r1 = vec(p[1]).sub(p[0]);
+ c[1] = vec2(r1.dot(u), min(r1.dot(v), 0.0f));
+ c[2] = vec2(vec(p[2]).sub(p[0]).dot(u), 0);
+ for(int i = 3; i < numverts; i++)
+ {
+ vec r = vec(p[i]).sub(p[0]);
+ c[i] = vec2(r.dot(u), max(r.dot(t), 0.0f));
+ }
+
+ float carea = 1e16f;
+ vec2 cx(0, 0), cy(0, 0), co(0, 0), cmin(0, 0), cmax(0, 0);
+ loopi(numverts)
+ {
+ vec2 px = vec2(c[i+1 < numverts ? i+1 : 0]).sub(c[i]);
+ float len = px.squaredlen();
+ if(!len) continue;
+ px.mul(1/sqrtf(len));
+ vec2 py(-px.y, px.x), pmin(0, 0), pmax(0, 0);
+ if(numplanes >= 2 && (i == 0 || i >= 3)) px.neg();
+ loopj(numverts)
+ {
+ vec2 rj = vec2(c[j]).sub(c[i]), pj(rj.dot(px), rj.dot(py));
+ pmin.x = min(pmin.x, pj.x);
+ pmin.y = min(pmin.y, pj.y);
+ pmax.x = max(pmax.x, pj.x);
+ pmax.y = max(pmax.y, pj.y);
+ }
+ float area = (pmax.x-pmin.x)*(pmax.y-pmin.y);
+ if(area < carea) { carea = area; cx = px; cy = py; co = c[i]; cmin = pmin; cmax = pmax; }
+ }
+
+ int scale = int(min(cmax.x - cmin.x, cmax.y - cmin.y));
+ float lpu = 16.0f / float(lightlod && scale < (1 << lightlod) ? max(lightprecision / 2, 1) : lightprecision);
+ int lw = clamp(int(ceil((cmax.x - cmin.x + 1)*lpu)), LM_MINW, LM_MAXW), lh = clamp(int(ceil((cmax.y - cmin.y + 1)*lpu)), LM_MINH, LM_MAXH);
+ w->w = lw;
+ w->h = lh;
+ if(!preview)
+ {
+ w->w += 2*blurlms;
+ w->h += 2*blurlms;
+ }
+ if(!alloclightmap(w)) return NO_SURFACE;
+
+ vec2 cscale = vec2(cmax).sub(cmin).div(vec2(lw-1, lh-1)),
+ comin = vec2(cx).mul(cmin.x).add(vec2(cy).mul(cmin.y)).add(co);
+ loopi(numverts)
+ {
+ vec2 ri = vec2(c[i]).sub(comin);
+ c[i] = vec2(ri.dot(cx)/cscale.x, ri.dot(cy)/cscale.y);
+ }
+
+ vec xstep1 = vec(v).mul(cx.y).add(vec(u).mul(cx.x)).mul(cscale.x),
+ ystep1 = vec(v).mul(cy.y).add(vec(u).mul(cy.x)).mul(cscale.y),
+ origin1 = vec(v).mul(comin.y).add(vec(u).mul(comin.x)).add(p[0]),
+ xstep2 = xstep1, ystep2 = ystep1, origin2 = origin1;
+ float side0 = LM_MAXW + 1, sidestep = 0;
+ if(numplanes >= 2)
+ {
+ xstep2 = vec(t).mul(cx.y).add(vec(u).mul(cx.x)).mul(cscale.x);
+ ystep2 = vec(t).mul(cy.y).add(vec(u).mul(cy.x)).mul(cscale.y);
+ origin2 = vec(t).mul(comin.y).add(vec(u).mul(comin.x)).add(p[0]);
+ if(cx.y) { side0 = comin.y/-(cx.y*cscale.x); sidestep = cy.y*cscale.y/-(cx.y*cscale.x); }
+ else if(cy.y) { side0 = ceil(comin.y/-(cy.y*cscale.y))*(LM_MAXW + 1); sidestep = -(LM_MAXW + 1); if(cy.y < 0) { side0 = (LM_MAXW + 1) - side0; sidestep = -sidestep; } }
+ else side0 = comin.y <= 0 ? LM_MAXW + 1 : -1;
+ }
+
+ int surftype = NO_SURFACE;
+ if(preview)
+ {
+ surftype = previewlightmapalpha(w, lpu, origin1, xstep1, ystep1, origin2, xstep2, ystep2, side0, sidestep);
+ }
+ else
+ {
+ lerpvert lv[MAXFACEVERTS];
+ int numv = numverts;
+ calclerpverts(c, n, lv, numv);
+
+ if(!generatelightmap(w, lpu, lv, numv, origin1, xstep1, ystep1, origin2, xstep2, ystep2, side0, sidestep)) return NO_SURFACE;
+ surftype = finishlightmap(w);
+ }
+ if(surftype<SURFACE_LIGHTMAP) return surftype;
+
+ vec2 texscale(float(USHRT_MAX+1)/LM_PACKW, float(USHRT_MAX+1)/LM_PACKH);
+ if(lw != w->w) texscale.x *= float(w->w - 1) / (lw - 1);
+ if(lh != w->h) texscale.y *= float(w->h - 1) / (lh - 1);
+ loopk(numverts)
+ {
+ litverts[k].u = ushort(floor(clamp(c[k].x*texscale.x, 0.0f, float(USHRT_MAX))));
+ litverts[k].v = ushort(floor(clamp(c[k].y*texscale.y, 0.0f, float(USHRT_MAX))));
+ }
+ return surftype;
}
static void removelmalpha(lightmapworker *w)
{
- if(!(w->type&LM_ALPHA)) return;
- for(uchar *dst = w->colorbuf, *src = w->colorbuf, *end = &src[w->w*w->h*4];
- src < end;
- dst += 3, src += 4)
- {
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- }
- w->type &= ~LM_ALPHA;
- w->bpp = 3;
- w->lastlightmap->type = w->type;
- w->lastlightmap->bpp = w->bpp;
+ if(!(w->type&LM_ALPHA)) return;
+ for(uchar *dst = w->colorbuf, *src = w->colorbuf, *end = &src[w->w*w->h*4];
+ src < end;
+ dst += 3, src += 4)
+ {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ }
+ w->type &= ~LM_ALPHA;
+ w->bpp = 3;
+ w->lastlightmap->type = w->type;
+ w->lastlightmap->bpp = w->bpp;
}
static lightmapinfo *setupsurfaces(lightmapworker *w, lightmaptask &task)
{
- cube &c = *task.c;
- const ivec &co = task.o;
- int size = task.size, usefacemask = task.usefaces;
-
- w->curlightmaps = NULL;
- w->c = &c;
-
- surfaceinfo surfaces[6];
- vertinfo litverts[6*2*MAXFACEVERTS];
- int numlitverts = 0;
- memclear(surfaces);
- loopi(6)
- {
- int usefaces = usefacemask&0xF;
- usefacemask >>= 4;
- if(!usefaces)
- {
- if(!c.ext) continue;
- surfaceinfo &surf = surfaces[i];
- surf = c.ext->surfaces[i];
- int numverts = surf.totalverts();
- if(numverts)
- {
- memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
- surf.verts = numlitverts;
- numlitverts += numverts;
- }
- continue;
- }
-
- VSlot &vslot = lookupvslot(c.texture[i], false),
- *layer = vslot.layer && !(c.material&MAT_ALPHA) ? &lookupvslot(vslot.layer, false) : NULL;
- Shader *shader = vslot.slot->shader;
- int shadertype = shader->type;
- if(layer) shadertype |= layer->slot->shader->type;
-
- surfaceinfo &surf = surfaces[i];
- vertinfo *curlitverts = &litverts[numlitverts];
- int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0;
- ivec mo(co);
- int msz = size, convex = 0;
- if(numverts)
- {
- vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
- loopj(numverts) curlitverts[j].set(verts[j].getxyz());
- if(c.merged&(1<<i))
- {
- msz = 1<<calcmergedsize(i, mo, size, verts, numverts);
- mo.mask(~(msz-1));
-
- if(!(surf.numverts&MAXFACEVERTS))
- {
- surf.verts = numlitverts;
- surf.numverts |= numverts;
- numlitverts += numverts;
- }
- }
- else if(!flataxisface(c, i)) convex = faceconvexity(verts, numverts, size);
- }
- else
- {
- ivec v[4];
- genfaceverts(c, i, v);
- if(!flataxisface(c, i)) convex = faceconvexity(v);
- int order = usefaces&4 || convex < 0 ? 1 : 0;
- ivec vo = ivec(co).mask(0xFFF).shl(3);
- curlitverts[numverts++].set(v[order].mul(size).add(vo));
- if(usefaces&1) curlitverts[numverts++].set(v[order+1].mul(size).add(vo));
- curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
- if(usefaces&2) curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
- }
-
- vec pos[MAXFACEVERTS], n[MAXFACEVERTS], po(ivec(co).mask(~0xFFF));
- loopj(numverts) pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
-
- plane planes[2];
- int numplanes = 0;
- planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
- if(numverts < 4 || !convex) loopk(numverts) findnormal(pos[k], planes[0], n[k]);
- else
- {
- planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
- vec avg = vec(planes[0]).add(planes[1]).normalize();
- findnormal(pos[0], avg, n[0]);
- findnormal(pos[1], planes[0], n[1]);
- findnormal(pos[2], avg, n[2]);
- for(int k = 3; k < numverts; k++) findnormal(pos[k], planes[1], n[k]);
- }
-
- if(shadertype&(SHADER_NORMALSLMS | SHADER_ENVMAP))
- {
- loopk(numverts) curlitverts[k].norm = encodenormal(n[k]);
- if(!(surf.numverts&MAXFACEVERTS))
- {
- surf.verts = numlitverts;
- surf.numverts |= numverts;
- numlitverts += numverts;
- }
- }
-
- if(!findlights(w, mo.x, mo.y, mo.z, msz, pos, n, numverts, *vslot.slot, vslot))
- {
- if(surf.numverts&MAXFACEVERTS) surf.numverts |= LAYER_TOP;
- continue;
- }
-
- w->slot = vslot.slot;
- w->vslot = &vslot;
- w->type = shader->type&SHADER_NORMALSLMS ? LM_BUMPMAP0 : LM_DIFFUSE;
- if(layer) w->type |= LM_ALPHA;
- w->bpp = w->type&LM_ALPHA ? 4 : 3;
- w->orient = i;
- w->rotate = vslot.rotation;
- int surftype = setupsurface(w, planes, numplanes, pos, n, numverts, curlitverts);
- switch(surftype)
- {
- case SURFACE_LIGHTMAP_BOTTOM:
- if((shader->type^layer->slot->shader->type)&SHADER_NORMALSLMS ||
- (shader->type&SHADER_NORMALSLMS && vslot.rotation!=layer->rotation))
- {
- freelightmap(w);
- break;
- }
- // fall through
- case SURFACE_LIGHTMAP_BLEND:
- case SURFACE_LIGHTMAP_TOP:
- {
- if(!(surf.numverts&MAXFACEVERTS))
- {
- surf.verts = numlitverts;
- surf.numverts |= numverts;
- numlitverts += numverts;
- }
-
- w->lastlightmap->surface = i;
- w->lastlightmap->layers = (surftype==SURFACE_LIGHTMAP_BOTTOM ? LAYER_BOTTOM : LAYER_TOP);
- if(surftype==SURFACE_LIGHTMAP_BLEND)
- {
- surf.numverts |= LAYER_BLEND;
- w->lastlightmap->layers = LAYER_TOP;
- if((shader->type^layer->slot->shader->type)&SHADER_NORMALSLMS ||
- (shader->type&SHADER_NORMALSLMS && vslot.rotation!=layer->rotation))
- break;
- w->lastlightmap->layers |= LAYER_BOTTOM;
- }
- else
- {
- if(surftype==SURFACE_LIGHTMAP_BOTTOM)
- {
- surf.numverts |= LAYER_BOTTOM;
- w->lastlightmap->layers = LAYER_BOTTOM;
- }
- else
- {
- surf.numverts |= LAYER_TOP;
- w->lastlightmap->layers = LAYER_TOP;
- }
- if(w->type&LM_ALPHA) removelmalpha(w);
- }
- continue;
- }
-
- case SURFACE_AMBIENT_BOTTOM:
- freelightmap(w);
- surf.numverts |= layer ? LAYER_BOTTOM : LAYER_TOP;
- continue;
-
- case SURFACE_AMBIENT_TOP:
- freelightmap(w);
- surf.numverts |= LAYER_TOP;
- continue;
-
- default:
- freelightmap(w);
- continue;
- }
-
- w->slot = layer->slot;
- w->vslot = layer;
- w->type = layer->slot->shader->type&SHADER_NORMALSLMS ? LM_BUMPMAP0 : LM_DIFFUSE;
- w->bpp = 3;
- w->rotate = layer->rotation;
- vertinfo *blendverts = surf.numverts&MAXFACEVERTS ? &curlitverts[numverts] : curlitverts;
- switch(setupsurface(w, planes, numplanes, pos, n, numverts, blendverts))
- {
- case SURFACE_LIGHTMAP_TOP:
- {
- if(!(surf.numverts&MAXFACEVERTS))
- {
- surf.verts = numlitverts;
- surf.numverts |= numverts;
- numlitverts += numverts;
- }
- else if(!(surf.numverts&LAYER_DUP))
- {
- surf.numverts |= LAYER_DUP;
- w->lastlightmap->layers |= LAYER_DUP;
- loopk(numverts)
- {
- vertinfo &src = curlitverts[k];
- vertinfo &dst = blendverts[k];
- dst.setxyz(src.getxyz());
- dst.norm = src.norm;
- }
- numlitverts += numverts;
- }
- surf.numverts |= LAYER_BOTTOM;
- w->lastlightmap->layers |= LAYER_BOTTOM;
-
- w->lastlightmap->surface = i;
- break;
- }
-
- case SURFACE_AMBIENT_TOP:
- {
- freelightmap(w);
- surf.numverts |= LAYER_BOTTOM;
- break;
- }
-
- default: freelightmap(w); break;
- }
- }
- loopk(6)
- {
- surfaceinfo &surf = surfaces[k];
- if(surf.used())
- {
- cubeext *ext = c.ext && c.ext->maxverts >= numlitverts ? c.ext : growcubeext(c.ext, numlitverts);
- memcpy(ext->surfaces, surfaces, sizeof(ext->surfaces));
- memcpy(ext->verts(), litverts, numlitverts*sizeof(vertinfo));
- task.ext = ext;
- break;
- }
- }
- return w->curlightmaps ? w->curlightmaps : (lightmapinfo *)-1;
+ cube &c = *task.c;
+ const ivec &co = task.o;
+ int size = task.size, usefacemask = task.usefaces;
+
+ w->curlightmaps = NULL;
+ w->c = &c;
+
+ surfaceinfo surfaces[6];
+ vertinfo litverts[6*2*MAXFACEVERTS];
+ int numlitverts = 0;
+ memclear(surfaces);
+ loopi(6)
+ {
+ int usefaces = usefacemask&0xF;
+ usefacemask >>= 4;
+ if(!usefaces)
+ {
+ if(!c.ext) continue;
+ surfaceinfo &surf = surfaces[i];
+ surf = c.ext->surfaces[i];
+ int numverts = surf.totalverts();
+ if(numverts)
+ {
+ memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
+ surf.verts = numlitverts;
+ numlitverts += numverts;
+ }
+ continue;
+ }
+
+ VSlot &vslot = lookupvslot(c.texture[i], false),
+ *layer = vslot.layer && !(c.material&MAT_ALPHA) ? &lookupvslot(vslot.layer, false) : NULL;
+ Shader *shader = vslot.slot->shader;
+ int shadertype = shader->type;
+ if(layer) shadertype |= layer->slot->shader->type;
+
+ surfaceinfo &surf = surfaces[i];
+ vertinfo *curlitverts = &litverts[numlitverts];
+ int numverts = c.ext ? c.ext->surfaces[i].numverts&MAXFACEVERTS : 0;
+ ivec mo(co);
+ int msz = size, convex = 0;
+ if(numverts)
+ {
+ vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
+ loopj(numverts) curlitverts[j].set(verts[j].getxyz());
+ if(c.merged&(1<<i))
+ {
+ msz = 1<<calcmergedsize(i, mo, size, verts, numverts);
+ mo.mask(~(msz-1));
+
+ if(!(surf.numverts&MAXFACEVERTS))
+ {
+ surf.verts = numlitverts;
+ surf.numverts |= numverts;
+ numlitverts += numverts;
+ }
+ }
+ else if(!flataxisface(c, i)) convex = faceconvexity(verts, numverts, size);
+ }
+ else
+ {
+ ivec v[4];
+ genfaceverts(c, i, v);
+ if(!flataxisface(c, i)) convex = faceconvexity(v);
+ int order = usefaces&4 || convex < 0 ? 1 : 0;
+ ivec vo = ivec(co).mask(0xFFF).shl(3);
+ curlitverts[numverts++].set(v[order].mul(size).add(vo));
+ if(usefaces&1) curlitverts[numverts++].set(v[order+1].mul(size).add(vo));
+ curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
+ if(usefaces&2) curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
+ }
+
+ vec pos[MAXFACEVERTS], n[MAXFACEVERTS], po(ivec(co).mask(~0xFFF));
+ loopj(numverts) pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
+
+ plane planes[2];
+ int numplanes = 0;
+ planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
+ if(numverts < 4 || !convex) loopk(numverts) findnormal(pos[k], planes[0], n[k]);
+ else
+ {
+ planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
+ vec avg = vec(planes[0]).add(planes[1]).normalize();
+ findnormal(pos[0], avg, n[0]);
+ findnormal(pos[1], planes[0], n[1]);
+ findnormal(pos[2], avg, n[2]);
+ for(int k = 3; k < numverts; k++) findnormal(pos[k], planes[1], n[k]);
+ }
+
+ if(shadertype&(SHADER_NORMALSLMS | SHADER_ENVMAP))
+ {
+ loopk(numverts) curlitverts[k].norm = encodenormal(n[k]);
+ if(!(surf.numverts&MAXFACEVERTS))
+ {
+ surf.verts = numlitverts;
+ surf.numverts |= numverts;
+ numlitverts += numverts;
+ }
+ }
+
+ if(!findlights(w, mo.x, mo.y, mo.z, msz, pos, n, numverts, *vslot.slot, vslot))
+ {
+ if(surf.numverts&MAXFACEVERTS) surf.numverts |= LAYER_TOP;
+ continue;
+ }
+
+ w->slot = vslot.slot;
+ w->vslot = &vslot;
+ w->type = shader->type&SHADER_NORMALSLMS ? LM_BUMPMAP0 : LM_DIFFUSE;
+ if(layer) w->type |= LM_ALPHA;
+ w->bpp = w->type&LM_ALPHA ? 4 : 3;
+ w->orient = i;
+ w->rotate = vslot.rotation;
+ int surftype = setupsurface(w, planes, numplanes, pos, n, numverts, curlitverts);
+ switch(surftype)
+ {
+ case SURFACE_LIGHTMAP_BOTTOM:
+ if((shader->type^layer->slot->shader->type)&SHADER_NORMALSLMS ||
+ (shader->type&SHADER_NORMALSLMS && vslot.rotation!=layer->rotation))
+ {
+ freelightmap(w);
+ break;
+ }
+ // fall through
+ case SURFACE_LIGHTMAP_BLEND:
+ case SURFACE_LIGHTMAP_TOP:
+ {
+ if(!(surf.numverts&MAXFACEVERTS))
+ {
+ surf.verts = numlitverts;
+ surf.numverts |= numverts;
+ numlitverts += numverts;
+ }
+
+ w->lastlightmap->surface = i;
+ w->lastlightmap->layers = (surftype==SURFACE_LIGHTMAP_BOTTOM ? LAYER_BOTTOM : LAYER_TOP);
+ if(surftype==SURFACE_LIGHTMAP_BLEND)
+ {
+ surf.numverts |= LAYER_BLEND;
+ w->lastlightmap->layers = LAYER_TOP;
+ if((shader->type^layer->slot->shader->type)&SHADER_NORMALSLMS ||
+ (shader->type&SHADER_NORMALSLMS && vslot.rotation!=layer->rotation))
+ break;
+ w->lastlightmap->layers |= LAYER_BOTTOM;
+ }
+ else
+ {
+ if(surftype==SURFACE_LIGHTMAP_BOTTOM)
+ {
+ surf.numverts |= LAYER_BOTTOM;
+ w->lastlightmap->layers = LAYER_BOTTOM;
+ }
+ else
+ {
+ surf.numverts |= LAYER_TOP;
+ w->lastlightmap->layers = LAYER_TOP;
+ }
+ if(w->type&LM_ALPHA) removelmalpha(w);
+ }
+ continue;
+ }
+
+ case SURFACE_AMBIENT_BOTTOM:
+ freelightmap(w);
+ surf.numverts |= layer ? LAYER_BOTTOM : LAYER_TOP;
+ continue;
+
+ case SURFACE_AMBIENT_TOP:
+ freelightmap(w);
+ surf.numverts |= LAYER_TOP;
+ continue;
+
+ default:
+ freelightmap(w);
+ continue;
+ }
+
+ w->slot = layer->slot;
+ w->vslot = layer;
+ w->type = layer->slot->shader->type&SHADER_NORMALSLMS ? LM_BUMPMAP0 : LM_DIFFUSE;
+ w->bpp = 3;
+ w->rotate = layer->rotation;
+ vertinfo *blendverts = surf.numverts&MAXFACEVERTS ? &curlitverts[numverts] : curlitverts;
+ switch(setupsurface(w, planes, numplanes, pos, n, numverts, blendverts))
+ {
+ case SURFACE_LIGHTMAP_TOP:
+ {
+ if(!(surf.numverts&MAXFACEVERTS))
+ {
+ surf.verts = numlitverts;
+ surf.numverts |= numverts;
+ numlitverts += numverts;
+ }
+ else if(!(surf.numverts&LAYER_DUP))
+ {
+ surf.numverts |= LAYER_DUP;
+ w->lastlightmap->layers |= LAYER_DUP;
+ loopk(numverts)
+ {
+ vertinfo &src = curlitverts[k];
+ vertinfo &dst = blendverts[k];
+ dst.setxyz(src.getxyz());
+ dst.norm = src.norm;
+ }
+ numlitverts += numverts;
+ }
+ surf.numverts |= LAYER_BOTTOM;
+ w->lastlightmap->layers |= LAYER_BOTTOM;
+
+ w->lastlightmap->surface = i;
+ break;
+ }
+
+ case SURFACE_AMBIENT_TOP:
+ {
+ freelightmap(w);
+ surf.numverts |= LAYER_BOTTOM;
+ break;
+ }
+
+ default: freelightmap(w); break;
+ }
+ }
+ loopk(6)
+ {
+ surfaceinfo &surf = surfaces[k];
+ if(surf.used())
+ {
+ cubeext *ext = c.ext && c.ext->maxverts >= numlitverts ? c.ext : growcubeext(c.ext, numlitverts);
+ memcpy(ext->surfaces, surfaces, sizeof(ext->surfaces));
+ memcpy(ext->verts(), litverts, numlitverts*sizeof(vertinfo));
+ task.ext = ext;
+ break;
+ }
+ }
+ return w->curlightmaps ? w->curlightmaps : (lightmapinfo *)-1;
}
int lightmapworker::work(void *data)
{
- lightmapworker *w = (lightmapworker *)data;
- SDL_LockMutex(tasklock);
- while(!w->doneworking)
- {
- if(allocidx < lightmaptasks[0].length())
- {
- lightmaptask &t = lightmaptasks[0][allocidx++];
- t.worker = w;
- SDL_UnlockMutex(tasklock);
- lightmapinfo *l = setupsurfaces(w, t);
- SDL_LockMutex(tasklock);
- t.lightmaps = l;
- packlightmaps(w);
- }
- else
- {
- if(packidx >= lightmaptasks[0].length()) SDL_CondSignal(emptycond);
- SDL_CondWait(fullcond, tasklock);
- }
- }
- SDL_UnlockMutex(tasklock);
- return 0;
+ lightmapworker *w = (lightmapworker *)data;
+ SDL_LockMutex(tasklock);
+ while(!w->doneworking)
+ {
+ if(allocidx < lightmaptasks[0].length())
+ {
+ lightmaptask &t = lightmaptasks[0][allocidx++];
+ t.worker = w;
+ SDL_UnlockMutex(tasklock);
+ lightmapinfo *l = setupsurfaces(w, t);
+ SDL_LockMutex(tasklock);
+ t.lightmaps = l;
+ packlightmaps(w);
+ }
+ else
+ {
+ if(packidx >= lightmaptasks[0].length()) SDL_CondSignal(emptycond);
+ SDL_CondWait(fullcond, tasklock);
+ }
+ }
+ SDL_UnlockMutex(tasklock);
+ return 0;
}
static bool processtasks(bool finish = false)
{
- if(tasklock) SDL_LockMutex(tasklock);
- while(finish || lightmaptasks[1].length())
- {
- if(packidx >= lightmaptasks[0].length())
- {
- if(lightmaptasks[1].empty()) break;
- lightmaptasks[0].setsize(0);
- lightmaptasks[0].move(lightmaptasks[1]);
- packidx = allocidx = 0;
- if(fullcond) SDL_CondBroadcast(fullcond);
- }
- else if(lightmapping > 1)
- {
- SDL_CondWaitTimeout(emptycond, tasklock, 250);
- CHECK_PROGRESS_LOCKED({ SDL_UnlockMutex(tasklock); return false; }, SDL_UnlockMutex(tasklock), SDL_LockMutex(tasklock));
- }
- else
- {
- while(allocidx < lightmaptasks[0].length())
- {
- lightmaptask &t = lightmaptasks[0][allocidx++];
- t.worker = lightmapworkers[0];
- t.lightmaps = setupsurfaces(lightmapworkers[0], t);
- packlightmaps(lightmapworkers[0]);
- CHECK_PROGRESS(return false);
- }
- }
- }
- if(tasklock) SDL_UnlockMutex(tasklock);
- return true;
+ if(tasklock) SDL_LockMutex(tasklock);
+ while(finish || lightmaptasks[1].length())
+ {
+ if(packidx >= lightmaptasks[0].length())
+ {
+ if(lightmaptasks[1].empty()) break;
+ lightmaptasks[0].setsize(0);
+ lightmaptasks[0].move(lightmaptasks[1]);
+ packidx = allocidx = 0;
+ if(fullcond) SDL_CondBroadcast(fullcond);
+ }
+ else if(lightmapping > 1)
+ {
+ SDL_CondWaitTimeout(emptycond, tasklock, 250);
+ CHECK_PROGRESS_LOCKED({ SDL_UnlockMutex(tasklock); return false; }, SDL_UnlockMutex(tasklock), SDL_LockMutex(tasklock));
+ }
+ else
+ {
+ while(allocidx < lightmaptasks[0].length())
+ {
+ lightmaptask &t = lightmaptasks[0][allocidx++];
+ t.worker = lightmapworkers[0];
+ t.lightmaps = setupsurfaces(lightmapworkers[0], t);
+ packlightmaps(lightmapworkers[0]);
+ CHECK_PROGRESS(return false);
+ }
+ }
+ }
+ if(tasklock) SDL_UnlockMutex(tasklock);
+ return true;
}
static void generatelightmaps(cube *c, const ivec &co, int size)
{
- CHECK_PROGRESS(return);
-
- taskprogress++;
-
- loopi(8)
- {
- ivec o(i, co, size);
- if(c[i].children)
- generatelightmaps(c[i].children, o, size >> 1);
- else if(!isempty(c[i]))
- {
- if(c[i].ext)
- {
- loopj(6)
- {
- surfaceinfo &surf = c[i].ext->surfaces[j];
- if(surf.lmid[0] >= LMID_RESERVED || surf.lmid[1] >= LMID_RESERVED) goto nextcube;
- surf.clear();
- }
- }
- int usefacemask = 0;
- loopj(6) if(c[i].texture[j] != DEFAULT_SKY && (!(c[i].merged&(1<<j)) || (c[i].ext && c[i].ext->surfaces[j].numverts&MAXFACEVERTS)))
- {
- usefacemask |= visibletris(c[i], j, o, size)<<(4*j);
- }
- if(usefacemask)
- {
- lightmaptask &t = lightmaptasks[1].add();
- t.o = o;
- t.size = size;
- t.usefaces = usefacemask;
- t.c = &c[i];
- t.ext = NULL;
- t.lightmaps = NULL;
- t.progress = taskprogress;
- if(lightmaptasks[1].length() >= MAXLIGHTMAPTASKS && !processtasks()) return;
- }
- }
- nextcube:;
- }
+ CHECK_PROGRESS(return);
+
+ taskprogress++;
+
+ loopi(8)
+ {
+ ivec o(i, co, size);
+ if(c[i].children)
+ generatelightmaps(c[i].children, o, size >> 1);
+ else if(!isempty(c[i]))
+ {
+ if(c[i].ext)
+ {
+ loopj(6)
+ {
+ surfaceinfo &surf = c[i].ext->surfaces[j];
+ if(surf.lmid[0] >= LMID_RESERVED || surf.lmid[1] >= LMID_RESERVED) goto nextcube;
+ surf.clear();
+ }
+ }
+ int usefacemask = 0;
+ loopj(6) if(c[i].texture[j] != DEFAULT_SKY && (!(c[i].merged&(1<<j)) || (c[i].ext && c[i].ext->surfaces[j].numverts&MAXFACEVERTS)))
+ {
+ usefacemask |= visibletris(c[i], j, o, size)<<(4*j);
+ }
+ if(usefacemask)
+ {
+ lightmaptask &t = lightmaptasks[1].add();
+ t.o = o;
+ t.size = size;
+ t.usefaces = usefacemask;
+ t.c = &c[i];
+ t.ext = NULL;
+ t.lightmaps = NULL;
+ t.progress = taskprogress;
+ if(lightmaptasks[1].length() >= MAXLIGHTMAPTASKS && !processtasks()) return;
+ }
+ }
+ nextcube:;
+ }
}
static bool previewblends(lightmapworker *w, cube &c, const ivec &co, int size)
{
- if(isempty(c) || c.material&MAT_ALPHA) return false;
-
- int usefacemask = 0;
- loopi(6) if(c.texture[i] != DEFAULT_SKY && lookupvslot(c.texture[i], false).layer)
- usefacemask |= visibletris(c, i, co, size)<<(4*i);
- if(!usefacemask) return false;
-
- if(!setblendmaporigin(w->blendmapcache, co, size))
- {
- if(!c.ext) return false;
- bool blends = false;
- loopi(6) if(c.ext->surfaces[i].numverts&LAYER_BOTTOM)
- {
- c.ext->surfaces[i].brighten();
- blends = true;
- }
- return blends;
- }
-
- w->firstlightmap = w->lastlightmap = w->curlightmaps = NULL;
- w->bufstart = w->bufused = 0;
- w->c = &c;
-
- surfaceinfo surfaces[6];
- vertinfo litverts[6*2*MAXFACEVERTS];
- int numlitverts = 0;
- memcpy(surfaces, c.ext ? c.ext->surfaces : brightsurfaces, sizeof(surfaces));
- loopi(6)
- {
- int usefaces = usefacemask&0xF;
- usefacemask >>= 4;
- if(!usefaces)
- {
- surfaceinfo &surf = surfaces[i];
- int numverts = surf.totalverts();
- if(numverts)
- {
- memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
- surf.verts = numlitverts;
- numlitverts += numverts;
- }
- continue;
- }
-
- VSlot &vslot = lookupvslot(c.texture[i], false),
- &layer = lookupvslot(vslot.layer, false);
- Shader *shader = vslot.slot->shader;
- int shadertype = shader->type | layer.slot->shader->type;
-
- vertinfo *curlitverts = &litverts[numlitverts];
- int numverts = 0;
- ivec v[4];
- genfaceverts(c, i, v);
- int convex = flataxisface(c, i) ? 0 : faceconvexity(v),
- order = usefaces&4 || convex < 0 ? 1 : 0;
- ivec vo = ivec(co).mask(0xFFF).shl(3);
- curlitverts[numverts++].set(v[order].mul(size).add(vo));
- if(usefaces&1) curlitverts[numverts++].set(v[order+1].mul(size).add(vo));
- curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
- if(usefaces&2) curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
-
- vec pos[4], n[4], po(ivec(co).mask(~0xFFF));
- loopj(numverts) pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
-
- plane planes[2];
- int numplanes = 0;
- planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
- if(numverts < 4 || !convex) loopk(numverts) n[k] = planes[0];
- else
- {
- planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
- vec avg = vec(planes[0]).add(planes[1]).normalize();
- n[0] = avg;
- n[1] = planes[0];
- n[2] = avg;
- for(int k = 3; k < numverts; k++) n[k] = planes[1];
- }
-
- surfaceinfo &surf = surfaces[i];
- w->slot = vslot.slot;
- w->vslot = &vslot;
- w->type = shadertype&SHADER_NORMALSLMS ? LM_BUMPMAP0|LM_ALPHA : LM_DIFFUSE|LM_ALPHA;
- w->bpp = 4;
- w->orient = i;
- w->rotate = vslot.rotation;
- int surftype = setupsurface(w, planes, numplanes, pos, n, numverts, curlitverts, true);
- switch(surftype)
- {
- case SURFACE_AMBIENT_TOP:
- surf = brightsurface;
- continue;
-
- case SURFACE_AMBIENT_BOTTOM:
- surf = brightbottomsurface;
- continue;
-
- case SURFACE_LIGHTMAP_BLEND:
- {
- if(surf.numverts == (LAYER_BLEND|numverts) &&
- surf.lmid[0] == surf.lmid[1] &&
- (surf.numverts&MAXFACEVERTS) == numverts &&
- !memcmp(curlitverts, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo)) &&
- lightmaps.inrange(surf.lmid[0]-LMID_RESERVED) &&
- lightmaps[surf.lmid[0]-LMID_RESERVED].type==w->type)
- {
- vertinfo *oldverts = c.ext->verts() + surf.verts;
- layoutinfo layout;
- layout.w = w->w;
- layout.h = w->h;
- layout.x = (oldverts[0].x - curlitverts[0].x)/((USHRT_MAX+1)/LM_PACKW);
- layout.y = (oldverts[0].y - curlitverts[0].y)/((USHRT_MAX+1)/LM_PACKH);
- if(LM_PACKW - layout.x >= w->w && LM_PACKH - layout.y >= w->h)
- {
- layout.lmid = surf.lmid[0];
- copylightmap(*w->lastlightmap, layout);
- updatelightmap(layout);
- surf.verts = numlitverts;
- numlitverts += numverts;
- continue;
- }
- }
-
- surf.verts = numlitverts;
- surf.numverts = LAYER_BLEND|numverts;
- numlitverts += numverts;
- layoutinfo layout;
- if(packlightmap(*w->lastlightmap, layout)) updatelightmap(layout);
- surf.lmid[0] = surf.lmid[1] = layout.lmid;
- ushort offsetx = layout.x*((USHRT_MAX+1)/LM_PACKW), offsety = layout.y*((USHRT_MAX+1)/LM_PACKH);
- loopk(numverts)
- {
- vertinfo &v = curlitverts[k];
- v.u += offsetx;
- v.v += offsety;
- }
- continue;
- }
- }
- }
-
- setsurfaces(c, surfaces, litverts, numlitverts);
- return true;
+ if(isempty(c) || c.material&MAT_ALPHA) return false;
+
+ int usefacemask = 0;
+ loopi(6) if(c.texture[i] != DEFAULT_SKY && lookupvslot(c.texture[i], false).layer)
+ usefacemask |= visibletris(c, i, co, size)<<(4*i);
+ if(!usefacemask) return false;
+
+ if(!setblendmaporigin(w->blendmapcache, co, size))
+ {
+ if(!c.ext) return false;
+ bool blends = false;
+ loopi(6) if(c.ext->surfaces[i].numverts&LAYER_BOTTOM)
+ {
+ c.ext->surfaces[i].brighten();
+ blends = true;
+ }
+ return blends;
+ }
+
+ w->firstlightmap = w->lastlightmap = w->curlightmaps = NULL;
+ w->bufstart = w->bufused = 0;
+ w->c = &c;
+
+ surfaceinfo surfaces[6];
+ vertinfo litverts[6*2*MAXFACEVERTS];
+ int numlitverts = 0;
+ memcpy(surfaces, c.ext ? c.ext->surfaces : brightsurfaces, sizeof(surfaces));
+ loopi(6)
+ {
+ int usefaces = usefacemask&0xF;
+ usefacemask >>= 4;
+ if(!usefaces)
+ {
+ surfaceinfo &surf = surfaces[i];
+ int numverts = surf.totalverts();
+ if(numverts)
+ {
+ memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
+ surf.verts = numlitverts;
+ numlitverts += numverts;
+ }
+ continue;
+ }
+
+ VSlot &vslot = lookupvslot(c.texture[i], false),
+ &layer = lookupvslot(vslot.layer, false);
+ Shader *shader = vslot.slot->shader;
+ int shadertype = shader->type | layer.slot->shader->type;
+
+ vertinfo *curlitverts = &litverts[numlitverts];
+ int numverts = 0;
+ ivec v[4];
+ genfaceverts(c, i, v);
+ int convex = flataxisface(c, i) ? 0 : faceconvexity(v),
+ order = usefaces&4 || convex < 0 ? 1 : 0;
+ ivec vo = ivec(co).mask(0xFFF).shl(3);
+ curlitverts[numverts++].set(v[order].mul(size).add(vo));
+ if(usefaces&1) curlitverts[numverts++].set(v[order+1].mul(size).add(vo));
+ curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
+ if(usefaces&2) curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
+
+ vec pos[4], n[4], po(ivec(co).mask(~0xFFF));
+ loopj(numverts) pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
+
+ plane planes[2];
+ int numplanes = 0;
+ planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
+ if(numverts < 4 || !convex) loopk(numverts) n[k] = planes[0];
+ else
+ {
+ planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
+ vec avg = vec(planes[0]).add(planes[1]).normalize();
+ n[0] = avg;
+ n[1] = planes[0];
+ n[2] = avg;
+ for(int k = 3; k < numverts; k++) n[k] = planes[1];
+ }
+
+ surfaceinfo &surf = surfaces[i];
+ w->slot = vslot.slot;
+ w->vslot = &vslot;
+ w->type = shadertype&SHADER_NORMALSLMS ? LM_BUMPMAP0|LM_ALPHA : LM_DIFFUSE|LM_ALPHA;
+ w->bpp = 4;
+ w->orient = i;
+ w->rotate = vslot.rotation;
+ int surftype = setupsurface(w, planes, numplanes, pos, n, numverts, curlitverts, true);
+ switch(surftype)
+ {
+ case SURFACE_AMBIENT_TOP:
+ surf = brightsurface;
+ continue;
+
+ case SURFACE_AMBIENT_BOTTOM:
+ surf = brightbottomsurface;
+ continue;
+
+ case SURFACE_LIGHTMAP_BLEND:
+ {
+ if(surf.numverts == (LAYER_BLEND|numverts) &&
+ surf.lmid[0] == surf.lmid[1] &&
+ (surf.numverts&MAXFACEVERTS) == numverts &&
+ !memcmp(curlitverts, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo)) &&
+ lightmaps.inrange(surf.lmid[0]-LMID_RESERVED) &&
+ lightmaps[surf.lmid[0]-LMID_RESERVED].type==w->type)
+ {
+ vertinfo *oldverts = c.ext->verts() + surf.verts;
+ layoutinfo layout;
+ layout.w = w->w;
+ layout.h = w->h;
+ layout.x = (oldverts[0].x - curlitverts[0].x)/((USHRT_MAX+1)/LM_PACKW);
+ layout.y = (oldverts[0].y - curlitverts[0].y)/((USHRT_MAX+1)/LM_PACKH);
+ if(LM_PACKW - layout.x >= w->w && LM_PACKH - layout.y >= w->h)
+ {
+ layout.lmid = surf.lmid[0];
+ copylightmap(*w->lastlightmap, layout);
+ updatelightmap(layout);
+ surf.verts = numlitverts;
+ numlitverts += numverts;
+ continue;
+ }
+ }
+
+ surf.verts = numlitverts;
+ surf.numverts = LAYER_BLEND|numverts;
+ numlitverts += numverts;
+ layoutinfo layout;
+ if(packlightmap(*w->lastlightmap, layout)) updatelightmap(layout);
+ surf.lmid[0] = surf.lmid[1] = layout.lmid;
+ ushort offsetx = layout.x*((USHRT_MAX+1)/LM_PACKW), offsety = layout.y*((USHRT_MAX+1)/LM_PACKH);
+ loopk(numverts)
+ {
+ vertinfo &v = curlitverts[k];
+ v.u += offsetx;
+ v.v += offsety;
+ }
+ continue;
+ }
+ }
+ }
+
+ setsurfaces(c, surfaces, litverts, numlitverts);
+ return true;
}
static bool previewblends(lightmapworker *w, cube *c, const ivec &co, int size, const ivec &bo, const ivec &bs)
{
- bool changed = false;
- loopoctabox(co, size, bo, bs)
- {
- ivec o(i, co, size);
- cubeext *ext = c[i].ext;
- if(ext && ext->va && ext->va->hasmerges)
- {
- changed = true;
- destroyva(ext->va);
- ext->va = NULL;
- invalidatemerges(c[i], co, size, true);
- }
- if(c[i].children ? previewblends(w, c[i].children, o, size/2, bo, bs) : previewblends(w, c[i], o, size))
- {
- changed = true;
- ext = c[i].ext;
- if(ext && ext->va)
- {
- destroyva(ext->va);
- ext->va = NULL;
- }
- }
- }
- return changed;
+ bool changed = false;
+ loopoctabox(co, size, bo, bs)
+ {
+ ivec o(i, co, size);
+ cubeext *ext = c[i].ext;
+ if(ext && ext->va && ext->va->hasmerges)
+ {
+ changed = true;
+ destroyva(ext->va);
+ ext->va = NULL;
+ invalidatemerges(c[i], co, size, true);
+ }
+ if(c[i].children ? previewblends(w, c[i].children, o, size/2, bo, bs) : previewblends(w, c[i], o, size))
+ {
+ changed = true;
+ ext = c[i].ext;
+ if(ext && ext->va)
+ {
+ destroyva(ext->va);
+ ext->va = NULL;
+ }
+ }
+ }
+ return changed;
}
void previewblends(const ivec &bo, const ivec &bs)
{
- loadlayermasks();
- if(lightmapworkers.empty()) lightmapworkers.add(new lightmapworker);
- lightmapworkers[0]->reset();
- if(previewblends(lightmapworkers[0], worldroot, ivec(0, 0, 0), worldsize/2, bo, bs))
- commitchanges(true);
+ loadlayermasks();
+ if(lightmapworkers.empty()) lightmapworkers.add(new lightmapworker);
+ lightmapworkers[0]->reset();
+ if(previewblends(lightmapworkers[0], worldroot, ivec(0, 0, 0), worldsize/2, bo, bs))
+ commitchanges(true);
}
-
+
void cleanuplightmaps()
{
- loopv(lightmaps)
- {
- LightMap &lm = lightmaps[i];
- lm.tex = lm.offsetx = lm.offsety = -1;
- }
- loopv(lightmaptexs) glDeleteTextures(1, &lightmaptexs[i].id);
- lightmaptexs.shrink(0);
- if(progresstex) { glDeleteTextures(1, &progresstex); progresstex = 0; }
+ loopv(lightmaps)
+ {
+ LightMap &lm = lightmaps[i];
+ lm.tex = lm.offsetx = lm.offsety = -1;
+ }
+ loopv(lightmaptexs) glDeleteTextures(1, &lightmaptexs[i].id);
+ lightmaptexs.shrink(0);
+ if(progresstex) { glDeleteTextures(1, &progresstex); progresstex = 0; }
}
void resetlightmaps(bool fullclean)
{
- cleanuplightmaps();
- lightmaps.shrink(0);
- compressed.clear();
- clearlightcache();
- if(fullclean) while(lightmapworkers.length()) delete lightmapworkers.pop();
+ cleanuplightmaps();
+ lightmaps.shrink(0);
+ compressed.clear();
+ clearlightcache();
+ if(fullclean) while(lightmapworkers.length()) delete lightmapworkers.pop();
}
lightmapworker::lightmapworker()
{
- buf = new uchar[LIGHTMAPBUFSIZE];
- bufstart = bufused = 0;
- firstlightmap = lastlightmap = curlightmaps = NULL;
- ambient = new uchar[4*(LM_MAXW + 4)*(LM_MAXH + 4)];
- blur = new uchar[4*(LM_MAXW + 4)*(LM_MAXH + 4)];
- colordata = new vec[4*(LM_MAXW+1 + 4)*(LM_MAXH+1 + 4)];
- raydata = new vec[(LM_MAXW + 4)*(LM_MAXH + 4)];
- shadowraycache = newshadowraycache();
- blendmapcache = newblendmapcache();
- needspace = doneworking = false;
- spacecond = NULL;
- thread = NULL;
+ buf = new uchar[LIGHTMAPBUFSIZE];
+ bufstart = bufused = 0;
+ firstlightmap = lastlightmap = curlightmaps = NULL;
+ ambient = new uchar[4*(LM_MAXW + 4)*(LM_MAXH + 4)];
+ blur = new uchar[4*(LM_MAXW + 4)*(LM_MAXH + 4)];
+ colordata = new vec[4*(LM_MAXW+1 + 4)*(LM_MAXH+1 + 4)];
+ raydata = new vec[(LM_MAXW + 4)*(LM_MAXH + 4)];
+ shadowraycache = newshadowraycache();
+ blendmapcache = newblendmapcache();
+ needspace = doneworking = false;
+ spacecond = NULL;
+ thread = NULL;
}
lightmapworker::~lightmapworker()
{
- cleanupthread();
- delete[] buf;
- delete[] ambient;
- delete[] blur;
- delete[] colordata;
- delete[] raydata;
- freeshadowraycache(shadowraycache);
- freeblendmapcache(blendmapcache);
+ cleanupthread();
+ delete[] buf;
+ delete[] ambient;
+ delete[] blur;
+ delete[] colordata;
+ delete[] raydata;
+ freeshadowraycache(shadowraycache);
+ freeblendmapcache(blendmapcache);
}
void lightmapworker::cleanupthread()
{
- if(spacecond) { SDL_DestroyCond(spacecond); spacecond = NULL; }
- thread = NULL;
+ if(spacecond) { SDL_DestroyCond(spacecond); spacecond = NULL; }
+ thread = NULL;
}
void lightmapworker::reset()
{
- bufstart = bufused = 0;
- firstlightmap = lastlightmap = curlightmaps = NULL;
- needspace = doneworking = false;
- resetshadowraycache(shadowraycache);
+ bufstart = bufused = 0;
+ firstlightmap = lastlightmap = curlightmaps = NULL;
+ needspace = doneworking = false;
+ resetshadowraycache(shadowraycache);
}
bool lightmapworker::setupthread()
{
- if(!spacecond) spacecond = SDL_CreateCond();
- if(!spacecond) return false;
- thread = SDL_CreateThread(work, "lightmap worker", this);
- return thread!=NULL;
+ if(!spacecond) spacecond = SDL_CreateCond();
+ if(!spacecond) return false;
+ thread = SDL_CreateThread(work, "lightmap worker", this);
+ return thread!=NULL;
}
static Uint32 calclighttimer(Uint32 interval, void *param)
{
- check_calclight_progress = true;
- return interval;
+ check_calclight_progress = true;
+ return interval;
}
bool setlightmapquality(int quality)
{
- switch(quality)
- {
- case 1: lmshadows = 2; lmaa = 3; lerptjoints = 1; break;
- case 0: lmshadows = lmshadows_; lmaa = lmaa_; lerptjoints = lerptjoints_; break;
- case -1: lmshadows = 1; lmaa = 0; lerptjoints = 0; break;
- default: return false;
- }
- return true;
+ switch(quality)
+ {
+ case 1: lmshadows = 2; lmaa = 3; lerptjoints = 1; break;
+ case 0: lmshadows = lmshadows_; lmaa = lmaa_; lerptjoints = lerptjoints_; break;
+ case -1: lmshadows = 1; lmaa = 0; lerptjoints = 0; break;
+ default: return false;
+ }
+ return true;
}
VARP(lightthreads, 0, 0, 16);
@@ -2058,200 +2058,142 @@ VARP(lightthreads, 0, 0, 16);
static void cleanuplocks()
{
- FREELOCK(lightlock, SDL_DestroyMutex);
- FREELOCK(tasklock, SDL_DestroyMutex);
- FREELOCK(fullcond, SDL_DestroyCond);
- FREELOCK(emptycond, SDL_DestroyCond);
+ FREELOCK(lightlock, SDL_DestroyMutex);
+ FREELOCK(tasklock, SDL_DestroyMutex);
+ FREELOCK(fullcond, SDL_DestroyCond);
+ FREELOCK(emptycond, SDL_DestroyCond);
}
static void setupthreads(int numthreads)
{
- loopi(2) lightmaptasks[i].setsize(0);
- lightmapexts.setsize(0);
- packidx = allocidx = 0;
- lightmapping = numthreads;
- if(lightmapping > 1)
- {
- ALLOCLOCK(lightlock, SDL_CreateMutex);
- ALLOCLOCK(tasklock, SDL_CreateMutex);
- ALLOCLOCK(fullcond, SDL_CreateCond);
- ALLOCLOCK(emptycond, SDL_CreateCond);
- }
- while(lightmapworkers.length() < lightmapping) lightmapworkers.add(new lightmapworker);
- loopi(lightmapping)
- {
- lightmapworker *w = lightmapworkers[i];
- w->reset();
- if(lightmapping <= 1 || w->setupthread()) continue;
- w->cleanupthread();
- lightmapping = i >= 1 ? max(i, 2) : 1;
- break;
- }
- if(lightmapping <= 1) cleanuplocks();
+ loopi(2) lightmaptasks[i].setsize(0);
+ lightmapexts.setsize(0);
+ packidx = allocidx = 0;
+ lightmapping = numthreads;
+ if(lightmapping > 1)
+ {
+ ALLOCLOCK(lightlock, SDL_CreateMutex);
+ ALLOCLOCK(tasklock, SDL_CreateMutex);
+ ALLOCLOCK(fullcond, SDL_CreateCond);
+ ALLOCLOCK(emptycond, SDL_CreateCond);
+ }
+ while(lightmapworkers.length() < lightmapping) lightmapworkers.add(new lightmapworker);
+ loopi(lightmapping)
+ {
+ lightmapworker *w = lightmapworkers[i];
+ w->reset();
+ if(lightmapping <= 1 || w->setupthread()) continue;
+ w->cleanupthread();
+ lightmapping = i >= 1 ? max(i, 2) : 1;
+ break;
+ }
+ if(lightmapping <= 1) cleanuplocks();
}
static void cleanupthreads()
{
- processtasks(true);
- if(lightmapping > 1)
- {
- SDL_LockMutex(tasklock);
- loopv(lightmapworkers) lightmapworkers[i]->doneworking = true;
- SDL_CondBroadcast(fullcond);
- loopv(lightmapworkers)
- {
- lightmapworker *w = lightmapworkers[i];
- if(w->needspace && w->spacecond) SDL_CondSignal(w->spacecond);
- }
- SDL_UnlockMutex(tasklock);
- loopv(lightmapworkers)
- {
- lightmapworker *w = lightmapworkers[i];
- if(w->thread) SDL_WaitThread(w->thread, NULL);
- }
- }
- loopv(lightmapexts)
- {
- lightmapext &e = lightmapexts[i];
- setcubeext(*e.c, e.ext);
- }
- loopv(lightmapworkers) lightmapworkers[i]->cleanupthread();
- cleanuplocks();
- lightmapping = 0;
+ processtasks(true);
+ if(lightmapping > 1)
+ {
+ SDL_LockMutex(tasklock);
+ loopv(lightmapworkers) lightmapworkers[i]->doneworking = true;
+ SDL_CondBroadcast(fullcond);
+ loopv(lightmapworkers)
+ {
+ lightmapworker *w = lightmapworkers[i];
+ if(w->needspace && w->spacecond) SDL_CondSignal(w->spacecond);
+ }
+ SDL_UnlockMutex(tasklock);
+ loopv(lightmapworkers)
+ {
+ lightmapworker *w = lightmapworkers[i];
+ if(w->thread) SDL_WaitThread(w->thread, NULL);
+ }
+ }
+ loopv(lightmapexts)
+ {
+ lightmapext &e = lightmapexts[i];
+ setcubeext(*e.c, e.ext);
+ }
+ loopv(lightmapworkers) lightmapworkers[i]->cleanupthread();
+ cleanuplocks();
+ lightmapping = 0;
}
void calclight(int *quality)
{
- if(!setlightmapquality(*quality))
- {
- conoutf(CON_ERROR, "valid range for calclight quality is -1..1");
- return;
- }
- renderbackground("computing lightmaps... (esc to abort)");
- mpremip(true);
- optimizeblendmap();
- loadlayermasks();
- int numthreads = lightthreads > 0 ? lightthreads : numcpus;
- if(numthreads > 1) preloadusedmapmodels(false, true);
- resetlightmaps(false);
- clearsurfaces(worldroot);
- taskprogress = progress = 0;
- progresstexticks = 0;
- progresslightmap = -1;
- calclight_canceled = false;
- check_calclight_progress = false;
- SDL_TimerID timer = SDL_AddTimer(250, calclighttimer, NULL);
- Uint32 start = SDL_GetTicks();
- calcnormals(lerptjoints > 0);
- show_calclight_progress();
- setupthreads(numthreads);
- generatelightmaps(worldroot, ivec(0, 0, 0), worldsize >> 1);
- cleanupthreads();
- clearnormals();
- Uint32 end = SDL_GetTicks();
- if(timer) SDL_RemoveTimer(timer);
- uint total = 0, lumels = 0;
- loopv(lightmaps)
- {
- insertunlit(i);
- if(!editmode) lightmaps[i].finalize();
- total += lightmaps[i].lightmaps;
- lumels += lightmaps[i].lumels;
- }
- if(!editmode) compressed.clear();
- initlights();
- renderbackground("lighting done...");
- allchanged();
- if(calclight_canceled)
- conoutf("calclight aborted");
- else
- conoutf("generated %d lightmaps using %d%% of %d textures (%.1f seconds)",
- total,
- lightmaps.length() ? lumels * 100 / (lightmaps.length() * LM_PACKW * LM_PACKH) : 0,
- lightmaps.length(),
- (end - start) / 1000.0f);
+ if(!setlightmapquality(*quality))
+ {
+ conoutf(CON_ERROR, "valid range for calclight quality is -1..1");
+ return;
+ }
+ renderbackground("computing lightmaps... (esc to abort)");
+ mpremip(true);
+ optimizeblendmap();
+ loadlayermasks();
+ int numthreads = lightthreads > 0 ? lightthreads : numcpus;
+ if(numthreads > 1) preloadusedmapmodels(false, true);
+ resetlightmaps(false);
+ clearsurfaces(worldroot);
+ taskprogress = progress = 0;
+ progresstexticks = 0;
+ progresslightmap = -1;
+ calclight_canceled = false;
+ check_calclight_progress = false;
+ SDL_TimerID timer = SDL_AddTimer(250, calclighttimer, NULL);
+ Uint32 start = SDL_GetTicks();
+ calcnormals(lerptjoints > 0);
+ show_calclight_progress();
+ setupthreads(numthreads);
+ generatelightmaps(worldroot, ivec(0, 0, 0), worldsize >> 1);
+ cleanupthreads();
+ clearnormals();
+ Uint32 end = SDL_GetTicks();
+ if(timer) SDL_RemoveTimer(timer);
+ uint total = 0, lumels = 0;
+ loopv(lightmaps)
+ {
+ insertunlit(i);
+ if(!editmode) lightmaps[i].finalize();
+ total += lightmaps[i].lightmaps;
+ lumels += lightmaps[i].lumels;
+ }
+ if(!editmode) compressed.clear();
+ initlights();
+ renderbackground("lighting done...");
+ allchanged();
+ if(calclight_canceled)
+ conoutf("calclight aborted");
+ else
+ conoutf("generated %d lightmaps using %d%% of %d textures (%.1f seconds)",
+ total,
+ lightmaps.length() ? lumels * 100 / (lightmaps.length() * LM_PACKW * LM_PACKH) : 0,
+ lightmaps.length(),
+ (end - start) / 1000.0f);
}
COMMAND(calclight, "i");
-VAR(patchnormals, 0, 0, 1);
-
-void patchlight(int *quality)
-{
- if(noedit(true)) return;
- if(!setlightmapquality(*quality))
- {
- conoutf(CON_ERROR, "valid range for patchlight quality is -1..1");
- return;
- }
- renderbackground("patching lightmaps... (esc to abort)");
- loadlayermasks();
- int numthreads = lightthreads > 0 ? lightthreads : numcpus;
- if(numthreads > 1) preloadusedmapmodels(false, true);
- cleanuplightmaps();
- taskprogress = progress = 0;
- progresstexticks = 0;
- progresslightmap = -1;
- int total = 0, lumels = 0;
- loopv(lightmaps)
- {
- if((lightmaps[i].type&LM_TYPE) != LM_BUMPMAP1) progresslightmap = i;
- total -= lightmaps[i].lightmaps;
- lumels -= lightmaps[i].lumels;
- }
- calclight_canceled = false;
- check_calclight_progress = false;
- SDL_TimerID timer = SDL_AddTimer(250, calclighttimer, NULL);
- if(patchnormals) renderprogress(0, "computing normals...");
- Uint32 start = SDL_GetTicks();
- if(patchnormals) calcnormals(lerptjoints > 0);
- show_calclight_progress();
- setupthreads(numthreads);
- generatelightmaps(worldroot, ivec(0, 0, 0), worldsize >> 1);
- cleanupthreads();
- if(patchnormals) clearnormals();
- Uint32 end = SDL_GetTicks();
- if(timer) SDL_RemoveTimer(timer);
- loopv(lightmaps)
- {
- total += lightmaps[i].lightmaps;
- lumels += lightmaps[i].lumels;
- }
- initlights();
- renderbackground("lighting done...");
- allchanged();
- if(calclight_canceled)
- conoutf("patchlight aborted");
- else
- conoutf("patched %d lightmaps using %d%% of %d textures (%.1f seconds)",
- total,
- lightmaps.length() ? lumels * 100 / (lightmaps.length() * LM_PACKW * LM_PACKH) : 0,
- lightmaps.length(),
- (end - start) / 1000.0f);
-}
-
-COMMAND(patchlight, "i");
-
void clearlightmaps()
{
- if(noedit(true)) return;
- renderprogress(0, "clearing lightmaps...");
- resetlightmaps(false);
- clearsurfaces(worldroot);
- initlights();
- allchanged();
+ if(noedit(true)) return;
+ renderprogress(0, "clearing lightmaps...");
+ resetlightmaps(false);
+ clearsurfaces(worldroot);
+ initlights();
+ allchanged();
}
COMMAND(clearlightmaps, "");
void setfullbrightlevel(int fullbrightlevel)
{
- if(lightmaptexs.length() > LMID_BRIGHT)
- {
- uchar bright[3] = { uchar(fullbrightlevel), uchar(fullbrightlevel), uchar(fullbrightlevel) };
- createtexture(lightmaptexs[LMID_BRIGHT].id, 1, 1, bright, 0, 1);
- }
- initlights();
+ if(lightmaptexs.length() > LMID_BRIGHT)
+ {
+ uchar bright[3] = { uchar(fullbrightlevel), uchar(fullbrightlevel), uchar(fullbrightlevel) };
+ createtexture(lightmaptexs[LMID_BRIGHT].id, 1, 1, bright, 0, 1);
+ }
+ initlights();
}
VARF(fullbright, 0, 0, 1, if(lightmaptexs.length()) { initlights(); lightents(); });
@@ -2259,183 +2201,68 @@ VARF(fullbrightlevel, 0, 128, 255, setfullbrightlevel(fullbrightlevel));
vector<LightMapTexture> lightmaptexs;
-static void rotatenormals(LightMap &lmlv, int x, int y, int w, int h, bool flipx, bool flipy, bool swapxy)
-{
- uchar *lv = lmlv.data + 3*(y*LM_PACKW + x);
- int stride = 3*(LM_PACKW-w);
- loopi(h)
- {
- loopj(w)
- {
- if(flipx) lv[0] = 255 - lv[0];
- if(flipy) lv[1] = 255 - lv[1];
- if(swapxy) swap(lv[0], lv[1]);
- lv += 3;
- }
- lv += stride;
- }
-}
-
-static void rotatenormals(cube *c)
-{
- loopi(8)
- {
- cube &ch = c[i];
- if(ch.children)
- {
- rotatenormals(ch.children);
- continue;
- }
- else if(!ch.ext) continue;
- loopj(6) if(lightmaps.inrange(ch.ext->surfaces[j].lmid[0]+1-LMID_RESERVED))
- {
- VSlot &vslot = lookupvslot(ch.texture[j], false);
- if(!vslot.rotation) continue;
- surfaceinfo &surface = ch.ext->surfaces[j];
- int numverts = surface.numverts&MAXFACEVERTS;
- if(!numverts) continue;
- LightMap &lmlv = lightmaps[surface.lmid[0]+1-LMID_RESERVED];
- if((lmlv.type&LM_TYPE)!=LM_BUMPMAP1) continue;
- ushort x1 = USHRT_MAX, y1 = USHRT_MAX, x2 = 0, y2 = 0;
- vertinfo *verts = ch.ext->verts() + surface.verts;
- loopk(numverts)
- {
- vertinfo &v = verts[k];
- x1 = min(x1, v.u);
- y1 = min(y1, v.u);
- x2 = max(x2, v.u);
- y2 = max(y2, v.v);
- }
- if(x1 > x2 || y1 > y2) continue;
- x1 /= (USHRT_MAX+1)/LM_PACKW;
- y1 /= (USHRT_MAX+1)/LM_PACKH;
- x2 /= (USHRT_MAX+1)/LM_PACKW;
- y2 /= (USHRT_MAX+1)/LM_PACKH;
- const texrotation &r = texrotations[vslot.rotation < 4 ? 4-vslot.rotation : vslot.rotation];
- rotatenormals(lmlv, x1, y1, x2-x1, y1-y1, r.flipx, r.flipy, r.swapxy);
- }
- }
-}
-
-void fixlightmapnormals()
-{
- rotatenormals(worldroot);
-}
-
-void fixrotatedlightmaps(cube &c, const ivec &co, int size)
-{
- if(c.children)
- {
- loopi(8) fixrotatedlightmaps(c.children[i], ivec(i, co, size>>1), size>>1);
- return;
- }
- if(!c.ext) return;
- loopi(6)
- {
- if(c.merged&(1<<i)) continue;
- surfaceinfo &surf = c.ext->surfaces[i];
- int numverts = surf.numverts&MAXFACEVERTS;
- if(numverts!=4 || (surf.lmid[0] < LMID_RESERVED && surf.lmid[1] < LMID_RESERVED)) continue;
- vertinfo *verts = c.ext->verts() + surf.verts;
- int vis = visibletris(c, i, co, size);
- if(!vis || vis==3) continue;
- if((verts[0].u != verts[1].u || verts[0].v != verts[1].v) &&
- (verts[0].u != verts[3].u || verts[0].v != verts[3].v) &&
- (verts[2].u != verts[1].u || verts[2].v != verts[1].v) &&
- (verts[2].u != verts[3].u || verts[2].v != verts[3].v))
- continue;
- if(vis&4)
- {
- vertinfo tmp = verts[0];
- verts[0].x = verts[1].x; verts[0].y = verts[1].y; verts[0].z = verts[1].z;
- verts[1].x = verts[2].x; verts[1].y = verts[2].y; verts[1].z = verts[2].z;
- verts[2].x = verts[3].x; verts[2].y = verts[3].y; verts[2].z = verts[3].z;
- verts[3].x = tmp.x; verts[3].y = tmp.y; verts[3].z = tmp.z;
- if(surf.numverts&LAYER_DUP) loopk(4)
- {
- vertinfo &v = verts[k], &b = verts[k+4];
- b.x = v.x;
- b.y = v.y;
- b.z = v.z;
- }
- }
- surf.numverts = (surf.numverts & ~MAXFACEVERTS) | 3;
- if(vis&2)
- {
- verts[1] = verts[2]; verts[2] = verts[3];
- if(surf.numverts&LAYER_DUP) { verts[3] = verts[4]; verts[4] = verts[6]; verts[5] = verts[7]; }
- }
- else if(surf.numverts&LAYER_DUP) { verts[3] = verts[4]; verts[4] = verts[5]; verts[5] = verts[6]; }
- }
-}
-
-void fixrotatedlightmaps()
-{
- loopi(8) fixrotatedlightmaps(worldroot[i], ivec(i, ivec(0, 0, 0), worldsize>>1), worldsize>>1);
-}
-
static void copylightmap(LightMap &lm, uchar *dst, size_t stride)
{
- const uchar *c = lm.data;
- loopi(LM_PACKH)
- {
- memcpy(dst, c, lm.bpp*LM_PACKW);
- c += lm.bpp*LM_PACKW;
- dst += stride;
- }
+ const uchar *c = lm.data;
+ loopi(LM_PACKH)
+ {
+ memcpy(dst, c, lm.bpp*LM_PACKW);
+ c += lm.bpp*LM_PACKW;
+ dst += stride;
+ }
}
void genreservedlightmaptexs()
{
- while(lightmaptexs.length() < LMID_RESERVED)
- {
- LightMapTexture &tex = lightmaptexs.add();
- tex.type = lightmaptexs.length()&1 ? LM_DIFFUSE : LM_BUMPMAP1;
- glGenTextures(1, &tex.id);
- }
- uchar unlit[3] = { ambientcolor[0], ambientcolor[1], ambientcolor[2] };
- createtexture(lightmaptexs[LMID_AMBIENT].id, 1, 1, unlit, 0, 1);
- bvec front(128, 128, 255);
- createtexture(lightmaptexs[LMID_AMBIENT1].id, 1, 1, &front, 0, 1);
- uchar bright[3] = { uchar(fullbrightlevel), uchar(fullbrightlevel), uchar(fullbrightlevel) };
- createtexture(lightmaptexs[LMID_BRIGHT].id, 1, 1, bright, 0, 1);
- createtexture(lightmaptexs[LMID_BRIGHT1].id, 1, 1, &front, 0, 1);
- uchar dark[3] = { 0, 0, 0 };
- createtexture(lightmaptexs[LMID_DARK].id, 1, 1, dark, 0, 1);
- createtexture(lightmaptexs[LMID_DARK1].id, 1, 1, &front, 0, 1);
+ while(lightmaptexs.length() < LMID_RESERVED)
+ {
+ LightMapTexture &tex = lightmaptexs.add();
+ tex.type = lightmaptexs.length()&1 ? LM_DIFFUSE : LM_BUMPMAP1;
+ glGenTextures(1, &tex.id);
+ }
+ uchar unlit[3] = { ambientcolor[0], ambientcolor[1], ambientcolor[2] };
+ createtexture(lightmaptexs[LMID_AMBIENT].id, 1, 1, unlit, 0, 1);
+ bvec front(128, 128, 255);
+ createtexture(lightmaptexs[LMID_AMBIENT1].id, 1, 1, &front, 0, 1);
+ uchar bright[3] = { uchar(fullbrightlevel), uchar(fullbrightlevel), uchar(fullbrightlevel) };
+ createtexture(lightmaptexs[LMID_BRIGHT].id, 1, 1, bright, 0, 1);
+ createtexture(lightmaptexs[LMID_BRIGHT1].id, 1, 1, &front, 0, 1);
+ uchar dark[3] = { 0, 0, 0 };
+ createtexture(lightmaptexs[LMID_DARK].id, 1, 1, dark, 0, 1);
+ createtexture(lightmaptexs[LMID_DARK1].id, 1, 1, &front, 0, 1);
}
static void findunlit(int i)
{
- LightMap &lm = lightmaps[i];
- if(lm.unlitx>=0) return;
- else if((lm.type&LM_TYPE)==LM_BUMPMAP0)
- {
- if(i+1>=lightmaps.length() || (lightmaps[i+1].type&LM_TYPE)!=LM_BUMPMAP1) return;
- }
- else if((lm.type&LM_TYPE)!=LM_DIFFUSE) return;
- uchar *data = lm.data;
- loop(y, 2) loop(x, LM_PACKW)
- {
- if(!data[0] && !data[1] && !data[2])
- {
- memcpy(data, ambientcolor.v, 3);
- if((lm.type&LM_TYPE)==LM_BUMPMAP0) ((bvec *)lightmaps[i+1].data)[y*LM_PACKW + x] = bvec(128, 128, 255);
- lm.unlitx = x;
- lm.unlity = y;
- return;
- }
- if(data[0]==ambientcolor[0] && data[1]==ambientcolor[1] && data[2]==ambientcolor[2])
- {
- if((lm.type&LM_TYPE)!=LM_BUMPMAP0 || ((bvec *)lightmaps[i+1].data)[y*LM_PACKW + x] == bvec(128, 128, 255))
- {
- lm.unlitx = x;
- lm.unlity = y;
- return;
- }
- }
- data += lm.bpp;
- }
+ LightMap &lm = lightmaps[i];
+ if(lm.unlitx>=0) return;
+ else if((lm.type&LM_TYPE)==LM_BUMPMAP0)
+ {
+ if(i+1>=lightmaps.length() || (lightmaps[i+1].type&LM_TYPE)!=LM_BUMPMAP1) return;
+ }
+ else if((lm.type&LM_TYPE)!=LM_DIFFUSE) return;
+ uchar *data = lm.data;
+ loop(y, 2) loop(x, LM_PACKW)
+ {
+ if(!data[0] && !data[1] && !data[2])
+ {
+ memcpy(data, ambientcolor.v, 3);
+ if((lm.type&LM_TYPE)==LM_BUMPMAP0) ((bvec *)lightmaps[i+1].data)[y*LM_PACKW + x] = bvec(128, 128, 255);
+ lm.unlitx = x;
+ lm.unlity = y;
+ return;
+ }
+ if(data[0]==ambientcolor[0] && data[1]==ambientcolor[1] && data[2]==ambientcolor[2])
+ {
+ if((lm.type&LM_TYPE)!=LM_BUMPMAP0 || ((bvec *)lightmaps[i+1].data)[y*LM_PACKW + x] == bvec(128, 128, 255))
+ {
+ lm.unlitx = x;
+ lm.unlity = y;
+ return;
+ }
+ }
+ data += lm.bpp;
+ }
}
VARF(roundlightmaptex, 0, 4, 16, { cleanuplightmaps(); initlights(); allchanged(); });
@@ -2443,286 +2270,286 @@ VARF(batchlightmaps, 0, 4, 256, { cleanuplightmaps(); initlights(); allchanged()
void genlightmaptexs(int flagmask, int flagval)
{
- if(lightmaptexs.length() < LMID_RESERVED) genreservedlightmaptexs();
-
- int remaining[LM_TYPE+1] = { 0 }, total = 0;
- loopv(lightmaps)
- {
- LightMap &lm = lightmaps[i];
- if(lm.tex >= 0 || (lm.type&flagmask)!=flagval) continue;
- int type = lm.type&LM_TYPE;
- remaining[type]++;
- total++;
- if(lm.unlitx < 0) findunlit(i);
- }
-
- int sizelimit = (maxtexsize ? min(maxtexsize, hwtexsize) : hwtexsize)/max(LM_PACKW, LM_PACKH);
- sizelimit = min(batchlightmaps, sizelimit*sizelimit);
- while(total)
- {
- int type = LM_DIFFUSE;
- LightMap *firstlm = NULL;
- loopv(lightmaps)
- {
- LightMap &lm = lightmaps[i];
- if(lm.tex >= 0 || (lm.type&flagmask) != flagval) continue;
- type = lm.type&LM_TYPE;
- firstlm = &lm;
- break;
- }
- if(!firstlm) break;
- int used = 0, uselimit = min(remaining[type], sizelimit);
- do used++; while((1<<used) <= uselimit);
- used--;
- int oldval = remaining[type];
- remaining[type] -= 1<<used;
- if(remaining[type] && (2<<used) <= min(roundlightmaptex, sizelimit))
- {
- remaining[type] -= min(remaining[type], 1<<used);
- used++;
- }
- total -= oldval - remaining[type];
- LightMapTexture &tex = lightmaptexs.add();
- tex.type = firstlm->type;
- tex.w = LM_PACKW<<((used+1)/2);
- tex.h = LM_PACKH<<(used/2);
- int bpp = firstlm->bpp;
- uchar *data = used ? new uchar[bpp*tex.w*tex.h] : NULL;
- int offsetx = 0, offsety = 0;
- loopv(lightmaps)
- {
- LightMap &lm = lightmaps[i];
- if(lm.tex >= 0 || (lm.type&flagmask) != flagval || (lm.type&LM_TYPE) != type) continue;
-
- lm.tex = lightmaptexs.length()-1;
- lm.offsetx = offsetx;
- lm.offsety = offsety;
- if(tex.unlitx < 0 && lm.unlitx >= 0)
- {
- tex.unlitx = offsetx + lm.unlitx;
- tex.unlity = offsety + lm.unlity;
- }
-
- if(data) copylightmap(lm, &data[bpp*(offsety*tex.w + offsetx)], bpp*tex.w);
-
- offsetx += LM_PACKW;
- if(offsetx >= tex.w) { offsetx = 0; offsety += LM_PACKH; }
- if(offsety >= tex.h) break;
- }
-
- glGenTextures(1, &tex.id);
- createtexture(tex.id, tex.w, tex.h, data ? data : firstlm->data, 3, 1, bpp==4 ? GL_RGBA : GL_RGB);
- if(data) delete[] data;
- }
+ if(lightmaptexs.length() < LMID_RESERVED) genreservedlightmaptexs();
+
+ int remaining[LM_TYPE+1] = { 0 }, total = 0;
+ loopv(lightmaps)
+ {
+ LightMap &lm = lightmaps[i];
+ if(lm.tex >= 0 || (lm.type&flagmask)!=flagval) continue;
+ int type = lm.type&LM_TYPE;
+ remaining[type]++;
+ total++;
+ if(lm.unlitx < 0) findunlit(i);
+ }
+
+ int sizelimit = (maxtexsize ? min(maxtexsize, hwtexsize) : hwtexsize)/max(LM_PACKW, LM_PACKH);
+ sizelimit = min(batchlightmaps, sizelimit*sizelimit);
+ while(total)
+ {
+ int type = LM_DIFFUSE;
+ LightMap *firstlm = NULL;
+ loopv(lightmaps)
+ {
+ LightMap &lm = lightmaps[i];
+ if(lm.tex >= 0 || (lm.type&flagmask) != flagval) continue;
+ type = lm.type&LM_TYPE;
+ firstlm = &lm;
+ break;
+ }
+ if(!firstlm) break;
+ int used = 0, uselimit = min(remaining[type], sizelimit);
+ do used++; while((1<<used) <= uselimit);
+ used--;
+ int oldval = remaining[type];
+ remaining[type] -= 1<<used;
+ if(remaining[type] && (2<<used) <= min(roundlightmaptex, sizelimit))
+ {
+ remaining[type] -= min(remaining[type], 1<<used);
+ used++;
+ }
+ total -= oldval - remaining[type];
+ LightMapTexture &tex = lightmaptexs.add();
+ tex.type = firstlm->type;
+ tex.w = LM_PACKW<<((used+1)/2);
+ tex.h = LM_PACKH<<(used/2);
+ int bpp = firstlm->bpp;
+ uchar *data = used ? new uchar[bpp*tex.w*tex.h] : NULL;
+ int offsetx = 0, offsety = 0;
+ loopv(lightmaps)
+ {
+ LightMap &lm = lightmaps[i];
+ if(lm.tex >= 0 || (lm.type&flagmask) != flagval || (lm.type&LM_TYPE) != type) continue;
+
+ lm.tex = lightmaptexs.length()-1;
+ lm.offsetx = offsetx;
+ lm.offsety = offsety;
+ if(tex.unlitx < 0 && lm.unlitx >= 0)
+ {
+ tex.unlitx = offsetx + lm.unlitx;
+ tex.unlity = offsety + lm.unlity;
+ }
+
+ if(data) copylightmap(lm, &data[bpp*(offsety*tex.w + offsetx)], bpp*tex.w);
+
+ offsetx += LM_PACKW;
+ if(offsetx >= tex.w) { offsetx = 0; offsety += LM_PACKH; }
+ if(offsety >= tex.h) break;
+ }
+
+ glGenTextures(1, &tex.id);
+ createtexture(tex.id, tex.w, tex.h, data ? data : firstlm->data, 3, 1, bpp==4 ? GL_RGBA : GL_RGB);
+ if(data) delete[] data;
+ }
}
bool brightengeom = false, shouldlightents = false;
void clearlights()
{
- clearlightcache();
- const vector<extentity *> &ents = entities::getents();
- loopv(ents)
- {
- extentity &e = *ents[i];
- e.light.color = vec(1, 1, 1);
- e.light.dir = vec(0, 0, 1);
- }
- shouldlightents = false;
+ clearlightcache();
+ const vector<extentity *> &ents = entities::getents();
+ loopv(ents)
+ {
+ extentity &e = *ents[i];
+ e.light.color = vec(1, 1, 1);
+ e.light.dir = vec(0, 0, 1);
+ }
+ shouldlightents = false;
- genlightmaptexs(LM_ALPHA, 0);
- genlightmaptexs(LM_ALPHA, LM_ALPHA);
- brightengeom = true;
+ genlightmaptexs(LM_ALPHA, 0);
+ genlightmaptexs(LM_ALPHA, LM_ALPHA);
+ brightengeom = true;
}
void lightent(extentity &e, float height)
{
- if(e.type==ET_LIGHT) return;
- float ambient = 0.0f;
- if(e.type==ET_MAPMODEL)
- {
- model *m = loadmodel(NULL, e.attr2);
- if(m) height = m->above()*0.75f;
- }
- else if(e.type>=ET_GAMESPECIFIC) ambient = 0.4f;
- vec target(e.o.x, e.o.y, e.o.z + height);
- lightreaching(target, e.light.color, e.light.dir, false, &e, ambient);
+ if(e.type==ET_LIGHT) return;
+ float ambient = 0.0f;
+ if(e.type==ET_MAPMODEL)
+ {
+ model *m = loadmodel(NULL, e.attr2);
+ if(m) height = m->above()*0.75f;
+ }
+ else if(e.type>=ET_GAMESPECIFIC) ambient = 0.4f;
+ vec target(e.o.x, e.o.y, e.o.z + height);
+ lightreaching(target, e.light.color, e.light.dir, false, &e, ambient);
}
void lightents(bool force)
{
- if(!force && !shouldlightents) return;
+ if(!force && !shouldlightents) return;
- const vector<extentity *> &ents = entities::getents();
- loopv(ents) lightent(*ents[i]);
+ const vector<extentity *> &ents = entities::getents();
+ loopv(ents) lightent(*ents[i]);
- shouldlightents = false;
+ shouldlightents = false;
}
void initlights()
{
- if((fullbright && editmode) || lightmaps.empty())
- {
- clearlights();
- return;
- }
+ if((fullbright && editmode) || lightmaps.empty())
+ {
+ clearlights();
+ return;
+ }
- clearlightcache();
- genlightmaptexs(LM_ALPHA, 0);
- genlightmaptexs(LM_ALPHA, LM_ALPHA);
- brightengeom = false;
- shouldlightents = true;
+ clearlightcache();
+ genlightmaptexs(LM_ALPHA, 0);
+ genlightmaptexs(LM_ALPHA, LM_ALPHA);
+ brightengeom = false;
+ shouldlightents = true;
}
static inline void fastskylight(const vec &o, float tolerance, uchar *skylight, int flags = RAY_ALPHAPOLY, extentity *t = NULL, bool fast = false)
{
- flags |= RAY_SHADOW;
- if(skytexturelight) flags |= RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0);
- if(fast)
- {
- static const vec ray(0, 0, 1);
- if(shadowray(vec(ray).mul(tolerance).add(o), ray, 1e16f, flags, t)>1e15f)
- memcpy(skylight, skylightcolor.v, 3);
- else memcpy(skylight, ambientcolor.v, 3);
- }
- else
- {
- static const vec rays[5] =
- {
- vec(cosf(66*RAD)*cosf(65*RAD), sinf(66*RAD)*cosf(65*RAD), sinf(65*RAD)),
- vec(cosf(156*RAD)*cosf(65*RAD), sinf(156*RAD)*cosf(65*RAD), sinf(65*RAD)),
- vec(cosf(246*RAD)*cosf(65*RAD), sinf(246*RAD)*cosf(65*RAD), sinf(65*RAD)),
- vec(cosf(336*RAD)*cosf(65*RAD), sinf(336*RAD)*cosf(65*RAD), sinf(65*RAD)),
- vec(0, 0, 1),
- };
- int hit = 0;
- loopi(5) if(shadowray(vec(rays[i]).mul(tolerance).add(o), rays[i], 1e16f, flags, t)>1e15f) hit++;
- loopk(3) skylight[k] = uchar(ambientcolor[k] + (max(skylightcolor[k], ambientcolor[k]) - ambientcolor[k])*hit/5.0f);
- }
+ flags |= RAY_SHADOW;
+ if(skytexturelight) flags |= RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0);
+ if(fast)
+ {
+ static const vec ray(0, 0, 1);
+ if(shadowray(vec(ray).mul(tolerance).add(o), ray, 1e16f, flags, t)>1e15f)
+ memcpy(skylight, skylightcolor.v, 3);
+ else memcpy(skylight, ambientcolor.v, 3);
+ }
+ else
+ {
+ static const vec rays[5] =
+ {
+ vec(cosf(66*RAD)*cosf(65*RAD), sinf(66*RAD)*cosf(65*RAD), sinf(65*RAD)),
+ vec(cosf(156*RAD)*cosf(65*RAD), sinf(156*RAD)*cosf(65*RAD), sinf(65*RAD)),
+ vec(cosf(246*RAD)*cosf(65*RAD), sinf(246*RAD)*cosf(65*RAD), sinf(65*RAD)),
+ vec(cosf(336*RAD)*cosf(65*RAD), sinf(336*RAD)*cosf(65*RAD), sinf(65*RAD)),
+ vec(0, 0, 1),
+ };
+ int hit = 0;
+ loopi(5) if(shadowray(vec(rays[i]).mul(tolerance).add(o), rays[i], 1e16f, flags, t)>1e15f) hit++;
+ loopk(3) skylight[k] = uchar(ambientcolor[k] + (max(skylightcolor[k], ambientcolor[k]) - ambientcolor[k])*hit/5.0f);
+ }
}
void lightreaching(const vec &target, vec &color, vec &dir, bool fast, extentity *t, float ambient)
{
- if((fullbright && editmode) || lightmaps.empty())
- {
- color = vec(1, 1, 1);
- dir = vec(0, 0, 1);
- return;
- }
-
- color = dir = vec(0, 0, 0);
- const vector<extentity *> &ents = entities::getents();
- const vector<int> &lights = checklightcache(int(target.x), int(target.y));
- loopv(lights)
- {
- extentity &e = *ents[lights[i]];
- if(e.type != ET_LIGHT)
- continue;
-
- vec ray(target);
- ray.sub(e.o);
- float mag = ray.magnitude();
- if(e.attr1 && mag >= float(e.attr1))
- continue;
-
- if(mag < 1e-4f) ray = vec(0, 0, -1);
- else
- {
- ray.div(mag);
- if(shadowray(e.o, ray, mag, RAY_SHADOW | RAY_POLY, t) < mag)
- continue;
- }
-
- float intensity = 1;
- if(e.attr1)
- intensity -= mag / float(e.attr1);
- if(e.attached && e.attached->type==ET_SPOTLIGHT)
- {
- vec spot = vec(e.attached->o).sub(e.o).normalize();
- float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
- if(spotatten <= 0) continue;
- intensity *= spotatten;
- }
-
- //if(target==player->o)
- //{
- // conoutf(CON_DEBUG, "%d - %f %f", i, intensity, mag);
- //}
-
- vec lightcol = vec(e.attr2, e.attr3, e.attr4).mul(1.0f/255);
- color.add(vec(lightcol).mul(intensity));
- dir.add(vec(ray).mul(-intensity*lightcol.x*lightcol.y*lightcol.z));
- }
- if(sunlight && shadowray(target, sunlightdir, 1e16f, RAY_SHADOW | RAY_POLY | (skytexturelight ? RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0) : 0), t) > 1e15f)
- {
- vec lightcol = vec(sunlightcolor.x, sunlightcolor.y, sunlightcolor.z).mul(sunlightscale/255);
- color.add(lightcol);
- dir.add(vec(sunlightdir).mul(lightcol.x*lightcol.y*lightcol.z));
- }
- if(hasskylight())
- {
- uchar skylight[3];
- if(t) calcskylight(NULL, target, vec(0, 0, 0), 0.5f, skylight, RAY_POLY, t);
- else fastskylight(target, 0.5f, skylight, RAY_POLY, t, fast);
- loopk(3) color[k] = min(1.5f, max(max(skylight[k]/255.0f, ambient), color[k]));
- }
- else loopk(3) color[k] = min(1.5f, max(max(ambientcolor[k]/255.0f, ambient), color[k]));
- if(dir.iszero()) dir = vec(0, 0, 1);
- else dir.normalize();
+ if((fullbright && editmode) || lightmaps.empty())
+ {
+ color = vec(1, 1, 1);
+ dir = vec(0, 0, 1);
+ return;
+ }
+
+ color = dir = vec(0, 0, 0);
+ const vector<extentity *> &ents = entities::getents();
+ const vector<int> &lights = checklightcache(int(target.x), int(target.y));
+ loopv(lights)
+ {
+ extentity &e = *ents[lights[i]];
+ if(e.type != ET_LIGHT)
+ continue;
+
+ vec ray(target);
+ ray.sub(e.o);
+ float mag = ray.magnitude();
+ if(e.attr1 && mag >= float(e.attr1))
+ continue;
+
+ if(mag < 1e-4f) ray = vec(0, 0, -1);
+ else
+ {
+ ray.div(mag);
+ if(shadowray(e.o, ray, mag, RAY_SHADOW | RAY_POLY, t) < mag)
+ continue;
+ }
+
+ float intensity = 1;
+ if(e.attr1)
+ intensity -= mag / float(e.attr1);
+ if(e.attached && e.attached->type==ET_SPOTLIGHT)
+ {
+ vec spot = vec(e.attached->o).sub(e.o).normalize();
+ float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
+ if(spotatten <= 0) continue;
+ intensity *= spotatten;
+ }
+
+ //if(target==player->o)
+ //{
+ // conoutf(CON_DEBUG, "%d - %f %f", i, intensity, mag);
+ //}
+
+ vec lightcol = vec(e.attr2, e.attr3, e.attr4).mul(1.0f/255);
+ color.add(vec(lightcol).mul(intensity));
+ dir.add(vec(ray).mul(-intensity*lightcol.x*lightcol.y*lightcol.z));
+ }
+ if(sunlight && shadowray(target, sunlightdir, 1e16f, RAY_SHADOW | RAY_POLY | (skytexturelight ? RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0) : 0), t) > 1e15f)
+ {
+ vec lightcol = vec(sunlightcolor.x, sunlightcolor.y, sunlightcolor.z).mul(sunlightscale/255);
+ color.add(lightcol);
+ dir.add(vec(sunlightdir).mul(lightcol.x*lightcol.y*lightcol.z));
+ }
+ if(hasskylight())
+ {
+ uchar skylight[3];
+ if(t) calcskylight(NULL, target, vec(0, 0, 0), 0.5f, skylight, RAY_POLY, t);
+ else fastskylight(target, 0.5f, skylight, RAY_POLY, t, fast);
+ loopk(3) color[k] = min(1.5f, max(max(skylight[k]/255.0f, ambient), color[k]));
+ }
+ else loopk(3) color[k] = min(1.5f, max(max(ambientcolor[k]/255.0f, ambient), color[k]));
+ if(dir.iszero()) dir = vec(0, 0, 1);
+ else dir.normalize();
}
entity *brightestlight(const vec &target, const vec &dir)
{
- if(sunlight && sunlightdir.dot(dir) > 0 && shadowray(target, sunlightdir, 1e16f, RAY_SHADOW | RAY_POLY | (skytexturelight ? RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0) : 0)) > 1e15f)
- return &sunlightent;
- const vector<extentity *> &ents = entities::getents();
- const vector<int> &lights = checklightcache(int(target.x), int(target.y));
- extentity *brightest = NULL;
- float bintensity = 0;
- loopv(lights)
- {
- extentity &e = *ents[lights[i]];
- if(e.type != ET_LIGHT || vec(e.o).sub(target).dot(dir)<0)
- continue;
-
- vec ray(target);
- ray.sub(e.o);
- float mag = ray.magnitude();
- if(e.attr1 && mag >= float(e.attr1))
- continue;
-
- ray.div(mag);
- if(shadowray(e.o, ray, mag, RAY_SHADOW | RAY_POLY) < mag)
- continue;
- float intensity = 1;
- if(e.attr1)
- intensity -= mag / float(e.attr1);
- if(e.attached && e.attached->type==ET_SPOTLIGHT)
- {
- vec spot = vec(e.attached->o).sub(e.o).normalize();
- float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
- if(spotatten <= 0) continue;
- intensity *= spotatten;
- }
-
- if(!brightest || intensity > bintensity)
- {
- brightest = &e;
- bintensity = intensity;
- }
- }
- return brightest;
+ if(sunlight && sunlightdir.dot(dir) > 0 && shadowray(target, sunlightdir, 1e16f, RAY_SHADOW | RAY_POLY | (skytexturelight ? RAY_SKIPSKY | (useskytexture ? RAY_SKYTEX : 0) : 0)) > 1e15f)
+ return &sunlightent;
+ const vector<extentity *> &ents = entities::getents();
+ const vector<int> &lights = checklightcache(int(target.x), int(target.y));
+ extentity *brightest = NULL;
+ float bintensity = 0;
+ loopv(lights)
+ {
+ extentity &e = *ents[lights[i]];
+ if(e.type != ET_LIGHT || vec(e.o).sub(target).dot(dir)<0)
+ continue;
+
+ vec ray(target);
+ ray.sub(e.o);
+ float mag = ray.magnitude();
+ if(e.attr1 && mag >= float(e.attr1))
+ continue;
+
+ ray.div(mag);
+ if(shadowray(e.o, ray, mag, RAY_SHADOW | RAY_POLY) < mag)
+ continue;
+ float intensity = 1;
+ if(e.attr1)
+ intensity -= mag / float(e.attr1);
+ if(e.attached && e.attached->type==ET_SPOTLIGHT)
+ {
+ vec spot = vec(e.attached->o).sub(e.o).normalize();
+ float maxatten = sincos360[clamp(int(e.attached->attr1), 1, 89)].x, spotatten = (ray.dot(spot) - maxatten) / (1 - maxatten);
+ if(spotatten <= 0) continue;
+ intensity *= spotatten;
+ }
+
+ if(!brightest || intensity > bintensity)
+ {
+ brightest = &e;
+ bintensity = intensity;
+ }
+ }
+ return brightest;
}
void dumplms()
{
- loopv(lightmaps)
- {
- ImageData temp(LM_PACKW, LM_PACKH, lightmaps[i].bpp, lightmaps[i].data);
- const char *map = game::getclientmap(), *name = strrchr(map, '/');
- defformatstring(buf, "lightmap_%s_%d.png", name ? name+1 : map, i);
- savepng(buf, temp, true);
- }
+ loopv(lightmaps)
+ {
+ ImageData temp(LM_PACKW, LM_PACKH, lightmaps[i].bpp, lightmaps[i].data);
+ const char *map = game::getclientmap(), *name = strrchr(map, '/');
+ defformatstring(buf, "lightmap_%s_%d.png", name ? name+1 : map, i);
+ savepng(buf, temp, true);
+ }
}
COMMAND(dumplms, "");