diff --git a/source/src/main.cpp b/source/src/main.cpp index 9b12e836..5874e014 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -674,8 +674,6 @@ int main(int argc, char **argv) checkinput(); - cleardlights(); - if(lastmillis) updateworld(curtime, lastmillis); lastmillis += curtime; diff --git a/source/src/protos.h b/source/src/protos.h index b7120744..1b115d51 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -369,8 +369,8 @@ extern void consolescores(); // world extern void setupworld(int factor); extern void empty_world(int factor, bool force); -extern void remip(block &b, int level = 0); -extern void remipmore(block &b, int level = 0); +extern void remip(const block &b, int level = 0); +extern void remipmore(const block &b, int level = 0); extern int closestent(); extern int findentity(int type, int index = 0); extern int findentity(int type, int index, uchar attr2); @@ -381,8 +381,10 @@ extern int lastcalclight; extern void fullbrightlight(int level); extern void calclight(); -extern void dodynlight(vec &vold, vec &v, int reach, int strength, dynent *owner); -extern void cleardlights(); +extern void adddynlight(const vec &o, int reach, int expire, int fade, uchar r, uchar g = 0, uchar b = 0); +extern void dodynlights(); +extern void undodynlights(); +extern void cleardynlights(); extern block *blockcopy(block &b); extern void blockpaste(block &b); extern void freeblock(block *&b); diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 95232cc7..3ae1ed67 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -826,6 +826,7 @@ void readdepth(int w, int h, vec &pos) void gl_drawframe(int w, int h, float changelod, float curfps) { + dodynlights(); drawminimap(w, h); recomputecamera(); @@ -959,5 +960,7 @@ void gl_drawframe(int w, int h, float changelod, float curfps) glEnable(GL_CULL_FACE); glEnable(GL_FOG); + + undodynlights(); } diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index 48f0247f..0c572fc2 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -619,7 +619,8 @@ void grenadeent::splash() particle_splash(0, 50, 300, o); particle_fireball(5, o); addscorchmark(o); - dodynlight(o, o, 0, 0, owner); + adddynlight(o, 16, 200, 100, 255); + adddynlight(o, 16, 400, 400, 192, 160, 128); if(owner != player1) return; int damage = guns[GUN_GRENADE].damage; radialeffect(owner, o, damage, owner, GUN_GRENADE); diff --git a/source/src/world.cpp b/source/src/world.cpp index 86a1f1fd..9b32ca8b 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -16,7 +16,7 @@ header hdr; // mip level indistinguishable from its constituent cubes (saves considerable // rendering time if this is possible). -void remip(block &b, int level) +void remip(const block &b, int level) { if(level>=SMALLEST_FACTOR) return; int lighterr = getvar("lighterror")*3; @@ -107,7 +107,7 @@ void remip(block &b, int level) remip(s, level+1); } -void remipmore(block &b, int level) +void remipmore(const block &b, int level) { block bb = b; if(bb.x>1) bb.x--; @@ -273,7 +273,7 @@ void setupworld(int factor) void empty_world(int factor, bool force) // main empty world creation routine, if passed factor -1 will enlarge old world by 1 { if(!force && noteditmode()) return; - cleardlights(); + cleardynlights(); pruneundos(); clearworldsounds(); sqr *oldworld = world; diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index f4873d25..345cc1b1 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -266,7 +266,7 @@ int numspawn[3], maploaded = 0, numflagspawn[2]; bool load_world(char *mname) // still supports all map formats that have existed since the earliest cube betas! { preparectf(true); - cleardlights(); + cleardynlights(); pruneundos(); clearworldsounds(); setnames(mname); diff --git a/source/src/worldlight.cpp b/source/src/worldlight.cpp index a2732e35..6ebabce0 100644 --- a/source/src/worldlight.cpp +++ b/source/src/worldlight.cpp @@ -5,7 +5,7 @@ VAR(lightscale,1,4,100); -void lightray(float bx, float by, persistent_entity &light) // done in realtime, needs to be fast +void lightray(float bx, float by, const persistent_entity &light, float fade = 1, bool flicker = false) // done in realtime, needs to be fast { float lx = light.x+(rnd(21)-10)*0.1f; float ly = light.y+(rnd(21)-10)*0.1f; @@ -19,7 +19,8 @@ void lightray(float bx, float by, persistent_entity &light) // done in realt const float PRECF = 4096.0f; int x = (int)(lx*PRECF); int y = (int)(ly*PRECF); - int l = light.attr2<>(PRECBITS+4))+1); + x += stepx*dimness; + y += stepy*dimness; + } if(OUTBORD(x>>PRECBITS, y>>PRECBITS)) return; - int g = light.attr3<>(PRECBITS+4))+1); + x += stepx*dimness; + y += stepy*dimness; + } if(OUTBORD(x>>PRECBITS, y>>PRECBITS)) return; @@ -102,7 +109,7 @@ void lightray(float bx, float by, persistent_entity &light) // done in realt } -void calclightsource(persistent_entity &l) +void calclightsource(const persistent_entity &l, float fade = 1, bool flicker = true) { int reach = l.attr1; int sx = l.x-reach; @@ -114,13 +121,13 @@ void calclightsource(persistent_entity &l) const float s = 0.8f; - for(float sx2 = (float)sx; sx2<=ex; sx2+=s*2) { lightray(sx2, (float)sy, l); lightray(sx2, (float)ey, l); } - for(float sy2 = sy+s; sy2<=ey-s; sy2+=s*2) { lightray((float)sx, sy2, l); lightray((float)ex, sy2, l); } + for(float sx2 = (float)sx; sx2<=ex; sx2+=s*2) { lightray(sx2, (float)sy, l, fade, flicker); lightray(sx2, (float)ey, l, fade, flicker); } + for(float sy2 = sy+s; sy2<=ey-s; sy2+=s*2) { lightray((float)sx, sy2, l, fade, flicker); lightray((float)ex, sy2, l, fade, flicker); } rndtime(); } -void postlightarea(block &a) // median filter, smooths out random noise in light and makes it more mipable +void postlightarea(const block &a) // median filter, smooths out random noise in light and makes it more mipable { loop(x,a.xs) loop(y,a.ys) // assumes area not on edge of world { @@ -165,41 +172,73 @@ void calclight() lastcalclight = totalmillis; } -VARP(dynlight, 0, 16, 32); - -vector dlights; - -void cleardlights() +struct dlight { - while(!dlights.empty()) + vec o; + block *backup; + int reach, fade, expire; + uchar r, g, b; + + float calcintensity() const { - block *backup = dlights.pop(); - blockpaste(*backup); - freeblock(backup); - lastcalclight = totalmillis; + if(!fade || lastmillis < expire - fade) return 1.0f; + return max(float(expire - lastmillis)/fade, 0.0f); } +}; + +vector dlights; + +void adddynlight(const vec &o, int reach, int expire, int fade, uchar r, uchar g, uchar b) +{ + dlight &d = dlights.add(); + d.o = o; + d.reach = reach; + d.fade = fade; + d.expire = lastmillis + expire; + d.r = r; + d.g = g; + d.b = b; + + block bak = { (int)o.x-reach, (int)o.y-reach, reach*2+1, reach*2+1 }; + + if(bak.x<1) bak.x = 1; + if(bak.y<1) bak.y = 1; + if(bak.xs+bak.x>ssize-2) bak.xs = ssize-2-bak.x; + if(bak.ys+bak.y>ssize-2) bak.ys = ssize-2-bak.y; + + d.backup = blockcopy(bak); // backup area before rendering in dynlight } -void dodynlight(vec &vold, vec &v, int reach, int strength, dynent *owner) +void cleardynlights() { - if(!reach) reach = dynlight; - if(!reach) return; - - int creach = reach+16; // dependant on lightray random offsets! - block b = { (int)v.x-creach, (int)v.y-creach, creach*2+1, creach*2+1 }; - - if(b.x<1) b.x = 1; - if(b.y<1) b.y = 1; - if(b.xs+b.x>ssize-2) b.xs = ssize-2-b.x; - if(b.ys+b.y>ssize-2) b.ys = ssize-2-b.y; - - dlights.add(blockcopy(b)); // backup area before rendering in dynlight - persistent_entity l((int)v.x, (int)v.y, (int)v.z, LIGHT, reach, strength, 0, 0); - calclightsource(l); - postlightarea(b); + loopv(dlights) freeblock(dlights[i].backup); + dlights.setsize(0); +} + +void dodynlights() +{ + if(dlights.empty()) return; + loopv(dlights) + { + dlight &d = dlights[i]; + if(lastmillis >= d.expire) + { + freeblock(d.backup); + dlights.remove(i--); + continue; + } + persistent_entity l((int)d.o.x, (int)d.o.y, (int)d.o.z, LIGHT, d.reach, d.r, d.g, d.b); + calclightsource(l, d.calcintensity(), false); + postlightarea(*d.backup); + } lastcalclight = totalmillis; } +void undodynlights() +{ + loopvrev(dlights) blockpaste(*dlights[i].backup); +} + // utility functions also used by editing code block *blockcopy(block &s)