Initial Comit: First commit.
[SauerEngine.git] / src / engine / renderva.cpp
blob29dfaedff3c18a493bb098b11fb3eadeb443dd9b
1 // renderva.cpp: handles the occlusion and rendering of vertex arrays
3 #include "pch.h"
4 #include "engine.h"
6 static inline void drawtris(GLsizei numindices, const GLvoid *indices, ushort minvert, ushort maxvert)
8 if(hasDRE) glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, numindices, GL_UNSIGNED_SHORT, indices);
9 else glDrawElements(GL_TRIANGLES, numindices, GL_UNSIGNED_SHORT, indices);
10 glde++;
13 static inline void drawvatris(vtxarray *va, GLsizei numindices, const GLvoid *indices)
15 drawtris(numindices, indices, va->minvert, va->maxvert);
18 ///////// view frustrum culling ///////////////////////
20 plane vfcP[5]; // perpindictular vectors to view frustrum bounding planes
21 float vfcDfog; // far plane culling distance (fog limit).
22 float vfcDnear[5], vfcDfar[5];
23 float vfcfov, vfcfovy;
25 vtxarray *visibleva;
27 int isvisiblesphere(float rad, const vec &cv)
29 int v = VFC_FULL_VISIBLE;
30 float dist;
32 loopi(5)
34 dist = vfcP[i].dist(cv);
35 if(dist < -rad) return VFC_NOT_VISIBLE;
36 if(dist < rad) v = VFC_PART_VISIBLE;
39 dist -= vfcDfog;
40 if(dist > rad) return VFC_FOGGED; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM
41 if(dist > -rad) v = VFC_PART_VISIBLE;
43 return v;
46 int isvisiblecube(const ivec &o, int size)
48 int v = VFC_FULL_VISIBLE;
49 float dist;
51 loopi(5)
53 dist = o.dist(vfcP[i]);
54 if(dist < -vfcDfar[i]*size) return VFC_NOT_VISIBLE;
55 if(dist < -vfcDnear[i]*size) v = VFC_PART_VISIBLE;
58 dist -= vfcDfog;
59 if(dist > -vfcDnear[4]*size) return VFC_FOGGED;
60 if(dist > -vfcDfar[4]*size) v = VFC_PART_VISIBLE;
62 return v;
65 float vadist(vtxarray *va, const vec &p)
67 return p.dist_to_bb(va->bbmin, va->bbmax);
70 #define VASORTSIZE 64
72 static vtxarray *vasort[VASORTSIZE];
74 void addvisibleva(vtxarray *va)
76 float dist = vadist(va, camera1->o);
77 va->distance = int(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
79 int hash = min(int(dist*VASORTSIZE/hdr.worldsize), VASORTSIZE-1);
80 vtxarray **prev = &vasort[hash], *cur = vasort[hash];
82 while(cur && va->distance >= cur->distance)
84 prev = &cur->next;
85 cur = cur->next;
88 va->next = *prev;
89 *prev = va;
92 void sortvisiblevas()
94 visibleva = NULL;
95 vtxarray **last = &visibleva;
96 loopi(VASORTSIZE) if(vasort[i])
98 vtxarray *va = vasort[i];
99 *last = va;
100 while(va->next) va = va->next;
101 last = &va->next;
105 void findvisiblevas(vector<vtxarray *> &vas, bool resetocclude = false)
107 loopv(vas)
109 vtxarray &v = *vas[i];
110 int prevvfc = resetocclude ? VFC_NOT_VISIBLE : v.curvfc;
111 v.curvfc = isvisiblecube(v.o, v.size);
112 if(v.curvfc!=VFC_NOT_VISIBLE)
114 if(pvsoccluded(v.o, v.size))
116 v.curvfc += PVS_FULL_VISIBLE - VFC_FULL_VISIBLE;
117 continue;
119 addvisibleva(&v);
120 if(v.children.length()) findvisiblevas(v.children, prevvfc>=VFC_NOT_VISIBLE);
121 if(prevvfc>=VFC_NOT_VISIBLE)
123 v.occluded = !v.texs || pvsoccluded(v.geommin, v.geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
124 v.query = NULL;
130 void calcvfcD()
132 loopi(5)
134 plane &p = vfcP[i];
135 vfcDnear[i] = vfcDfar[i] = 0;
136 loopk(3) if(p[k] > 0) vfcDfar[i] += p[k];
137 else vfcDnear[i] += p[k];
141 void setvfcP(float yaw, float pitch, const vec &camera, float minyaw = -M_PI, float maxyaw = M_PI, float minpitch = -M_PI, float maxpitch = M_PI)
143 yaw *= RAD;
144 pitch *= RAD;
145 vfcP[0].toplane(vec(yaw + M_PI/2 - min(vfcfov, -minyaw), pitch), camera); // left plane
146 vfcP[1].toplane(vec(yaw - M_PI/2 + min(vfcfov, maxyaw), pitch), camera); // right plane
147 vfcP[2].toplane(vec(yaw, pitch + M_PI/2 - min(vfcfovy, -minpitch)), camera); // top plane
148 vfcP[3].toplane(vec(yaw, pitch - M_PI/2 + min(vfcfovy, maxpitch)), camera); // bottom plane
149 vfcP[4].toplane(vec(yaw, pitch), camera); // near/far planes
150 extern int fog;
151 vfcDfog = fog;
152 calcvfcD();
155 plane oldvfcP[5];
157 void reflectvfcP(float z, float minyaw, float maxyaw, float minpitch, float maxpitch)
159 memcpy(oldvfcP, vfcP, sizeof(vfcP));
161 if(z < 0) setvfcP(camera1->yaw, camera1->pitch, camera1->o, minyaw, maxyaw, minpitch, maxpitch);
162 else
164 vec o(camera1->o);
165 o.z = z-(camera1->o.z-z);
166 setvfcP(camera1->yaw, -camera1->pitch, o, minyaw, maxyaw, -maxpitch, -minpitch);
170 void restorevfcP()
172 memcpy(vfcP, oldvfcP, sizeof(vfcP));
173 calcvfcD();
176 extern vector<vtxarray *> varoot;
178 void visiblecubes(float fov, float fovy)
180 memset(vasort, 0, sizeof(vasort));
182 vfcfov = fov*0.5f*RAD;
183 vfcfovy = fovy*0.5f*RAD;
185 // Calculate view frustrum: Only changes if resize, but...
186 setvfcP(camera1->yaw, camera1->pitch, camera1->o);
188 findvisiblevas(varoot);
189 sortvisiblevas();
192 static inline bool insideva(const vtxarray *va, const vec &v, int margin = 1)
194 int size = va->size + margin;
195 return v.x>=va->o.x-margin && v.y>=va->o.y-margin && v.z>=va->o.z-margin &&
196 v.x<=va->o.x+size && v.y<=va->o.y+size && v.z<=va->o.z+size;
199 static ivec vaorigin;
201 static void resetorigin()
203 vaorigin = ivec(-1, -1, -1);
206 static bool setorigin(vtxarray *va, bool shadowmatrix = false)
208 ivec o = floatvtx ? ivec(0, 0, 0) : ivec(va->o).mask(~VVEC_INT_MASK).add(0x8000>>VVEC_FRAC);
209 if(o != vaorigin)
211 vaorigin = o;
212 glPopMatrix();
213 glPushMatrix();
214 glTranslatef(o.x, o.y, o.z);
215 static const float scale = 1.0f / (1<<VVEC_FRAC);
216 glScalef(scale, scale, scale);
218 if(shadowmatrix) adjustshadowmatrix(o, scale);
219 return true;
221 return false;
224 ///////// occlusion queries /////////////
226 #define MAXQUERY 2048
228 struct queryframe
230 int cur, max;
231 occludequery queries[MAXQUERY];
234 static queryframe queryframes[2] = {{0, 0}, {0, 0}};
235 static uint flipquery = 0;
237 int getnumqueries()
239 return queryframes[flipquery].cur;
242 void flipqueries()
244 flipquery = (flipquery + 1) % 2;
245 queryframe &qf = queryframes[flipquery];
246 loopi(qf.cur) qf.queries[i].owner = NULL;
247 qf.cur = 0;
250 occludequery *newquery(void *owner)
252 queryframe &qf = queryframes[flipquery];
253 if(qf.cur >= qf.max)
255 if(qf.max >= MAXQUERY) return NULL;
256 glGenQueries_(1, &qf.queries[qf.max++].id);
258 occludequery *query = &qf.queries[qf.cur++];
259 query->owner = owner;
260 query->fragments = -1;
261 return query;
264 void resetqueries()
266 loopi(2) loopj(queryframes[i].max) queryframes[i].queries[j].owner = NULL;
269 void clearqueries()
271 loopi(2)
273 queryframe &qf = queryframes[i];
274 loopj(qf.max)
276 glDeleteQueries_(1, &qf.queries[j].id);
277 qf.queries[j].owner = NULL;
279 qf.cur = qf.max = 0;
283 VAR(oqfrags, 0, 8, 64);
284 VAR(oqreflect, 0, 4, 64);
286 bool checkquery(occludequery *query, bool nowait)
288 GLuint fragments;
289 if(query->fragments >= 0) fragments = query->fragments;
290 else
292 if(nowait)
294 GLint avail;
295 glGetQueryObjectiv_(query->id, GL_QUERY_RESULT_AVAILABLE, &avail);
296 if(!avail) return false;
298 glGetQueryObjectuiv_(query->id, GL_QUERY_RESULT_ARB, &fragments);
299 query->fragments = fragments;
301 return fragments < (uint)(reflecting || refracting ? oqreflect : oqfrags);
304 void drawbb(const ivec &bo, const ivec &br, const vec &camera, int scale, const ivec &origin)
306 glBegin(GL_QUADS);
308 loopi(6)
310 int dim = dimension(i), coord = dimcoord(i);
312 if(coord)
314 if(camera[dim] < bo[dim] + br[dim]) continue;
316 else if(camera[dim] > bo[dim]) continue;
318 loopj(4)
320 const ivec &cc = cubecoords[fv[i][j]];
321 glVertex3f(((cc.x ? bo.x+br.x : bo.x) - origin.x) << scale,
322 ((cc.y ? bo.y+br.y : bo.y) - origin.y) << scale,
323 ((cc.z ? bo.z+br.z : bo.z) - origin.z) << scale);
326 xtraverts += 4;
329 glEnd();
332 extern int octaentsize;
334 static octaentities *visiblemms, **lastvisiblemms;
336 void findvisiblemms(const vector<extentity *> &ents)
338 for(vtxarray *va = visibleva; va; va = va->next)
340 if(!va->mapmodels || va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue;
341 loopv(*va->mapmodels)
343 octaentities *oe = (*va->mapmodels)[i];
344 if(isvisiblecube(oe->o, oe->size) >= VFC_FOGGED || pvsoccluded(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin))) continue;
346 bool occluded = oe->query && oe->query->owner == oe && checkquery(oe->query);
347 if(occluded)
349 oe->distance = -1;
351 oe->next = NULL;
352 *lastvisiblemms = oe;
353 lastvisiblemms = &oe->next;
355 else
357 int visible = 0;
358 loopv(oe->mapmodels)
360 extentity &e = *ents[oe->mapmodels[i]];
361 if(e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
362 e.visible = true;
363 ++visible;
365 if(!visible) continue;
367 oe->distance = int(camera1->o.dist_to_bb(oe->o, oe->size));
369 octaentities **prev = &visiblemms, *cur = visiblemms;
370 while(cur && cur->distance >= 0 && oe->distance > cur->distance)
372 prev = &cur->next;
373 cur = cur->next;
376 if(*prev == NULL) lastvisiblemms = &oe->next;
377 oe->next = *prev;
378 *prev = oe;
384 VAR(oqmm, 0, 4, 8);
386 extern bool getentboundingbox(extentity &e, ivec &o, ivec &r);
388 void rendermapmodel(extentity &e)
390 int anim = ANIM_MAPMODEL|ANIM_LOOP, basetime = 0;
391 if(e.attr3) switch(e.triggerstate)
393 case TRIGGER_RESET: anim = ANIM_TRIGGER|ANIM_START; break;
394 case TRIGGERING: anim = ANIM_TRIGGER; basetime = e.lasttrigger; break;
395 case TRIGGERED: anim = ANIM_TRIGGER|ANIM_END; break;
396 case TRIGGER_RESETTING: anim = ANIM_TRIGGER|ANIM_REVERSE; basetime = e.lasttrigger; break;
398 mapmodelinfo &mmi = getmminfo(e.attr2);
399 if(&mmi) rendermodel(&e.light, mmi.name, anim, e.o, (float)((e.attr1+7)-(e.attr1+7)%15), 0, MDL_CULL_VFC | MDL_CULL_DIST | MDL_DYNLIGHT, NULL, NULL, basetime);
402 extern int reflectdist;
404 static vector<octaentities *> renderedmms;
406 vtxarray *reflectedva;
408 void renderreflectedmapmodels()
410 vector<octaentities *> reflectedmms;
411 vector<octaentities *> &mms = reflecting ? reflectedmms : renderedmms;
412 const vector<extentity *> &ents = et->getents();
414 if(reflecting)
416 for(vtxarray *va = reflectedva; va; va = va->rnext)
418 if(!va->mapmodels || va->distance > reflectdist) continue;
419 loopv(*va->mapmodels) reflectedmms.add((*va->mapmodels)[i]);
422 loopv(mms)
424 octaentities *oe = mms[i];
425 if(reflecting || refracting>0 ? oe->bbmax.z <= reflectz : oe->bbmin.z >= reflectz) continue;
426 if(isvisiblecube(oe->o, oe->size) >= VFC_FOGGED) continue;
427 loopv(oe->mapmodels)
429 extentity &e = *ents[oe->mapmodels[i]];
430 if(e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
431 e.visible = true;
434 if(mms.length())
436 startmodelbatches();
437 loopv(mms)
439 octaentities *oe = mms[i];
440 loopv(oe->mapmodels)
442 extentity &e = *ents[oe->mapmodels[i]];
443 if(!e.visible) continue;
444 rendermapmodel(e);
445 e.visible = false;
448 endmodelbatches();
452 void rendermapmodels()
454 const vector<extentity *> &ents = et->getents();
456 visiblemms = NULL;
457 lastvisiblemms = &visiblemms;
458 findvisiblemms(ents);
460 static int skipoq = 0;
461 bool doquery = hasOQ && oqfrags && oqmm;
463 renderedmms.setsizenodelete(0);
464 startmodelbatches();
465 for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance>=0)
467 loopv(oe->mapmodels)
469 extentity &e = *ents[oe->mapmodels[i]];
470 if(!e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
471 if(renderedmms.empty() || renderedmms.last()!=oe)
473 renderedmms.add(oe);
474 oe->query = doquery && oe->distance>0 && !(++skipoq%oqmm) ? newquery(oe) : NULL;
475 if(oe->query) startmodelquery(oe->query);
477 rendermapmodel(e);
478 e.visible = false;
480 if(renderedmms.length() && renderedmms.last()==oe && oe->query) endmodelquery();
482 endmodelbatches();
484 bool colormask = true;
485 for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance<0)
487 oe->query = doquery ? newquery(oe) : NULL;
488 if(!oe->query) continue;
489 if(colormask)
491 glDepthMask(GL_FALSE);
492 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
493 nocolorshader->set();
494 colormask = false;
496 startquery(oe->query);
497 drawbb(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin));
498 endquery(oe->query);
500 if(!colormask)
502 glDepthMask(GL_TRUE);
503 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, fading ? GL_FALSE : GL_TRUE);
507 static inline bool bbinsideva(const ivec &bo, const ivec &br, vtxarray *va)
509 return bo.x >= va->bbmin.x && bo.y >= va->bbmin.y && va->o.z >= va->bbmin.z &&
510 bo.x + br.x <= va->bbmax.x && bo.y + br.y <= va->bbmax.y && bo.z + br.z <= va->bbmax.z;
513 static inline bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size)
515 loopoctabox(o, size, bo, br)
517 ivec co(i, o.x, o.y, o.z, size);
518 if(c[i].ext && c[i].ext->va)
520 vtxarray *va = c[i].ext->va;
521 if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) continue;
523 if(c[i].children && bboccluded(bo, br, c[i].children, co, size>>1)) continue;
524 return false;
526 return true;
529 bool bboccluded(const ivec &bo, const ivec &br)
531 int diff = (bo.x^(bo.x+br.x)) | (bo.y^(bo.y+br.y)) | (bo.z^(bo.z+br.z));
532 if(diff&~((1<<worldscale)-1)) return false;
533 int scale = worldscale-1;
534 if(diff&(1<<scale)) return bboccluded(bo, br, worldroot, ivec(0, 0, 0), 1<<scale);
535 cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)];
536 if(c->ext && c->ext->va)
538 vtxarray *va = c->ext->va;
539 if(va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) return true;
541 scale--;
542 while(c->children && !(diff&(1<<scale)))
544 c = &c->children[octastep(bo.x, bo.y, bo.z, scale)];
545 if(c->ext && c->ext->va)
547 vtxarray *va = c->ext->va;
548 if(va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) return true;
550 scale--;
552 if(c->children) return bboccluded(bo, br, c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale);
553 return false;
556 VAR(outline, 0, 0, 0xFFFFFF);
557 VAR(dtoutline, 0, 1, 1);
559 void renderoutline()
561 notextureshader->set();
563 glDisable(GL_TEXTURE_2D);
564 glEnableClientState(GL_VERTEX_ARRAY);
566 glPushMatrix();
568 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
569 glColor3ub((outline>>16)&0xFF, (outline>>8)&0xFF, outline&0xFF);
571 enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
573 if(!dtoutline) glDisable(GL_DEPTH_TEST);
575 resetorigin();
576 vtxarray *prev = NULL;
577 for(vtxarray *va = visibleva; va; va = va->next)
579 if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue;
581 if(!prev || va->vbuf != prev->vbuf)
583 setorigin(va);
584 if(hasVBO)
586 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
587 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
589 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
592 drawvatris(va, 3*va->tris, va->edata);
593 xtravertsva += va->verts;
595 prev = va;
598 if(!dtoutline) glEnable(GL_DEPTH_TEST);
600 disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
602 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
604 glPopMatrix();
606 if(hasVBO)
608 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
609 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
611 glDisableClientState(GL_VERTEX_ARRAY);
612 glEnable(GL_TEXTURE_2D);
614 defaultshader->set();
617 void rendershadowmapreceivers()
619 if(!hasBE) return;
621 static Shader *shadowmapshader = NULL;
622 if(!shadowmapshader) shadowmapshader = lookupshaderbyname("shadowmapreceiver");
623 shadowmapshader->set();
625 glDisable(GL_TEXTURE_2D);
626 glEnableClientState(GL_VERTEX_ARRAY);
628 glCullFace(GL_BACK);
629 glDepthMask(GL_FALSE);
630 glDepthFunc(GL_GREATER);
632 extern int ati_minmax_bug;
633 if(!ati_minmax_bug) glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
635 glEnable(GL_BLEND);
636 glBlendEquation_(GL_MAX_EXT);
637 glBlendFunc(GL_ONE, GL_ONE);
639 glPushMatrix();
641 resetorigin();
642 vtxarray *prev = NULL;
643 for(vtxarray *va = visibleva; va; va = va->next)
645 if(!va->texs || va->curvfc >= VFC_FOGGED || !isshadowmapreceiver(va)) continue;
647 if(!prev || va->vbuf != prev->vbuf)
649 setorigin(va);
650 if(hasVBO)
652 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
653 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
655 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
658 drawvatris(va, 3*va->tris, va->edata);
659 xtravertsva += va->verts;
661 prev = va;
664 glPopMatrix();
666 glDisable(GL_BLEND);
667 glBlendEquation_(GL_FUNC_ADD_EXT);
669 glCullFace(GL_FRONT);
670 glDepthMask(GL_TRUE);
671 glDepthFunc(GL_LESS);
673 if(!ati_minmax_bug) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
675 if(hasVBO)
677 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
678 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
680 glDisableClientState(GL_VERTEX_ARRAY);
681 glEnable(GL_TEXTURE_2D);
684 void renderdepthobstacles(const vec &bbmin, const vec &bbmax, float scale, float *ranges, int numranges)
686 float scales[4] = { 0, 0, 0, 0 }, offsets[4] = { 0, 0, 0, 0 };
687 if(numranges < 0)
689 SETSHADER(depthfxsplitworld);
691 loopi(-numranges)
693 if(!i) scales[i] = 1.0f/scale;
694 else scales[i] = scales[i-1]*256;
697 else
699 SETSHADER(depthfxworld);
701 if(!numranges) loopi(4) scales[i] = 1.0f/scale;
702 else loopi(numranges)
704 scales[i] = 1.0f/scale;
705 offsets[i] = -ranges[i]/scale;
708 setlocalparamfv("depthscale", SHPARAM_VERTEX, 0, scales);
709 setlocalparamfv("depthoffsets", SHPARAM_VERTEX, 1, offsets);
711 glDisable(GL_TEXTURE_2D);
712 glEnableClientState(GL_VERTEX_ARRAY);
714 glPushMatrix();
716 resetorigin();
717 vtxarray *prev = NULL;
718 for(vtxarray *va = visibleva; va; va = va->next)
720 if(!va->texs || va->occluded >= OCCLUDE_GEOM ||
721 va->o.x > bbmax.x || va->o.y > bbmax.y || va->o.z > bbmax.z ||
722 va->o.x + va->size < bbmin.x || va->o.y + va->size < bbmin.y || va->o.z + va->size < bbmin.z)
723 continue;
725 if(!prev || va->vbuf != prev->vbuf)
727 setorigin(va);
728 if(hasVBO)
730 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
731 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
733 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
736 drawvatris(va, 3*va->tris, va->edata);
737 xtravertsva += va->verts;
739 prev = va;
742 glPopMatrix();
744 if(hasVBO)
746 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
747 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
749 glDisableClientState(GL_VERTEX_ARRAY);
750 glEnable(GL_TEXTURE_2D);
752 defaultshader->set();
755 // [rotation][dimension] = vec4
756 float orientation_tangent [6][3][4] =
758 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
759 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
760 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
761 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
762 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
763 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
765 float orientation_binormal[6][3][4] =
767 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
768 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
769 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
770 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
771 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
772 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
775 struct renderstate
777 bool colormask, depthmask, mtglow, skippedglow;
778 GLuint vbuf;
779 float fogplane;
780 int diffusetmu, lightmaptmu, glowtmu, fogtmu, causticstmu;
781 GLfloat color[4];
782 vec glowcolor;
783 GLuint textures[8];
784 Slot *slot;
785 float texgenSk, texgenSoff, texgenTk, texgenToff;
786 int texgendim;
787 bool mttexgen;
788 int visibledynlights;
789 uint dynlightmask;
791 renderstate() : colormask(true), depthmask(true), mtglow(false), skippedglow(false), vbuf(0), fogplane(-1), diffusetmu(0), lightmaptmu(1), glowtmu(-1), fogtmu(-1), causticstmu(-1), glowcolor(1, 1, 1), slot(NULL), texgendim(-1), mttexgen(false), visibledynlights(0), dynlightmask(0)
793 loopk(4) color[k] = 1;
794 loopk(8) textures[k] = 0;
798 void renderquery(renderstate &cur, occludequery *query, vtxarray *va)
800 nocolorshader->set();
801 if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
802 if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); }
804 vec camera(camera1->o);
805 if(reflecting) camera.z = reflectz;
807 startquery(query);
809 drawbb(va->bbmin, ivec(va->bbmax).sub(va->bbmin), camera, vaorigin.x >= 0 ? VVEC_FRAC : 0, vaorigin.x >= 0 ? vaorigin : ivec(0, 0, 0));
811 endquery(query);
814 enum
816 RENDERPASS_LIGHTMAP = 0,
817 RENDERPASS_COLOR,
818 RENDERPASS_Z,
819 RENDERPASS_GLOW,
820 RENDERPASS_CAUSTICS,
821 RENDERPASS_FOG
824 struct geombatch
826 const elementset &es;
827 Slot &slot;
828 ushort *edata;
829 vtxarray *va;
830 int next, batch;
832 geombatch(const elementset &es, ushort *edata, vtxarray *va)
833 : es(es), slot(lookuptexture(es.texture)), edata(edata), va(va),
834 next(-1), batch(-1)
837 int compare(const geombatch &b) const
839 if(va->vbuf < b.va->vbuf) return -1;
840 if(va->vbuf > b.va->vbuf) return 1;
841 if(va->dynlightmask < b.va->dynlightmask) return -1;
842 if(va->dynlightmask > b.va->dynlightmask) return 1;
843 if(renderpath!=R_FIXEDFUNCTION)
845 if(slot.shader < b.slot.shader) return -1;
846 if(slot.shader > b.slot.shader) return 1;
847 if(slot.params.length() < b.slot.params.length()) return -1;
848 if(slot.params.length() > b.slot.params.length()) return 1;
850 if(es.texture < b.es.texture) return -1;
851 if(es.texture > b.es.texture) return 1;
852 if(es.lmid < b.es.lmid) return -1;
853 if(es.lmid > b.es.lmid) return 1;
854 if(es.envmap < b.es.envmap) return -1;
855 if(es.envmap > b.es.envmap) return 1;
856 return 0;
860 static vector<geombatch> geombatches;
861 static int firstbatch = -1, numbatches = 0;
863 static void mergetexs(vtxarray *va, elementset *texs = NULL, int numtexs = 0, ushort *edata = NULL)
865 if(!texs)
867 texs = va->eslist;
868 numtexs = va->texs;
869 edata = va->edata;
872 if(firstbatch < 0)
874 firstbatch = geombatches.length();
875 numbatches = numtexs;
876 loopi(numtexs-1)
878 geombatches.add(geombatch(texs[i], edata, va)).next = i+1;
879 edata += texs[i].length[5];
881 geombatches.add(geombatch(texs[numtexs-1], edata, va));
882 return;
885 int prevbatch = -1, curbatch = firstbatch, curtex = 0;
888 geombatch &b = geombatches.add(geombatch(texs[curtex], edata, va));
889 edata += texs[curtex].length[5];
890 int dir = -1;
891 while(curbatch >= 0)
893 dir = b.compare(geombatches[curbatch]);
894 if(dir <= 0) break;
895 prevbatch = curbatch;
896 curbatch = geombatches[curbatch].next;
898 if(!dir)
900 int last = curbatch, next;
901 for(;;)
903 next = geombatches[last].batch;
904 if(next < 0) break;
905 last = next;
907 if(last==curbatch)
909 b.batch = curbatch;
910 b.next = geombatches[curbatch].next;
911 if(prevbatch < 0) firstbatch = geombatches.length()-1;
912 else geombatches[prevbatch].next = geombatches.length()-1;
913 curbatch = geombatches.length()-1;
915 else
917 b.batch = next;
918 geombatches[last].batch = geombatches.length()-1;
921 else
923 numbatches++;
924 b.next = curbatch;
925 if(prevbatch < 0) firstbatch = geombatches.length()-1;
926 else geombatches[prevbatch].next = geombatches.length()-1;
927 prevbatch = geombatches.length()-1;
930 while(++curtex < numtexs);
933 static void mergeglowtexs(vtxarray *va)
935 int start = -1;
936 ushort *edata = va->edata, *startdata = NULL;
937 loopi(va->texs)
939 elementset &es = va->eslist[i];
940 Slot &slot = lookuptexture(es.texture, false);
941 if(slot.texmask&(1<<TEX_GLOW) && !slot.mtglowed)
943 if(start<0) { start = i; startdata = edata; }
945 else if(start>=0)
947 mergetexs(va, &va->eslist[start], i-start, startdata);
948 start = -1;
950 edata += es.length[5];
952 if(start>=0) mergetexs(va, &va->eslist[start], va->texs-start, startdata);
955 static void changefogplane(renderstate &cur, int pass, vtxarray *va)
957 if(renderpath!=R_FIXEDFUNCTION)
959 if(fading || fogging)
961 float fogplane = reflectz - vaorigin.z;
962 if(cur.fogplane!=fogplane)
964 cur.fogplane = fogplane;
965 if(fogging) setfogplane(1.0f/(1<<VVEC_FRAC), fogplane, false, -0.25f/(1<<VVEC_FRAC), 0.5f + 0.25f*fogplane);
966 else setfogplane(0, 0, false, 0.25f/(1<<VVEC_FRAC), 0.5f - 0.25f*fogplane);
970 else if(pass==RENDERPASS_FOG || (cur.fogtmu>=0 && (pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_GLOW)))
972 if(pass==RENDERPASS_LIGHTMAP) glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
973 else if(pass==RENDERPASS_GLOW) glActiveTexture_(GL_TEXTURE1_ARB);
974 GLfloat s[4] = { 0, 0, -1.0f/(waterfog<<VVEC_FRAC), (reflectz - vaorigin.z)/waterfog };
975 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
976 if(pass==RENDERPASS_LIGHTMAP) glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
977 else if(pass==RENDERPASS_GLOW) glActiveTexture_(GL_TEXTURE0_ARB);
981 static void changevbuf(renderstate &cur, int pass, vtxarray *va)
983 if(setorigin(va, pass==RENDERPASS_LIGHTMAP && !envmapping))
985 cur.visibledynlights = 0;
986 cur.dynlightmask = 0;
988 if(hasVBO)
990 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
991 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
993 cur.vbuf = va->vbuf;
995 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
997 if(pass==RENDERPASS_LIGHTMAP)
999 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1000 glTexCoordPointer(2, GL_SHORT, VTXSIZE, floatvtx ? &((fvertex *)va->vdata)[0].u : &va->vdata[0].u);
1001 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1003 if(renderpath!=R_FIXEDFUNCTION)
1005 glColorPointer(3, GL_UNSIGNED_BYTE, VTXSIZE, floatvtx ? &((fvertex *)va->vdata)[0].n : &va->vdata[0].n);
1006 setenvparamf("camera", SHPARAM_VERTEX, 4,
1007 (camera1->o.x - vaorigin.x)*(1<<VVEC_FRAC),
1008 (camera1->o.y - vaorigin.y)*(1<<VVEC_FRAC),
1009 (camera1->o.z - vaorigin.z)*(1<<VVEC_FRAC),
1015 static void changebatchtmus(renderstate &cur, int pass, geombatch &b)
1017 bool changed = false;
1018 extern bool brightengeom;
1019 int lmid = brightengeom ? LMID_BRIGHT : b.es.lmid;
1020 if(cur.textures[cur.lightmaptmu]!=lightmaptexs[lmid].id)
1022 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1023 glBindTexture(GL_TEXTURE_2D, cur.textures[cur.lightmaptmu] = lightmaptexs[lmid].id);
1024 changed = true;
1026 if(renderpath!=R_FIXEDFUNCTION)
1028 int tmu = cur.lightmaptmu+1;
1029 if(b.slot.shader->type&SHADER_NORMALSLMS)
1031 if(cur.textures[tmu]!=lightmaptexs[lmid+1].id)
1033 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1034 glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = lightmaptexs[lmid+1].id);
1035 changed = true;
1037 tmu++;
1039 if(b.slot.shader->type&SHADER_ENVMAP && b.es.envmap!=EMID_CUSTOM)
1041 GLuint emtex = lookupenvmap(b.es.envmap);
1042 if(cur.textures[tmu]!=emtex)
1044 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1045 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cur.textures[tmu] = emtex);
1046 changed = true;
1050 if(changed) glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1053 static void changeglow(renderstate &cur, int pass, Slot &slot)
1055 vec color = slot.glowcolor;
1056 if(slot.pulseglowspeed)
1058 float k = lastmillis*slot.pulseglowspeed;
1059 k -= floor(k);
1060 k = fabs(k*2 - 1);
1061 color.lerp(color, slot.pulseglowcolor, k);
1063 if(pass==RENDERPASS_GLOW)
1065 if(cur.glowcolor!=color) glColor3fv(color.v);
1067 else
1069 if(cur.glowcolor!=color)
1071 if(color==vec(1, 1, 1))
1073 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1074 setuptmu(cur.glowtmu, "P + T");
1076 else if(hasTE3 || hasTE4)
1078 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1079 if(cur.glowcolor==vec(1, 1, 1))
1081 if(hasTE3) setuptmu(cur.glowtmu, "TPK3");
1082 else if(hasTE4) setuptmu(cur.glowtmu, "TKP14");
1084 colortmu(cur.glowtmu, color.x, color.y, color.z);
1086 else
1088 slot.mtglowed = false;
1089 cur.skippedglow = true;
1090 return;
1093 else glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1094 if(!cur.mtglow) { glEnable(GL_TEXTURE_2D); cur.mtglow = true; }
1095 slot.mtglowed = true;
1097 loopvj(slot.sts)
1099 Slot::Tex &t = slot.sts[j];
1100 if(t.type==TEX_GLOW && t.combined<0)
1102 if(cur.textures[cur.glowtmu]!=t.t->id)
1103 glBindTexture(GL_TEXTURE_2D, cur.textures[cur.glowtmu] = t.t->id);
1104 break;
1107 cur.glowcolor = color;
1110 static void changeslottmus(renderstate &cur, int pass, Slot &slot)
1112 if(pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_COLOR)
1114 GLuint diffusetex = slot.sts.empty() ? notexture->id : slot.sts[0].t->id;
1115 if(cur.textures[cur.diffusetmu]!=diffusetex)
1116 glBindTexture(GL_TEXTURE_2D, cur.textures[cur.diffusetmu] = diffusetex);
1119 if(renderpath==R_FIXEDFUNCTION)
1121 if(slot.texmask&(1<<TEX_GLOW))
1123 if(pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_COLOR)
1125 if(cur.glowtmu<0) { slot.mtglowed = false; cur.skippedglow = true; }
1126 else changeglow(cur, pass, slot);
1128 else if(pass==RENDERPASS_GLOW && !slot.mtglowed) changeglow(cur, pass, slot);
1130 if(cur.mtglow)
1132 if(!(slot.texmask&(1<<TEX_GLOW)) || !slot.mtglowed)
1134 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1135 glDisable(GL_TEXTURE_2D);
1136 cur.mtglow = false;
1138 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1141 else
1143 int tmu = cur.lightmaptmu+1, envmaptmu = -1;
1144 if(slot.shader->type&SHADER_NORMALSLMS) tmu++;
1145 if(slot.shader->type&SHADER_ENVMAP) envmaptmu = tmu++;
1146 loopvj(slot.sts)
1148 Slot::Tex &t = slot.sts[j];
1149 if(t.type==TEX_DIFFUSE || t.combined>=0) continue;
1150 if(t.type==TEX_ENVMAP)
1152 if(envmaptmu>=0 && cur.textures[envmaptmu]!=t.t->id)
1154 glActiveTexture_(GL_TEXTURE0_ARB+envmaptmu);
1155 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cur.textures[envmaptmu] = t.t->id);
1157 continue;
1159 else if(cur.textures[tmu]!=t.t->id)
1161 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1162 glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = t.t->id);
1164 tmu++;
1166 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1169 Texture *curtex = !cur.slot || cur.slot->sts.empty() ? notexture : cur.slot->sts[0].t,
1170 *tex = slot.sts.empty() ? notexture : slot.sts[0].t;
1171 if(!cur.slot || slot.sts.empty() ||
1172 (curtex->xs != tex->xs || curtex->ys != tex->ys ||
1173 cur.slot->rotation != slot.rotation || cur.slot->scale != slot.scale ||
1174 cur.slot->xoffset != slot.xoffset || cur.slot->yoffset != slot.yoffset ||
1175 cur.slot->scrollS != slot.scrollS || cur.slot->scrollT != slot.scrollT))
1177 float k = 8.0f/slot.scale/(1<<VVEC_FRAC),
1178 xs = slot.rotation>=2 && slot.rotation<=4 ? -tex->xs : tex->xs,
1179 ys = (slot.rotation>=1 && slot.rotation<=2) || slot.rotation==5 ? -tex->ys : tex->ys;
1180 if((slot.rotation&5)==1)
1182 cur.texgenSk = k/xs; cur.texgenSoff = (slot.scrollT*lastmillis*tex->xs - slot.yoffset)/xs;
1183 cur.texgenTk = k/ys; cur.texgenToff = (slot.scrollS*lastmillis*tex->ys - slot.xoffset)/ys;
1185 else
1187 cur.texgenSk = k/xs; cur.texgenSoff = (slot.scrollS*lastmillis*tex->xs - slot.xoffset)/xs;
1188 cur.texgenTk = k/ys; cur.texgenToff = (slot.scrollT*lastmillis*tex->ys - slot.yoffset)/ys;
1190 cur.texgendim = -1;
1193 cur.slot = &slot;
1196 static void changeshader(renderstate &cur, Shader *s, Slot &slot, bool shadowed)
1198 if(glaring)
1200 Shader *g = s->hasvariant(min(s->variants[4].length()-1, cur.visibledynlights), 4);
1201 if(g) g->set(&slot);
1202 else
1204 static Shader *noglareshader = NULL;
1205 if(!noglareshader) noglareshader = lookupshaderbyname("noglareworld");
1206 noglareshader->set(&slot);
1209 else if(fading)
1211 if(shadowed) s->variant(min(s->variants[3].length()-1, cur.visibledynlights), 3)->set(&slot);
1212 else s->variant(min(s->variants[2].length()-1, cur.visibledynlights), 2)->set(&slot);
1214 else if(shadowed) s->variant(min(s->variants[1].length()-1, cur.visibledynlights), 1)->set(&slot);
1215 else if(!cur.visibledynlights) s->set(&slot);
1216 else s->variant(min(s->variants[0].length()-1, cur.visibledynlights-1))->set(&slot);
1217 if(s->type&SHADER_GLSLANG) cur.texgendim = -1;
1220 static void changetexgen(renderstate &cur, Slot &slot, int dim)
1222 static const int si[] = { 1, 0, 0 };
1223 static const int ti[] = { 2, 2, 1 };
1225 GLfloat sgen[4] = { 0.0f, 0.0f, 0.0f, cur.texgenSoff },
1226 tgen[4] = { 0.0f, 0.0f, 0.0f, cur.texgenToff };
1227 int sdim = si[dim], tdim = ti[dim];
1228 if((slot.rotation&5)==1)
1230 sgen[tdim] = (dim <= 1 ? -cur.texgenSk : cur.texgenSk);
1231 sgen[3] += (vaorigin[tdim]<<VVEC_FRAC)*sgen[tdim];
1232 tgen[sdim] = cur.texgenTk;
1233 tgen[3] += (vaorigin[sdim]<<VVEC_FRAC)*tgen[sdim];
1235 else
1237 sgen[sdim] = cur.texgenSk;
1238 sgen[3] += (vaorigin[sdim]<<VVEC_FRAC)*sgen[sdim];
1239 tgen[tdim] = (dim <= 1 ? -cur.texgenTk : cur.texgenTk);
1240 tgen[3] += (vaorigin[tdim]<<VVEC_FRAC)*tgen[tdim];
1243 if(renderpath==R_FIXEDFUNCTION)
1245 if(cur.texgendim!=dim)
1247 glTexGenfv(GL_S, GL_OBJECT_PLANE, sgen);
1248 glTexGenfv(GL_T, GL_OBJECT_PLANE, tgen);
1249 // KLUGE: workaround for buggy nvidia drivers
1250 // object planes are somehow invalid unless texgen is toggled
1251 extern int nvidia_texgen_bug;
1252 if(nvidia_texgen_bug)
1254 glDisable(GL_TEXTURE_GEN_S);
1255 glDisable(GL_TEXTURE_GEN_T);
1256 glEnable(GL_TEXTURE_GEN_S);
1257 glEnable(GL_TEXTURE_GEN_T);
1261 if(cur.mtglow)
1263 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1264 glTexGenfv(GL_S, GL_OBJECT_PLANE, sgen);
1265 glTexGenfv(GL_T, GL_OBJECT_PLANE, tgen);
1266 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1267 cur.mttexgen = cur.mtglow;
1270 else
1272 // have to pass in env, otherwise same problem as fixed function
1273 setlocalparamfv("texgenS", SHPARAM_VERTEX, 0, sgen);
1274 setlocalparamfv("texgenT", SHPARAM_VERTEX, 1, tgen);
1275 setlocalparamfv("orienttangent", SHPARAM_VERTEX, 2, orientation_tangent[slot.rotation][dim]);
1276 setlocalparamfv("orientbinormal", SHPARAM_VERTEX, 3, orientation_binormal[slot.rotation][dim]);
1279 cur.texgendim = dim;
1282 struct batchdrawinfo
1284 ushort *edata;
1285 ushort len, minvert, maxvert;
1287 batchdrawinfo(geombatch &b, int dim, ushort offset, ushort len)
1288 : edata(b.edata + offset), len(len),
1289 minvert(b.va->shadowed ? b.es.minvert[dim] : min(b.es.minvert[dim], b.es.minvert[dim+1])),
1290 maxvert(b.va->shadowed ? b.es.maxvert[dim] : max(b.es.maxvert[dim], b.es.maxvert[dim+1]))
1294 static void renderbatch(renderstate &cur, int pass, geombatch &b)
1296 static vector<batchdrawinfo> draws[6];
1297 for(geombatch *curbatch = &b;; curbatch = &geombatches[curbatch->batch])
1299 int dim = 0;
1300 ushort offset = 0, len = 0;
1301 loopi(3)
1303 offset += len;
1304 len = curbatch->es.length[dim + (curbatch->va->shadowed ? 0 : 1)] - offset;
1305 if(len) draws[dim].add(batchdrawinfo(*curbatch, dim, offset, len));
1306 dim++;
1308 if(curbatch->va->shadowed)
1310 offset += len;
1311 len = curbatch->es.length[dim] - offset;
1312 if(len) draws[dim].add(batchdrawinfo(*curbatch, dim, offset, len));
1314 dim++;
1316 if(curbatch->batch < 0) break;
1318 loop(shadowed, 2)
1320 bool rendered = false;
1321 loop(dim, 3)
1323 vector<batchdrawinfo> &draw = draws[2*dim + shadowed];
1324 if(draw.empty()) continue;
1326 if(!rendered)
1328 if(renderpath!=R_FIXEDFUNCTION) changeshader(cur, b.slot.shader, b.slot, shadowed!=0);
1329 rendered = true;
1331 if(cur.texgendim!=dim || cur.mtglow>cur.mttexgen)
1332 changetexgen(cur, b.slot, dim);
1334 gbatches++;
1335 loopv(draw)
1337 batchdrawinfo &info = draw[i];
1338 drawtris(info.len, info.edata, info.minvert, info.maxvert);
1339 vtris += info.len/3;
1341 draw.setsizenodelete(0);
1346 static void resetbatches()
1348 geombatches.setsizenodelete(0);
1349 firstbatch = -1;
1350 numbatches = 0;
1353 static void renderbatches(renderstate &cur, int pass)
1355 cur.slot = NULL;
1356 int curbatch = firstbatch;
1357 if(curbatch >= 0)
1359 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
1360 if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); }
1362 while(curbatch >= 0)
1364 geombatch &b = geombatches[curbatch];
1365 curbatch = b.next;
1367 if(cur.vbuf != b.va->vbuf)
1369 changevbuf(cur, pass, b.va);
1370 changefogplane(cur, pass, b.va);
1372 if(pass == RENDERPASS_LIGHTMAP)
1374 changebatchtmus(cur, pass, b);
1375 if(cur.dynlightmask != b.va->dynlightmask)
1377 cur.visibledynlights = setdynlights(b.va, vaorigin);
1378 cur.dynlightmask = b.va->dynlightmask;
1381 if(cur.slot != &b.slot) changeslottmus(cur, pass, b.slot);
1383 renderbatch(cur, pass, b);
1386 if(pass == RENDERPASS_LIGHTMAP && cur.mtglow)
1388 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1389 glDisable(GL_TEXTURE_2D);
1390 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1391 cur.mtglow = false;
1394 resetbatches();
1397 void renderzpass(renderstate &cur, vtxarray *va)
1399 if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_Z, va);
1400 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
1401 if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
1403 extern int apple_glsldepth_bug;
1404 if(renderpath!=R_GLSLANG || !apple_glsldepth_bug)
1406 nocolorshader->set();
1407 drawvatris(va, 3*va->tris, va->edata);
1409 else
1411 static Shader *nocolorglslshader = NULL;
1412 if(!nocolorglslshader) nocolorglslshader = lookupshaderbyname("nocolorglsl");
1413 Slot *lastslot = NULL;
1414 int lastdraw = 0, offset = 0;
1415 loopi(va->texs)
1417 Slot &slot = lookuptexture(va->eslist[i].texture);
1418 if(lastslot && (slot.shader->type&SHADER_GLSLANG) != (lastslot->shader->type&SHADER_GLSLANG) && offset > lastdraw)
1420 (lastslot->shader->type&SHADER_GLSLANG ? nocolorglslshader : nocolorshader)->set();
1421 drawvatris(va, offset-lastdraw, va->edata+lastdraw);
1422 lastdraw = offset;
1424 lastslot = &slot;
1425 offset += va->eslist[i].length[5];
1427 if(offset > lastdraw)
1429 (lastslot->shader->type&SHADER_GLSLANG ? nocolorglslshader : nocolorshader)->set();
1430 drawvatris(va, offset-lastdraw, va->edata+lastdraw);
1433 xtravertsva += va->verts;
1436 vector<vtxarray *> foggedvas;
1438 #define startvaquery(va, flush) \
1439 do { \
1440 if(!refracting) \
1442 occludequery *query = reflecting ? va->rquery : va->query; \
1443 if(query) \
1445 flush; \
1446 startquery(query); \
1449 } while(0)
1452 #define endvaquery(va, flush) \
1453 do { \
1454 if(!refracting) \
1456 occludequery *query = reflecting ? va->rquery : va->query; \
1457 if(query) \
1459 flush; \
1460 endquery(query); \
1463 } while(0)
1465 void renderfoggedvas(renderstate &cur, bool doquery = false)
1467 static Shader *fogshader = NULL;
1468 if(!fogshader) fogshader = lookupshaderbyname("fogworld");
1469 fogshader->set();
1471 glDisable(GL_TEXTURE_2D);
1473 uchar wcol[3];
1474 getwatercolour(wcol);
1475 glColor3ubv(wcol);
1477 loopv(foggedvas)
1479 vtxarray *va = foggedvas[i];
1480 if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_FOG, va);
1482 if(doquery) startvaquery(va, );
1483 drawvatris(va, 3*va->tris, va->edata);
1484 vtris += va->tris;
1485 if(doquery) endvaquery(va, );
1488 glEnable(GL_TEXTURE_2D);
1490 foggedvas.setsizenodelete(0);
1493 VAR(batchgeom, 0, 1, 1);
1495 void renderva(renderstate &cur, vtxarray *va, int pass = RENDERPASS_LIGHTMAP, bool fogpass = false, bool doquery = false)
1497 switch(pass)
1499 case RENDERPASS_GLOW:
1500 if(!(va->texmask&(1<<TEX_GLOW))) return;
1501 mergeglowtexs(va);
1502 if(!batchgeom && geombatches.length()) renderbatches(cur, pass);
1503 break;
1505 case RENDERPASS_COLOR:
1506 case RENDERPASS_LIGHTMAP:
1507 vverts += va->verts;
1508 va->shadowed = false;
1509 va->dynlightmask = 0;
1510 if(fogpass ? va->geommax.z<=reflectz-waterfog : va->curvfc==VFC_FOGGED)
1512 foggedvas.add(va);
1513 break;
1515 if(renderpath!=R_FIXEDFUNCTION && !envmapping)
1517 va->shadowed = isshadowmapreceiver(va);
1518 calcdynlightmask(va);
1520 if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); });
1521 mergetexs(va);
1522 if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); });
1523 else if(!batchgeom && geombatches.length()) renderbatches(cur, pass);
1524 break;
1526 case RENDERPASS_FOG:
1527 if(cur.vbuf!=va->vbuf)
1529 changevbuf(cur, pass, va);
1530 changefogplane(cur, pass, va);
1532 drawvatris(va, 3*va->tris, va->edata);
1533 xtravertsva += va->verts;
1534 break;
1536 case RENDERPASS_CAUSTICS:
1537 if(cur.vbuf!=va->vbuf) changevbuf(cur, pass, va);
1538 drawvatris(va, 3*va->tris, va->edata);
1539 xtravertsva += va->verts;
1540 break;
1542 case RENDERPASS_Z:
1543 if(doquery) startvaquery(va, );
1544 renderzpass(cur, va);
1545 if(doquery) endvaquery(va, );
1546 break;
1550 VAR(oqdist, 0, 256, 1024);
1551 VAR(zpass, 0, 1, 1);
1552 VAR(glowpass, 0, 1, 1);
1554 extern int ati_texgen_bug;
1556 static void setuptexgen(int dims = 2)
1558 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1559 glEnable(GL_TEXTURE_GEN_S);
1560 if(dims>=2)
1562 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1563 glEnable(GL_TEXTURE_GEN_T);
1564 if(ati_texgen_bug) glEnable(GL_TEXTURE_GEN_R); // should not be needed, but apparently makes some ATI drivers happy
1568 static void disabletexgen(int dims = 2)
1570 glDisable(GL_TEXTURE_GEN_S);
1571 if(dims>=2)
1573 glDisable(GL_TEXTURE_GEN_T);
1574 if(ati_texgen_bug) glDisable(GL_TEXTURE_GEN_R);
1578 GLuint fogtex = 0;
1580 void createfogtex()
1582 extern int bilinear;
1583 uchar buf[2*256] = { 255, 0, 255, 255 };
1584 if(!bilinear) loopi(256) { buf[2*i] = 255; buf[2*i+1] = i; }
1585 glGenTextures(1, &fogtex);
1586 createtexture(fogtex, bilinear ? 2 : 256, 1, buf, 3, false, GL_LUMINANCE_ALPHA, GL_TEXTURE_1D);
1589 #define NUMCAUSTICS 32
1591 VARR(causticscale, 0, 100, 10000);
1592 VARR(causticmillis, 0, 75, 1000);
1593 VARP(caustics, 0, 1, 1);
1595 static Texture *caustictex[NUMCAUSTICS] = { NULL };
1597 void loadcaustics()
1599 if(caustictex[0]) return;
1600 loopi(NUMCAUSTICS)
1602 s_sprintfd(name)(
1603 renderpath==R_FIXEDFUNCTION ?
1604 "<mad:0.6,0.4>packages/caustics/caust%.2d.png" :
1605 "<mad:-0.6,0.6>packages/caustics/caust%.2d.png",
1607 caustictex[i] = textureload(name);
1611 void cleanupva()
1613 vaclearc(worldroot);
1614 clearqueries();
1615 if(fogtex) { glDeleteTextures(1, &fogtex); fogtex = 0; }
1616 loopi(NUMCAUSTICS) caustictex[i] = NULL;
1619 void setupcaustics(int tmu, float blend, GLfloat *color = NULL)
1621 if(!caustictex[0]) loadcaustics();
1623 GLfloat s[4] = { 0.011f, 0, 0.0066f, 0 };
1624 GLfloat t[4] = { 0, 0.011f, 0.0066f, 0 };
1625 loopk(3)
1627 s[k] *= 100.0f/(causticscale<<VVEC_FRAC);
1628 t[k] *= 100.0f/(causticscale<<VVEC_FRAC);
1630 int tex = (lastmillis/causticmillis)%NUMCAUSTICS;
1631 float frac = float(lastmillis%causticmillis)/causticmillis;
1632 if(color) color[3] = frac;
1633 else glColor4f(1, 1, 1, frac);
1634 loopi(2)
1636 glActiveTexture_(GL_TEXTURE0_ARB+tmu+i);
1637 glEnable(GL_TEXTURE_2D);
1638 glBindTexture(GL_TEXTURE_2D, caustictex[(tex+i)%NUMCAUSTICS]->id);
1639 if(renderpath==R_FIXEDFUNCTION)
1641 setuptexgen();
1642 setuptmu(tmu+i, !i ? "= T" : "T , P @ Ca");
1643 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
1644 glTexGenfv(GL_T, GL_OBJECT_PLANE, t);
1647 if(renderpath!=R_FIXEDFUNCTION)
1649 static Shader *causticshader = NULL;
1650 if(!causticshader) causticshader = lookupshaderbyname("caustic");
1651 causticshader->set();
1652 setlocalparamfv("texgenS", SHPARAM_VERTEX, 0, s);
1653 setlocalparamfv("texgenT", SHPARAM_VERTEX, 1, t);
1654 setlocalparamf("frameoffset", SHPARAM_PIXEL, 0, blend*(1-frac), blend*frac, blend);
1658 void setupTMUs(renderstate &cur, float causticspass, bool fogpass)
1660 if(!reflecting && !refracting && !envmapping && shadowmap && hasFBO)
1662 glDisableClientState(GL_VERTEX_ARRAY);
1664 if(hasVBO)
1666 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1667 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1670 rendershadowmap();
1672 glEnableClientState(GL_VERTEX_ARRAY);
1675 if(renderpath==R_FIXEDFUNCTION)
1677 if(nolights) cur.lightmaptmu = -1;
1678 else if(maxtmus>=3)
1680 if(maxtmus>=4 && causticspass>=1)
1682 cur.causticstmu = 0;
1683 cur.diffusetmu = 2;
1684 cur.lightmaptmu = 3;
1685 if(maxtmus>=5)
1687 if(fogpass) cur.fogtmu = 4;
1688 else if(glowpass) cur.glowtmu = 4;
1691 else if(fogpass && causticspass<1) cur.fogtmu = 2;
1692 else if(glowpass) cur.glowtmu = 2;
1694 if(cur.glowtmu>=0)
1696 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1697 setuptexgen();
1698 setuptmu(cur.glowtmu, "P + T");
1700 if(cur.fogtmu>=0)
1702 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
1703 glEnable(GL_TEXTURE_1D);
1704 setuptexgen(1);
1705 setuptmu(cur.fogtmu, "C , P @ Ta");
1706 if(!fogtex) createfogtex();
1707 glBindTexture(GL_TEXTURE_1D, fogtex);
1708 uchar wcol[3];
1709 getwatercolour(wcol);
1710 loopk(3) cur.color[k] = wcol[k]/255.0f;
1712 if(cur.causticstmu>=0) setupcaustics(cur.causticstmu, causticspass, cur.color);
1714 else
1716 // need to invalidate vertex params in case they were used somewhere else for streaming params
1717 invalidateenvparams(SHPARAM_VERTEX, 10, RESERVEDSHADERPARAMS + MAXSHADERPARAMS - 10);
1718 glEnableClientState(GL_COLOR_ARRAY);
1719 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glEnable(GL_TEXTURE_2D); }
1720 glActiveTexture_(GL_TEXTURE0_ARB);
1721 setenvparamf("ambient", SHPARAM_PIXEL, 5, hdr.ambient/255.0f, hdr.ambient/255.0f, hdr.ambient/255.0f);
1722 setenvparamf("millis", SHPARAM_VERTEX, 6, lastmillis/1000.0f, lastmillis/1000.0f, lastmillis/1000.0f);
1725 glColor4fv(cur.color);
1727 if(cur.lightmaptmu>=0)
1729 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1730 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1732 setuptmu(cur.lightmaptmu, "P * T x 2");
1733 glEnable(GL_TEXTURE_2D);
1734 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1735 glMatrixMode(GL_TEXTURE);
1736 glLoadIdentity();
1737 glScalef(1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f);
1738 glMatrixMode(GL_MODELVIEW);
1740 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1741 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1742 glEnable(GL_TEXTURE_2D);
1743 setuptmu(cur.diffusetmu, cur.diffusetmu>0 ? "P * T" : "= T");
1746 if(renderpath==R_FIXEDFUNCTION) setuptexgen();
1749 void cleanupTMUs(renderstate &cur)
1751 if(cur.lightmaptmu>=0)
1753 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1754 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1756 resettmu(cur.lightmaptmu);
1757 glDisable(GL_TEXTURE_2D);
1758 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1759 glMatrixMode(GL_TEXTURE);
1760 glLoadIdentity();
1761 glMatrixMode(GL_MODELVIEW);
1763 if(cur.glowtmu>=0)
1765 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1766 resettmu(cur.glowtmu);
1767 disabletexgen();
1768 glDisable(GL_TEXTURE_2D);
1770 if(cur.fogtmu>=0)
1772 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
1773 resettmu(cur.fogtmu);
1774 disabletexgen(1);
1775 glDisable(GL_TEXTURE_1D);
1777 if(cur.causticstmu>=0) loopi(2)
1779 glActiveTexture_(GL_TEXTURE0_ARB+cur.causticstmu+i);
1780 resettmu(cur.causticstmu+i);
1781 disabletexgen();
1782 glDisable(GL_TEXTURE_2D);
1785 if(cur.lightmaptmu>=0)
1787 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1788 resettmu(cur.diffusetmu);
1789 glDisable(GL_TEXTURE_2D);
1792 if(renderpath==R_FIXEDFUNCTION) disabletexgen();
1793 else
1795 glDisableClientState(GL_COLOR_ARRAY);
1796 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glDisable(GL_TEXTURE_2D); }
1799 if(cur.lightmaptmu>=0)
1801 glActiveTexture_(GL_TEXTURE0_ARB);
1802 glClientActiveTexture_(GL_TEXTURE0_ARB);
1803 glEnable(GL_TEXTURE_2D);
1807 #define FIRSTVA (reflecting ? reflectedva : visibleva)
1808 #define NEXTVA (reflecting ? va->rnext : va->next)
1810 void rendergeommultipass(renderstate &cur, int pass, bool fogpass)
1812 cur.vbuf = 0;
1813 for(vtxarray *va = FIRSTVA; va; va = NEXTVA)
1815 if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue;
1816 if(refracting)
1818 if(refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) continue;
1819 if(isvisiblecube(va->o, va->size) >= VFC_NOT_VISIBLE) continue;
1820 if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
1822 else if(reflecting)
1824 if(va->geommax.z <= reflectz || (va->rquery && checkquery(va->rquery))) continue;
1826 if(fogpass ? va->geommax.z <= reflectz-waterfog : va->curvfc==VFC_FOGGED) continue;
1827 renderva(cur, va, pass, fogpass);
1829 if(geombatches.length()) renderbatches(cur, pass);
1832 VAR(oqgeom, 0, 1, 1);
1833 VAR(oqbatch, 0, 1, 1);
1835 void rendergeom(float causticspass, bool fogpass)
1837 renderstate cur;
1839 if(causticspass && ((renderpath==R_FIXEDFUNCTION && maxtmus<2) || !causticscale || !causticmillis)) causticspass = 0;
1841 glEnableClientState(GL_VERTEX_ARRAY);
1843 if(!reflecting && !refracting)
1845 flipqueries();
1846 vtris = vverts = 0;
1849 bool doOQ = reflecting ? hasOQ && oqfrags && oqreflect : !refracting && zpass!=0;
1850 if(!doOQ)
1852 setupTMUs(cur, causticspass, fogpass);
1853 if(shadowmap) pushshadowmap();
1856 finddynlights();
1858 glPushMatrix();
1860 resetorigin();
1862 resetbatches();
1864 for(vtxarray *va = FIRSTVA; va; va = NEXTVA)
1866 if(!va->texs) continue;
1867 if(refracting)
1869 if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_GEOM) continue;
1870 if(isvisiblecube(va->o, va->size) >= VFC_NOT_VISIBLE) continue;
1871 if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
1873 else if(reflecting)
1875 if(va->geommax.z <= reflectz) continue;
1876 if(doOQ)
1878 va->rquery = newquery(&va->rquery);
1879 if(!va->rquery) continue;
1880 if(va->occluded >= OCCLUDE_BB || va->curvfc >= VFC_NOT_VISIBLE)
1882 renderquery(cur, va->rquery, va);
1883 continue;
1887 else if(hasOQ && oqfrags && (zpass || va->distance > oqdist) && !insideva(va, camera1->o) && oqgeom)
1889 if(!zpass && va->query && va->query->owner == va)
1891 if(checkquery(va->query)) va->occluded = min(va->occluded+1, int(OCCLUDE_BB));
1892 else va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
1894 if(zpass && oqbatch)
1896 if(va->parent && va->parent->occluded >= OCCLUDE_BB)
1898 va->query = NULL;
1899 va->occluded = OCCLUDE_PARENT;
1900 continue;
1902 bool succeeded = false;
1903 if(va->query && va->query->owner == va && checkquery(va->query))
1905 va->occluded = min(va->occluded+1, int(OCCLUDE_BB));
1906 succeeded = true;
1908 va->query = newquery(va);
1909 if(!va->query || !succeeded)
1910 va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
1911 if(va->occluded >= OCCLUDE_GEOM)
1913 if(va->query) renderquery(cur, va->query, va);
1914 continue;
1917 else if(zpass && va->parent &&
1918 (va->parent->occluded == OCCLUDE_PARENT ||
1919 (va->parent->occluded >= OCCLUDE_BB &&
1920 va->parent->query && va->parent->query->owner == va->parent && va->parent->query->fragments < 0)))
1922 va->query = NULL;
1923 if(va->occluded >= OCCLUDE_GEOM || pvsoccluded(va->geommin, va->geommax))
1925 va->occluded = OCCLUDE_PARENT;
1926 continue;
1929 else if(va->occluded >= OCCLUDE_GEOM)
1931 va->query = newquery(va);
1932 if(va->query) renderquery(cur, va->query, va);
1933 continue;
1935 else va->query = newquery(va);
1937 else
1939 va->query = NULL;
1940 va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
1941 if(va->occluded >= OCCLUDE_GEOM) continue;
1944 renderva(cur, va, doOQ ? RENDERPASS_Z : (nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP), fogpass, true);
1947 if(geombatches.length()) renderbatches(cur, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP);
1949 if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); }
1950 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
1952 if(doOQ)
1954 setupTMUs(cur, causticspass, fogpass);
1955 if(shadowmap)
1957 glPopMatrix();
1958 glPushMatrix();
1959 pushshadowmap();
1960 resetorigin();
1962 glDepthFunc(GL_LEQUAL);
1963 cur.vbuf = 0;
1965 for(vtxarray **prevva = &FIRSTVA, *va = FIRSTVA; va; prevva = &NEXTVA, va = NEXTVA)
1967 if(!va->texs) continue;
1968 if(reflecting)
1970 if(va->geommax.z <= reflectz) continue;
1971 if(va->rquery && checkquery(va->rquery))
1973 if(va->occluded >= OCCLUDE_BB || va->curvfc >= VFC_NOT_VISIBLE) *prevva = va->rnext;
1974 continue;
1977 else if(oqbatch)
1979 if(va->occluded >= OCCLUDE_GEOM) continue;
1981 else if(va->parent && va->parent->occluded >= OCCLUDE_BB && (!va->parent->query || va->parent->query->fragments >= 0))
1983 va->query = NULL;
1984 va->occluded = OCCLUDE_BB;
1985 continue;
1987 else
1989 if(va->query && checkquery(va->query)) va->occluded = min(va->occluded+1, int(OCCLUDE_BB));
1990 else va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
1991 if(va->occluded >= OCCLUDE_GEOM) continue;
1994 renderva(cur, va, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP, fogpass);
1996 if(geombatches.length()) renderbatches(cur, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP);
1997 if(oqbatch && !reflecting) for(vtxarray **prevva = &FIRSTVA, *va = FIRSTVA; va; prevva = &NEXTVA, va = NEXTVA)
1999 if(!va->texs || va->occluded < OCCLUDE_GEOM) continue;
2000 else if(va->query && checkquery(va->query)) continue;
2001 else if(va->parent && (va->parent->occluded >= OCCLUDE_BB ||
2002 (va->parent->occluded >= OCCLUDE_GEOM && va->parent->query && checkquery(va->parent->query))))
2004 va->occluded = OCCLUDE_BB;
2005 continue;
2007 else
2009 va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
2010 if(va->occluded >= OCCLUDE_GEOM) continue;
2012 renderva(cur, va, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP, fogpass);
2014 if(geombatches.length()) renderbatches(cur, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP);
2016 if(foggedvas.empty()) glDepthFunc(GL_LESS);
2019 if(shadowmap) popshadowmap();
2021 cleanupTMUs(cur);
2023 if(foggedvas.length())
2025 renderfoggedvas(cur, !doOQ);
2026 if(doOQ) glDepthFunc(GL_LESS);
2029 if(renderpath==R_FIXEDFUNCTION ? (glowpass && cur.skippedglow) || (causticspass>=1 && cur.causticstmu<0) || (fogpass && cur.fogtmu<0) : causticspass)
2031 glDepthFunc(GL_LEQUAL);
2032 glDepthMask(GL_FALSE);
2033 glEnable(GL_BLEND);
2034 static GLfloat zerofog[4] = { 0, 0, 0, 1 }, onefog[4] = { 1, 1, 1, 1 };
2035 GLfloat oldfogc[4];
2036 glGetFloatv(GL_FOG_COLOR, oldfogc);
2038 if(renderpath==R_FIXEDFUNCTION && glowpass && cur.skippedglow)
2040 glBlendFunc(GL_ONE, GL_ONE);
2041 glFogfv(GL_FOG_COLOR, zerofog);
2042 setuptexgen();
2043 if(cur.fogtmu>=0)
2045 setuptmu(0, "C * T");
2046 glActiveTexture_(GL_TEXTURE1_ARB);
2047 glEnable(GL_TEXTURE_1D);
2048 setuptexgen(1);
2049 setuptmu(1, "P * T~a");
2050 if(!fogtex) createfogtex();
2051 glBindTexture(GL_TEXTURE_1D, fogtex);
2052 glActiveTexture_(GL_TEXTURE0_ARB);
2054 cur.glowcolor = vec(-1, -1, -1);
2055 cur.glowtmu = 0;
2056 rendergeommultipass(cur, RENDERPASS_GLOW, fogpass);
2057 disabletexgen();
2058 if(cur.fogtmu>=0)
2060 resettmu(0);
2061 glActiveTexture_(GL_TEXTURE1_ARB);
2062 resettmu(1);
2063 disabletexgen();
2064 glDisable(GL_TEXTURE_1D);
2065 glActiveTexture_(GL_TEXTURE0_ARB);
2069 if(renderpath==R_FIXEDFUNCTION ? causticspass>=1 && cur.causticstmu<0 : causticspass)
2071 setupcaustics(0, causticspass);
2072 glBlendFunc(GL_ZERO, renderpath==R_FIXEDFUNCTION ? GL_SRC_COLOR : GL_ONE_MINUS_SRC_COLOR);
2073 glFogfv(GL_FOG_COLOR, renderpath==R_FIXEDFUNCTION ? onefog : zerofog);
2074 if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
2075 rendergeommultipass(cur, RENDERPASS_CAUSTICS, fogpass);
2076 if(fading) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2077 loopi(2)
2079 glActiveTexture_(GL_TEXTURE0_ARB+i);
2080 resettmu(i);
2081 if(renderpath==R_FIXEDFUNCTION || !i)
2083 resettmu(i);
2084 disabletexgen();
2086 if(i) glDisable(GL_TEXTURE_2D);
2088 glActiveTexture_(GL_TEXTURE0_ARB);
2091 if(renderpath==R_FIXEDFUNCTION && fogpass && cur.fogtmu<0)
2093 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2094 glDisable(GL_TEXTURE_2D);
2095 glEnable(GL_TEXTURE_1D);
2096 setuptexgen(1);
2097 if(!fogtex) createfogtex();
2098 glBindTexture(GL_TEXTURE_1D, fogtex);
2099 setuptexgen(1);
2100 uchar wcol[3];
2101 getwatercolour(wcol);
2102 glColor3ubv(wcol);
2103 rendergeommultipass(cur, RENDERPASS_FOG, fogpass);
2104 disabletexgen(1);
2105 glDisable(GL_TEXTURE_1D);
2106 glEnable(GL_TEXTURE_2D);
2109 glFogfv(GL_FOG_COLOR, oldfogc);
2110 glDisable(GL_BLEND);
2111 glDepthFunc(GL_LESS);
2112 glDepthMask(GL_TRUE);
2115 glPopMatrix();
2117 if(hasVBO)
2119 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
2120 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
2122 glDisableClientState(GL_VERTEX_ARRAY);
2125 void findreflectedvas(vector<vtxarray *> &vas, int prevvfc = VFC_PART_VISIBLE)
2127 bool doOQ = hasOQ && oqfrags && oqreflect;
2128 loopv(vas)
2130 vtxarray *va = vas[i];
2131 if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc;
2132 if(va->curvfc == VFC_FOGGED || va->curvfc == PVS_FOGGED || va->o.z+va->size <= reflectz || isvisiblecube(va->o, va->size) >= VFC_FOGGED) continue;
2133 bool render = true;
2134 if(va->curvfc == VFC_FULL_VISIBLE)
2136 if(va->occluded >= OCCLUDE_BB) continue;
2137 if(va->occluded >= OCCLUDE_GEOM) render = false;
2139 else if(va->curvfc == PVS_FULL_VISIBLE) continue;
2140 if(render)
2142 if(va->curvfc >= VFC_NOT_VISIBLE) va->distance = (int)vadist(va, camera1->o);
2143 if(!doOQ && va->distance > reflectdist) continue;
2144 va->rquery = NULL;
2145 vtxarray **vprev = &reflectedva, *vcur = reflectedva;
2146 while(vcur && va->distance > vcur->distance)
2148 vprev = &vcur->rnext;
2149 vcur = vcur->rnext;
2151 va->rnext = *vprev;
2152 *vprev = va;
2154 if(va->children.length()) findreflectedvas(va->children, va->curvfc);
2158 void renderreflectedgeom(bool causticspass, bool fogpass)
2160 if(reflecting)
2162 reflectedva = NULL;
2163 findreflectedvas(varoot);
2164 rendergeom(causticspass ? 1 : 0, fogpass);
2166 else rendergeom(causticspass ? 1 : 0, fogpass);
2169 static vtxarray *prevskyva = NULL;
2171 void renderskyva(vtxarray *va, bool explicitonly = false)
2173 if(!prevskyva || va->vbuf != prevskyva->vbuf)
2175 if(!prevskyva)
2177 glEnableClientState(GL_VERTEX_ARRAY);
2178 glPushMatrix();
2179 resetorigin();
2182 setorigin(va);
2183 if(hasVBO)
2185 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
2186 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->skybuf);
2188 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
2191 drawvatris(va, explicitonly ? va->explicitsky : va->sky+va->explicitsky, explicitonly ? va->skydata+va->sky : va->skydata);
2193 if(!explicitonly) xtraverts += va->sky/3;
2194 xtraverts += va->explicitsky/3;
2196 prevskyva = va;
2199 int renderedsky = 0, renderedexplicitsky = 0, renderedskyfaces = 0, renderedskyclip = INT_MAX;
2201 static inline void updateskystats(vtxarray *va)
2203 renderedsky += va->sky;
2204 renderedexplicitsky += va->explicitsky;
2205 renderedskyfaces |= va->skyfaces&0x3F;
2206 if(!(va->skyfaces&0x1F) || camera1->o.z < va->skyclip) renderedskyclip = min(renderedskyclip, va->skyclip);
2207 else renderedskyclip = 0;
2210 void renderreflectedskyvas(vector<vtxarray *> &vas, int prevvfc = VFC_PART_VISIBLE)
2212 loopv(vas)
2214 vtxarray *va = vas[i];
2215 if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc;
2216 if((va->curvfc == VFC_FULL_VISIBLE && va->occluded >= OCCLUDE_BB) || va->curvfc==PVS_FULL_VISIBLE) continue;
2217 if(va->o.z+va->size <= reflectz || isvisiblecube(va->o, va->size) == VFC_NOT_VISIBLE) continue;
2218 if(va->sky+va->explicitsky)
2220 updateskystats(va);
2221 renderskyva(va);
2223 if(va->children.length()) renderreflectedskyvas(va->children, va->curvfc);
2227 bool rendersky(bool explicitonly)
2229 prevskyva = NULL;
2230 renderedsky = renderedexplicitsky = renderedskyfaces = 0;
2231 renderedskyclip = INT_MAX;
2233 if(reflecting)
2235 renderreflectedskyvas(varoot);
2237 else for(vtxarray *va = visibleva; va; va = va->next)
2239 if((va->occluded >= OCCLUDE_BB && va->skyfaces&0x80) || !(va->sky+va->explicitsky)) continue;
2241 // count possibly visible sky even if not actually rendered
2242 updateskystats(va);
2243 if(explicitonly && !va->explicitsky) continue;
2244 renderskyva(va, explicitonly);
2247 if(prevskyva)
2249 glPopMatrix();
2250 glDisableClientState(GL_VERTEX_ARRAY);
2251 if(hasVBO)
2253 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
2254 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
2258 return renderedsky+renderedexplicitsky > 0;