From 875ed5eeb1e5e9b017cde8c2410634197628f72a Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Mon, 28 Apr 2008 07:27:48 +0000 Subject: [PATCH] reflection scissoring optimization git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1830 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/Makefile | 1 + source/src/geom.h | 16 ++ source/src/protos.h | 10 +- source/src/rendercubes.cpp | 234 +---------------------------- source/src/rendergl.cpp | 49 +++++-- source/src/vertmodel.h | 4 +- source/src/water.cpp | 294 +++++++++++++++++++++++++++++++++++++ 7 files changed, 358 insertions(+), 250 deletions(-) create mode 100644 source/src/water.cpp diff --git a/source/src/Makefile b/source/src/Makefile index 142c15be..21417e11 100644 --- a/source/src/Makefile +++ b/source/src/Makefile @@ -31,6 +31,7 @@ CLIENT_OBJS= \ sound.o \ texture.o \ tools.o \ + water.o \ weapon.o \ world.o \ worldio.o \ diff --git a/source/src/geom.h b/source/src/geom.h index df5e7545..15c0af2b 100644 --- a/source/src/geom.h +++ b/source/src/geom.h @@ -68,6 +68,22 @@ struct vec } }; +struct vec4 +{ + union + { + struct { float x, y, z, w; }; + float v[4]; + }; + + vec4() {} + explicit vec4(const vec &p, float w = 0) : x(p.x), y(p.y), z(p.z), w(w) {} + vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} + + float &operator[](int i) { return v[i]; } + float operator[](int i) const { return v[i]; } +}; + struct ivec { union diff --git a/source/src/protos.h b/source/src/protos.h index 2cafa369..5560abe4 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -215,14 +215,18 @@ extern void render_flat(int tex, int x, int y, int size, int h, sqr *l1, sqr *l2 extern void render_flatdelta(int wtex, int x, int y, int size, float h1, float h2, float h3, float h4, sqr *l1, sqr *l2, sqr *l3, sqr *l4, bool isceil); extern 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 topleft); extern void render_tris(int x, int y, int size, bool topleft, sqr *h1, sqr *h2, sqr *s, sqr *t, sqr *u, sqr *v); -extern void setwatercolor(const char *r = "", const char *g = "", const char *b = "", const char *a = ""); -extern void addwaterquad(int x, int y, int size); -extern int renderwater(float hf, GLuint reflecttex, GLuint refracttex); extern void resetcubes(); extern void setupstrips(); extern void renderstripssky(); extern void renderstrips(); +// water +extern void setwatercolor(const char *r = "", const char *g = "", const char *b = "", const char *a = ""); +extern void calcwaterscissor(); +extern void addwaterquad(int x, int y, int size); +extern int renderwater(float hf, GLuint reflecttex, GLuint refracttex); +extern void resetwater(); + // client extern void connects(char *servername, char *serverport = NULL, char *password = NULL); extern void abortconnect(); diff --git a/source/src/rendercubes.cpp b/source/src/rendercubes.cpp index e5d0b7ee..d07298ad 100644 --- a/source/src/rendercubes.cpp +++ b/source/src/rendercubes.cpp @@ -338,246 +338,16 @@ void render_square(int wtex, float floor1, float floor2, float ceil1, float ceil nquads++; } -int wx1, wy1, wx2, wy2; - -VARP(watersubdiv, 1, 4, 64); -VARF(waterlevel, -128, -128, 127, if(!noteditmode()) hdr.waterlevel = waterlevel); - -void setwatercolor(const char *r, const char *g, const char *b, const char *a) -{ - if(r[0]) - { - hdr.watercolor[0] = ATOI(r); - hdr.watercolor[1] = ATOI(g); - hdr.watercolor[2] = ATOI(b); - hdr.watercolor[3] = a[0] ? ATOI(a) : 178; - } - else - { - hdr.watercolor[0] = 20; - hdr.watercolor[1] = 25; - hdr.watercolor[2] = 20; - hdr.watercolor[3] = 178; - } -} - -COMMANDN(watercolour, setwatercolor, ARG_4STR); - -// renders water for bounding rect area that contains water... simple but very inefficient - -#define VERTW(vertw, body) \ - inline void vertw(float v1, float v2, float v3, float t) \ - { \ - float angle = v1*v2*0.1f + t; \ - float h = 0.3f*sinf(angle); \ - body; \ - glVertex3f(v1, v2, v3+h); \ - } -#define VERTWT(vertwt, body) VERTW(vertwt, { float v = cosf(angle); float duv = 0.2f*v; body; }) -VERTW(vertw, {}) -VERTW(vertwc, { - float v = cosf(angle); - glColor4ub(hdr.watercolor[0], hdr.watercolor[1], hdr.watercolor[2], (uchar)(hdr.watercolor[3] + (max(v, 0.0f) - 0.5f)*51.0f)); -}) -VERTWT(vertwt, { - glTexCoord3f(v1+duv, v2+duv, v3+h); -}) -VERTWT(vertwtc, { - glColor4f(1, 1, 1, 0.15f + max(v, 0.0f)*0.15f); - glTexCoord3f(v1+duv, v2+duv, v3+h); -}) -VERTWT(vertwmtc, { - glColor4f(1, 1, 1, 0.15f + max(v, 0.0f)*0.15f); - glMultiTexCoord3f_(GL_TEXTURE0_ARB, v1-duv, v2+duv, v3+h); - glMultiTexCoord3f_(GL_TEXTURE1_ARB, v1+duv, v2+duv, v3+h); -}) - -#define renderwaterstrips(vertw, hf, t) \ - for(int x = wx1; x=2 && reflecttex) - { - if(refracttex) - { - setupmultitexrefract(reflecttex, refracttex); - renderwaterstrips(vertwmtc, hf, t); - } - else - { - setupmultitexreflect(reflecttex); - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_SRC_ALPHA); - renderwaterstrips(vertwtc, hf, t); - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - } - cleanupmultitex(reflecttex, refracttex); - - return nquads; - } - - if(!refracttex) - { - glDisable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - } - glDepthMask(GL_FALSE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - if(reflecttex) - { - if(!refracttex) - { - glColor4ubv(hdr.watercolor); - renderwaterstrips(vertw, hf, t); - - glEnable(GL_TEXTURE_2D); - } - - setprojtexmatrix(); - - glBindTexture(GL_TEXTURE_2D, refracttex ? refracttex : reflecttex); - } - - if(refracttex) - { - glColor3f(1, 1, 1); - renderwaterstrips(vertwt, hf, t); - glEnable(GL_BLEND); - - glBindTexture(GL_TEXTURE_2D, reflecttex); - glDepthMask(GL_TRUE); - } - if(reflecttex) { renderwaterstrips(vertwtc, hf, t); } - else { renderwaterstrips(vertwc, hf, t); } - - if(reflecttex) - { - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } - else glEnable(GL_TEXTURE_2D); - - glDisable(GL_BLEND); - if(!refracttex) glDepthMask(GL_TRUE); - - return nquads; -} - -void addwaterquad(int x, int y, int size) // update bounding rect that contains water -{ - int x2 = x+size; - int y2 = y+size; - if(wx1<0) - { - wx1 = x; - wy1 = y; - wx2 = x2; - wy2 = y2; - } - else - { - if(xwx2) wx2 = x2; - if(y2>wy2) wy2 = y2; - } -} - void resetcubes() { verts.setsizenodelete(0); floorstrip = deltastrip = false; - if(!reflecting) wx1 = -1; nquads = 0; sbright.r = sbright.g = sbright.b = 255; sdark.r = sdark.g = sdark.b = 0; + + resetwater(); } diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 46a9f3ac..9e93aad8 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -401,6 +401,7 @@ VARP(reflectres, 6, 8, 10); VAR(reflectclip, 0, 3, 100); VARP(waterreflect, 0, 1, 1); VARP(waterrefract, 0, 0, 1); +VAR(reflectscissor, 0, 1, 1); void drawreflection(float hf, int w, int h, float changelod, bool refract) { @@ -430,6 +431,19 @@ void drawreflection(float hf, int w, int h, float changelod, bool refract) reflectlastsize = size; } + extern float wsx1, wsx2, wsy1, wsy2; + int sx = 0, sy = 0, sw = size, sh = size; + bool scissor = reflectscissor && (wsx1 > -1 || wsy1 > -1 || wsx1 < 1 || wsy1 < 1); + if(scissor) + { + sx = int(floor((wsx1+1)*0.5f*size)); + sy = int(floor((wsy1+1)*0.5f*size)); + sw = int(ceil((wsx2+1)*0.5f*size)) - sx; + sh = int(ceil((wsy2+1)*0.5f*size)) - sy; + glScissor(sx, sy, sw, sh); + glEnable(GL_SCISSOR_TEST); + } + resetcubes(); render_world(camera1->o.x, camera1->o.y, refract ? camera1->o.z : hf, changelod, @@ -511,8 +525,10 @@ void drawreflection(float hf, int w, int h, float changelod, bool refract) if(!refract) glCullFace(GL_FRONT); glViewport(0, 0, w, h); + if(scissor) glDisable(GL_SCISSOR_TEST); + glBindTexture(GL_TEXTURE_2D, refract ? refracttex : reflecttex); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size, size); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, sx, sy, sx, sy, sw, sh); glDisable(GL_TEXTURE_2D); @@ -655,30 +671,36 @@ bool outsidemap(physent *pl) float cursordepth = 0.9f; GLint viewport[4]; -GLdouble mm[16], pm[16], invmm[16]; +GLdouble mvmatrix[16], projmatrix[16], mvpmatrix[16], invmvmatrix[16]; vec worldpos, camdir, camup, camright; void readmatrices() { glGetIntegerv(GL_VIEWPORT, viewport); - glGetDoublev(GL_MODELVIEW_MATRIX, mm); - glGetDoublev(GL_PROJECTION_MATRIX, pm); - camright = vec(float(mm[0]), float(mm[4]), float(mm[8])); - camup = vec(float(mm[1]), float(mm[5]), float(mm[9])); - camdir = vec(float(-mm[2]), float(-mm[6]), float(-mm[10])); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); + camright = vec(float(mvmatrix[0]), float(mvmatrix[4]), float(mvmatrix[8])); + camup = vec(float(mvmatrix[1]), float(mvmatrix[5]), float(mvmatrix[9])); + camdir = vec(float(-mvmatrix[2]), float(-mvmatrix[6]), float(-mvmatrix[10])); + loopi(4) loopj(4) + { + double c = 0; + loopk(4) c += projmatrix[k*4 + j] * mvmatrix[i*4 + k]; + mvpmatrix[i*4 + j] = c; + } loopi(3) { - loopj(3) invmm[i*4 + j] = mm[i + j*4]; - invmm[i*4 + 3] = 0; + loopj(3) invmvmatrix[i*4 + j] = mvmatrix[i + j*4]; + invmvmatrix[i*4 + 3] = 0; } loopi(3) { double c = 0; - loopj(3) c -= mm[i*4 + j] * mm[12 + j]; - invmm[12 + i] = c; + loopj(3) c -= mvmatrix[i*4 + j] * mvmatrix[12 + j]; + invmvmatrix[12 + i] = c; } - invmm[15] = 1; + invmvmatrix[15] = 1; } // stupid function to cater for stupid ATI linux drivers that return incorrect depth values @@ -698,7 +720,7 @@ void readdepth(int w, int h, vec &pos) { glReadPixels(w/2, h/2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &cursordepth); double worldx = 0, worldy = 0, worldz = 0; - gluUnProject(w/2, h/2, depthcorrect(cursordepth), mm, pm, viewport, &worldx, &worldy, &worldz); + gluUnProject(w/2, h/2, depthcorrect(cursordepth), mvmatrix, projmatrix, viewport, &worldx, &worldy, &worldz); pos.x = (float)worldx; pos.y = (float)worldy; pos.z = (float)worldz; @@ -741,6 +763,7 @@ void gl_drawframe(int w, int h, float changelod, float curfps) extern int wx1; if(wx1>=0) { + if(reflectscissor) calcwaterscissor(); drawreflection(hf, w, h, changelod, false); if(waterrefract) drawreflection(hf, w, h, changelod, true); } diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index b2b18a51..559046d7 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -429,9 +429,9 @@ struct vertmodel : model glGetDoublev(GL_MODELVIEW_MATRIX, mm); vec eyepos; loopk(3) eyepos[k] = tagpos.x*mm[0+k] + tagpos.y*mm[4+k] + tagpos.z*mm[8+k] + mm[12+k]; - extern GLdouble invmm[16]; + extern GLdouble invmvmatrix[16]; vec worldpos; - loopk(3) worldpos[k] = eyepos.x*invmm[0+k] + eyepos.y*invmm[4+k] + eyepos.z*invmm[8+k] + invmm[12+k]; + loopk(3) worldpos[k] = eyepos.x*invmvmatrix[0+k] + eyepos.y*invmvmatrix[4+k] + eyepos.z*invmvmatrix[8+k] + invmvmatrix[12+k]; particle_emit(emitters[i].type, emitters[i].args, basetime, emitters[i].seed, worldpos); } } diff --git a/source/src/water.cpp b/source/src/water.cpp new file mode 100644 index 00000000..c8ad8fbb --- /dev/null +++ b/source/src/water.cpp @@ -0,0 +1,294 @@ +#include "pch.h" +#include "cube.h" + +int wx1, wy1, wx2, wy2; +float wsx1, wsy1, wsx2, wsy2; + +VARP(watersubdiv, 1, 4, 64); +VARF(waterlevel, -128, -128, 127, if(!noteditmode()) hdr.waterlevel = waterlevel); + +void setwatercolor(const char *r, const char *g, const char *b, const char *a) +{ + if(r[0]) + { + hdr.watercolor[0] = ATOI(r); + hdr.watercolor[1] = ATOI(g); + hdr.watercolor[2] = ATOI(b); + hdr.watercolor[3] = a[0] ? ATOI(a) : 178; + } + else + { + hdr.watercolor[0] = 20; + hdr.watercolor[1] = 25; + hdr.watercolor[2] = 20; + hdr.watercolor[3] = 178; + } +} + +COMMANDN(watercolour, setwatercolor, ARG_4STR); + +// renders water for bounding rect area that contains water... simple but very inefficient + +#define VERTW(vertw, body) \ + inline void vertw(float v1, float v2, float v3, float t) \ + { \ + float angle = v1*v2*0.1f + t; \ + float h = 0.3f*sinf(angle); \ + body; \ + glVertex3f(v1, v2, v3+h); \ + } +#define VERTWT(vertwt, body) VERTW(vertwt, { float v = cosf(angle); float duv = 0.2f*v; body; }) +VERTW(vertw, {}) +VERTW(vertwc, { + float v = cosf(angle); + glColor4ub(hdr.watercolor[0], hdr.watercolor[1], hdr.watercolor[2], (uchar)(hdr.watercolor[3] + (max(v, 0.0f) - 0.5f)*51.0f)); +}) +VERTWT(vertwt, { + glTexCoord3f(v1+duv, v2+duv, v3+h); +}) +VERTWT(vertwtc, { + glColor4f(1, 1, 1, 0.15f + max(v, 0.0f)*0.15f); + glTexCoord3f(v1+duv, v2+duv, v3+h); +}) +VERTWT(vertwmtc, { + glColor4f(1, 1, 1, 0.15f + max(v, 0.0f)*0.15f); + glMultiTexCoord3f_(GL_TEXTURE0_ARB, v1-duv, v2+duv, v3+h); + glMultiTexCoord3f_(GL_TEXTURE1_ARB, v1+duv, v2+duv, v3+h); +}) + +extern int nquads; + +#define renderwaterstrips(vertw, hf, t) \ + for(int x = wx1; x=2 && reflecttex) + { + if(refracttex) + { + setupmultitexrefract(reflecttex, refracttex); + renderwaterstrips(vertwmtc, hf, t); + } + else + { + setupmultitexreflect(reflecttex); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_SRC_ALPHA); + renderwaterstrips(vertwtc, hf, t); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + } + cleanupmultitex(reflecttex, refracttex); + + return nquads; + } + + if(!refracttex) + { + glDisable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + } + glDepthMask(GL_FALSE); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if(reflecttex) + { + if(!refracttex) + { + glColor4ubv(hdr.watercolor); + renderwaterstrips(vertw, hf, t); + + glEnable(GL_TEXTURE_2D); + } + + setprojtexmatrix(); + + glBindTexture(GL_TEXTURE_2D, refracttex ? refracttex : reflecttex); + } + + if(refracttex) + { + glColor3f(1, 1, 1); + renderwaterstrips(vertwt, hf, t); + glEnable(GL_BLEND); + + glBindTexture(GL_TEXTURE_2D, reflecttex); + glDepthMask(GL_TRUE); + } + if(reflecttex) { renderwaterstrips(vertwtc, hf, t); } + else { renderwaterstrips(vertwc, hf, t); } + + if(reflecttex) + { + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + } + else glEnable(GL_TEXTURE_2D); + + glDisable(GL_BLEND); + if(!refracttex) glDepthMask(GL_TRUE); + + return nquads; +} + +void addwaterquad(int x, int y, int size) // update bounding rect that contains water +{ + int x2 = x+size; + int y2 = y+size; + if(wx1<0) + { + wx1 = x; + wy1 = y; + wx2 = x2; + wy2 = y2; + } + else + { + if(xwx2) wx2 = x2; + if(y2>wy2) wy2 = y2; + } +} + +void calcwaterscissor() +{ + extern GLdouble mvpmatrix[16]; + vec4 v[4]; + float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1; + loopi(4) + { + vec p(i&1 ? wx2 : wx1, i&2 ? wy2 : wy1, hdr.waterlevel-0.3f); + float w = p.x*mvpmatrix[3] + p.y*mvpmatrix[7] + p.z*mvpmatrix[11] + mvpmatrix[15], + x = (p.x*mvpmatrix[0] + p.y*mvpmatrix[4] + p.z*mvpmatrix[8] + mvpmatrix[12]), + y = (p.x*mvpmatrix[1] + p.y*mvpmatrix[5] + p.z*mvpmatrix[9] + mvpmatrix[13]), + z = (p.x*mvpmatrix[2] + p.y*mvpmatrix[6] + p.z*mvpmatrix[10] + mvpmatrix[14]); + v[i] = vec4(x, y, z, w); + if(z >= 0) + { + x /= w; + y /= w; + sx1 = min(sx1, x); + sy1 = min(sy1, y); + sx2 = max(sx2, x); + sy2 = max(sy2, y); + } + } + if(sx1 >= sx2 || sy1 >= sy2) + { + sx1 = sy1 = -1; + sx2 = sy2 = 1; + } + else loopi(4) + { + const vec4 &p = v[i]; + if(p.z >= 0) continue; + loopj(2) + { + const vec4 &o = v[i^(1<