From b1cf271061a961d86e9ae376f2a015685dc5003e Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Mon, 13 Oct 2008 13:31:33 +0000 Subject: [PATCH] use projective texturing for blob shadows git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2996 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/protos.h | 6 +- source/src/rendercubes.cpp | 129 +++++++++++++++++++++++++++++++++++-- source/src/rendergl.cpp | 23 +++---- source/src/vertmodel.h | 58 ++++++++++++++--- 4 files changed, 189 insertions(+), 27 deletions(-) diff --git a/source/src/protos.h b/source/src/protos.h index 9f192416..74fc58ca 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -203,7 +203,7 @@ extern serverinfo *getconnectedserverinfo(); extern void pingservers(); // rendergl -extern glmatrixf mvmatrix, projmatrix, mvpmatrix, invmvmatrix, invmvpmatrix; +extern glmatrixf mvmatrix, projmatrix, clipmatrix, mvpmatrix, invmvmatrix, invmvpmatrix; extern void gl_checkextensions(); extern void gl_init(int w, int h, int bpp, int depth, int fsaa); @@ -272,6 +272,10 @@ extern void setupstrips(); extern void renderstripssky(); extern void renderstrips(); +extern vec shadowtexgenS, shadowtexgenT; + +extern void rendershadow(int x, int y, int xs, int ys); + // water extern void setwatercolor(const char *r = "", const char *g = "", const char *b = "", const char *a = ""); extern void calcwaterscissor(); diff --git a/source/src/rendercubes.cpp b/source/src/rendercubes.cpp index 332c75f7..fae99fad 100644 --- a/source/src/rendercubes.cpp +++ b/source/src/rendercubes.cpp @@ -128,7 +128,7 @@ COMMAND(showmip, ARG_NONE); VAR(mergestrips, 0, 1, 1); -#define stripend() \ +#define stripend(verts) \ if(floorstrip || deltastrip) { \ int type = GL_TRIANGLE_STRIP, len = verts.length()-firstindex; \ if(mergestrips) switch(len) { \ @@ -139,7 +139,7 @@ VAR(mergestrips, 0, 1, 1); floorstrip = deltastrip = false; \ } -void finishstrips() { stripend(); } +void finishstrips() { stripend(verts); } sqr sbright, sdark; VARP(lighterror, 1, 4, 100); @@ -160,7 +160,7 @@ void render_flat(int wtex, int x, int y, int size, int h, sqr *l1, sqr *l2, sqr if(first) // start strip here { - stripend(); + stripend(verts); firstindex = verts.length(); striptex = wtex; oh = h; @@ -237,7 +237,7 @@ void render_flatdelta(int wtex, int x, int y, int size, float h1, float h2, floa if(first) { - stripend(); + stripend(verts); firstindex = verts.length(); striptex = wtex; ox = x; @@ -277,7 +277,7 @@ void render_flatdelta(int wtex, int x, int y, int size, float h1, float h2, floa void render_2tris(sqr *h, sqr *s, int x1, int y1, int x2, int y2, int x3, int y3, sqr *l1, sqr *l2, sqr *l3) // floor/ceil tris on a corner cube { - stripend(); + stripend(verts); Texture *t = lookupworldtexture(h->ftex); float xf = TEXTURESCALE/t->xs; @@ -315,7 +315,7 @@ void render_tris(int x, int y, int size, bool topleft, void render_square(int wtex, float floor1, float floor2, float ceil1, float ceil2, int x1, int y1, int x2, int y2, int size, sqr *l1, sqr *l2, bool flip) // wall quads { - stripend(); + stripend(verts); if(showm) { l1 = &sbright; l2 = &sdark; } Texture *t = lookupworldtexture(wtex); @@ -350,10 +350,127 @@ void resetcubes() floorstrip = deltastrip = false; nquads = 0; + sbright.r = sbright.g = sbright.b = 255; sdark.r = sdark.g = sdark.b = 0; resetwater(); +} + +struct shadowvertex { float u, v, x, y, z; }; +vector shadowverts; + +static void resetshadowverts() +{ + shadowverts.setsizenodelete(0); + + floorstrip = deltastrip = false; } +static void rendershadowstrips() +{ + stripend(shadowverts); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + shadowvertex *buf = shadowverts.getbuf(); + glVertexPointer(3, GL_FLOAT, sizeof(shadowvertex), &buf->x); + glTexCoordPointer(2, GL_FLOAT, sizeof(shadowvertex), &buf->u); + + loopj(renderedtexs) + { + stripbatch &sb = stripbatches[j]; + RENDERSTRIPS(sb.tris, GL_TRIANGLES); + RENDERSTRIPS(sb.tristrips, GL_TRIANGLE_STRIP); + RENDERSTRIPS(sb.quads, GL_QUADS); + } + renderedtexs = 0; + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + xtraverts += shadowverts.length(); +} + +#define shadowvert(v1, v2, v3) { \ + shadowvertex &v = shadowverts.add(); \ + v.x = (float)(v1); v.y = (float)(v2); v.z = (float)(v3); \ + v.u = v.x*shadowtexgenS.x + v.y*shadowtexgenS.y + shadowtexgenS.z; \ + v.v = v.x*shadowtexgenT.x + v.y*shadowtexgenT.y + shadowtexgenT.z; \ +} + +vec shadowtexgenS, shadowtexgenT; + +static void rendershadow_flat(int x, int y, int h) // floor quads +{ + bool first = !floorstrip || y!=oy+1 || h!=oh || x!=ox; + + if(first) // start strip here + { + stripend(shadowverts); + firstindex = shadowverts.length(); + striptex = DEFAULT_FLOOR; + oh = h; + ox = x; + floorstrip = true; + shadowvert(x, y, h); + shadowvert(x+1, y, h); + } + else // continue strip + { + shadowverts.setsizenodelete(shadowverts.length()-2); + } + + shadowvert(x, y+1, h); + shadowvert(x+1, y+1, h); + + oy = y; + nquads++; +} + +static void rendershadow_flatdelta(int x, int y, float h1, float h2, float h3, float h4) // floor quads on a slope +{ + bool first = !deltastrip || y!=oy+1 || x!=ox; + + if(first) + { + stripend(shadowverts); + firstindex = shadowverts.length(); + striptex = DEFAULT_FLOOR; + ox = x; + deltastrip = true; + shadowvert(x, y, h1); + shadowvert(x+1, y, h2); + } + + shadowvert(x, y+1, h4); + shadowvert(x+1, y+1, h3); + + oy = y; +} + +void rendershadow(int x, int y, int xs, int ys) +{ + resetshadowverts(); + + #define df(x) s->floor-(x->vdelta/4.0f) + + sqr *w = wmip[0]; + for(int xx = x; xxtype==SPACE || s->type==CHF) + { + rendershadow_flat(xx, yy, s->floor); + } + if(s->type==FHF) + { + sqr *t = SW(s,1,0), *u = SW(s,1,1), *v = SW(s,0,1); + rendershadow_flatdelta(xx, yy, df(s), df(t), df(u), df(v)); + } + } + + rendershadowstrips(); +} diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index f073449c..f944773f 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -144,7 +144,7 @@ void enablepolygonoffset(GLenum type) return; } - glmatrixf offsetmatrix = projmatrix; + glmatrixf offsetmatrix = reflecting ? clipmatrix : projmatrix; offsetmatrix[14] += depthoffset * projmatrix[10]; glMatrixMode(GL_PROJECTION); @@ -163,7 +163,7 @@ void disablepolygonoffset(GLenum type, bool restore) if(restore) { glMatrixMode(GL_PROJECTION); - glLoadMatrixf(projmatrix.v); + glLoadMatrixf(reflecting ? clipmatrix.v : projmatrix.v); glMatrixMode(GL_MODELVIEW); } } @@ -519,7 +519,9 @@ void transplayer() glTranslatef(-camera1->o.x, -camera1->o.y, -camera1->o.z); } -void genclipmatrix(float a, float b, float c, float d, glmatrixf &matrix) +glmatrixf clipmatrix; + +void genclipmatrix(float a, float b, float c, float d) { // transform the clip plane into camera space float clip[4]; @@ -529,11 +531,11 @@ void genclipmatrix(float a, float b, float c, float d, glmatrixf &matrix) y = ((clip[1]<0 ? -1 : (clip[1]>0 ? 1 : 0)) + projmatrix[9]) / projmatrix[5], w = (1 + projmatrix[10]) / projmatrix[14], scale = 2 / (x*clip[0] + y*clip[1] - clip[2] + w*clip[3]); - matrix = projmatrix; - matrix[2] = clip[0]*scale; - matrix[6] = clip[1]*scale; - matrix[10] = clip[2]*scale + 1.0f; - matrix[14] = clip[3]*scale; + clipmatrix = projmatrix; + clipmatrix[2] = clip[0]*scale; + clipmatrix[6] = clip[1]*scale; + clipmatrix[10] = clip[2]*scale + 1.0f; + clipmatrix[14] = clip[3]*scale; } bool reflecting = false, refracting = false; @@ -607,11 +609,10 @@ void drawreflection(float hf, int w, int h, float changelod, bool refract) glScalef(1, 1, -1); } - glmatrixf clipmat; - genclipmatrix(0, 0, -1, 0.1f*reflectclip+hf, clipmat); + genclipmatrix(0, 0, -1, 0.1f*reflectclip+hf); glMatrixMode(GL_PROJECTION); glPushMatrix(); - glLoadMatrixf(clipmat.v); + glLoadMatrixf(clipmatrix.v); glMatrixMode(GL_MODELVIEW); renderstripssky(); diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index 8fa9b6d0..e93dc5cf 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -2,6 +2,8 @@ VARP(dynshadowsize, 4, 5, 8); VARP(aadynshadow, 0, 2, 3); VARP(saveshadows, 0, 1, 1); +VARP(dynshadowquad, 0, 0, 1); + VAR(shadowyaw, 0, 45, 360); vec shadowdir(0, 0, -1), shadowpos(0, 0, 0); @@ -433,6 +435,12 @@ struct vertmodel : model if(!enabledepthmask) { glDepthMask(GL_TRUE); enabledepthmask = true; } } + if(enableoffset) + { + disablepolygonoffset(GL_POLYGON_OFFSET_FILL); + enableoffset = false; + } + bool isstat = as.frame==0 && as.range==1; if(isstat && statlist && !stenciling) { @@ -1123,12 +1131,43 @@ struct vertmodel : model float x1 = -shadowrad, x2 = shadowrad; float y1 = -shadowrad, y2 = shadowrad; - glBegin(GL_POLYGON); - glTexCoord2f(0, 1); glVertex3f(x1*c - y1*s + o.x, y1*c + x1*s + o.y, o.z); - glTexCoord2f(1, 1); glVertex3f(x2*c - y1*s + o.x, y1*c + x2*s + o.y, o.z); - glTexCoord2f(1, 0); glVertex3f(x2*c - y2*s + o.x, y2*c + x2*s + o.y, o.z); - glTexCoord2f(0, 0); glVertex3f(x1*c - y2*s + o.x, y2*c + x1*s + o.y, o.z); - glEnd(); + if(dynshadowquad) + { + glBegin(GL_QUADS); + glTexCoord2f(0, 1); glVertex3f(x1*c - y1*s + o.x, y1*c + x1*s + o.y, o.z); + glTexCoord2f(1, 1); glVertex3f(x2*c - y1*s + o.x, y1*c + x2*s + o.y, o.z); + glTexCoord2f(1, 0); glVertex3f(x2*c - y2*s + o.x, y2*c + x2*s + o.y, o.z); + glTexCoord2f(0, 0); glVertex3f(x1*c - y2*s + o.x, y2*c + x1*s + o.y, o.z); + glEnd(); + xtraverts += 4; + return; + } + + if(!enableoffset) + { + enablepolygonoffset(GL_POLYGON_OFFSET_FILL); + enableoffset = true; + } + if(lastvertexarray) + { + glDisableClientState(GL_VERTEX_ARRAY); + lastvertexarray = NULL; + } + if(lasttexcoordarray) + { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + lasttexcoordarray = NULL; + } + + shadowtexgenS.x = ((x2*c - y2*s) - (x1*c - y2*s)) / (2*shadowrad*2*shadowrad); + shadowtexgenS.y = ((y2*c + x2*s) - (y2*c + x1*s)) / (2*shadowrad*2*shadowrad); + shadowtexgenS.z = -(x1*c - y2*s + o.x)*shadowtexgenS.x - (y2*c + x1*s + o.y)*shadowtexgenS.y; + + shadowtexgenT.x = ((x1*c - y1*s) - (x1*c - y2*s)) / (2*shadowrad*2*shadowrad); + shadowtexgenT.y = ((y1*c + x1*s) - (y2*c + x1*s)) / (2*shadowrad*2*shadowrad); + shadowtexgenT.z = -(x1*c - y2*s + o.x)*shadowtexgenT.x - (y2*c + x1*s + o.y)*shadowtexgenT.y; + + ::rendershadow(int(floor(o.x-shadowrad)), int(floor(o.y-shadowrad)), int(ceil(o.x+shadowrad)), int(ceil(o.y+shadowrad))); } char *shadowfile() @@ -1222,7 +1261,7 @@ struct vertmodel : model loopv(parts) parts[i]->calcbbs(); } - static bool enablealphablend, enablealphatest, enabledepthmask; + static bool enablealphablend, enablealphatest, enabledepthmask, enableoffset; static GLuint lasttex; static float lastalphatest; static void *lastvertexarray, *lasttexcoordarray, *lastcolorarray; @@ -1231,7 +1270,7 @@ struct vertmodel : model void startrender() { - enablealphablend = enablealphatest = false; + enablealphablend = enablealphatest = enableoffset = false; enabledepthmask = true; lasttex = 0; lastalphatest = -1; @@ -1246,12 +1285,13 @@ struct vertmodel : model if(lastvertexarray) glDisableClientState(GL_VERTEX_ARRAY); if(lasttexcoordarray) glDisableClientState(GL_TEXTURE_COORD_ARRAY); if(lastcolorarray) glDisableClientState(GL_COLOR_ARRAY); + if(enableoffset) disablepolygonoffset(GL_POLYGON_OFFSET_FILL); } static modelcache dynalloc, statalloc; }; -bool vertmodel::enablealphablend = false, vertmodel::enablealphatest = false, vertmodel::enabledepthmask = true; +bool vertmodel::enablealphablend = false, vertmodel::enablealphatest = false, vertmodel::enabledepthmask = true, vertmodel::enableoffset = false; GLuint vertmodel::lasttex = 0; float vertmodel::lastalphatest = -1; void *vertmodel::lastvertexarray = NULL, *vertmodel::lasttexcoordarray = NULL, *vertmodel::lastcolorarray = NULL;