diff options
Diffstat (limited to 'src/engine/renderva.cpp')
| -rw-r--r-- | src/engine/renderva.cpp | 2856 |
1 files changed, 1428 insertions, 1428 deletions
diff --git a/src/engine/renderva.cpp b/src/engine/renderva.cpp index cef5ac5..dc3dca1 100644 --- a/src/engine/renderva.cpp +++ b/src/engine/renderva.cpp @@ -4,13 +4,13 @@ static inline void drawtris(GLsizei numindices, const GLvoid *indices, ushort minvert, ushort maxvert) { - glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, numindices, GL_UNSIGNED_SHORT, indices); - glde++; + glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, numindices, GL_UNSIGNED_SHORT, indices); + glde++; } static inline void drawvatris(vtxarray *va, GLsizei numindices, const GLvoid *indices) { - drawtris(numindices, indices, va->minvert, va->maxvert); + drawtris(numindices, indices, va->minvert, va->maxvert); } ///////// view frustrum culling /////////////////////// @@ -23,65 +23,65 @@ vtxarray *visibleva; bool isfoggedsphere(float rad, const vec &cv) { - loopi(4) if(vfcP[i].dist(cv) < -rad) return true; - float dist = vfcP[4].dist(cv); - return dist < -rad || dist > vfcDfog + rad; + loopi(4) if(vfcP[i].dist(cv) < -rad) return true; + float dist = vfcP[4].dist(cv); + return dist < -rad || dist > vfcDfog + rad; } int isvisiblesphere(float rad, const vec &cv) { - int v = VFC_FULL_VISIBLE; - float dist; + int v = VFC_FULL_VISIBLE; + float dist; - loopi(5) - { - dist = vfcP[i].dist(cv); - if(dist < -rad) return VFC_NOT_VISIBLE; - if(dist < rad) v = VFC_PART_VISIBLE; - } + loopi(5) + { + dist = vfcP[i].dist(cv); + if(dist < -rad) return VFC_NOT_VISIBLE; + if(dist < rad) v = VFC_PART_VISIBLE; + } - dist -= vfcDfog; - if(dist > rad) return VFC_FOGGED; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM - if(dist > -rad) v = VFC_PART_VISIBLE; + dist -= vfcDfog; + if(dist > rad) return VFC_FOGGED; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM + if(dist > -rad) v = VFC_PART_VISIBLE; - return v; + return v; } static inline int ishiddencube(const ivec &o, int size) { - loopi(5) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true; - return false; + loopi(5) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true; + return false; } static inline int isfoggedcube(const ivec &o, int size) { - loopi(4) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true; - float dist = o.dist(vfcP[4]); - return dist < -vfcDfar[4]*size || dist > vfcDfog - vfcDnear[4]*size; + loopi(4) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true; + float dist = o.dist(vfcP[4]); + return dist < -vfcDfar[4]*size || dist > vfcDfog - vfcDnear[4]*size; } int isvisiblecube(const ivec &o, int size) { - int v = VFC_FULL_VISIBLE; - float dist; + int v = VFC_FULL_VISIBLE; + float dist; - loopi(5) - { - dist = o.dist(vfcP[i]); - if(dist < -vfcDfar[i]*size) return VFC_NOT_VISIBLE; - if(dist < -vfcDnear[i]*size) v = VFC_PART_VISIBLE; - } + loopi(5) + { + dist = o.dist(vfcP[i]); + if(dist < -vfcDfar[i]*size) return VFC_NOT_VISIBLE; + if(dist < -vfcDnear[i]*size) v = VFC_PART_VISIBLE; + } - dist -= vfcDfog; - if(dist > -vfcDnear[4]*size) return VFC_FOGGED; - if(dist > -vfcDfar[4]*size) v = VFC_PART_VISIBLE; + dist -= vfcDfog; + if(dist > -vfcDnear[4]*size) return VFC_FOGGED; + if(dist > -vfcDfar[4]*size) v = VFC_PART_VISIBLE; - return v; + return v; } float vadist(vtxarray *va, const vec &p) { - return p.dist_to_bb(va->bbmin, va->bbmax); + return p.dist_to_bb(va->bbmin, va->bbmax); } #define VASORTSIZE 64 @@ -90,128 +90,128 @@ static vtxarray *vasort[VASORTSIZE]; void addvisibleva(vtxarray *va) { - float dist = vadist(va, camera1->o); - va->distance = int(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/ + float dist = vadist(va, camera1->o); + va->distance = int(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/ - int hash = clamp(int(dist*VASORTSIZE/worldsize), 0, VASORTSIZE-1); - vtxarray **prev = &vasort[hash], *cur = vasort[hash]; + int hash = clamp(int(dist*VASORTSIZE/worldsize), 0, VASORTSIZE-1); + vtxarray **prev = &vasort[hash], *cur = vasort[hash]; - while(cur && va->distance >= cur->distance) - { - prev = &cur->next; - cur = cur->next; - } + while(cur && va->distance >= cur->distance) + { + prev = &cur->next; + cur = cur->next; + } - va->next = *prev; - *prev = va; + va->next = *prev; + *prev = va; } void sortvisiblevas() { - visibleva = NULL; - vtxarray **last = &visibleva; - loopi(VASORTSIZE) if(vasort[i]) - { - vtxarray *va = vasort[i]; - *last = va; - while(va->next) va = va->next; - last = &va->next; - } + visibleva = NULL; + vtxarray **last = &visibleva; + loopi(VASORTSIZE) if(vasort[i]) + { + vtxarray *va = vasort[i]; + *last = va; + while(va->next) va = va->next; + last = &va->next; + } } void findvisiblevas(vector<vtxarray *> &vas, bool resetocclude = false) { - loopv(vas) - { - vtxarray &v = *vas[i]; - int prevvfc = resetocclude ? (int) VFC_NOT_VISIBLE : (int) v.curvfc; - v.curvfc = isvisiblecube(v.o, v.size); - if(v.curvfc!=VFC_NOT_VISIBLE) - { - addvisibleva(&v); - if(v.children.length()) findvisiblevas(v.children, prevvfc>=VFC_NOT_VISIBLE); - if(prevvfc>=VFC_NOT_VISIBLE) - { - v.occluded = !v.texs ? OCCLUDE_GEOM : OCCLUDE_NOTHING; - v.query = NULL; - } - } - } + loopv(vas) + { + vtxarray &v = *vas[i]; + int prevvfc = resetocclude ? (int) VFC_NOT_VISIBLE : (int) v.curvfc; + v.curvfc = isvisiblecube(v.o, v.size); + if(v.curvfc!=VFC_NOT_VISIBLE) + { + addvisibleva(&v); + if(v.children.length()) findvisiblevas(v.children, prevvfc>=VFC_NOT_VISIBLE); + if(prevvfc>=VFC_NOT_VISIBLE) + { + v.occluded = !v.texs ? OCCLUDE_GEOM : OCCLUDE_NOTHING; + v.query = NULL; + } + } + } } void calcvfcD() { - loopi(5) - { - plane &p = vfcP[i]; - vfcDnear[i] = vfcDfar[i] = 0; - loopk(3) if(p[k] > 0) vfcDfar[i] += p[k]; - else vfcDnear[i] += p[k]; - } + loopi(5) + { + plane &p = vfcP[i]; + vfcDnear[i] = vfcDfar[i] = 0; + loopk(3) if(p[k] > 0) vfcDfar[i] += p[k]; + else vfcDnear[i] += p[k]; + } } void setvfcP(float z, const vec &bbmin, const vec &bbmax) { - vec4 px = camprojmatrix.rowx(), py = camprojmatrix.rowy(), pz = camprojmatrix.rowz(), pw = camprojmatrix.roww(); - vfcP[0] = plane(vec4(pw).mul(-bbmin.x).add(px)).normalize(); // left plane - vfcP[1] = plane(vec4(pw).mul(bbmax.x).sub(px)).normalize(); // right plane - vfcP[2] = plane(vec4(pw).mul(-bbmin.y).add(py)).normalize(); // bottom plane - vfcP[3] = plane(vec4(pw).mul(bbmax.y).sub(py)).normalize(); // top plane - vfcP[4] = plane(vec4(pw).add(pz)).normalize(); // near/far planes - if(z >= 0) loopi(5) vfcP[i].reflectz(z); + vec4 px = camprojmatrix.rowx(), py = camprojmatrix.rowy(), pz = camprojmatrix.rowz(), pw = camprojmatrix.roww(); + vfcP[0] = plane(vec4(pw).mul(-bbmin.x).add(px)).normalize(); // left plane + vfcP[1] = plane(vec4(pw).mul(bbmax.x).sub(px)).normalize(); // right plane + vfcP[2] = plane(vec4(pw).mul(-bbmin.y).add(py)).normalize(); // bottom plane + vfcP[3] = plane(vec4(pw).mul(bbmax.y).sub(py)).normalize(); // top plane + vfcP[4] = plane(vec4(pw).add(pz)).normalize(); // near/far planes + if(z >= 0) loopi(5) vfcP[i].reflectz(z); - vfcDfog = fog; - calcvfcD(); + vfcDfog = fog; + calcvfcD(); } plane oldvfcP[5]; void savevfcP() { - memcpy(oldvfcP, vfcP, sizeof(vfcP)); + memcpy(oldvfcP, vfcP, sizeof(vfcP)); } void restorevfcP() { - memcpy(vfcP, oldvfcP, sizeof(vfcP)); - calcvfcD(); + memcpy(vfcP, oldvfcP, sizeof(vfcP)); + calcvfcD(); } void visiblecubes(bool cull) { - memclear(vasort); - - if(cull) - { - setvfcP(); - findvisiblevas(varoot); - sortvisiblevas(); - } - else - { - memclear(vfcP); - vfcDfog = 1000000; - memclear(vfcDnear); - memclear(vfcDfar); - visibleva = NULL; - loopv(valist) - { - vtxarray *va = valist[i]; - va->distance = 0; - va->curvfc = VFC_FULL_VISIBLE; - va->occluded = !va->texs ? OCCLUDE_GEOM : OCCLUDE_NOTHING; - va->query = NULL; - va->next = visibleva; - visibleva = va; - } - } + memclear(vasort); + + if(cull) + { + setvfcP(); + findvisiblevas(varoot); + sortvisiblevas(); + } + else + { + memclear(vfcP); + vfcDfog = 1000000; + memclear(vfcDnear); + memclear(vfcDfar); + visibleva = NULL; + loopv(valist) + { + vtxarray *va = valist[i]; + va->distance = 0; + va->curvfc = VFC_FULL_VISIBLE; + va->occluded = !va->texs ? OCCLUDE_GEOM : OCCLUDE_NOTHING; + va->query = NULL; + va->next = visibleva; + visibleva = va; + } + } } static inline bool insideva(const vtxarray *va, const vec &v, int margin = 2) { - int size = va->size + margin; - return v.x>=va->o.x-margin && v.y>=va->o.y-margin && v.z>=va->o.z-margin && - v.x<=va->o.x+size && v.y<=va->o.y+size && v.z<=va->o.z+size; + int size = va->size + margin; + return v.x>=va->o.x-margin && v.y>=va->o.y-margin && v.z>=va->o.z-margin && + v.x<=va->o.x+size && v.y<=va->o.y+size && v.z<=va->o.z+size; } ///////// occlusion queries ///////////// @@ -221,37 +221,37 @@ static inline bool insideva(const vtxarray *va, const vec &v, int margin = 2) struct queryframe { - int cur, max; - occludequery queries[MAXQUERY]; - - queryframe() : cur(0), max(0) {} - - void flip() { loopi(cur) queries[i].owner = NULL; cur = 0; } - - occludequery *newquery(void *owner) - { - if(cur >= max) - { - if(max >= MAXQUERY) return NULL; - glGenQueries_(1, &queries[max++].id); - } - occludequery *query = &queries[cur++]; - query->owner = owner; - query->fragments = -1; - return query; - } - - void reset() { loopi(max) queries[i].owner = NULL; } - - void cleanup() - { - loopi(max) - { - glDeleteQueries_(1, &queries[i].id); - queries[i].owner = NULL; - } - cur = max = 0; - } + int cur, max; + occludequery queries[MAXQUERY]; + + queryframe() : cur(0), max(0) {} + + void flip() { loopi(cur) queries[i].owner = NULL; cur = 0; } + + occludequery *newquery(void *owner) + { + if(cur >= max) + { + if(max >= MAXQUERY) return NULL; + glGenQueries_(1, &queries[max++].id); + } + occludequery *query = &queries[cur++]; + query->owner = owner; + query->fragments = -1; + return query; + } + + void reset() { loopi(max) queries[i].owner = NULL; } + + void cleanup() + { + loopi(max) + { + glDeleteQueries_(1, &queries[i].id); + queries[i].owner = NULL; + } + cur = max = 0; + } }; static queryframe queryframes[MAXQUERYFRAMES]; @@ -259,28 +259,28 @@ static uint flipquery = 0; int getnumqueries() { - return queryframes[flipquery].cur; + return queryframes[flipquery].cur; } void flipqueries() { - flipquery = (flipquery + 1) % MAXQUERYFRAMES; - queryframes[flipquery].flip(); + flipquery = (flipquery + 1) % MAXQUERYFRAMES; + queryframes[flipquery].flip(); } occludequery *newquery(void *owner) { - return queryframes[flipquery].newquery(owner); + return queryframes[flipquery].newquery(owner); } void resetqueries() { - loopi(MAXQUERYFRAMES) queryframes[i].reset(); + loopi(MAXQUERYFRAMES) queryframes[i].reset(); } void clearqueries() { - loopi(MAXQUERYFRAMES) queryframes[i].cleanup(); + loopi(MAXQUERYFRAMES) queryframes[i].cleanup(); } VAR(oqfrags, 0, 8, 64); @@ -288,107 +288,107 @@ VAR(oqwait, 0, 1, 1); void startquery(occludequery *query) { - glBeginQuery_(GL_SAMPLES_PASSED, query->id); + glBeginQuery_(GL_SAMPLES_PASSED, query->id); } void endquery(occludequery *query) { - glEndQuery_(GL_SAMPLES_PASSED); + glEndQuery_(GL_SAMPLES_PASSED); } bool checkquery(occludequery *query, bool nowait) { - GLuint fragments; - if(query->fragments >= 0) fragments = query->fragments; - else - { - if(nowait || !oqwait) - { - GLint avail; - glGetQueryObjectiv_(query->id, GL_QUERY_RESULT_AVAILABLE, &avail); - if(!avail) return false; - } - glGetQueryObjectuiv_(query->id, GL_QUERY_RESULT, &fragments); - query->fragments = fragments; - } - return fragments < uint(oqfrags); + GLuint fragments; + if(query->fragments >= 0) fragments = query->fragments; + else + { + if(nowait || !oqwait) + { + GLint avail; + glGetQueryObjectiv_(query->id, GL_QUERY_RESULT_AVAILABLE, &avail); + if(!avail) return false; + } + glGetQueryObjectuiv_(query->id, GL_QUERY_RESULT, &fragments); + query->fragments = fragments; + } + return fragments < uint(oqfrags); } static GLuint bbvbo = 0, bbebo = 0; static void setupbb() { - if(!bbvbo) - { - glGenBuffers_(1, &bbvbo); - gle::bindvbo(bbvbo); - vec verts[8]; - loopi(8) verts[i] = vec(i&1, (i>>1)&1, (i>>2)&1); - glBufferData_(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); - gle::clearvbo(); - } - if(!bbebo) - { - glGenBuffers_(1, &bbebo); - gle::bindebo(bbebo); - GLushort tris[3*2*6]; - #define GENFACEORIENT(orient, v0, v1, v2, v3) do { \ - int offset = orient*3*2; \ - tris[offset + 0] = v0; \ - tris[offset + 1] = v1; \ - tris[offset + 2] = v2; \ - tris[offset + 3] = v0; \ - tris[offset + 4] = v2; \ - tris[offset + 5] = v3; \ - } while(0); - #define GENFACEVERT(orient, vert, ox,oy,oz, rx,ry,rz) (ox | oy | oz) - GENFACEVERTS(0, 1, 0, 2, 0, 4, , , , , , ) - #undef GENFACEORIENT - #undef GENFACEVERT - glBufferData_(GL_ELEMENT_ARRAY_BUFFER, sizeof(tris), tris, GL_STATIC_DRAW); - gle::clearebo(); - } + if(!bbvbo) + { + glGenBuffers_(1, &bbvbo); + gle::bindvbo(bbvbo); + vec verts[8]; + loopi(8) verts[i] = vec(i&1, (i>>1)&1, (i>>2)&1); + glBufferData_(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + gle::clearvbo(); + } + if(!bbebo) + { + glGenBuffers_(1, &bbebo); + gle::bindebo(bbebo); + GLushort tris[3*2*6]; + #define GENFACEORIENT(orient, v0, v1, v2, v3) do { \ + int offset = orient*3*2; \ + tris[offset + 0] = v0; \ + tris[offset + 1] = v1; \ + tris[offset + 2] = v2; \ + tris[offset + 3] = v0; \ + tris[offset + 4] = v2; \ + tris[offset + 5] = v3; \ + } while(0); + #define GENFACEVERT(orient, vert, ox,oy,oz, rx,ry,rz) (ox | oy | oz) + GENFACEVERTS(0, 1, 0, 2, 0, 4, , , , , , ) + #undef GENFACEORIENT + #undef GENFACEVERT + glBufferData_(GL_ELEMENT_ARRAY_BUFFER, sizeof(tris), tris, GL_STATIC_DRAW); + gle::clearebo(); + } } static void cleanupbb() { - if(bbvbo) { glDeleteBuffers_(1, &bbvbo); bbvbo = 0; } - if(bbebo) { glDeleteBuffers_(1, &bbebo); bbebo = 0; } + if(bbvbo) { glDeleteBuffers_(1, &bbvbo); bbvbo = 0; } + if(bbebo) { glDeleteBuffers_(1, &bbebo); bbebo = 0; } } void startbb(bool mask) { - setupbb(); - gle::bindvbo(bbvbo); - gle::bindebo(bbebo); - gle::vertexpointer(sizeof(vec), (const vec *)0); - gle::enablevertex(); - SETSHADER(bbquery); - if(mask) - { - glDepthMask(GL_FALSE); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - } + setupbb(); + gle::bindvbo(bbvbo); + gle::bindebo(bbebo); + gle::vertexpointer(sizeof(vec), (const vec *)0); + gle::enablevertex(); + SETSHADER(bbquery); + if(mask) + { + glDepthMask(GL_FALSE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } } void endbb(bool mask) { - gle::disablevertex(); - gle::clearvbo(); - gle::clearebo(); - if(mask) - { - glDepthMask(GL_TRUE); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - } + gle::disablevertex(); + gle::clearvbo(); + gle::clearebo(); + if(mask) + { + glDepthMask(GL_TRUE); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } } void drawbb(const ivec &bo, const ivec &br) { - LOCALPARAMF(bborigin, bo.x, bo.y, bo.z); - LOCALPARAMF(bbsize, br.x, br.y, br.z); - glDrawRangeElements_(GL_TRIANGLES, 0, 8-1, 3*2*6, GL_UNSIGNED_SHORT, (ushort *)0); - xtraverts += 8; + LOCALPARAMF(bborigin, bo.x, bo.y, bo.z); + LOCALPARAMF(bbsize, br.x, br.y, br.z); + glDrawRangeElements_(GL_TRIANGLES, 0, 8-1, 3*2*6, GL_UNSIGNED_SHORT, (ushort *)0); + xtraverts += 8; } extern int octaentsize; @@ -397,214 +397,214 @@ static octaentities *visiblemms, **lastvisiblemms; static inline bool insideoe(const octaentities *oe, const vec &v, int margin = 1) { - return v.x>=oe->bbmin.x-margin && v.y>=oe->bbmin.y-margin && v.z>=oe->bbmin.z-margin && - v.x<=oe->bbmax.x+margin && v.y<=oe->bbmax.y+margin && v.z<=oe->bbmax.z+margin; + return v.x>=oe->bbmin.x-margin && v.y>=oe->bbmin.y-margin && v.z>=oe->bbmin.z-margin && + v.x<=oe->bbmax.x+margin && v.y<=oe->bbmax.y+margin && v.z<=oe->bbmax.z+margin; } void findvisiblemms(const vector<extentity *> &ents, bool doquery) { - visiblemms = NULL; - lastvisiblemms = &visiblemms; - for(vtxarray *va = visibleva; va; va = va->next) - { - if(va->mapmodels.empty() || va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue; - loopv(va->mapmodels) - { - octaentities *oe = va->mapmodels[i]; - if(isfoggedcube(oe->o, oe->size)) continue; - - bool occluded = doquery && oe->query && oe->query->owner == oe && checkquery(oe->query); - if(occluded) - { - oe->distance = -1; - - oe->next = NULL; - *lastvisiblemms = oe; - lastvisiblemms = &oe->next; - } - else - { - int visible = 0; - loopv(oe->mapmodels) - { - extentity &e = *ents[oe->mapmodels[i]]; - if(e.flags&EF_NOVIS) continue; - e.flags |= EF_RENDER; - ++visible; - } - if(!visible) continue; - - oe->distance = int(camera1->o.dist_to_bb(oe->o, oe->size)); - - octaentities **prev = &visiblemms, *cur = visiblemms; - while(cur && cur->distance >= 0 && oe->distance > cur->distance) - { - prev = &cur->next; - cur = cur->next; - } - - if(*prev == NULL) lastvisiblemms = &oe->next; - oe->next = *prev; - *prev = oe; - } - } - } + visiblemms = NULL; + lastvisiblemms = &visiblemms; + for(vtxarray *va = visibleva; va; va = va->next) + { + if(va->mapmodels.empty() || va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue; + loopv(va->mapmodels) + { + octaentities *oe = va->mapmodels[i]; + if(isfoggedcube(oe->o, oe->size)) continue; + + bool occluded = doquery && oe->query && oe->query->owner == oe && checkquery(oe->query); + if(occluded) + { + oe->distance = -1; + + oe->next = NULL; + *lastvisiblemms = oe; + lastvisiblemms = &oe->next; + } + else + { + int visible = 0; + loopv(oe->mapmodels) + { + extentity &e = *ents[oe->mapmodels[i]]; + if(e.flags&EF_NOVIS) continue; + e.flags |= EF_RENDER; + ++visible; + } + if(!visible) continue; + + oe->distance = int(camera1->o.dist_to_bb(oe->o, oe->size)); + + octaentities **prev = &visiblemms, *cur = visiblemms; + while(cur && cur->distance >= 0 && oe->distance > cur->distance) + { + prev = &cur->next; + cur = cur->next; + } + + if(*prev == NULL) lastvisiblemms = &oe->next; + oe->next = *prev; + *prev = oe; + } + } + } } VAR(oqmm, 0, 4, 8); void rendermapmodel(extentity &e) { - int anim = ANIM_MAPMODEL|ANIM_LOOP, basetime = 0; - mapmodelinfo *mmi = getmminfo(e.attr2); - if(mmi) rendermodel(&e.light, mmi->name, anim, e.o, e.attr1, 0, MDL_CULL_VFC | MDL_CULL_DIST | MDL_DYNLIGHT, NULL, NULL, basetime); + int anim = ANIM_MAPMODEL|ANIM_LOOP, basetime = 0; + mapmodelinfo *mmi = getmminfo(e.attr2); + if(mmi) rendermodel(&e.light, mmi->name, anim, e.o, e.attr1, 0, MDL_CULL_VFC | MDL_CULL_DIST | MDL_DYNLIGHT, NULL, NULL, basetime); } vtxarray *reflectedva; void renderreflectedmapmodels() { - const vector<extentity *> &ents = entities::getents(); - - octaentities *mms = visiblemms; - if(reflecting) - { - octaentities **lastmms = &mms; - for(vtxarray *va = reflectedva; va; va = va->rnext) - { - if(va->mapmodels.empty() || va->distance > reflectdist) continue; - loopv(va->mapmodels) - { - octaentities *oe = va->mapmodels[i]; - *lastmms = oe; - lastmms = &oe->rnext; - } - } - *lastmms = NULL; - } - for(octaentities *oe = mms; oe; oe = reflecting ? oe->rnext : oe->next) if(reflecting || oe->distance >= 0) - { - if(reflecting || refracting>0 ? oe->bbmax.z <= reflectz : oe->bbmin.z >= reflectz) continue; - if(isfoggedcube(oe->o, oe->size)) continue; - loopv(oe->mapmodels) - { - extentity &e = *ents[oe->mapmodels[i]]; - if(e.flags&(EF_NOVIS | EF_RENDER)) continue; - e.flags |= EF_RENDER; - } - } - if(mms) - { - startmodelbatches(); - for(octaentities *oe = mms; oe; oe = reflecting ? oe->rnext : oe->next) - { - loopv(oe->mapmodels) - { - extentity &e = *ents[oe->mapmodels[i]]; - if(!(e.flags&EF_RENDER)) continue; - rendermapmodel(e); - e.flags &= ~EF_RENDER; - } - } - endmodelbatches(); - } + const vector<extentity *> &ents = entities::getents(); + + octaentities *mms = visiblemms; + if(reflecting) + { + octaentities **lastmms = &mms; + for(vtxarray *va = reflectedva; va; va = va->rnext) + { + if(va->mapmodels.empty() || va->distance > reflectdist) continue; + loopv(va->mapmodels) + { + octaentities *oe = va->mapmodels[i]; + *lastmms = oe; + lastmms = &oe->rnext; + } + } + *lastmms = NULL; + } + for(octaentities *oe = mms; oe; oe = reflecting ? oe->rnext : oe->next) if(reflecting || oe->distance >= 0) + { + if(reflecting || refracting>0 ? oe->bbmax.z <= reflectz : oe->bbmin.z >= reflectz) continue; + if(isfoggedcube(oe->o, oe->size)) continue; + loopv(oe->mapmodels) + { + extentity &e = *ents[oe->mapmodels[i]]; + if(e.flags&(EF_NOVIS | EF_RENDER)) continue; + e.flags |= EF_RENDER; + } + } + if(mms) + { + startmodelbatches(); + for(octaentities *oe = mms; oe; oe = reflecting ? oe->rnext : oe->next) + { + loopv(oe->mapmodels) + { + extentity &e = *ents[oe->mapmodels[i]]; + if(!(e.flags&EF_RENDER)) continue; + rendermapmodel(e); + e.flags &= ~EF_RENDER; + } + } + endmodelbatches(); + } } void rendermapmodels() { - static int skipoq = 0; - bool doquery = !drawtex && oqfrags && oqmm; - const vector<extentity *> &ents = entities::getents(); - findvisiblemms(ents, doquery); - - startmodelbatches(); - for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance>=0) - { - bool rendered = false; - loopv(oe->mapmodels) - { - extentity &e = *ents[oe->mapmodels[i]]; - if(!(e.flags&EF_RENDER)) continue; - if(!rendered) - { - rendered = true; - oe->query = doquery && oe->distance>0 && !(++skipoq%oqmm) ? newquery(oe) : NULL; - if(oe->query) startmodelquery(oe->query); - } - rendermapmodel(e); - e.flags &= ~EF_RENDER; - } - if(rendered && oe->query) endmodelquery(); - } - endmodelbatches(); - - bool queried = true; - for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance<0) - { - oe->query = doquery && !insideoe(oe, camera1->o) ? newquery(oe) : NULL; - if(!oe->query) continue; - if(queried) - { - startbb(); - queried = false; - } - startquery(oe->query); - drawbb(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin)); - endquery(oe->query); - } - if(!queried) - { - endbb(); - } + static int skipoq = 0; + bool doquery = !drawtex && oqfrags && oqmm; + const vector<extentity *> &ents = entities::getents(); + findvisiblemms(ents, doquery); + + startmodelbatches(); + for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance>=0) + { + bool rendered = false; + loopv(oe->mapmodels) + { + extentity &e = *ents[oe->mapmodels[i]]; + if(!(e.flags&EF_RENDER)) continue; + if(!rendered) + { + rendered = true; + oe->query = doquery && oe->distance>0 && !(++skipoq%oqmm) ? newquery(oe) : NULL; + if(oe->query) startmodelquery(oe->query); + } + rendermapmodel(e); + e.flags &= ~EF_RENDER; + } + if(rendered && oe->query) endmodelquery(); + } + endmodelbatches(); + + bool queried = true; + for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance<0) + { + oe->query = doquery && !insideoe(oe, camera1->o) ? newquery(oe) : NULL; + if(!oe->query) continue; + if(queried) + { + startbb(); + queried = false; + } + startquery(oe->query); + drawbb(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin)); + endquery(oe->query); + } + if(!queried) + { + endbb(); + } } static inline bool bbinsideva(const ivec &bo, const ivec &br, vtxarray *va) { - return bo.x >= va->bbmin.x && bo.y >= va->bbmin.y && bo.z >= va->bbmin.z && - br.x <= va->bbmax.x && br.y <= va->bbmax.y && br.z <= va->bbmax.z; + return bo.x >= va->bbmin.x && bo.y >= va->bbmin.y && bo.z >= va->bbmin.z && + br.x <= va->bbmax.x && br.y <= va->bbmax.y && br.z <= va->bbmax.z; } static inline bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size) { - loopoctabox(o, size, bo, br) - { - ivec co(i, o, size); - if(c[i].ext && c[i].ext->va) - { - vtxarray *va = c[i].ext->va; - if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) continue; - } - if(c[i].children && bboccluded(bo, br, c[i].children, co, size>>1)) continue; - return false; - } - return true; + loopoctabox(o, size, bo, br) + { + ivec co(i, o, size); + if(c[i].ext && c[i].ext->va) + { + vtxarray *va = c[i].ext->va; + if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) continue; + } + if(c[i].children && bboccluded(bo, br, c[i].children, co, size>>1)) continue; + return false; + } + return true; } bool bboccluded(const ivec &bo, const ivec &br) { - int diff = (bo.x^br.x) | (bo.y^br.y) | (bo.z^br.z); - if(diff&~((1<<worldscale)-1)) return false; - int scale = worldscale-1; - if(diff&(1<<scale)) return bboccluded(bo, br, worldroot, ivec(0, 0, 0), 1<<scale); - cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)]; - if(c->ext && c->ext->va) - { - vtxarray *va = c->ext->va; - if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) return true; - } - scale--; - while(c->children && !(diff&(1<<scale))) - { - c = &c->children[octastep(bo.x, bo.y, bo.z, scale)]; - if(c->ext && c->ext->va) - { - vtxarray *va = c->ext->va; - if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) return true; - } - scale--; - } - if(c->children) return bboccluded(bo, br, c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale); - return false; + int diff = (bo.x^br.x) | (bo.y^br.y) | (bo.z^br.z); + if(diff&~((1<<worldscale)-1)) return false; + int scale = worldscale-1; + if(diff&(1<<scale)) return bboccluded(bo, br, worldroot, ivec(0, 0, 0), 1<<scale); + cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)]; + if(c->ext && c->ext->va) + { + vtxarray *va = c->ext->va; + if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) return true; + } + scale--; + while(c->children && !(diff&(1<<scale))) + { + c = &c->children[octastep(bo.x, bo.y, bo.z, scale)]; + if(c->ext && c->ext->va) + { + vtxarray *va = c->ext->va; + if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) return true; + } + scale--; + } + if(c->children) return bboccluded(bo, br, c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale); + return false; } VAR(outline, 0, 0, 1); @@ -613,213 +613,213 @@ VAR(dtoutline, 0, 1, 1); void renderoutline() { - notextureshader->set(); + notextureshader->set(); - gle::enablevertex(); + gle::enablevertex(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - gle::color(vec::hexcolor(outlinecolour)); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gle::color(vec::hexcolor(outlinecolour)); - enablepolygonoffset(GL_POLYGON_OFFSET_LINE); + enablepolygonoffset(GL_POLYGON_OFFSET_LINE); - if(!dtoutline) glDisable(GL_DEPTH_TEST); + if(!dtoutline) glDisable(GL_DEPTH_TEST); - vtxarray *prev = NULL; - for(vtxarray *va = visibleva; va; va = va->next) - { - if(va->occluded >= OCCLUDE_BB) continue; - if(!va->alphaback && !va->alphafront && (!va->texs || va->occluded >= OCCLUDE_GEOM)) continue; + vtxarray *prev = NULL; + for(vtxarray *va = visibleva; va; va = va->next) + { + if(va->occluded >= OCCLUDE_BB) continue; + if(!va->alphaback && !va->alphafront && (!va->texs || va->occluded >= OCCLUDE_GEOM)) continue; - if(!prev || va->vbuf != prev->vbuf) - { - gle::bindvbo(va->vbuf); - gle::bindebo(va->ebuf); - const vertex *ptr = 0; - gle::vertexpointer(sizeof(vertex), ptr->pos.v); - } + if(!prev || va->vbuf != prev->vbuf) + { + gle::bindvbo(va->vbuf); + gle::bindebo(va->ebuf); + const vertex *ptr = 0; + gle::vertexpointer(sizeof(vertex), ptr->pos.v); + } - if(va->texs && va->occluded < OCCLUDE_GEOM) - { - drawvatris(va, 3*va->tris, va->edata); - xtravertsva += va->verts; - } - if(va->alphatris) - { - drawvatris(va, 3*va->alphatris, &va->edata[3*(va->tris + va->blendtris)]); - xtravertsva += 3*va->alphatris; - } + if(va->texs && va->occluded < OCCLUDE_GEOM) + { + drawvatris(va, 3*va->tris, va->edata); + xtravertsva += va->verts; + } + if(va->alphatris) + { + drawvatris(va, 3*va->alphatris, &va->edata[3*(va->tris + va->blendtris)]); + xtravertsva += 3*va->alphatris; + } - prev = va; - } + prev = va; + } - if(!dtoutline) glEnable(GL_DEPTH_TEST); + if(!dtoutline) glEnable(GL_DEPTH_TEST); - disablepolygonoffset(GL_POLYGON_OFFSET_LINE); + disablepolygonoffset(GL_POLYGON_OFFSET_LINE); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - gle::clearvbo(); - gle::clearebo(); - gle::disablevertex(); + gle::clearvbo(); + gle::clearebo(); + gle::disablevertex(); } HVAR(blendbrushcolor, 0, 0x0000C0, 0xFFFFFF); void renderblendbrush(GLuint tex, float x, float y, float w, float h) { - SETSHADER(blendbrush); + SETSHADER(blendbrush); - gle::enablevertex(); + gle::enablevertex(); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_LEQUAL); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glBindTexture(GL_TEXTURE_2D, tex); - gle::color(vec::hexcolor(blendbrushcolor), 0.25f); + glBindTexture(GL_TEXTURE_2D, tex); + gle::color(vec::hexcolor(blendbrushcolor), 0.25f); - LOCALPARAMF(texgenS, 1.0f/w, 0, 0, -x/w); - LOCALPARAMF(texgenT, 0, 1.0f/h, 0, -y/h); + LOCALPARAMF(texgenS, 1.0f/w, 0, 0, -x/w); + LOCALPARAMF(texgenT, 0, 1.0f/h, 0, -y/h); - vtxarray *prev = NULL; - for(vtxarray *va = visibleva; va; va = va->next) - { - if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue; - if(va->o.x + va->size <= x || va->o.y + va->size <= y || va->o.x >= x + w || va->o.y >= y + h) continue; + vtxarray *prev = NULL; + for(vtxarray *va = visibleva; va; va = va->next) + { + if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue; + if(va->o.x + va->size <= x || va->o.y + va->size <= y || va->o.x >= x + w || va->o.y >= y + h) continue; - if(!prev || va->vbuf != prev->vbuf) - { - gle::bindvbo(va->vbuf); - gle::bindebo(va->ebuf); - const vertex *ptr = 0; - gle::vertexpointer(sizeof(vertex), ptr->pos.v); - } + if(!prev || va->vbuf != prev->vbuf) + { + gle::bindvbo(va->vbuf); + gle::bindebo(va->ebuf); + const vertex *ptr = 0; + gle::vertexpointer(sizeof(vertex), ptr->pos.v); + } - drawvatris(va, 3*va->tris, va->edata); - xtravertsva += va->verts; + drawvatris(va, 3*va->tris, va->edata); + xtravertsva += va->verts; - prev = va; - } + prev = va; + } - glDisable(GL_BLEND); + glDisable(GL_BLEND); - glDepthFunc(GL_LESS); + glDepthFunc(GL_LESS); - gle::clearvbo(); - gle::clearebo(); - gle::disablevertex(); + gle::clearvbo(); + gle::clearebo(); + gle::disablevertex(); } void rendershadowmapreceivers() { - SETSHADER(shadowmapreceiver); + SETSHADER(shadowmapreceiver); - gle::enablevertex(); + gle::enablevertex(); - glCullFace(GL_FRONT); - glDepthMask(GL_FALSE); - glDepthFunc(GL_GREATER); + glCullFace(GL_FRONT); + glDepthMask(GL_FALSE); + glDepthFunc(GL_GREATER); - extern int ati_minmax_bug; - if(!ati_minmax_bug) glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); + extern int ati_minmax_bug; + if(!ati_minmax_bug) glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); - glEnable(GL_BLEND); - glBlendEquation_(GL_MAX); - glBlendFunc(GL_ONE, GL_ONE); + glEnable(GL_BLEND); + glBlendEquation_(GL_MAX); + glBlendFunc(GL_ONE, GL_ONE); - vtxarray *prev = NULL; - for(vtxarray *va = visibleva; va; va = va->next) - { - if(!va->texs || va->curvfc >= VFC_FOGGED || !isshadowmapreceiver(va)) continue; + vtxarray *prev = NULL; + for(vtxarray *va = visibleva; va; va = va->next) + { + if(!va->texs || va->curvfc >= VFC_FOGGED || !isshadowmapreceiver(va)) continue; - if(!prev || va->vbuf != prev->vbuf) - { - gle::bindvbo(va->vbuf); - gle::bindebo(va->ebuf); - const vertex *ptr = 0; - gle::vertexpointer(sizeof(vertex), ptr->pos.v); - } + if(!prev || va->vbuf != prev->vbuf) + { + gle::bindvbo(va->vbuf); + gle::bindebo(va->ebuf); + const vertex *ptr = 0; + gle::vertexpointer(sizeof(vertex), ptr->pos.v); + } - drawvatris(va, 3*va->tris, va->edata); - xtravertsva += va->verts; + drawvatris(va, 3*va->tris, va->edata); + xtravertsva += va->verts; - prev = va; - } + prev = va; + } - glDisable(GL_BLEND); - glBlendEquation_(GL_FUNC_ADD); + glDisable(GL_BLEND); + glBlendEquation_(GL_FUNC_ADD); - glCullFace(GL_BACK); - glDepthMask(GL_TRUE); - glDepthFunc(GL_LESS); + glCullFace(GL_BACK); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LESS); - if(!ati_minmax_bug) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + if(!ati_minmax_bug) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - gle::clearvbo(); - gle::clearebo(); - gle::disablevertex(); + gle::clearvbo(); + gle::clearebo(); + gle::disablevertex(); } void renderdepthobstacles(const vec &bbmin, const vec &bbmax, float scale, float *ranges, int numranges) { - float scales[4] = { 0, 0, 0, 0 }, offsets[4] = { 0, 0, 0, 0 }; - if(numranges < 0) - { - SETSHADER(depthfxsplitworld); - - loopi(-numranges) - { - if(!i) scales[i] = 1.0f/scale; - else scales[i] = scales[i-1]*256; - } - } - else - { - SETSHADER(depthfxworld); - - if(!numranges) loopi(4) scales[i] = 1.0f/scale; - else loopi(numranges) - { - scales[i] = 1.0f/scale; - offsets[i] = -ranges[i]/scale; - } - } - LOCALPARAMF(depthscale, scales[0], scales[1], scales[2], scales[3]); - LOCALPARAMF(depthoffsets, offsets[0], offsets[1], offsets[2], offsets[3]); - - gle::enablevertex(); - - vtxarray *prev = NULL; - for(vtxarray *va = visibleva; va; va = va->next) - { - if(!va->texs || va->occluded >= OCCLUDE_GEOM || - va->o.x > bbmax.x || va->o.y > bbmax.y || va->o.z > bbmax.z || - va->o.x + va->size < bbmin.x || va->o.y + va->size < bbmin.y || va->o.z + va->size < bbmin.z) - continue; - - if(!prev || va->vbuf != prev->vbuf) - { - gle::bindvbo(va->vbuf); - gle::bindebo(va->ebuf); - const vertex *ptr = 0; - gle::vertexpointer(sizeof(vertex), ptr->pos.v); - } - - drawvatris(va, 3*va->tris, va->edata); - xtravertsva += va->verts; - if(va->alphatris > 0) - { - drawvatris(va, 3*va->alphatris, va->edata + 3*(va->tris + va->blendtris)); - xtravertsva += 3*va->alphatris; - } - - prev = va; - } - - gle::clearvbo(); - gle::clearebo(); - gle::disablevertex(); + float scales[4] = { 0, 0, 0, 0 }, offsets[4] = { 0, 0, 0, 0 }; + if(numranges < 0) + { + SETSHADER(depthfxsplitworld); + + loopi(-numranges) + { + if(!i) scales[i] = 1.0f/scale; + else scales[i] = scales[i-1]*256; + } + } + else + { + SETSHADER(depthfxworld); + + if(!numranges) loopi(4) scales[i] = 1.0f/scale; + else loopi(numranges) + { + scales[i] = 1.0f/scale; + offsets[i] = -ranges[i]/scale; + } + } + LOCALPARAMF(depthscale, scales[0], scales[1], scales[2], scales[3]); + LOCALPARAMF(depthoffsets, offsets[0], offsets[1], offsets[2], offsets[3]); + + gle::enablevertex(); + + vtxarray *prev = NULL; + for(vtxarray *va = visibleva; va; va = va->next) + { + if(!va->texs || va->occluded >= OCCLUDE_GEOM || + va->o.x > bbmax.x || va->o.y > bbmax.y || va->o.z > bbmax.z || + va->o.x + va->size < bbmin.x || va->o.y + va->size < bbmin.y || va->o.z + va->size < bbmin.z) + continue; + + if(!prev || va->vbuf != prev->vbuf) + { + gle::bindvbo(va->vbuf); + gle::bindebo(va->ebuf); + const vertex *ptr = 0; + gle::vertexpointer(sizeof(vertex), ptr->pos.v); + } + + drawvatris(va, 3*va->tris, va->edata); + xtravertsva += va->verts; + if(va->alphatris > 0) + { + drawvatris(va, 3*va->alphatris, va->edata + 3*(va->tris + va->blendtris)); + xtravertsva += 3*va->alphatris; + } + + prev = va; + } + + gle::clearvbo(); + gle::clearebo(); + gle::disablevertex(); } VAR(oqdist, 0, 256, 1024); @@ -828,101 +828,101 @@ VAR(envpass, 0, 1, 1); struct renderstate { - bool colormask, depthmask, blending; - int alphaing; - GLuint vbuf; - bool vattribs, vquery; - vec colorscale, lightcolor; - float alphascale; - GLuint textures[8]; - Slot *slot, *texgenslot; - VSlot *vslot, *texgenvslot; - vec2 texgenscroll; - int texgendim; - int visibledynlights; - uint dynlightmask; - - renderstate() : colormask(true), depthmask(true), blending(false), alphaing(0), vbuf(0), vattribs(false), vquery(false), colorscale(1, 1, 1), alphascale(0), slot(NULL), texgenslot(NULL), vslot(NULL), texgenvslot(NULL), texgenscroll(0, 0), texgendim(-1), visibledynlights(0), dynlightmask(0) - { - loopk(8) textures[k] = 0; - } + bool colormask, depthmask, blending; + int alphaing; + GLuint vbuf; + bool vattribs, vquery; + vec colorscale, lightcolor; + float alphascale; + GLuint textures[8]; + Slot *slot, *texgenslot; + VSlot *vslot, *texgenvslot; + vec2 texgenscroll; + int texgendim; + int visibledynlights; + uint dynlightmask; + + renderstate() : colormask(true), depthmask(true), blending(false), alphaing(0), vbuf(0), vattribs(false), vquery(false), colorscale(1, 1, 1), alphascale(0), slot(NULL), texgenslot(NULL), vslot(NULL), texgenvslot(NULL), texgenscroll(0, 0), texgendim(-1), visibledynlights(0), dynlightmask(0) + { + loopk(8) textures[k] = 0; + } }; static inline void disablevbuf(renderstate &cur) { - gle::clearvbo(); - gle::clearebo(); - cur.vbuf = 0; + gle::clearvbo(); + gle::clearebo(); + cur.vbuf = 0; } static inline void enablevquery(renderstate &cur) { - if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } - if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); } - startbb(false); - cur.vquery = true; + if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } + if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); } + startbb(false); + cur.vquery = true; } static inline void disablevquery(renderstate &cur) { - endbb(false); - cur.vquery = false; + endbb(false); + cur.vquery = false; } static void renderquery(renderstate &cur, occludequery *query, vtxarray *va, bool full = true) { - if(!cur.vquery) enablevquery(cur); + if(!cur.vquery) enablevquery(cur); - startquery(query); + startquery(query); - if(full) drawbb(ivec(va->bbmin).sub(1), ivec(va->bbmax).sub(va->bbmin).add(2)); - else drawbb(va->geommin, ivec(va->geommax).sub(va->geommin)); + if(full) drawbb(ivec(va->bbmin).sub(1), ivec(va->bbmax).sub(va->bbmin).add(2)); + else drawbb(va->geommin, ivec(va->geommax).sub(va->geommin)); - endquery(query); + endquery(query); } enum { - RENDERPASS_LIGHTMAP = 0, - RENDERPASS_Z, - RENDERPASS_CAUSTICS, - RENDERPASS_FOG, - RENDERPASS_LIGHTMAP_BLEND + RENDERPASS_LIGHTMAP = 0, + RENDERPASS_Z, + RENDERPASS_CAUSTICS, + RENDERPASS_FOG, + RENDERPASS_LIGHTMAP_BLEND }; struct geombatch { - const elementset &es; - VSlot &vslot; - ushort *edata; - vtxarray *va; - int next, batch; - - geombatch(const elementset &es, ushort *edata, vtxarray *va) - : es(es), vslot(lookupvslot(es.texture)), edata(edata), va(va), - next(-1), batch(-1) - {} - - int compare(const geombatch &b) const - { - if(va->vbuf < b.va->vbuf) return -1; - if(va->vbuf > b.va->vbuf) return 1; - if(va->dynlightmask < b.va->dynlightmask) return -1; - if(va->dynlightmask > b.va->dynlightmask) return 1; - if(vslot.slot->shader < b.vslot.slot->shader) return -1; - if(vslot.slot->shader > b.vslot.slot->shader) return 1; - if(vslot.slot->params.length() < b.vslot.slot->params.length()) return -1; - if(vslot.slot->params.length() > b.vslot.slot->params.length()) return 1; - if(es.texture < b.es.texture) return -1; - if(es.texture > b.es.texture) return 1; - if(es.lmid < b.es.lmid) return -1; - if(es.lmid > b.es.lmid) return 1; - if(es.envmap < b.es.envmap) return -1; - if(es.envmap > b.es.envmap) return 1; - if(es.dim < b.es.dim) return -1; - if(es.dim > b.es.dim) return 1; - return 0; - } + const elementset &es; + VSlot &vslot; + ushort *edata; + vtxarray *va; + int next, batch; + + geombatch(const elementset &es, ushort *edata, vtxarray *va) + : es(es), vslot(lookupvslot(es.texture)), edata(edata), va(va), + next(-1), batch(-1) + {} + + int compare(const geombatch &b) const + { + if(va->vbuf < b.va->vbuf) return -1; + if(va->vbuf > b.va->vbuf) return 1; + if(va->dynlightmask < b.va->dynlightmask) return -1; + if(va->dynlightmask > b.va->dynlightmask) return 1; + if(vslot.slot->shader < b.vslot.slot->shader) return -1; + if(vslot.slot->shader > b.vslot.slot->shader) return 1; + if(vslot.slot->params.length() < b.vslot.slot->params.length()) return -1; + if(vslot.slot->params.length() > b.vslot.slot->params.length()) return 1; + if(es.texture < b.es.texture) return -1; + if(es.texture > b.es.texture) return 1; + if(es.lmid < b.es.lmid) return -1; + if(es.lmid > b.es.lmid) return 1; + if(es.envmap < b.es.envmap) return -1; + if(es.envmap > b.es.envmap) return 1; + if(es.dim < b.es.dim) return -1; + if(es.dim > b.es.dim) return 1; + return 0; + } }; static vector<geombatch> geombatches; @@ -930,486 +930,486 @@ static int firstbatch = -1, numbatches = 0; static void mergetexs(renderstate &cur, vtxarray *va, elementset *texs = NULL, int numtexs = 0, ushort *edata = NULL) { - if(!texs) - { - texs = va->eslist; - numtexs = va->texs; - edata = va->edata; - if(cur.alphaing) - { - texs += va->texs + va->blends; - edata += 3*(va->tris + va->blendtris); - numtexs = va->alphaback; - if(cur.alphaing > 1) numtexs += va->alphafront; - } - } - - if(firstbatch < 0) - { - firstbatch = geombatches.length(); - numbatches = numtexs; - loopi(numtexs-1) - { - geombatches.add(geombatch(texs[i], edata, va)).next = i+1; - edata += texs[i].length[1]; - } - geombatches.add(geombatch(texs[numtexs-1], edata, va)); - return; - } - - int prevbatch = -1, curbatch = firstbatch, curtex = 0; - do - { - geombatch &b = geombatches.add(geombatch(texs[curtex], edata, va)); - edata += texs[curtex].length[1]; - int dir = -1; - while(curbatch >= 0) - { - dir = b.compare(geombatches[curbatch]); - if(dir <= 0) break; - prevbatch = curbatch; - curbatch = geombatches[curbatch].next; - } - if(!dir) - { - int last = curbatch, next; - for(;;) - { - next = geombatches[last].batch; - if(next < 0) break; - last = next; - } - if(last==curbatch) - { - b.batch = curbatch; - b.next = geombatches[curbatch].next; - if(prevbatch < 0) firstbatch = geombatches.length()-1; - else geombatches[prevbatch].next = geombatches.length()-1; - curbatch = geombatches.length()-1; - } - else - { - b.batch = next; - geombatches[last].batch = geombatches.length()-1; - } - } - else - { - numbatches++; - b.next = curbatch; - if(prevbatch < 0) firstbatch = geombatches.length()-1; - else geombatches[prevbatch].next = geombatches.length()-1; - prevbatch = geombatches.length()-1; - } - } - while(++curtex < numtexs); + if(!texs) + { + texs = va->eslist; + numtexs = va->texs; + edata = va->edata; + if(cur.alphaing) + { + texs += va->texs + va->blends; + edata += 3*(va->tris + va->blendtris); + numtexs = va->alphaback; + if(cur.alphaing > 1) numtexs += va->alphafront; + } + } + + if(firstbatch < 0) + { + firstbatch = geombatches.length(); + numbatches = numtexs; + loopi(numtexs-1) + { + geombatches.add(geombatch(texs[i], edata, va)).next = i+1; + edata += texs[i].length[1]; + } + geombatches.add(geombatch(texs[numtexs-1], edata, va)); + return; + } + + int prevbatch = -1, curbatch = firstbatch, curtex = 0; + do + { + geombatch &b = geombatches.add(geombatch(texs[curtex], edata, va)); + edata += texs[curtex].length[1]; + int dir = -1; + while(curbatch >= 0) + { + dir = b.compare(geombatches[curbatch]); + if(dir <= 0) break; + prevbatch = curbatch; + curbatch = geombatches[curbatch].next; + } + if(!dir) + { + int last = curbatch, next; + for(;;) + { + next = geombatches[last].batch; + if(next < 0) break; + last = next; + } + if(last==curbatch) + { + b.batch = curbatch; + b.next = geombatches[curbatch].next; + if(prevbatch < 0) firstbatch = geombatches.length()-1; + else geombatches[prevbatch].next = geombatches.length()-1; + curbatch = geombatches.length()-1; + } + else + { + b.batch = next; + geombatches[last].batch = geombatches.length()-1; + } + } + else + { + numbatches++; + b.next = curbatch; + if(prevbatch < 0) firstbatch = geombatches.length()-1; + else geombatches[prevbatch].next = geombatches.length()-1; + prevbatch = geombatches.length()-1; + } + } + while(++curtex < numtexs); } static inline void enablevattribs(renderstate &cur, bool all = true) { - gle::enablevertex(); - if(all) - { - gle::enabletexcoord0(); - gle::enabletexcoord1(); - gle::enablenormal(); - gle::enabletangent(); - } - cur.vattribs = true; + gle::enablevertex(); + if(all) + { + gle::enabletexcoord0(); + gle::enabletexcoord1(); + gle::enablenormal(); + gle::enabletangent(); + } + cur.vattribs = true; } static inline void disablevattribs(renderstate &cur, bool all = true) { - gle::disablevertex(); - if(all) - { - gle::disabletexcoord0(); - gle::disabletexcoord1(); - gle::disablenormal(); - gle::disabletangent(); - } - cur.vattribs = false; + gle::disablevertex(); + if(all) + { + gle::disabletexcoord0(); + gle::disabletexcoord1(); + gle::disablenormal(); + gle::disabletangent(); + } + cur.vattribs = false; } static void changevbuf(renderstate &cur, int pass, vtxarray *va) { - gle::bindvbo(va->vbuf); - gle::bindebo(va->ebuf); - cur.vbuf = va->vbuf; + gle::bindvbo(va->vbuf); + gle::bindebo(va->ebuf); + cur.vbuf = va->vbuf; - vertex *vdata = (vertex *)0; - gle::vertexpointer(sizeof(vertex), vdata->pos.v); + vertex *vdata = (vertex *)0; + gle::vertexpointer(sizeof(vertex), vdata->pos.v); - if(pass==RENDERPASS_LIGHTMAP) - { - gle::normalpointer(sizeof(vertex), vdata->norm.v, GL_BYTE); - gle::texcoord0pointer(sizeof(vertex), vdata->tc.v); - gle::texcoord1pointer(sizeof(vertex), vdata->lm.v, GL_SHORT); - gle::tangentpointer(sizeof(vertex), vdata->tangent.v, GL_BYTE); - } + if(pass==RENDERPASS_LIGHTMAP) + { + gle::normalpointer(sizeof(vertex), vdata->norm.v, GL_BYTE); + gle::texcoord0pointer(sizeof(vertex), vdata->tc.v); + gle::texcoord1pointer(sizeof(vertex), vdata->lm.v, GL_SHORT); + gle::tangentpointer(sizeof(vertex), vdata->tangent.v, GL_BYTE); + } } static void changebatchtmus(renderstate &cur, int pass, geombatch &b) { - bool changed = false; - extern bool brightengeom; - extern int fullbright; - int lmid = brightengeom && (b.es.lmid < LMID_RESERVED || (fullbright && editmode)) ? (int) LMID_BRIGHT : (int) b.es.lmid; - if(cur.textures[1]!=lightmaptexs[lmid].id) - { - glActiveTexture_(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, cur.textures[1] = lightmaptexs[lmid].id); - changed = true; - } - int tmu = 2; - if(b.vslot.slot->shader->type&SHADER_NORMALSLMS) - { - if(cur.textures[tmu]!=lightmaptexs[lmid+1].id) - { - glActiveTexture_(GL_TEXTURE0+tmu); - glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = lightmaptexs[lmid+1].id); - changed = true; - } - tmu++; - } - if(b.vslot.slot->shader->type&SHADER_ENVMAP && b.es.envmap!=EMID_CUSTOM) - { - GLuint emtex = lookupenvmap(b.es.envmap); - if(cur.textures[tmu]!=emtex) - { - glActiveTexture_(GL_TEXTURE0+tmu); - glBindTexture(GL_TEXTURE_CUBE_MAP, cur.textures[tmu] = emtex); - changed = true; - } - } - if(changed) glActiveTexture_(GL_TEXTURE0); - - if(cur.dynlightmask != b.va->dynlightmask) - { - cur.visibledynlights = setdynlights(b.va); - cur.dynlightmask = b.va->dynlightmask; - } + bool changed = false; + extern bool brightengeom; + extern int fullbright; + int lmid = brightengeom && (b.es.lmid < LMID_RESERVED || (fullbright && editmode)) ? (int) LMID_BRIGHT : (int) b.es.lmid; + if(cur.textures[1]!=lightmaptexs[lmid].id) + { + glActiveTexture_(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, cur.textures[1] = lightmaptexs[lmid].id); + changed = true; + } + int tmu = 2; + if(b.vslot.slot->shader->type&SHADER_NORMALSLMS) + { + if(cur.textures[tmu]!=lightmaptexs[lmid+1].id) + { + glActiveTexture_(GL_TEXTURE0+tmu); + glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = lightmaptexs[lmid+1].id); + changed = true; + } + tmu++; + } + if(b.vslot.slot->shader->type&SHADER_ENVMAP && b.es.envmap!=EMID_CUSTOM) + { + GLuint emtex = lookupenvmap(b.es.envmap); + if(cur.textures[tmu]!=emtex) + { + glActiveTexture_(GL_TEXTURE0+tmu); + glBindTexture(GL_TEXTURE_CUBE_MAP, cur.textures[tmu] = emtex); + changed = true; + } + } + if(changed) glActiveTexture_(GL_TEXTURE0); + + if(cur.dynlightmask != b.va->dynlightmask) + { + cur.visibledynlights = setdynlights(b.va); + cur.dynlightmask = b.va->dynlightmask; + } } static void changeslottmus(renderstate &cur, int pass, Slot &slot, VSlot &vslot) { - if(pass==RENDERPASS_LIGHTMAP) - { - GLuint diffusetex = slot.sts.empty() ? notexture->id : slot.sts[0].t->id; - if(cur.textures[0]!=diffusetex) - glBindTexture(GL_TEXTURE_2D, cur.textures[0] = diffusetex); - } - - if(cur.alphaing) - { - float alpha = cur.alphaing > 1 ? vslot.alphafront : vslot.alphaback; - if(cur.colorscale != vslot.colorscale || cur.alphascale != alpha) - { - cur.colorscale = vslot.colorscale; - cur.alphascale = alpha; - GLOBALPARAMF(colorparams, 2*alpha*vslot.colorscale.x, 2*alpha*vslot.colorscale.y, 2*alpha*vslot.colorscale.z, alpha); - setfogcolor(vec(curfogcolor).mul(alpha)); - } - } - else if(cur.colorscale != vslot.colorscale) - { - cur.colorscale = vslot.colorscale; - GLOBALPARAMF(colorparams, 2*vslot.colorscale.x, 2*vslot.colorscale.y, 2*vslot.colorscale.z, 1); - } - int tmu = 2, envmaptmu = -1; - if(slot.shader->type&SHADER_NORMALSLMS) tmu++; - if(slot.shader->type&SHADER_ENVMAP) envmaptmu = tmu++; - loopvj(slot.sts) - { - Slot::Tex &t = slot.sts[j]; - if(t.type==TEX_DIFFUSE || t.combined>=0) continue; - if(t.type==TEX_ENVMAP) - { - if(envmaptmu>=0 && t.t && cur.textures[envmaptmu]!=t.t->id) - { - glActiveTexture_(GL_TEXTURE0+envmaptmu); - glBindTexture(GL_TEXTURE_CUBE_MAP, cur.textures[envmaptmu] = t.t->id); - } - } - else - { - if(cur.textures[tmu]!=t.t->id) - { - glActiveTexture_(GL_TEXTURE0+tmu); - glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = t.t->id); - } - if(++tmu >= 8) break; - } - } - glActiveTexture_(GL_TEXTURE0); - - cur.slot = &slot; - cur.vslot = &vslot; + if(pass==RENDERPASS_LIGHTMAP) + { + GLuint diffusetex = slot.sts.empty() ? notexture->id : slot.sts[0].t->id; + if(cur.textures[0]!=diffusetex) + glBindTexture(GL_TEXTURE_2D, cur.textures[0] = diffusetex); + } + + if(cur.alphaing) + { + float alpha = cur.alphaing > 1 ? vslot.alphafront : vslot.alphaback; + if(cur.colorscale != vslot.colorscale || cur.alphascale != alpha) + { + cur.colorscale = vslot.colorscale; + cur.alphascale = alpha; + GLOBALPARAMF(colorparams, 2*alpha*vslot.colorscale.x, 2*alpha*vslot.colorscale.y, 2*alpha*vslot.colorscale.z, alpha); + setfogcolor(vec(curfogcolor).mul(alpha)); + } + } + else if(cur.colorscale != vslot.colorscale) + { + cur.colorscale = vslot.colorscale; + GLOBALPARAMF(colorparams, 2*vslot.colorscale.x, 2*vslot.colorscale.y, 2*vslot.colorscale.z, 1); + } + int tmu = 2, envmaptmu = -1; + if(slot.shader->type&SHADER_NORMALSLMS) tmu++; + if(slot.shader->type&SHADER_ENVMAP) envmaptmu = tmu++; + loopvj(slot.sts) + { + Slot::Tex &t = slot.sts[j]; + if(t.type==TEX_DIFFUSE || t.combined>=0) continue; + if(t.type==TEX_ENVMAP) + { + if(envmaptmu>=0 && t.t && cur.textures[envmaptmu]!=t.t->id) + { + glActiveTexture_(GL_TEXTURE0+envmaptmu); + glBindTexture(GL_TEXTURE_CUBE_MAP, cur.textures[envmaptmu] = t.t->id); + } + } + else + { + if(cur.textures[tmu]!=t.t->id) + { + glActiveTexture_(GL_TEXTURE0+tmu); + glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = t.t->id); + } + if(++tmu >= 8) break; + } + } + glActiveTexture_(GL_TEXTURE0); + + cur.slot = &slot; + cur.vslot = &vslot; } static void changeshader(renderstate &cur, Shader *s, Slot &slot, VSlot &vslot, bool shadowed) { - if(glaring) - { - static Shader *noglareshader = NULL, *noglareblendshader = NULL, *noglarealphashader = NULL; - Shader *fallback; - if(cur.blending) { if(!noglareblendshader) noglareblendshader = lookupshaderbyname("noglareblendworld"); fallback = noglareblendshader; } - else if(cur.alphaing) { if(!noglarealphashader) noglarealphashader = lookupshaderbyname("noglarealphaworld"); fallback = noglarealphashader; } - else { if(!noglareshader) noglareshader = lookupshaderbyname("noglareworld"); fallback = noglareshader; } - if(s->hasoption(4)) s->setvariant(cur.visibledynlights, 4, slot, vslot, fallback); - else s->setvariant(cur.blending ? 1 : 0, 4, slot, vslot, fallback); - } - else if(fading && !cur.blending && !cur.alphaing) - { - if(shadowed) s->setvariant(cur.visibledynlights, 3, slot, vslot); - else s->setvariant(cur.visibledynlights, 2, slot, vslot); - } - else if(shadowed) s->setvariant(cur.visibledynlights, 1, slot, vslot); - else if(!cur.visibledynlights) s->set(slot, vslot); - else s->setvariant(cur.visibledynlights-1, 0, slot, vslot); + if(glaring) + { + static Shader *noglareshader = NULL, *noglareblendshader = NULL, *noglarealphashader = NULL; + Shader *fallback; + if(cur.blending) { if(!noglareblendshader) noglareblendshader = lookupshaderbyname("noglareblendworld"); fallback = noglareblendshader; } + else if(cur.alphaing) { if(!noglarealphashader) noglarealphashader = lookupshaderbyname("noglarealphaworld"); fallback = noglarealphashader; } + else { if(!noglareshader) noglareshader = lookupshaderbyname("noglareworld"); fallback = noglareshader; } + if(s->hasoption(4)) s->setvariant(cur.visibledynlights, 4, slot, vslot, fallback); + else s->setvariant(cur.blending ? 1 : 0, 4, slot, vslot, fallback); + } + else if(fading && !cur.blending && !cur.alphaing) + { + if(shadowed) s->setvariant(cur.visibledynlights, 3, slot, vslot); + else s->setvariant(cur.visibledynlights, 2, slot, vslot); + } + else if(shadowed) s->setvariant(cur.visibledynlights, 1, slot, vslot); + else if(!cur.visibledynlights) s->set(slot, vslot); + else s->setvariant(cur.visibledynlights-1, 0, slot, vslot); } static void changetexgen(renderstate &cur, int dim, Slot &slot, VSlot &vslot) { - if(cur.texgenslot != &slot || cur.texgenvslot != &vslot) - { - Texture *curtex = !cur.texgenslot || cur.texgenslot->sts.empty() ? notexture : cur.texgenslot->sts[0].t, - *tex = slot.sts.empty() ? notexture : slot.sts[0].t; - if(!cur.texgenvslot || slot.sts.empty() || - (curtex->xs != tex->xs || curtex->ys != tex->ys || - cur.texgenvslot->rotation != vslot.rotation || cur.texgenvslot->scale != vslot.scale || - cur.texgenvslot->offset != vslot.offset || cur.texgenvslot->scroll != vslot.scroll)) - { - const texrotation &r = texrotations[vslot.rotation]; - float xs = r.flipx ? -tex->xs : tex->xs, - ys = r.flipy ? -tex->ys : tex->ys; - vec2 scroll(vslot.scroll); - if(r.swapxy) swap(scroll.x, scroll.y); - scroll.x *= lastmillis*tex->xs/xs; - scroll.y *= lastmillis*tex->ys/ys; - if(cur.texgenscroll != scroll) - { - cur.texgenscroll = scroll; - cur.texgendim = -1; - } - } - cur.texgenslot = &slot; - cur.texgenvslot = &vslot; - } - - if(cur.texgendim == dim) return; - GLOBALPARAM(texgenscroll, cur.texgenscroll); - cur.texgendim = dim; + if(cur.texgenslot != &slot || cur.texgenvslot != &vslot) + { + Texture *curtex = !cur.texgenslot || cur.texgenslot->sts.empty() ? notexture : cur.texgenslot->sts[0].t, + *tex = slot.sts.empty() ? notexture : slot.sts[0].t; + if(!cur.texgenvslot || slot.sts.empty() || + (curtex->xs != tex->xs || curtex->ys != tex->ys || + cur.texgenvslot->rotation != vslot.rotation || cur.texgenvslot->scale != vslot.scale || + cur.texgenvslot->offset != vslot.offset || cur.texgenvslot->scroll != vslot.scroll)) + { + const texrotation &r = texrotations[vslot.rotation]; + float xs = r.flipx ? -tex->xs : tex->xs, + ys = r.flipy ? -tex->ys : tex->ys; + vec2 scroll(vslot.scroll); + if(r.swapxy) swap(scroll.x, scroll.y); + scroll.x *= lastmillis*tex->xs/xs; + scroll.y *= lastmillis*tex->ys/ys; + if(cur.texgenscroll != scroll) + { + cur.texgenscroll = scroll; + cur.texgendim = -1; + } + } + cur.texgenslot = &slot; + cur.texgenvslot = &vslot; + } + + if(cur.texgendim == dim) return; + GLOBALPARAM(texgenscroll, cur.texgenscroll); + cur.texgendim = dim; } static void renderbatch(renderstate &cur, int pass, geombatch &b) { - geombatch *shadowed = NULL; - int rendered = -1; - for(geombatch *curbatch = &b;; curbatch = &geombatches[curbatch->batch]) - { - ushort len = curbatch->es.length[curbatch->va->shadowed ? 0 : 1]; - if(len) - { - if(rendered < 0) - { - changeshader(cur, b.vslot.slot->shader, *b.vslot.slot, b.vslot, false); - rendered = 0; - gbatches++; - } - ushort minvert = curbatch->es.minvert[0], maxvert = curbatch->es.maxvert[0]; - if(!curbatch->va->shadowed) { minvert = min(minvert, curbatch->es.minvert[1]); maxvert = max(maxvert, curbatch->es.maxvert[1]); } - drawtris(len, curbatch->edata, minvert, maxvert); - vtris += len/3; - } - if(curbatch->es.length[1] > len && !shadowed) shadowed = curbatch; - if(curbatch->batch < 0) break; - } - if(shadowed) for(geombatch *curbatch = shadowed;; curbatch = &geombatches[curbatch->batch]) - { - if(curbatch->va->shadowed && curbatch->es.length[1] > curbatch->es.length[0]) - { - if(rendered < 1) - { - changeshader(cur, b.vslot.slot->shader, *b.vslot.slot, b.vslot, true); - rendered = 1; - gbatches++; - } - ushort len = curbatch->es.length[1] - curbatch->es.length[0]; - drawtris(len, curbatch->edata + curbatch->es.length[0], curbatch->es.minvert[1], curbatch->es.maxvert[1]); - vtris += len/3; - } - if(curbatch->batch < 0) break; - } + geombatch *shadowed = NULL; + int rendered = -1; + for(geombatch *curbatch = &b;; curbatch = &geombatches[curbatch->batch]) + { + ushort len = curbatch->es.length[curbatch->va->shadowed ? 0 : 1]; + if(len) + { + if(rendered < 0) + { + changeshader(cur, b.vslot.slot->shader, *b.vslot.slot, b.vslot, false); + rendered = 0; + gbatches++; + } + ushort minvert = curbatch->es.minvert[0], maxvert = curbatch->es.maxvert[0]; + if(!curbatch->va->shadowed) { minvert = min(minvert, curbatch->es.minvert[1]); maxvert = max(maxvert, curbatch->es.maxvert[1]); } + drawtris(len, curbatch->edata, minvert, maxvert); + vtris += len/3; + } + if(curbatch->es.length[1] > len && !shadowed) shadowed = curbatch; + if(curbatch->batch < 0) break; + } + if(shadowed) for(geombatch *curbatch = shadowed;; curbatch = &geombatches[curbatch->batch]) + { + if(curbatch->va->shadowed && curbatch->es.length[1] > curbatch->es.length[0]) + { + if(rendered < 1) + { + changeshader(cur, b.vslot.slot->shader, *b.vslot.slot, b.vslot, true); + rendered = 1; + gbatches++; + } + ushort len = curbatch->es.length[1] - curbatch->es.length[0]; + drawtris(len, curbatch->edata + curbatch->es.length[0], curbatch->es.minvert[1], curbatch->es.maxvert[1]); + vtris += len/3; + } + if(curbatch->batch < 0) break; + } } static void resetbatches() { - geombatches.setsize(0); - firstbatch = -1; - numbatches = 0; + geombatches.setsize(0); + firstbatch = -1; + numbatches = 0; } static void renderbatches(renderstate &cur, int pass) { - cur.slot = NULL; - cur.vslot = NULL; - int curbatch = firstbatch; - if(curbatch >= 0) - { - if(cur.alphaing) - { - if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); } - } - else if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } - if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, cur.alphaing ? GL_FALSE : GL_TRUE); } - if(!cur.vattribs) - { - if(cur.vquery) disablevquery(cur); - enablevattribs(cur); - } - } - while(curbatch >= 0) - { - geombatch &b = geombatches[curbatch]; - curbatch = b.next; - - if(cur.vbuf != b.va->vbuf) changevbuf(cur, pass, b.va); - if(cur.vslot != &b.vslot) - { - changeslottmus(cur, pass, *b.vslot.slot, b.vslot); - if(cur.texgendim != b.es.dim || (cur.texgendim <= 2 && cur.texgenvslot != &b.vslot)) changetexgen(cur, b.es.dim, *b.vslot.slot, b.vslot); - } - else if(cur.texgendim != b.es.dim) changetexgen(cur, b.es.dim, *b.vslot.slot, b.vslot); - if(pass == RENDERPASS_LIGHTMAP) changebatchtmus(cur, pass, b); - - renderbatch(cur, pass, b); - } - - resetbatches(); + cur.slot = NULL; + cur.vslot = NULL; + int curbatch = firstbatch; + if(curbatch >= 0) + { + if(cur.alphaing) + { + if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); } + } + else if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } + if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, cur.alphaing ? GL_FALSE : GL_TRUE); } + if(!cur.vattribs) + { + if(cur.vquery) disablevquery(cur); + enablevattribs(cur); + } + } + while(curbatch >= 0) + { + geombatch &b = geombatches[curbatch]; + curbatch = b.next; + + if(cur.vbuf != b.va->vbuf) changevbuf(cur, pass, b.va); + if(cur.vslot != &b.vslot) + { + changeslottmus(cur, pass, *b.vslot.slot, b.vslot); + if(cur.texgendim != b.es.dim || (cur.texgendim <= 2 && cur.texgenvslot != &b.vslot)) changetexgen(cur, b.es.dim, *b.vslot.slot, b.vslot); + } + else if(cur.texgendim != b.es.dim) changetexgen(cur, b.es.dim, *b.vslot.slot, b.vslot); + if(pass == RENDERPASS_LIGHTMAP) changebatchtmus(cur, pass, b); + + renderbatch(cur, pass, b); + } + + resetbatches(); } void renderzpass(renderstate &cur, vtxarray *va) { - if(!cur.vattribs) - { - if(cur.vquery) disablevquery(cur); - enablevattribs(cur, false); - } - if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_Z, va); - if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } - if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } - int firsttex = 0, numtris = va->tris; - ushort *edata = va->edata; - if(cur.alphaing) - { - firsttex += va->texs + va->blends; - edata += 3*(va->tris + va->blendtris); - numtris = va->alphatris; - xtravertsva += 3*numtris; - } - else xtravertsva += va->verts; - nocolorshader->set(); - drawvatris(va, 3*numtris, edata); + if(!cur.vattribs) + { + if(cur.vquery) disablevquery(cur); + enablevattribs(cur, false); + } + if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_Z, va); + if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } + if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } + int firsttex = 0, numtris = va->tris; + ushort *edata = va->edata; + if(cur.alphaing) + { + firsttex += va->texs + va->blends; + edata += 3*(va->tris + va->blendtris); + numtris = va->alphatris; + xtravertsva += 3*numtris; + } + else xtravertsva += va->verts; + nocolorshader->set(); + drawvatris(va, 3*numtris, edata); } vector<vtxarray *> foggedvas; #define startvaquery(va, flush) \ - do { \ - if(va->query) \ - { \ - flush; \ - startquery(va->query); \ - } \ - } while(0) + do { \ + if(va->query) \ + { \ + flush; \ + startquery(va->query); \ + } \ + } while(0) #define endvaquery(va, flush) \ - do { \ - if(va->query) \ - { \ - flush; \ - endquery(va->query); \ - } \ - } while(0) + do { \ + if(va->query) \ + { \ + flush; \ + endquery(va->query); \ + } \ + } while(0) void renderfoggedvas(renderstate &cur, bool doquery = false) { - static Shader *fogshader = NULL; - if(!fogshader) fogshader = lookupshaderbyname("fogworld"); - if(fading) fogshader->setvariant(0, 2); - else fogshader->set(); + static Shader *fogshader = NULL; + if(!fogshader) fogshader = lookupshaderbyname("fogworld"); + if(fading) fogshader->setvariant(0, 2); + else fogshader->set(); - if(!cur.vattribs) enablevattribs(cur, false); + if(!cur.vattribs) enablevattribs(cur, false); - loopv(foggedvas) - { - vtxarray *va = foggedvas[i]; - if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_FOG, va); + loopv(foggedvas) + { + vtxarray *va = foggedvas[i]; + if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_FOG, va); - if(doquery) startvaquery(va, ); - drawvatris(va, 3*va->tris, va->edata); - vtris += va->tris; - if(doquery) endvaquery(va, ); - } + if(doquery) startvaquery(va, ); + drawvatris(va, 3*va->tris, va->edata); + vtris += va->tris; + if(doquery) endvaquery(va, ); + } - foggedvas.setsize(0); + foggedvas.setsize(0); } VAR(batchgeom, 0, 1, 1); void renderva(renderstate &cur, vtxarray *va, int pass = RENDERPASS_LIGHTMAP, bool fogpass = false, bool doquery = false) { - switch(pass) - { - case RENDERPASS_LIGHTMAP: - if(!cur.alphaing) vverts += va->verts; - va->shadowed = false; - va->dynlightmask = 0; - if(fogpass ? va->geommax.z<=reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) - { - if(!cur.alphaing && !cur.blending) foggedvas.add(va); - break; - } - if(!drawtex && !glaring && !cur.alphaing) - { - va->shadowed = isshadowmapreceiver(va); - calcdynlightmask(va); - } - if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); }); - mergetexs(cur, va); - if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); }); - else if(!batchgeom && geombatches.length()) renderbatches(cur, pass); - break; - - case RENDERPASS_LIGHTMAP_BLEND: - { - if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); }); - mergetexs(cur, va, &va->eslist[va->texs], va->blends, va->edata + 3*va->tris); - if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); }); - else if(!batchgeom && geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); - break; - } - - case RENDERPASS_FOG: - if(cur.vbuf!=va->vbuf) changevbuf(cur, pass, va); - drawvatris(va, 3*va->tris, va->edata); - xtravertsva += va->verts; - break; - - case RENDERPASS_CAUSTICS: - if(cur.vbuf!=va->vbuf) changevbuf(cur, pass, va); - drawvatris(va, 3*va->tris, va->edata); - xtravertsva += va->verts; - break; - - case RENDERPASS_Z: - if(doquery) startvaquery(va, ); - renderzpass(cur, va); - if(doquery) endvaquery(va, ); - break; - } + switch(pass) + { + case RENDERPASS_LIGHTMAP: + if(!cur.alphaing) vverts += va->verts; + va->shadowed = false; + va->dynlightmask = 0; + if(fogpass ? va->geommax.z<=reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) + { + if(!cur.alphaing && !cur.blending) foggedvas.add(va); + break; + } + if(!drawtex && !glaring && !cur.alphaing) + { + va->shadowed = isshadowmapreceiver(va); + calcdynlightmask(va); + } + if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); }); + mergetexs(cur, va); + if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); }); + else if(!batchgeom && geombatches.length()) renderbatches(cur, pass); + break; + + case RENDERPASS_LIGHTMAP_BLEND: + { + if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); }); + mergetexs(cur, va, &va->eslist[va->texs], va->blends, va->edata + 3*va->tris); + if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); }); + else if(!batchgeom && geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); + break; + } + + case RENDERPASS_FOG: + if(cur.vbuf!=va->vbuf) changevbuf(cur, pass, va); + drawvatris(va, 3*va->tris, va->edata); + xtravertsva += va->verts; + break; + + case RENDERPASS_CAUSTICS: + if(cur.vbuf!=va->vbuf) changevbuf(cur, pass, va); + drawvatris(va, 3*va->tris, va->edata); + xtravertsva += va->verts; + break; + + case RENDERPASS_Z: + if(doquery) startvaquery(va, ); + renderzpass(cur, va); + if(doquery) endvaquery(va, ); + break; + } } #define NUMCAUSTICS 32 @@ -1418,24 +1418,24 @@ static Texture *caustictex[NUMCAUSTICS] = { NULL }; void loadcaustics(bool force) { - static bool needcaustics = false; - if(force) needcaustics = true; - if(!caustics || !needcaustics) return; - useshaderbyname("caustic"); - if(caustictex[0]) return; - loopi(NUMCAUSTICS) - { - defformatstring(name, "<grey><noswizzle>packages/caustics/caust%.2d.png", i); - caustictex[i] = textureload(name); - } + static bool needcaustics = false; + if(force) needcaustics = true; + if(!caustics || !needcaustics) return; + useshaderbyname("caustic"); + if(caustictex[0]) return; + loopi(NUMCAUSTICS) + { + defformatstring(name, "<grey><noswizzle>packages/caustics/caust%.2d.png", i); + caustictex[i] = textureload(name); + } } void cleanupva() { - clearvas(worldroot); - clearqueries(); - cleanupbb(); - loopi(NUMCAUSTICS) caustictex[i] = NULL; + clearvas(worldroot); + clearqueries(); + cleanupbb(); + loopi(NUMCAUSTICS) caustictex[i] = NULL; } VARR(causticscale, 0, 50, 10000); @@ -1445,38 +1445,38 @@ VARFP(caustics, 0, 1, 1, loadcaustics()); void setupcaustics(float blend) { - if(!caustictex[0]) loadcaustics(true); + if(!caustictex[0]) loadcaustics(true); - vec s = vec(0.011f, 0, 0.0066f).mul(100.0f/causticscale), t = vec(0, 0.011f, 0.0066f).mul(100.0f/causticscale); - int tex = (lastmillis/causticmillis)%NUMCAUSTICS; - float frac = float(lastmillis%causticmillis)/causticmillis; - loopi(2) - { - glActiveTexture_(GL_TEXTURE0+i); - glBindTexture(GL_TEXTURE_2D, caustictex[(tex+i)%NUMCAUSTICS]->id); - } - glActiveTexture_(GL_TEXTURE0); - SETSHADER(caustic); - LOCALPARAM(texgenS, s); - LOCALPARAM(texgenT, t); - blend *= causticcontrast; - LOCALPARAMF(frameblend, blend*(1-frac), blend*frac, blend, 1 - blend); + vec s = vec(0.011f, 0, 0.0066f).mul(100.0f/causticscale), t = vec(0, 0.011f, 0.0066f).mul(100.0f/causticscale); + int tex = (lastmillis/causticmillis)%NUMCAUSTICS; + float frac = float(lastmillis%causticmillis)/causticmillis; + loopi(2) + { + glActiveTexture_(GL_TEXTURE0+i); + glBindTexture(GL_TEXTURE_2D, caustictex[(tex+i)%NUMCAUSTICS]->id); + } + glActiveTexture_(GL_TEXTURE0); + SETSHADER(caustic); + LOCALPARAM(texgenS, s); + LOCALPARAM(texgenT, t); + blend *= causticcontrast; + LOCALPARAMF(frameblend, blend*(1-frac), blend*frac, blend, 1 - blend); } void setupgeom(renderstate &cur) { - GLOBALPARAMF(colorparams, 2, 2, 2, 1); - GLOBALPARAM(camera, camera1->o); - GLOBALPARAMF(ambient, ambientcolor.x/255.0f, ambientcolor.y/255.0f, ambientcolor.z/255.0f); - GLOBALPARAMF(millis, lastmillis/1000.0f); + GLOBALPARAMF(colorparams, 2, 2, 2, 1); + GLOBALPARAM(camera, camera1->o); + GLOBALPARAMF(ambient, ambientcolor.x/255.0f, ambientcolor.y/255.0f, ambientcolor.z/255.0f); + GLOBALPARAMF(millis, lastmillis/1000.0f); - glActiveTexture_(GL_TEXTURE0); + glActiveTexture_(GL_TEXTURE0); } void cleanupgeom(renderstate &cur) { - if(cur.vattribs) disablevattribs(cur); - if(cur.vbuf) disablevbuf(cur); + if(cur.vattribs) disablevattribs(cur); + if(cur.vbuf) disablevbuf(cur); } #define FIRSTVA (reflecting ? reflectedva : visibleva) @@ -1484,398 +1484,398 @@ void cleanupgeom(renderstate &cur) static void rendergeommultipass(renderstate &cur, int pass, bool fogpass) { - if(cur.vbuf) disablevbuf(cur); - if(!cur.vattribs) enablevattribs(cur, false); - cur.texgendim = -1; - for(vtxarray *va = FIRSTVA; va; va = NEXTVA) - { - if(!va->texs) continue; - if(refracting) - { - if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_GEOM) continue; - if(ishiddencube(va->o, va->size)) continue; - } - else if(reflecting) - { - if(va->geommax.z <= reflectz) continue; - } - else if(va->occluded >= OCCLUDE_GEOM) continue; - if(fogpass ? va->geommax.z <= reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) continue; - renderva(cur, va, pass, fogpass); - } - if(geombatches.length()) renderbatches(cur, pass); + if(cur.vbuf) disablevbuf(cur); + if(!cur.vattribs) enablevattribs(cur, false); + cur.texgendim = -1; + for(vtxarray *va = FIRSTVA; va; va = NEXTVA) + { + if(!va->texs) continue; + if(refracting) + { + if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_GEOM) continue; + if(ishiddencube(va->o, va->size)) continue; + } + else if(reflecting) + { + if(va->geommax.z <= reflectz) continue; + } + else if(va->occluded >= OCCLUDE_GEOM) continue; + if(fogpass ? va->geommax.z <= reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) continue; + renderva(cur, va, pass, fogpass); + } + if(geombatches.length()) renderbatches(cur, pass); } VAR(oqgeom, 0, 1, 1); void rendergeom(float causticspass, bool fogpass) { - if(causticspass && (!causticscale || !causticmillis)) causticspass = 0; - - bool mainpass = !reflecting && !refracting && !drawtex && !glaring, - doOQ = oqfrags && oqgeom && mainpass, - doZP = doOQ && zpass, - doSM = shadowmap && !drawtex && !glaring; - renderstate cur; - if(mainpass) - { - flipqueries(); - vtris = vverts = 0; - } - if(!doZP) - { - if(shadowmap && mainpass) rendershadowmap(); - setupgeom(cur); - if(doSM) pushshadowmap(); - } - - finddynlights(); - - resetbatches(); - - int blends = 0; - for(vtxarray *va = FIRSTVA; va; va = NEXTVA) - { - if(!va->texs) continue; - if(refracting) - { - if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_GEOM) continue; - if(ishiddencube(va->o, va->size)) continue; - } - else if(reflecting) - { - if(va->geommax.z <= reflectz) continue; - } - else if(doOQ && (zpass || va->distance > oqdist) && !insideva(va, camera1->o)) - { - if(va->parent && va->parent->occluded >= OCCLUDE_BB) - { - va->query = NULL; - va->occluded = OCCLUDE_PARENT; - continue; - } - va->occluded = va->query && va->query->owner == va && checkquery(va->query) ? min(va->occluded+1, int(OCCLUDE_BB)) : OCCLUDE_NOTHING; - va->query = newquery(va); - if((!va->query && zpass) || !va->occluded) - va->occluded = OCCLUDE_NOTHING; - if(va->occluded >= OCCLUDE_GEOM) - { - if(va->query) - { - if(!zpass && geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); - if(cur.vattribs) disablevattribs(cur, !doZP); - if(cur.vbuf) disablevbuf(cur); - renderquery(cur, va->query, va); - } - continue; - } - } - else - { - va->query = NULL; - va->occluded = OCCLUDE_NOTHING; - } - - if(!doZP) blends += va->blends; - renderva(cur, va, doZP ? RENDERPASS_Z : RENDERPASS_LIGHTMAP, fogpass, doOQ); - } - - if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); - - if(cur.vquery) disablevquery(cur); - if(cur.vattribs) disablevattribs(cur, !doZP); - if(cur.vbuf) disablevbuf(cur); - - if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } - if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } - - bool multipassing = false; - - if(doZP) - { + if(causticspass && (!causticscale || !causticmillis)) causticspass = 0; + + bool mainpass = !reflecting && !refracting && !drawtex && !glaring, + doOQ = oqfrags && oqgeom && mainpass, + doZP = doOQ && zpass, + doSM = shadowmap && !drawtex && !glaring; + renderstate cur; + if(mainpass) + { + flipqueries(); + vtris = vverts = 0; + } + if(!doZP) + { + if(shadowmap && mainpass) rendershadowmap(); + setupgeom(cur); + if(doSM) pushshadowmap(); + } + + finddynlights(); + + resetbatches(); + + int blends = 0; + for(vtxarray *va = FIRSTVA; va; va = NEXTVA) + { + if(!va->texs) continue; + if(refracting) + { + if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_GEOM) continue; + if(ishiddencube(va->o, va->size)) continue; + } + else if(reflecting) + { + if(va->geommax.z <= reflectz) continue; + } + else if(doOQ && (zpass || va->distance > oqdist) && !insideva(va, camera1->o)) + { + if(va->parent && va->parent->occluded >= OCCLUDE_BB) + { + va->query = NULL; + va->occluded = OCCLUDE_PARENT; + continue; + } + va->occluded = va->query && va->query->owner == va && checkquery(va->query) ? min(va->occluded+1, int(OCCLUDE_BB)) : OCCLUDE_NOTHING; + va->query = newquery(va); + if((!va->query && zpass) || !va->occluded) + va->occluded = OCCLUDE_NOTHING; + if(va->occluded >= OCCLUDE_GEOM) + { + if(va->query) + { + if(!zpass && geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); + if(cur.vattribs) disablevattribs(cur, !doZP); + if(cur.vbuf) disablevbuf(cur); + renderquery(cur, va->query, va); + } + continue; + } + } + else + { + va->query = NULL; + va->occluded = OCCLUDE_NOTHING; + } + + if(!doZP) blends += va->blends; + renderva(cur, va, doZP ? RENDERPASS_Z : RENDERPASS_LIGHTMAP, fogpass, doOQ); + } + + if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); + + if(cur.vquery) disablevquery(cur); + if(cur.vattribs) disablevattribs(cur, !doZP); + if(cur.vbuf) disablevbuf(cur); + + if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } + if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } + + bool multipassing = false; + + if(doZP) + { glFlush(); - if(shadowmap && mainpass) rendershadowmap(); - setupgeom(cur); - if(doSM) pushshadowmap(); - - if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); } - cur.texgendim = -1; - - for(vtxarray *va = visibleva; va; va = va->next) - { - if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue; - blends += va->blends; - renderva(cur, va, RENDERPASS_LIGHTMAP, fogpass); - } - if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); - for(vtxarray *va = visibleva; va; va = va->next) - { - if(!va->texs || va->occluded < OCCLUDE_GEOM) continue; - else if((va->parent && va->parent->occluded >= OCCLUDE_BB) || - (va->query && checkquery(va->query))) - { - va->occluded = OCCLUDE_BB; - continue; - } - - blends += va->blends; - renderva(cur, va, RENDERPASS_LIGHTMAP, fogpass); - } - if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); - } - - if(blends) - { - if(cur.vbuf) disablevbuf(cur); - - if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); } - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - - cur.texgendim = -1; - cur.blending = true; - for(vtxarray *va = FIRSTVA; va; va = NEXTVA) - { - if(!va->blends) continue; - if(refracting) - { - if(refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) continue; - if(ishiddencube(va->o, va->size)) continue; - if(va->occluded >= OCCLUDE_GEOM) continue; - } - else if(reflecting) - { - if(va->geommax.z <= reflectz) continue; - } - else if(va->occluded >= OCCLUDE_GEOM) continue; - if(fogpass ? va->geommax.z <= reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) continue; - renderva(cur, va, RENDERPASS_LIGHTMAP_BLEND, fogpass); - } - if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); - cur.blending = false; - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - } - - if(doSM) popshadowmap(); - - if(cur.vattribs) disablevattribs(cur); - - if(foggedvas.length()) renderfoggedvas(cur, doOQ && !zpass); - - if(causticspass) - { - if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); } - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - - setupcaustics(causticspass); - glBlendFunc(GL_ZERO, GL_SRC_COLOR); - if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - rendergeommultipass(cur, RENDERPASS_CAUSTICS, fogpass); - if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - } - - if(multipassing) glDepthFunc(GL_LESS); - - cleanupgeom(cur); + if(shadowmap && mainpass) rendershadowmap(); + setupgeom(cur); + if(doSM) pushshadowmap(); + + if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); } + cur.texgendim = -1; + + for(vtxarray *va = visibleva; va; va = va->next) + { + if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue; + blends += va->blends; + renderva(cur, va, RENDERPASS_LIGHTMAP, fogpass); + } + if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); + for(vtxarray *va = visibleva; va; va = va->next) + { + if(!va->texs || va->occluded < OCCLUDE_GEOM) continue; + else if((va->parent && va->parent->occluded >= OCCLUDE_BB) || + (va->query && checkquery(va->query))) + { + va->occluded = OCCLUDE_BB; + continue; + } + + blends += va->blends; + renderva(cur, va, RENDERPASS_LIGHTMAP, fogpass); + } + if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); + } + + if(blends) + { + if(cur.vbuf) disablevbuf(cur); + + if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); } + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + + cur.texgendim = -1; + cur.blending = true; + for(vtxarray *va = FIRSTVA; va; va = NEXTVA) + { + if(!va->blends) continue; + if(refracting) + { + if(refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) continue; + if(ishiddencube(va->o, va->size)) continue; + if(va->occluded >= OCCLUDE_GEOM) continue; + } + else if(reflecting) + { + if(va->geommax.z <= reflectz) continue; + } + else if(va->occluded >= OCCLUDE_GEOM) continue; + if(fogpass ? va->geommax.z <= reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) continue; + renderva(cur, va, RENDERPASS_LIGHTMAP_BLEND, fogpass); + } + if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); + cur.blending = false; + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + } + + if(doSM) popshadowmap(); + + if(cur.vattribs) disablevattribs(cur); + + if(foggedvas.length()) renderfoggedvas(cur, doOQ && !zpass); + + if(causticspass) + { + if(!multipassing) { multipassing = true; glDepthFunc(GL_LEQUAL); } + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + + setupcaustics(causticspass); + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + rendergeommultipass(cur, RENDERPASS_CAUSTICS, fogpass); + if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + } + + if(multipassing) glDepthFunc(GL_LESS); + + cleanupgeom(cur); } void renderalphageom(bool fogpass) { - static vector<vtxarray *> alphavas; - alphavas.setsize(0); - bool hasback = false; - for(vtxarray *va = FIRSTVA; va; va = NEXTVA) - { - if(!va->alphatris) continue; - if(refracting) - { - if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_BB) continue; - if(ishiddencube(va->o, va->size)) continue; - } - else if(reflecting) - { - if(va->geommax.z <= reflectz) continue; - } - else - { - if(va->occluded >= OCCLUDE_BB) continue; - } - if(fogpass ? va->geommax.z <= reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) continue; - alphavas.add(va); - if(va->alphabacktris) hasback = true; - } - if(alphavas.empty()) return; - - resetbatches(); - - renderstate cur; - cur.alphaing = 1; - - loop(front, 2) if(front || hasback) - { - cur.alphaing = front+1; - if(!front) glCullFace(GL_FRONT); - cur.vbuf = 0; - cur.texgendim = -1; - loopv(alphavas) renderva(cur, alphavas[i], RENDERPASS_Z); - if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); } - cur.colormask = true; - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - - if(cur.vattribs) disablevattribs(cur, false); - if(cur.vbuf) disablevbuf(cur); - - setupgeom(cur); - - glDepthFunc(GL_LEQUAL); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - cur.vbuf = 0; - cur.texgendim = -1; - cur.colorscale = vec(1, 1, 1); - cur.alphascale = -1; - loopv(alphavas) if(front || alphavas[i]->alphabacktris) renderva(cur, alphavas[i], RENDERPASS_LIGHTMAP, fogpass); - if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); - - cleanupgeom(cur); - - resetfogcolor(); - if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } - glDisable(GL_BLEND); - glDepthFunc(GL_LESS); - if(!front) glCullFace(GL_BACK); - } - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, fading ? GL_FALSE : GL_TRUE); + static vector<vtxarray *> alphavas; + alphavas.setsize(0); + bool hasback = false; + for(vtxarray *va = FIRSTVA; va; va = NEXTVA) + { + if(!va->alphatris) continue; + if(refracting) + { + if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_BB) continue; + if(ishiddencube(va->o, va->size)) continue; + } + else if(reflecting) + { + if(va->geommax.z <= reflectz) continue; + } + else + { + if(va->occluded >= OCCLUDE_BB) continue; + } + if(fogpass ? va->geommax.z <= reflectz-refractfog || !refractfog : va->curvfc==VFC_FOGGED) continue; + alphavas.add(va); + if(va->alphabacktris) hasback = true; + } + if(alphavas.empty()) return; + + resetbatches(); + + renderstate cur; + cur.alphaing = 1; + + loop(front, 2) if(front || hasback) + { + cur.alphaing = front+1; + if(!front) glCullFace(GL_FRONT); + cur.vbuf = 0; + cur.texgendim = -1; + loopv(alphavas) renderva(cur, alphavas[i], RENDERPASS_Z); + if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); } + cur.colormask = true; + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + + if(cur.vattribs) disablevattribs(cur, false); + if(cur.vbuf) disablevbuf(cur); + + setupgeom(cur); + + glDepthFunc(GL_LEQUAL); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + cur.vbuf = 0; + cur.texgendim = -1; + cur.colorscale = vec(1, 1, 1); + cur.alphascale = -1; + loopv(alphavas) if(front || alphavas[i]->alphabacktris) renderva(cur, alphavas[i], RENDERPASS_LIGHTMAP, fogpass); + if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); + + cleanupgeom(cur); + + resetfogcolor(); + if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); } + glDisable(GL_BLEND); + glDepthFunc(GL_LESS); + if(!front) glCullFace(GL_BACK); + } + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, fading ? GL_FALSE : GL_TRUE); } void findreflectedvas(vector<vtxarray *> &vas, int prevvfc = VFC_PART_VISIBLE) { - loopv(vas) - { - vtxarray *va = vas[i]; - if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc; - if(va->curvfc == VFC_FOGGED || va->curvfc == PVS_FOGGED || va->o.z+va->size <= reflectz || isfoggedcube(va->o, va->size)) continue; - bool render = true; - if(va->curvfc == VFC_FULL_VISIBLE) - { - if(va->occluded >= OCCLUDE_BB) continue; - if(va->occluded >= OCCLUDE_GEOM) render = false; - } - else if(va->curvfc == PVS_FULL_VISIBLE) continue; - if(render) - { - if(va->curvfc >= VFC_NOT_VISIBLE) va->distance = (int)vadist(va, camera1->o); - vtxarray **vprev = &reflectedva, *vcur = reflectedva; - while(vcur && va->distance > vcur->distance) - { - vprev = &vcur->rnext; - vcur = vcur->rnext; - } - va->rnext = *vprev; - *vprev = va; - } - if(va->children.length()) findreflectedvas(va->children, va->curvfc); - } + loopv(vas) + { + vtxarray *va = vas[i]; + if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc; + if(va->curvfc == VFC_FOGGED || va->curvfc == PVS_FOGGED || va->o.z+va->size <= reflectz || isfoggedcube(va->o, va->size)) continue; + bool render = true; + if(va->curvfc == VFC_FULL_VISIBLE) + { + if(va->occluded >= OCCLUDE_BB) continue; + if(va->occluded >= OCCLUDE_GEOM) render = false; + } + else if(va->curvfc == PVS_FULL_VISIBLE) continue; + if(render) + { + if(va->curvfc >= VFC_NOT_VISIBLE) va->distance = (int)vadist(va, camera1->o); + vtxarray **vprev = &reflectedva, *vcur = reflectedva; + while(vcur && va->distance > vcur->distance) + { + vprev = &vcur->rnext; + vcur = vcur->rnext; + } + va->rnext = *vprev; + *vprev = va; + } + if(va->children.length()) findreflectedvas(va->children, va->curvfc); + } } void renderreflectedgeom(bool causticspass, bool fogpass) { - if(reflecting) - { - reflectedva = NULL; - findreflectedvas(varoot); - rendergeom(causticspass ? 1 : 0, fogpass); - } - else rendergeom(causticspass ? 1 : 0, fogpass); + if(reflecting) + { + reflectedva = NULL; + findreflectedvas(varoot); + rendergeom(causticspass ? 1 : 0, fogpass); + } + else rendergeom(causticspass ? 1 : 0, fogpass); } static vtxarray *prevskyva = NULL; void renderskyva(vtxarray *va, bool explicitonly = false) { - if(!prevskyva || va->vbuf != prevskyva->vbuf) - { - gle::bindvbo(va->vbuf); - gle::bindebo(va->skybuf); - const vertex *ptr = 0; - gle::vertexpointer(sizeof(vertex), ptr->pos.v); - if(!prevskyva) gle::enablevertex(); - } + if(!prevskyva || va->vbuf != prevskyva->vbuf) + { + gle::bindvbo(va->vbuf); + gle::bindebo(va->skybuf); + const vertex *ptr = 0; + gle::vertexpointer(sizeof(vertex), ptr->pos.v); + if(!prevskyva) gle::enablevertex(); + } - drawvatris(va, explicitonly ? va->explicitsky : va->sky+va->explicitsky, explicitonly ? va->skydata+va->sky : va->skydata); + drawvatris(va, explicitonly ? va->explicitsky : va->sky+va->explicitsky, explicitonly ? va->skydata+va->sky : va->skydata); - if(!explicitonly) xtraverts += va->sky/3; - xtraverts += va->explicitsky/3; + if(!explicitonly) xtraverts += va->sky/3; + xtraverts += va->explicitsky/3; - prevskyva = va; + prevskyva = va; } int renderedsky = 0, renderedexplicitsky = 0, renderedskyfaces = 0, renderedskyclip = INT_MAX; static inline void updateskystats(vtxarray *va) { - renderedsky += va->sky; - renderedexplicitsky += va->explicitsky; - renderedskyfaces |= va->skyfaces&0x3F; - if(!(va->skyfaces&0x1F) || camera1->o.z < va->skyclip) renderedskyclip = min(renderedskyclip, va->skyclip); - else renderedskyclip = 0; + renderedsky += va->sky; + renderedexplicitsky += va->explicitsky; + renderedskyfaces |= va->skyfaces&0x3F; + if(!(va->skyfaces&0x1F) || camera1->o.z < va->skyclip) renderedskyclip = min(renderedskyclip, va->skyclip); + else renderedskyclip = 0; } void renderreflectedskyvas(vector<vtxarray *> &vas, int prevvfc = VFC_PART_VISIBLE) { - loopv(vas) - { - vtxarray *va = vas[i]; - if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc; - if((va->curvfc == VFC_FULL_VISIBLE && va->occluded >= OCCLUDE_BB) || va->curvfc==PVS_FULL_VISIBLE) continue; - if(va->o.z+va->size <= reflectz || ishiddencube(va->o, va->size)) continue; - if(va->sky+va->explicitsky) - { - updateskystats(va); - renderskyva(va); - } - if(va->children.length()) renderreflectedskyvas(va->children, va->curvfc); - } + loopv(vas) + { + vtxarray *va = vas[i]; + if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc; + if((va->curvfc == VFC_FULL_VISIBLE && va->occluded >= OCCLUDE_BB) || va->curvfc==PVS_FULL_VISIBLE) continue; + if(va->o.z+va->size <= reflectz || ishiddencube(va->o, va->size)) continue; + if(va->sky+va->explicitsky) + { + updateskystats(va); + renderskyva(va); + } + if(va->children.length()) renderreflectedskyvas(va->children, va->curvfc); + } } bool rendersky(bool explicitonly) { - prevskyva = NULL; - renderedsky = renderedexplicitsky = renderedskyfaces = 0; - renderedskyclip = INT_MAX; - - if(reflecting) - { - renderreflectedskyvas(varoot); - } - else for(vtxarray *va = visibleva; va; va = va->next) - { - if((va->occluded >= OCCLUDE_BB && va->skyfaces&0x80) || !(va->sky+va->explicitsky)) continue; - - // count possibly visible sky even if not actually rendered - updateskystats(va); - if(explicitonly && !va->explicitsky) continue; - renderskyva(va, explicitonly); - } - - if(prevskyva) - { - gle::disablevertex(); - gle::clearvbo(); - gle::clearebo(); - } - - return renderedsky+renderedexplicitsky > 0; + prevskyva = NULL; + renderedsky = renderedexplicitsky = renderedskyfaces = 0; + renderedskyclip = INT_MAX; + + if(reflecting) + { + renderreflectedskyvas(varoot); + } + else for(vtxarray *va = visibleva; va; va = va->next) + { + if((va->occluded >= OCCLUDE_BB && va->skyfaces&0x80) || !(va->sky+va->explicitsky)) continue; + + // count possibly visible sky even if not actually rendered + updateskystats(va); + if(explicitonly && !va->explicitsky) continue; + renderskyva(va, explicitonly); + } + + if(prevskyva) + { + gle::disablevertex(); + gle::clearvbo(); + gle::clearebo(); + } + + return renderedsky+renderedexplicitsky > 0; } |
