From b76491d06e861765dfbea09a61b50b90e4620b7f Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 17 Sep 2008 03:34:58 +0000 Subject: [PATCH] vertex lighting option for mapmodels git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2656 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/editing.cpp | 2 +- source/src/geom.h | 22 +++++++- source/src/md2.h | 4 ++ source/src/md3.h | 4 ++ source/src/model.h | 4 +- source/src/protos.h | 3 ++ source/src/rendermodel.cpp | 8 +++ source/src/vertmodel.h | 108 +++++++++++++++++++++++++++++++++---- source/src/world.h | 1 + source/src/worldlight.cpp | 11 ++++ 10 files changed, 154 insertions(+), 13 deletions(-) diff --git a/source/src/editing.cpp b/source/src/editing.cpp index a7e9299c..db5e7fd9 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -465,7 +465,7 @@ VARF(fullbright, 0, 0, 1, if(fullbright) { if(noteditmode()) return; - loopi(mipsize) world[i].r = world[i].g = world[i].b = 176; + fullbrightlight(176); } ); diff --git a/source/src/geom.h b/source/src/geom.h index 65bf4a1b..5ca5a350 100644 --- a/source/src/geom.h +++ b/source/src/geom.h @@ -251,7 +251,27 @@ struct glmatrixf out.z = in.x*v[2] + in.y*v[6] + in.z*v[10] + v[14]; out.w = in.x*v[3] + in.y*v[7] + in.z*v[11] + v[15]; } - + + float transformx(const vec &p) const + { + return p.x*v[0] + p.y*v[4] + p.z*v[8] + v[12]; + } + + float transformy(const vec &p) const + { + return p.x*v[1] + p.y*v[5] + p.z*v[9] + v[13]; + } + + float transformz(const vec &p) const + { + return p.x*v[2] + p.y*v[6] + p.z*v[10] + v[14]; + } + + float transformw(const vec &p) const + { + return p.x*v[3] + p.y*v[7] + p.z*v[11] + v[15]; + } + vec gettranslation() const { return vec(v[12], v[13], v[14]); diff --git a/source/src/md2.h b/source/src/md2.h index 5a36263e..48bc8068 100644 --- a/source/src/md2.h +++ b/source/src/md2.h @@ -189,6 +189,10 @@ struct md2 : vertmodel (shadowpos = shadowdir).mul(shadowdist); } + modelpos = o; + modelyaw = yaw; + modelpitch = pitch; + glPushMatrix(); matrixpos = 0; matrixstack[0].identity(); diff --git a/source/src/md3.h b/source/src/md3.h index 1bed526a..d21d274b 100644 --- a/source/src/md3.h +++ b/source/src/md3.h @@ -174,6 +174,10 @@ struct md3 : vertmodel (shadowpos = shadowdir).mul(shadowdist); } + modelpos = o; + modelyaw = yaw; + modelpitch = pitch; + glPushMatrix(); matrixpos = 0; matrixstack[0].identity(); diff --git a/source/src/model.h b/source/src/model.h index 514c7656..50577c73 100644 --- a/source/src/model.h +++ b/source/src/model.h @@ -38,12 +38,12 @@ struct dynent; struct model { - bool cullface; + bool cullface, vertexlight; float alphatest, translucency, scale, radius, shadowdist; vec translate; int cachelimit, batch; - model() : cullface(true), alphatest(0.9f), translucency(0.25f), scale(1), radius(0), shadowdist(0), translate(0, 0, 0), cachelimit(8), batch(-1) {} + model() : cullface(true), vertexlight(false), alphatest(0.9f), translucency(0.25f), scale(1), radius(0), shadowdist(0), translate(0, 0, 0), cachelimit(8), batch(-1) {} virtual ~model() {} virtual bool load() = 0; diff --git a/source/src/protos.h b/source/src/protos.h index 31f8a4e1..b7120744 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -377,6 +377,9 @@ extern int findentity(int type, int index, uchar attr2); extern entity *newentity(int x, int y, int z, char *what, int v1, int v2, int v3, int v4); // worldlight +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(); diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 596307a0..8f53b52b 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -21,6 +21,14 @@ void mdlcullface(int cullface) COMMAND(mdlcullface, ARG_1INT); +void mdlvertexlight(int vertexlight) +{ + checkmdl; + loadingmodel->vertexlight = vertexlight!=0; +} + +COMMAND(mdlvertexlight, ARG_1INT); + void mdltranslucent(int translucency) { checkmdl; diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index 6da7714e..2c02fd2d 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -6,6 +6,9 @@ VAR(shadowyaw, 0, 45, 360); vec shadowdir(0, 0, -1), shadowpos(0, 0, 0); VAR(dbgstenc, 0, 0, 2); +VAR(dbgvlight, 0, 0, 1); + +vec modelpos; struct vertmodel : model { @@ -74,6 +77,7 @@ struct vertmodel : model }; struct tcvert { float u, v; }; + struct lightvert { uchar r, g, b, a; }; struct tri { ushort vert[3]; ushort neighbor[3]; }; struct part; @@ -99,6 +103,18 @@ struct vertmodel : model int numidxs() { return int((size - sizeof(shadowcacheentry)) / sizeof(ushort)); } }; + struct lightcacheentry : modelcacheentry + { + anpos cur, prev; + float t; + int lastcalclight; + vec pos; + float yaw, pitch; + + lightvert *verts() { return (lightvert *)getdata(); } + int numverts() { return int((size - sizeof(lightcacheentry)) / sizeof(lightvert)); } + }; + struct mesh { char *name; @@ -115,6 +131,7 @@ struct vertmodel : model modelcachelist dyncache; modelcachelist shadowcache; + modelcachelist lightcache; ushort *dynidx; int dynlen; @@ -327,6 +344,57 @@ struct vertmodel : model return d; } + lightcacheentry *lightvertexes(animstate &as, anpos &cur, anpos *prev, float ai_t, vec *buf) + { + if(dbgvlight) return NULL; + + lightcacheentry *d = lightcache.start(); + int cachelen = 0; + for(; d != lightcache.end(); d = d->next, cachelen++) + { + if(d->lastcalclight != lastcalclight || d->pos != modelpos || d->cur != cur) continue; + if(prev) + { + if(d->prev == *prev && d->t == ai_t) return d; + } + else if(d->prev.fr1 < 0) return d; + } + + bb curbb; + getcurbb(curbb, as, cur, prev, ai_t); + float dist = max(curbb.low.magnitude(), curbb.high.magnitude()); + if(OUTBORDRAD(modelpos.x, modelpos.y, dist)) return NULL; + + d = (owner->numframes > 1 || as.anim&ANIM_DYNALLOC ? dynalloc : statalloc).allocate(numverts*sizeof(lightvert)); + if(!d) return NULL; + + if(cachelen >= owner->model->cachelimit) lightcache.removelast(); + lightcache.addfirst(d); + d->lastcalclight = lastcalclight; + d->pos = modelpos; + d->yaw = modelyaw; + d->pitch = modelpitch; + d->cur = cur; + d->t = ai_t; + if(prev) d->prev = *prev; + else d->prev.fr1 = -1; + + const glmatrixf &m = matrixstack[matrixpos]; + lightvert *v = d->verts(); + loopi(numverts) + { + int x = (int)m.transformx(*buf), y = (int)m.transformy(*buf); + const sqr *s = S(x, y); + v->r = s->r; + v->g = s->g; + v->b = s->b; + v->a = 255; + v++; + buf++; + } + return d; + } + void getcurbb(bb &b, animstate &as, anpos &cur, anpos *prev, float ai_t) { b = bbs[cur.fr1]; @@ -395,6 +463,7 @@ struct vertmodel : model glVertexPointer(3, GL_FLOAT, sizeof(vec), buf); lastvertexarray = buf; } + lightvert *vlight = NULL; if(as.anim&ANIM_NOSKIN && (!isstat || stenciling)) { if(lasttexcoordarray) @@ -403,11 +472,31 @@ struct vertmodel : model lasttexcoordarray = NULL; } } - else if(lasttexcoordarray != tcverts) + else { - if(!lasttexcoordarray) glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(tcvert), tcverts); - lasttexcoordarray = tcverts; + if(lasttexcoordarray != tcverts) + { + if(!lasttexcoordarray) glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(tcvert), tcverts); + lasttexcoordarray = tcverts; + } + if(owner->model->vertexlight) + { + if(d) d->locked = true; + lightcacheentry *l = lightvertexes(as, cur, isstat ? NULL : prev, ai_t, buf); + if(d) d->locked = false; + if(l) vlight = l->verts(); + } + } + if(lastcolorarray != vlight) + { + if(vlight) + { + if(!lastcolorarray) glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(lightvert), vlight); + } + else glDisableClientState(GL_COLOR_ARRAY); + lastcolorarray = vlight; } if(stenciling) { @@ -421,14 +510,14 @@ struct vertmodel : model return; } - if(isstat) glNewList(statlist = glGenLists(1), GL_COMPILE); + if(isstat && !owner->model->vertexlight) glNewList(statlist = glGenLists(1), GL_COMPILE); loopi(numdyndraws) { const drawcall &d = dyndraws[i]; if(hasDRE) glDrawRangeElements_(d.type, d.minvert, d.maxvert, d.count, GL_UNSIGNED_SHORT, &dynidx[d.start]); else glDrawElements(d.type, d.count, GL_UNSIGNED_SHORT, &dynidx[d.start]); } - if(isstat) + if(isstat && !owner->model->vertexlight) { glEndList(); glCallList(statlist); @@ -1111,7 +1200,7 @@ struct vertmodel : model static bool enablealphablend, enablealphatest, enabledepthmask; static GLuint lasttex; static float lastalphatest; - static void *lastvertexarray, *lasttexcoordarray; + static void *lastvertexarray, *lasttexcoordarray, *lastcolorarray; static glmatrixf matrixstack[32]; static int matrixpos; @@ -1121,7 +1210,7 @@ struct vertmodel : model enabledepthmask = true; lasttex = 0; lastalphatest = -1; - lastvertexarray = lasttexcoordarray = NULL; + lastvertexarray = lasttexcoordarray = lastcolorarray = NULL; } void endrender() @@ -1131,6 +1220,7 @@ struct vertmodel : model if(!enabledepthmask) glDepthMask(GL_TRUE); if(lastvertexarray) glDisableClientState(GL_VERTEX_ARRAY); if(lasttexcoordarray) glDisableClientState(GL_TEXTURE_COORD_ARRAY); + if(lastcolorarray) glDisableClientState(GL_COLOR_ARRAY); } static modelcache dynalloc, statalloc; @@ -1139,7 +1229,7 @@ struct vertmodel : model bool vertmodel::enablealphablend = false, vertmodel::enablealphatest = false, vertmodel::enabledepthmask = true; GLuint vertmodel::lasttex = 0; float vertmodel::lastalphatest = -1; -void *vertmodel::lastvertexarray = NULL, *vertmodel::lasttexcoordarray = NULL; +void *vertmodel::lastvertexarray = NULL, *vertmodel::lasttexcoordarray = NULL, *vertmodel::lastcolorarray = NULL; glmatrixf vertmodel::matrixstack[32]; int vertmodel::matrixpos = 0; diff --git a/source/src/world.h b/source/src/world.h index 8e29b50d..8f69ab25 100644 --- a/source/src/world.h +++ b/source/src/world.h @@ -56,6 +56,7 @@ struct header // map file format header #define SOLID(x) ((x)->type==SOLID) #define MINBORD 2 // 2 cubes from the edge of the world are always solid #define OUTBORD(x,y) ((x)=ssize-MINBORD || (y)>=ssize-MINBORD) +#define OUTBORDRAD(x,y,rad) (int(x-rad)=ssize-MINBORD || (y+rad)>=ssize-MINBORD) struct block { int x, y, xs, ys; }; diff --git a/source/src/worldlight.cpp b/source/src/worldlight.cpp index de57ec5b..a2732e35 100644 --- a/source/src/worldlight.cpp +++ b/source/src/worldlight.cpp @@ -137,6 +137,14 @@ void postlightarea(block &a) // median filter, smooths out random noise in li remip(a); } +int lastcalclight = 0; + +void fullbrightlight(int level) +{ + loopi(mipsize) world[i].r = world[i].g = world[i].b = level; + lastcalclight = totalmillis; +} + void calclight() { loop(x,ssize) loop(y,ssize) @@ -154,6 +162,7 @@ void calclight() block b = { 1, 1, ssize-2, ssize-2 }; postlightarea(b); setvar("fullbright", 0); + lastcalclight = totalmillis; } VARP(dynlight, 0, 16, 32); @@ -167,6 +176,7 @@ void cleardlights() block *backup = dlights.pop(); blockpaste(*backup); freeblock(backup); + lastcalclight = totalmillis; } } @@ -187,6 +197,7 @@ void dodynlight(vec &vold, vec &v, int reach, int strength, dynent *owner) persistent_entity l((int)v.x, (int)v.y, (int)v.z, LIGHT, reach, strength, 0, 0); calclightsource(l); postlightarea(b); + lastcalclight = totalmillis; } // utility functions also used by editing code