From b8686120bd636f21c6dfba3a9ff261a5d96f8b65 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 12 Sep 2008 00:41:44 +0000 Subject: [PATCH] model rendering optimizations git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2532 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/cube.h | 1 - source/src/geom.h | 10 ++++++++ source/src/md2.h | 43 ++++++++++++++++------------------ source/src/md3.h | 15 ++++-------- source/src/protos.h | 6 +++++ source/src/rendergl.cpp | 11 ++++++++- source/src/tristrip.h | 44 ++++++++++++++++++++++++----------- source/src/vertmodel.h | 51 ++++++++++++++++++++++++++++------------- 8 files changed, 116 insertions(+), 65 deletions(-) diff --git a/source/src/cube.h b/source/src/cube.h index 44c37c84..76b6d998 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -42,7 +42,6 @@ extern bool minimap, reflecting, refracting; extern bool intermission; extern int maxclients; extern hashtable mapinfo; -extern bool hasTE, hasMT, hasMDA; extern int hwtexsize; extern int numspawn[3], maploaded, numflagspawn[2]; extern int verbose; diff --git a/source/src/geom.h b/source/src/geom.h index 58d07d41..86073474 100644 --- a/source/src/geom.h +++ b/source/src/geom.h @@ -115,3 +115,13 @@ struct ivec int dot(const ivec &o) const { return x*o.x + y*o.y + z*o.z; } }; +static inline bool htcmp(const ivec &x, const ivec &y) +{ + return x == y; +} + +static inline uint hthash(const ivec &k) +{ + return k.x^k.y^k.z; +} + diff --git a/source/src/md2.h b/source/src/md2.h index a378c9ee..f2c86646 100644 --- a/source/src/md2.h +++ b/source/src/md2.h @@ -2,16 +2,6 @@ struct md2; md2 *loadingmd2 = 0; -static inline bool htcmp(const vertmodel::tcvert &x, const vertmodel::tcvert &y) -{ - return x.u==y.u && x.v==y.v && x.index==y.index; -} - -static inline uint hthash(const vertmodel::tcvert &x) -{ - return x.index; -} - struct md2 : vertmodel { struct md2_header @@ -44,9 +34,9 @@ struct md2 : vertmodel struct md2part : part { - void gentcverts(int *glcommands, vector &tcverts, vector &tris) + void gentcverts(int *glcommands, vector &tcverts, vector &vindexes, vector &tris) { - hashtable tchash; + hashtable tchash; vector idxs; for(int *command = glcommands; (*command)!=0;) { @@ -59,13 +49,17 @@ struct md2 : vertmodel union { int i; float f; } u, v; u.i = *command++; v.i = *command++; - tcvert tckey = { u.f, v.f, (ushort)*command++ }; + int vindex = *command++; + ivec tckey(u.i, v.i, vindex); int *idx = tchash.access(tckey); if(!idx) { idx = &tchash[tckey]; *idx = tcverts.length(); - tcverts.add(tckey); + tcvert &tc = tcverts.add(); + tc.u = u.f; + tc.v = v.f; + vindexes.add((ushort)vindex); } idxs.add(*idx); } @@ -113,20 +107,21 @@ struct md2 : vertmodel if(numglcommands < header.numglcommands) memset(&glcommands[numglcommands], 0, (header.numglcommands-numglcommands)*sizeof(int)); vector tcgen; + vector vgen; vector trigen; - gentcverts(glcommands, tcgen, trigen); + gentcverts(glcommands, tcgen, vgen, trigen); delete[] glcommands; - m.numtcverts = tcgen.length(); - m.tcverts = new tcvert[m.numtcverts]; - memcpy(m.tcverts, tcgen.getbuf(), m.numtcverts*sizeof(tcvert)); + m.numverts = tcgen.length(); + m.tcverts = new tcvert[m.numverts]; + memcpy(m.tcverts, tcgen.getbuf(), m.numverts*sizeof(tcvert)); m.numtris = trigen.length(); m.tris = new tri[m.numtris]; memcpy(m.tris, trigen.getbuf(), m.numtris*sizeof(tri)); - m.numverts = header.numvertices; m.verts = new vec[m.numverts*numframes]; + md2_vertex *tmpverts = new md2_vertex[header.numvertices]; int frame_offset = header.offsetframes; vec *curvert = m.verts; loopi(header.numframes) @@ -135,17 +130,19 @@ struct md2 : vertmodel fseek(file, frame_offset, SEEK_SET); fread(&frame, sizeof(md2_frame), 1, file); endianswap(&frame, sizeof(float), 6); - loopj(header.numvertices) + + fread(tmpverts, sizeof(md2_vertex), header.numvertices, file); + loopj(m.numverts) { - md2_vertex v; - fread(&v, sizeof(md2_vertex), 1, file); + const md2_vertex &v = tmpverts[vgen[j]]; *curvert++ = vec(v.vertex[0]*frame.scale[0]+frame.translate[0], -(v.vertex[1]*frame.scale[1]+frame.translate[1]), v.vertex[2]*frame.scale[2]+frame.translate[2]); } frame_offset += header.framesize; } - + delete[] tmpverts; + fclose(file); filename = newstring(path); diff --git a/source/src/md3.h b/source/src/md3.h index e7735d7e..98c4d7e9 100644 --- a/source/src/md3.h +++ b/source/src/md3.h @@ -113,17 +113,12 @@ struct md3 : vertmodel loopk(3) m.tris[j].vert[k] = (ushort)tri.vertexindices[k]; } - m.numtcverts = mheader.numvertices; - m.tcverts = new tcvert[m.numtcverts]; - fseek(f, mesh_offset + mheader.ofs_uv , SEEK_SET); - loopj(mheader.numvertices) - { - fread(&m.tcverts[j].u, sizeof(float), 2, f); // read the UV data - endianswap(&m.tcverts[j].u, sizeof(float), 2); - m.tcverts[j].index = j; - } - m.numverts = mheader.numvertices; + m.tcverts = new tcvert[m.numverts]; + fseek(f, mesh_offset + mheader.ofs_uv , SEEK_SET); + fread(m.tcverts, 2*sizeof(float), m.numverts, f); // read the UV data + endianswap(m.tcverts, sizeof(float), 2*m.numverts); + m.verts = new vec[numframes*m.numverts]; fseek(f, mesh_offset + mheader.ofs_vertices, SEEK_SET); loopj(numframes*mheader.numvertices) diff --git a/source/src/protos.h b/source/src/protos.h index acf877f0..01ee2ba5 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -1,6 +1,9 @@ // protos for ALL external functions in cube... #ifndef STANDALONE + +extern bool hasTE, hasMT, hasMDA, hasDRE; + // GL_ARB_multitexture extern PFNGLACTIVETEXTUREARBPROC glActiveTexture_; extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTexture_; @@ -11,6 +14,9 @@ extern PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3f_; extern PFNGLMULTIDRAWARRAYSEXTPROC glMultiDrawArrays_; extern PFNGLMULTIDRAWELEMENTSEXTPROC glMultiDrawElements_; +// GL_EXT_draw_range_elements +extern PFNGLDRAWRANGEELEMENTSEXTPROC glDrawRangeElements_; + struct color { float r, g, b, alpha; diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 7d559c83..64ef12f3 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -4,7 +4,7 @@ #include "cube.h" #include "bot/bot.h" -bool hasTE = false, hasMT = false, hasMDA = false; +bool hasTE = false, hasMT = false, hasMDA = false, hasDRE = false; // GL_ARB_multitexture PFNGLACTIVETEXTUREARBPROC glActiveTexture_ = NULL; @@ -16,6 +16,9 @@ PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3f_ = NULL; PFNGLMULTIDRAWARRAYSEXTPROC glMultiDrawArrays_ = NULL; PFNGLMULTIDRAWELEMENTSEXTPROC glMultiDrawElements_ = NULL; +// GL_EXT_draw_range_elements +PFNGLDRAWRANGEELEMENTSEXTPROC glDrawRangeElements_ = NULL; + void *getprocaddress(const char *name) { return SDL_GL_GetProcAddress(name); @@ -56,6 +59,12 @@ void gl_checkextensions() hasMDA = true; } + if(strstr(exts, "GL_EXT_draw_range_elements")) + { + glDrawRangeElements_ = (PFNGLDRAWRANGEELEMENTSEXTPROC)getprocaddress("glDrawRangeElementsEXT"); + hasDRE = true; + } + if(!strstr(exts, "GL_ARB_fragment_program")) { // not a required extension, but ensures the card has enough power to do reflections diff --git a/source/src/tristrip.h b/source/src/tristrip.h index 5cf62565..cc5742a3 100644 --- a/source/src/tristrip.h +++ b/source/src/tristrip.h @@ -3,6 +3,16 @@ VAR(tsswap, 0, 1, 1); struct tristrip { + struct drawcall + { + GLenum type; + GLuint start, minvert, maxvert; + GLsizei count; + + drawcall() {} + drawcall(GLenum type, GLuint start, GLsizei count = 0) : type(type), start(start), minvert(~0U), maxvert(0), count(count) {} + }; + enum { // must be larger than all other triangle/vert indices @@ -10,13 +20,6 @@ struct tristrip REMOVED = 0xFFFF }; - enum - { - // must be larger than all other vert indices - RESTART = 0xFFFE, - LIST = 0xFFFF - }; - struct triangle { ushort v[3], n[3]; @@ -227,7 +230,7 @@ struct tristrip } - void buildstrips(vector &strips, bool prims = true, bool degen = false) + void buildstrips(vector &strips, vector &draws, bool prims = true, bool degen = false) { vector singles; findconnectivity(); @@ -244,17 +247,30 @@ struct tristrip loopv(strip) singles.add(strip[i]); continue; } - if(!strips.empty()) + + if(!strips.empty() && degen) { strips.dup(); strips.add(strip[0]); } + else draws.add(drawcall(GL_TRIANGLE_STRIP, strips.length())); + drawcall &d = draws.last(); + loopv(strip) { - if(degen) { strips.dup(); strips.add(strip[0]); } - else strips.add(RESTART); + ushort index = strip[i]; + strips.add(index); + d.minvert = min(d.minvert, (GLuint)index); + d.maxvert = max(d.maxvert, (GLuint)index); } - loopv(strip) strips.add(strip[i]); + d.count = strips.length() - d.start; } if(prims && !singles.empty()) { - strips.add(LIST); - loopv(singles) strips.add(singles[i]); + drawcall &d = draws.add(drawcall(GL_TRIANGLES, strips.length())); + loopv(singles) + { + ushort index = singles[i]; + strips.add(index); + d.minvert = min(d.minvert, (GLuint)index); + d.maxvert = max(d.maxvert, (GLuint)index); + } + d.count = strips.length() - d.start; } if(dbgts) conoutf("strips = %d, tris = %d, inds = %d, merges = %d", numstrips, numtris, numtris + numstrips*2, (degen ? 2 : 1)*(numstrips-1)); } diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index 101cdbc5..367dd2dc 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -36,11 +36,13 @@ struct vertmodel : model bool operator==(const anpos &a) const { return fr1==a.fr1 && fr2==a.fr2 && (fr1==fr2 || t==a.t); } }; - struct tcvert { float u, v; ushort index; }; + struct tcvert { float u, v; }; struct tri { ushort vert[3]; }; struct part; + typedef tristrip::drawcall drawcall; + struct mesh { char *name; @@ -48,7 +50,7 @@ struct vertmodel : model vec *verts; tcvert *tcverts; tri *tris; - int numverts, numtcverts, numtris; + int numverts, numtris; Texture *skin; int tex; @@ -56,12 +58,14 @@ struct vertmodel : model vec *dynbuf; ushort *dynidx; int dynlen; + drawcall *dyndraws; + int numdyndraws; anpos dyncur, dynprev; float dynt; GLuint statlist; int statlen; - mesh() : name(0), owner(0), verts(0), tcverts(0), tris(0), skin(notexture), tex(0), dynbuf(0), dynidx(0), statlist(0) + mesh() : name(0), owner(0), verts(0), tcverts(0), tris(0), skin(notexture), tex(0), dynbuf(0), dynidx(0), dyndraws(0), statlist(0) { dyncur.fr1 = dynprev.fr1 = -1; } @@ -75,6 +79,7 @@ struct vertmodel : model if(statlist) glDeleteLists(statlist, 1); DELETEA(dynidx); DELETEA(dynbuf); + DELETEA(dyndraws); } void genstrips() @@ -82,11 +87,15 @@ struct vertmodel : model tristrip ts; ts.addtriangles(tris->vert, numtris); vector idxs; - ts.buildstrips(idxs); + vector draws; + ts.buildstrips(idxs, draws); dynbuf = new vec[numverts]; dynidx = new ushort[idxs.length()]; memcpy(dynidx, idxs.getbuf(), idxs.length()*sizeof(ushort)); dynlen = idxs.length(); + dyndraws = new drawcall[draws.length()]; + memcpy(dyndraws, draws.getbuf(), draws.length()*sizeof(drawcall)); + numdyndraws = draws.length(); } void gendynverts(anpos &cur, anpos *prev, float ai_t) @@ -170,20 +179,24 @@ struct vertmodel : model { if(isstat) glNewList(statlist = glGenLists(1), GL_COMPILE); gendynverts(cur, prev, ai_t); - loopj(dynlen) + if(lastvertexarray != dynbuf) + { + if(!lastvertexarray) glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(vec), dynbuf); + lastvertexarray = dynbuf; + } + if(lasttexcoordarray != tcverts) { - ushort index = dynidx[j]; - if(index>=tristrip::RESTART || !j) - { - if(j) glEnd(); - glBegin(index==tristrip::LIST ? GL_TRIANGLES : GL_TRIANGLE_STRIP); - if(index>=tristrip::RESTART) continue; - } - tcvert &tc = tcverts[index]; - if(isstat || !(as.anim&ANIM_NOSKIN)) glTexCoord2f(tc.u, tc.v); - glVertex3fv(&dynbuf[tc.index].x); + if(!lasttexcoordarray) glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(tcvert), tcverts); + lasttexcoordarray = tcverts; + } + 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]); } - glEnd(); if(isstat) { glEndList(); @@ -748,6 +761,7 @@ struct vertmodel : model static bool enablealphablend, enablealphatest, enabledepthmask; static GLuint lasttex; static float lastalphatest; + static void *lastvertexarray, *lasttexcoordarray; void startrender() { @@ -755,6 +769,7 @@ struct vertmodel : model enabledepthmask = true; lasttex = 0; lastalphatest = -1; + lastvertexarray = lasttexcoordarray = NULL; } void endrender() @@ -762,9 +777,13 @@ struct vertmodel : model if(enablealphablend) glDisable(GL_BLEND); if(enablealphatest) glDisable(GL_ALPHA_TEST); if(!enabledepthmask) glDepthMask(GL_TRUE); + if(lastvertexarray) glDisableClientState(GL_VERTEX_ARRAY); + if(lasttexcoordarray) glDisableClientState(GL_TEXTURE_COORD_ARRAY); } }; 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; +