Initial sauer
[SauerbratenRemote.git] / src / engine / renderva.cpp
blob5940550b79938607c840a7f457305cf63c571d6e
1 // renderva.cpp: handles the occlusion and rendering of vertex arrays
3 #include "pch.h"
4 #include "engine.h"
6 void drawvatris(vtxarray *va, GLsizei numindices, const GLvoid *indices, ushort minvert = 0, ushort maxvert = 0)
8 if(!minvert && !maxvert) { minvert = va->minvert; maxvert = va->maxvert; }
9 if(hasDRE) glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, numindices, GL_UNSIGNED_SHORT, indices);
10 else glDrawElements(GL_TRIANGLES, numindices, GL_UNSIGNED_SHORT, indices);
11 glde++;
14 ///////// view frustrum culling ///////////////////////
16 plane vfcP[5]; // perpindictular vectors to view frustrum bounding planes
17 float vfcDfog; // far plane culling distance (fog limit).
18 int vfcw, vfch, vfcfov;
20 vtxarray *visibleva;
22 int isvisiblesphere(float rad, const vec &cv)
24 int v = VFC_FULL_VISIBLE;
25 float dist;
27 loopi(5)
29 dist = vfcP[i].dist(cv);
30 if(dist < -rad) return VFC_NOT_VISIBLE;
31 if(dist < rad) v = VFC_PART_VISIBLE;
34 dist -= vfcDfog;
35 if(dist > rad) return VFC_FOGGED; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM
36 if(dist > -rad) v = VFC_PART_VISIBLE;
38 return v;
41 int isvisiblecube(const vec &o, int size)
43 vec center(o);
44 center.add(size/2.0f);
45 return isvisiblesphere(size*SQRT3/2.0f, center);
48 float vadist(vtxarray *va, const vec &p)
50 if(va->min.x>va->max.x)
52 ivec o(va->x, va->y, va->z);
53 return p.dist_to_bb(o, ivec(o).add(va->size)); // box contains only sky/water
55 return p.dist_to_bb(va->min, va->max);
58 #define VASORTSIZE 64
60 static vtxarray *vasort[VASORTSIZE];
62 void addvisibleva(vtxarray *va)
64 extern int lodsize, loddistance;
66 float dist = vadist(va, camera1->o);
67 va->distance = int(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
68 va->curlod = lodsize==0 || va->distance<loddistance ? 0 : 1;
70 int hash = min(int(dist*VASORTSIZE/hdr.worldsize), VASORTSIZE-1);
71 vtxarray **prev = &vasort[hash], *cur = vasort[hash];
73 while(cur && va->distance > cur->distance)
75 prev = &cur->next;
76 cur = cur->next;
79 va->next = *prev;
80 *prev = va;
83 void sortvisiblevas()
85 visibleva = NULL;
86 vtxarray **last = &visibleva;
87 loopi(VASORTSIZE) if(vasort[i])
89 vtxarray *va = vasort[i];
90 *last = va;
91 while(va->next) va = va->next;
92 last = &va->next;
96 void findvisiblevas(vector<vtxarray *> &vas, bool resetocclude = false)
98 loopv(vas)
100 vtxarray &v = *vas[i];
101 int prevvfc = resetocclude ? VFC_NOT_VISIBLE : v.curvfc;
102 v.curvfc = isvisiblecube(vec(v.x, v.y, v.z), v.size);
103 if(v.curvfc!=VFC_NOT_VISIBLE)
105 addvisibleva(&v);
106 if(v.children->length()) findvisiblevas(*v.children, prevvfc==VFC_NOT_VISIBLE);
107 if(prevvfc==VFC_NOT_VISIBLE)
109 v.occluded = OCCLUDE_NOTHING;
110 v.query = NULL;
116 void setvfcP(float yaw, float pitch, const vec &camera)
118 float yawd = (90.0f - vfcfov/2.0f) * RAD;
119 float pitchd = (90.0f - (vfcfov*float(vfch)/float(vfcw))/2.0f) * RAD;
120 yaw *= RAD;
121 pitch *= RAD;
122 vfcP[0].toplane(vec(yaw + yawd, pitch), camera); // left plane
123 vfcP[1].toplane(vec(yaw - yawd, pitch), camera); // right plane
124 vfcP[2].toplane(vec(yaw, pitch + pitchd), camera); // top plane
125 vfcP[3].toplane(vec(yaw, pitch - pitchd), camera); // bottom plane
126 vfcP[4].toplane(vec(yaw, pitch), camera); // near/far planes
127 extern int fog;
128 vfcDfog = fog;
131 plane oldvfcP[5];
133 void reflectvfcP(float z)
135 memcpy(oldvfcP, vfcP, sizeof(vfcP));
137 vec o(camera1->o);
138 o.z = z-(camera1->o.z-z);
139 setvfcP(camera1->yaw, -camera1->pitch, o);
142 void restorevfcP()
144 memcpy(vfcP, oldvfcP, sizeof(vfcP));
147 extern vector<vtxarray *> varoot;
149 void visiblecubes(cube *c, int size, int cx, int cy, int cz, int w, int h, int fov)
151 memset(vasort, 0, sizeof(vasort));
153 vfcw = w;
154 vfch = h;
155 vfcfov = fov;
157 // Calculate view frustrum: Only changes if resize, but...
158 setvfcP(camera1->yaw, camera1->pitch, camera1->o);
160 findvisiblevas(varoot);
161 sortvisiblevas();
164 bool insideva(const vtxarray *va, const vec &v)
166 return v.x>=va->x && v.y>=va->y && v.z>=va->z && v.x<=va->x+va->size && v.y<=va->y+va->size && v.z<=va->z+va->size;
169 static ivec vaorigin;
171 void resetorigin()
173 vaorigin = ivec(-1, -1, -1);
176 void setorigin(vtxarray *va, bool shadowmatrix = false)
178 ivec o(va->x, va->y, va->z);
179 o.mask(~VVEC_INT_MASK);
180 if(o != vaorigin)
182 vaorigin = o;
183 glPopMatrix();
184 glPushMatrix();
185 glTranslatef(o.x, o.y, o.z);
186 static const float scale = 1.0f/(1<<VVEC_FRAC);
187 glScalef(scale, scale, scale);
189 if(shadowmatrix) adjustshadowmatrix(o, scale);
193 ///////// occlusion queries /////////////
195 #define MAXQUERY 2048
197 struct queryframe
199 int cur, max;
200 occludequery queries[MAXQUERY];
203 static queryframe queryframes[2] = {{0, 0}, {0, 0}};
204 static uint flipquery = 0;
206 int getnumqueries()
208 return queryframes[flipquery].cur;
211 void flipqueries()
213 flipquery = (flipquery + 1) % 2;
214 queryframe &qf = queryframes[flipquery];
215 loopi(qf.cur) qf.queries[i].owner = NULL;
216 qf.cur = 0;
219 occludequery *newquery(void *owner)
221 queryframe &qf = queryframes[flipquery];
222 if(qf.cur >= qf.max)
224 if(qf.max >= MAXQUERY) return NULL;
225 glGenQueries_(1, &qf.queries[qf.max++].id);
227 occludequery *query = &qf.queries[qf.cur++];
228 query->owner = owner;
229 query->fragments = -1;
230 return query;
233 void resetqueries()
235 loopi(2) loopj(queryframes[i].max) queryframes[i].queries[j].owner = NULL;
238 void clearqueries()
240 loopi(2)
242 queryframe &qf = queryframes[i];
243 loopj(qf.max) glDeleteQueries_(1, &qf.queries[j].id);
244 qf.cur = qf.max = 0;
248 VAR(oqfrags, 0, 8, 64);
249 VAR(oqreflect, 0, 4, 64);
251 bool checkquery(occludequery *query, bool nowait)
253 GLuint fragments;
254 if(query->fragments >= 0) fragments = query->fragments;
255 else
257 if(nowait)
259 GLint avail;
260 glGetQueryObjectiv_(query->id, GL_QUERY_RESULT_AVAILABLE, &avail);
261 if(!avail) return false;
263 glGetQueryObjectuiv_(query->id, GL_QUERY_RESULT_ARB, &fragments);
264 query->fragments = fragments;
266 return fragments < (uint)(reflecting ? oqreflect : oqfrags);
269 void drawbb(const ivec &bo, const ivec &br, const vec &camera)
271 glBegin(GL_QUADS);
273 loopi(6)
275 int dim = dimension(i), coord = dimcoord(i);
277 if(coord)
279 if(camera[dim] < bo[dim] + br[dim]) continue;
281 else if(camera[dim] > bo[dim]) continue;
283 loopj(4)
285 const ivec &cc = cubecoords[fv[i][j]];
286 glVertex3i(cc.x ? bo.x+br.x : bo.x,
287 cc.y ? bo.y+br.y : bo.y,
288 cc.z ? bo.z+br.z : bo.z);
291 xtraverts += 4;
294 glEnd();
297 extern int octaentsize;
299 static octaentities *visiblemms, **lastvisiblemms;
301 void findvisiblemms(const vector<extentity *> &ents)
303 for(vtxarray *va = visibleva; va; va = va->next)
305 if(!va->mapmodels || va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue;
306 loopv(*va->mapmodels)
308 octaentities *oe = (*va->mapmodels)[i];
309 if(isvisiblecube(oe->o.tovec(), oe->size) >= VFC_FOGGED) continue;
311 bool occluded = oe->query && oe->query->owner == oe && checkquery(oe->query);
312 if(occluded)
314 oe->distance = -1;
316 oe->next = NULL;
317 *lastvisiblemms = oe;
318 lastvisiblemms = &oe->next;
320 else
322 int visible = 0;
323 loopv(oe->mapmodels)
325 extentity &e = *ents[oe->mapmodels[i]];
326 if(e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
327 e.visible = true;
328 ++visible;
330 if(!visible) continue;
332 oe->distance = int(camera1->o.dist_to_bb(oe->o, oe->size));
334 octaentities **prev = &visiblemms, *cur = visiblemms;
335 while(cur && cur->distance >= 0 && oe->distance > cur->distance)
337 prev = &cur->next;
338 cur = cur->next;
341 if(*prev == NULL) lastvisiblemms = &oe->next;
342 oe->next = *prev;
343 *prev = oe;
349 VAR(oqmm, 0, 4, 8);
351 extern bool getentboundingbox(extentity &e, ivec &o, ivec &r);
353 void rendermapmodel(extentity &e)
355 int anim = ANIM_MAPMODEL|ANIM_LOOP, basetime = 0;
356 if(e.attr3) switch(e.triggerstate)
358 case TRIGGER_RESET: anim = ANIM_TRIGGER|ANIM_START; break;
359 case TRIGGERING: anim = ANIM_TRIGGER; basetime = e.lasttrigger; break;
360 case TRIGGERED: anim = ANIM_TRIGGER|ANIM_END; break;
361 case TRIGGER_RESETTING: anim = ANIM_TRIGGER|ANIM_REVERSE; basetime = e.lasttrigger; break;
363 mapmodelinfo &mmi = getmminfo(e.attr2);
364 if(&mmi) rendermodel(e.color, e.dir, mmi.name, anim, 0, mmi.tex, e.o, (float)((e.attr1+7)-(e.attr1+7)%15), 0, 0, basetime, NULL, MDL_CULL_VFC | MDL_CULL_DIST);
367 extern int reflectdist;
369 static vector<octaentities *> renderedmms;
371 vtxarray *reflectedva;
373 void renderreflectedmapmodels(float z, bool refract)
375 bool reflected = !refract && camera1->o.z >= z;
376 vector<octaentities *> reflectedmms;
377 vector<octaentities *> &mms = reflected ? reflectedmms : renderedmms;
378 const vector<extentity *> &ents = et->getents();
380 if(reflected)
382 reflectvfcP(z);
383 for(vtxarray *va = reflectedva; va; va = va->rnext)
385 if(!va->mapmodels || va->distance > reflectdist) continue;
386 loopv(*va->mapmodels) reflectedmms.add((*va->mapmodels)[i]);
389 loopv(mms)
391 octaentities *oe = mms[i];
392 if(refract ? oe->o.z >= z : oe->o.z+oe->size <= z) continue;
393 if(reflected && isvisiblecube(oe->o.tovec(), oe->size) >= VFC_FOGGED) continue;
394 loopv(oe->mapmodels)
396 extentity &e = *ents[oe->mapmodels[i]];
397 if(e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
398 e.visible = true;
401 if(mms.length())
403 startmodelbatches();
404 loopv(mms)
406 octaentities *oe = mms[i];
407 loopv(oe->mapmodels)
409 extentity &e = *ents[oe->mapmodels[i]];
410 if(!e.visible) continue;
411 rendermapmodel(e);
412 e.visible = false;
415 endmodelbatches();
417 if(reflected) restorevfcP();
420 void rendermapmodels()
422 const vector<extentity *> &ents = et->getents();
424 visiblemms = NULL;
425 lastvisiblemms = &visiblemms;
426 findvisiblemms(ents);
428 static int skipoq = 0;
429 bool doquery = hasOQ && oqfrags && oqmm;
431 renderedmms.setsizenodelete(0);
432 startmodelbatches();
433 for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance>=0)
435 loopv(oe->mapmodels)
437 extentity &e = *ents[oe->mapmodels[i]];
438 if(!e.visible || (e.attr3 && e.triggerstate == TRIGGER_DISAPPEARED)) continue;
439 if(renderedmms.empty() || renderedmms.last()!=oe)
441 renderedmms.add(oe);
442 oe->query = doquery && oe->distance>0 && !(++skipoq%oqmm) ? newquery(oe) : NULL;
443 if(oe->query) startmodelquery(oe->query);
445 rendermapmodel(e);
446 e.visible = false;
448 if(renderedmms.length() && renderedmms.last()==oe && oe->query) endmodelquery();
450 endmodelbatches();
452 bool colormask = true;
453 for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance<0)
455 oe->query = doquery ? newquery(oe) : NULL;
456 if(!oe->query) continue;
457 if(colormask)
459 glDepthMask(GL_FALSE);
460 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
461 nocolorshader->set();
462 colormask = false;
464 startquery(oe->query);
465 drawbb(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin));
466 endquery(oe->query);
468 if(!colormask)
470 glDepthMask(GL_TRUE);
471 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, refracting && renderpath!=R_FIXEDFUNCTION ? GL_FALSE : GL_TRUE);
475 bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size)
477 loopoctabox(o, size, bo, br)
479 ivec co(i, o.x, o.y, o.z, size);
480 if(c[i].ext && c[i].ext->va)
482 vtxarray *va = c[i].ext->va;
483 if(va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue;
485 if(c[i].children && bboccluded(bo, br, c[i].children, co, size>>1)) continue;
486 return false;
488 return true;
491 VAR(outline, 0, 0, 0xFFFFFF);
492 VAR(dtoutline, 0, 0, 1);
494 void renderoutline()
496 if(!editmode || !outline) return;
498 notextureshader->set();
500 glDisable(GL_TEXTURE_2D);
501 glEnableClientState(GL_VERTEX_ARRAY);
503 glPushMatrix();
505 glEnable(GL_POLYGON_OFFSET_LINE);
506 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
507 glColor3ub((outline>>16)&0xFF, (outline>>8)&0xFF, outline&0xFF);
509 if(dtoutline) glDisable(GL_DEPTH_TEST);
511 resetorigin();
512 GLuint vbufGL = 0, ebufGL = 0;
513 for(vtxarray *va = visibleva; va; va = va->next)
515 lodlevel &lod = va->curlod ? va->l1 : va->l0;
516 if(!lod.texs || va->occluded >= OCCLUDE_GEOM) continue;
518 setorigin(va);
520 bool vbufchanged = true;
521 if(hasVBO)
523 if(vbufGL == va->vbufGL) vbufchanged = false;
524 else
526 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbufGL);
527 vbufGL = va->vbufGL;
529 if(ebufGL != lod.ebufGL)
531 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.ebufGL);
532 ebufGL = lod.ebufGL;
535 if(vbufchanged) glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &(va->vbuf[0].x));
537 drawvatris(va, 3*lod.tris, lod.ebuf);
538 xtravertsva += va->verts;
541 if(dtoutline) glEnable(GL_DEPTH_TEST);
543 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
544 glDisable(GL_POLYGON_OFFSET_LINE);
546 glPopMatrix();
548 if(hasVBO)
550 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
551 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
553 glDisableClientState(GL_VERTEX_ARRAY);
554 glEnable(GL_TEXTURE_2D);
556 defaultshader->set();
559 void rendershadowmapreceivers()
561 if(!hasBE) return;
563 static Shader *shadowmapshader = NULL;
564 if(!shadowmapshader) shadowmapshader = lookupshaderbyname("shadowmapreceiver");
565 shadowmapshader->set();
567 glDisable(GL_TEXTURE_2D);
568 glEnableClientState(GL_VERTEX_ARRAY);
570 glCullFace(GL_BACK);
571 glDepthMask(GL_FALSE);
572 glDepthFunc(GL_GREATER);
574 extern int apple_minmax_bug;
575 if(!apple_minmax_bug) glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
577 glEnable(GL_BLEND);
578 glBlendEquation_(GL_MAX_EXT);
579 glBlendFunc(GL_ONE, GL_ONE);
581 glPushMatrix();
583 resetorigin();
584 GLuint vbufGL = 0, ebufGL = 0;
585 for(vtxarray *va = visibleva; va; va = va->next)
587 lodlevel &lod = va->curlod ? va->l1 : va->l0;
588 if(va->curvfc >= VFC_FOGGED || !isshadowmapreceiver(va)) continue;
590 setorigin(va);
592 bool vbufchanged = true;
593 if(hasVBO)
595 if(vbufGL == va->vbufGL) vbufchanged = false;
596 else
598 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbufGL);
599 vbufGL = va->vbufGL;
601 if(ebufGL != lod.ebufGL)
603 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.ebufGL);
604 ebufGL = lod.ebufGL;
607 if(vbufchanged) glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &(va->vbuf[0].x));
609 drawvatris(va, 3*lod.tris, lod.ebuf);
610 xtravertsva += va->verts;
613 glPopMatrix();
615 glDisable(GL_BLEND);
616 glBlendEquation_(GL_FUNC_ADD_EXT);
618 glCullFace(GL_FRONT);
619 glDepthMask(GL_TRUE);
620 glDepthFunc(GL_LESS);
622 if(!apple_minmax_bug) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
624 if(hasVBO)
626 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
627 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
629 glDisableClientState(GL_VERTEX_ARRAY);
630 glEnable(GL_TEXTURE_2D);
633 VARP(maxdynlights, 0, MAXDYNLIGHTS, MAXDYNLIGHTS);
634 VARP(dynlightdist, 0, 1024, 10000);
636 struct dynlight
638 vec o;
639 float radius, dist;
640 vec color;
641 int fade, peak, expire;
643 float calcradius() const
645 return peak>0 && expire-lastmillis>fade ? (radius/peak)*(peak-(expire-lastmillis-fade)) : radius;
648 float intensity() const
650 if(fade + peak)
652 int remaining = expire - lastmillis;
653 return remaining > fade ? 1.0f - float(remaining - fade)/peak : float(remaining)/fade;
655 return 1.0f;
659 vector<dynlight> dynlights;
660 vector<dynlight *> closedynlights, visibledynlights;
662 void adddynlight(const vec &o, float radius, const vec &color, int fade, int peak)
664 if(o.dist(camera1->o) > dynlightdist) return;
666 int insert = 0, expire = fade + peak + lastmillis;
667 loopvrev(dynlights) if(expire>=dynlights[i].expire) { insert = i+1; break; }
668 dynlight d;
669 d.o = o;
670 d.radius = radius;
671 d.color = color;
672 d.fade = fade;
673 d.peak = peak;
674 d.expire = expire;
675 dynlights.insert(insert, d);
678 void cleardynlights()
680 int faded = -1;
681 loopv(dynlights) if(lastmillis<dynlights[i].expire) { faded = i; break; }
682 if(faded<0) dynlights.setsizenodelete(0);
683 else if(faded>0) dynlights.remove(0, faded);
686 int limitdynlights()
688 closedynlights.setsizenodelete(0);
689 if(maxdynlights) loopvj(dynlights)
691 dynlight &d = dynlights[j];
692 d.dist = camera1->o.dist(d.o) - d.calcradius();
693 if(d.dist>dynlightdist || isvisiblesphere(d.radius, d.o) >= VFC_FOGGED) continue;
694 int insert = 0;
695 loopvrev(closedynlights) if(d.dist >= closedynlights[i]->dist) { insert = i+1; break; }
696 if(closedynlights.length()>=maxdynlights)
698 if(insert+1>=maxdynlights) continue;
699 closedynlights.drop();
701 closedynlights.insert(insert, &d);
703 return closedynlights.length();
706 void dynlightreaching(const vec &target, vec &color, vec &dir)
708 vec dyncolor(0, 0, 0);//, dyndir(0, 0, 0);
709 loopv(dynlights)
711 dynlight &d = dynlights[i];
712 vec ray(d.o);
713 ray.sub(target);
714 float mag = ray.magnitude(), radius = d.calcradius();
715 if(radius<=0 || mag >= radius) continue;
716 float intensity = d.intensity()*(1 - mag/radius);
717 dyncolor.add(vec(d.color).mul(intensity));
718 //dyndir.add(ray.mul(intensity/mag));
720 #if 0
721 if(!dyndir.iszero())
723 dyndir.normalize();
724 float x = dyncolor.magnitude(), y = color.magnitude();
725 if(x+y>0)
727 dir.mul(x);
728 dyndir.mul(y);
729 dir.add(dyndir).div(x+y);
730 if(dir.iszero()) dir = vec(0, 0, 1);
731 else dir.normalize();
734 #endif
735 color.add(dyncolor);
738 void setdynlights(vtxarray *va)
740 visibledynlights.setsizenodelete(0);
741 loopv(closedynlights)
743 dynlight &d = *closedynlights[i];
744 if(d.o.dist_to_bb(va->min, va->max) < d.calcradius()) visibledynlights.add(&d);
746 if(visibledynlights.empty()) return;
748 static string vertexparams[MAXDYNLIGHTS] = { "" }, pixelparams[MAXDYNLIGHTS] = { "" };
749 if(!*vertexparams[0]) loopi(MAXDYNLIGHTS)
751 s_sprintf(vertexparams[i])("dynlight%dpos", i);
752 s_sprintf(pixelparams[i])("dynlight%dcolor", i);
755 loopv(visibledynlights)
757 dynlight &d = *visibledynlights[i];
758 setenvparamfv(vertexparams[i], SHPARAM_VERTEX, 10+i, vec4(d.o, 1).sub(ivec(va->x, va->y, va->z).mask(~VVEC_INT_MASK).tovec()).mul(1<<VVEC_FRAC).v);
759 vec color(d.color);
760 color.mul(2*d.intensity());
761 float radius = d.calcradius();
762 setenvparamf(pixelparams[i], SHPARAM_PIXEL, 10+i, color.x, color.y, color.z, -1.0f/(radius*radius*(1<<(2*VVEC_FRAC))));
766 float orientation_tangent [3][4] = { { 0,1, 0,0 }, { 1,0, 0,0 }, { 1,0,0,0 }};
767 float orientation_binormal[3][4] = { { 0,0,-1,0 }, { 0,0,-1,0 }, { 0,1,0,0 }};
769 struct renderstate
771 bool colormask, depthmask, texture;
772 GLuint vbufGL, ebufGL;
773 float fogplane;
774 int diffusetmu, lightmaptmu, glowtmu, fogtmu, causticstmu;
775 GLfloat color[4];
777 renderstate() : colormask(true), depthmask(true), texture(true), vbufGL(0), ebufGL(0), fogplane(-1), diffusetmu(0), lightmaptmu(1), glowtmu(-1), fogtmu(-1), causticstmu(-1)
779 loopk(4) color[k] = 1;
783 void renderquery(renderstate &cur, occludequery *query, vtxarray *va)
785 setorigin(va);
786 nocolorshader->set();
787 if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
788 if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); }
790 startquery(query);
792 ivec origin(va->x, va->y, va->z);
793 origin.mask(~VVEC_INT_MASK);
795 vec camera(camera1->o);
796 if(reflecting && !refracting) camera.z = reflecting;
798 ivec bbmin, bbmax;
799 if(va->children || va->mapmodels || va->l0.matsurfs || va->l0.sky || va->l0.explicitsky)
801 bbmin = ivec(va->x, va->y, va->z);
802 bbmax = ivec(va->size, va->size, va->size);
804 else
806 bbmin = va->min;
807 bbmax = va->max;
808 bbmax.sub(bbmin);
811 drawbb(bbmin.sub(origin).mul(1<<VVEC_FRAC),
812 bbmax.mul(1<<VVEC_FRAC),
813 vec(camera).sub(origin.tovec()).mul(1<<VVEC_FRAC));
815 endquery(query);
818 enum
820 RENDERPASS_LIGHTMAP = 0,
821 RENDERPASS_COLOR,
822 RENDERPASS_Z,
823 RENDERPASS_GLOW,
824 RENDERPASS_CAUSTICS,
825 RENDERPASS_FOG
828 void renderva(renderstate &cur, vtxarray *va, lodlevel &lod, int pass = RENDERPASS_LIGHTMAP, bool fogpass = false)
830 if(pass==RENDERPASS_GLOW)
832 bool noglow = true;
833 loopi(lod.texs)
835 Slot &slot = lookuptexture(lod.eslist[i].texture);
836 loopvj(slot.sts)
838 Slot::Tex &t = slot.sts[j];
839 if(t.type==TEX_GLOW && t.combined<0) noglow = false;
842 if(noglow) return;
845 setorigin(va, pass==RENDERPASS_LIGHTMAP && !envmapping);
846 bool vbufchanged = true;
847 if(hasVBO)
849 if(cur.vbufGL == va->vbufGL) vbufchanged = false;
850 else
852 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbufGL);
853 cur.vbufGL = va->vbufGL;
855 if(cur.ebufGL != lod.ebufGL)
857 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.ebufGL);
858 cur.ebufGL = lod.ebufGL;
861 if(vbufchanged) glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &(va->vbuf[0].x));
862 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
864 if(pass==RENDERPASS_Z)
866 if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
867 extern int apple_glsldepth_bug;
868 if(renderpath!=R_GLSLANG || !apple_glsldepth_bug)
870 nocolorshader->set();
871 drawvatris(va, 3*lod.tris, lod.ebuf);
873 else
875 static Shader *nocolorglslshader = NULL;
876 if(!nocolorglslshader) nocolorglslshader = lookupshaderbyname("nocolorglsl");
877 Slot *lastslot = NULL;
878 int lastdraw = 0, offset = 0;
879 loopi(lod.texs)
881 Slot &slot = lookuptexture(lod.eslist[i].texture);
882 if(lastslot && (slot.shader->type&SHADER_GLSLANG) != (lastslot->shader->type&SHADER_GLSLANG) && offset > lastdraw)
884 (lastslot->shader->type&SHADER_GLSLANG ? nocolorglslshader : nocolorshader)->set();
885 drawvatris(va, offset-lastdraw, lod.ebuf+lastdraw);
886 lastdraw = offset;
888 lastslot = &slot;
889 offset += lod.eslist[i].length[5];
891 if(offset > lastdraw)
893 (lastslot->shader->type&SHADER_GLSLANG ? nocolorglslshader : nocolorshader)->set();
894 drawvatris(va, offset-lastdraw, lod.ebuf+lastdraw);
897 xtravertsva += va->verts;
898 return;
901 if(refracting && renderpath!=R_FIXEDFUNCTION)
903 float fogplane = refracting - (va->z & ~VVEC_INT_MASK);
904 if(cur.fogplane!=fogplane)
906 cur.fogplane = fogplane;
907 setfogplane(1.0f/(1<<VVEC_FRAC), fogplane);
910 if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); }
912 if((pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_COLOR) && (fogpass ? va->z+va->size<=refracting-waterfog : va->curvfc==VFC_FOGGED))
914 // this case is never reached if called from rendergeommultipass()
915 static Shader *fogshader = NULL;
916 if(!fogshader) fogshader = lookupshaderbyname("fogworld");
917 fogshader->set();
919 if(cur.texture)
921 cur.texture = false;
922 glDisable(GL_TEXTURE_2D);
923 if(fogpass && cur.fogtmu<0)
925 uchar wcol[3];
926 getwatercolour(wcol);
927 glColor3ubv(wcol);
929 if(pass==RENDERPASS_LIGHTMAP)
931 if(renderpath!=R_FIXEDFUNCTION) glDisableClientState(GL_COLOR_ARRAY);
932 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
933 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
934 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
935 glDisable(GL_TEXTURE_2D);
936 if(cur.fogtmu>=0)
938 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
939 glDisable(GL_TEXTURE_1D);
941 if(cur.causticstmu>=0) loopi(2)
943 glActiveTexture_(GL_TEXTURE0_ARB+cur.causticstmu+i);
944 glDisable(GL_TEXTURE_2D);
946 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
947 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
951 drawvatris(va, 3*lod.tris, lod.ebuf);
952 vtris += lod.tris;
953 vverts += va->verts;
954 return;
957 if(!cur.texture)
959 cur.texture = true;
960 if(pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_COLOR)
962 glEnable(GL_TEXTURE_2D);
963 if(fogpass && cur.fogtmu<0) glColor4fv(cur.color);
965 if(pass==RENDERPASS_LIGHTMAP)
967 if(renderpath!=R_FIXEDFUNCTION) glEnableClientState(GL_COLOR_ARRAY);
968 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
969 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
970 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
971 glEnable(GL_TEXTURE_2D);
972 if(cur.fogtmu>=0)
974 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
975 glEnable(GL_TEXTURE_1D);
977 if(cur.causticstmu>=0) loopi(2)
979 glActiveTexture_(GL_TEXTURE0_ARB+cur.causticstmu+i);
980 glEnable(GL_TEXTURE_2D);
982 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
983 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
984 vbufchanged = true;
988 if(pass==RENDERPASS_FOG || (cur.fogtmu>=0 && (pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_GLOW)))
990 if(pass==RENDERPASS_LIGHTMAP) glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
991 else if(pass==RENDERPASS_GLOW) glActiveTexture_(GL_TEXTURE1_ARB);
992 GLfloat s[4] = { 0, 0, -1.0f/(waterfog<<VVEC_FRAC), (refracting - (va->z & ~VVEC_INT_MASK))/waterfog };
993 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
994 if(pass==RENDERPASS_LIGHTMAP) glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
995 else if(pass==RENDERPASS_GLOW) glActiveTexture_(GL_TEXTURE0_ARB);
998 bool shadowmapreceiver = false;
999 if(pass==RENDERPASS_CAUSTICS || pass==RENDERPASS_FOG)
1001 drawvatris(va, 3*lod.tris, lod.ebuf);
1002 xtravertsva += va->verts;
1003 return;
1005 else if(pass==RENDERPASS_LIGHTMAP)
1007 if(renderpath!=R_FIXEDFUNCTION)
1009 if(!envmapping && !va->curlod) shadowmapreceiver = isshadowmapreceiver(va);
1010 if(vbufchanged) glColorPointer(3, GL_UNSIGNED_BYTE, VTXSIZE, floatvtx ? &(((fvertex *)va->vbuf)[0].n) : &(va->vbuf[0].n));
1011 setenvparamfv("camera", SHPARAM_VERTEX, 4, vec4(camera1->o, 1).sub(ivec(va->x, va->y, va->z).mask(~VVEC_INT_MASK).tovec()).mul(1<<VVEC_FRAC).v);
1013 setdynlights(va);
1015 if(vbufchanged)
1017 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1018 glTexCoordPointer(2, GL_SHORT, VTXSIZE, floatvtx ? &(((fvertex *)va->vbuf)[0].u) : &(va->vbuf[0].u));
1019 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1023 ushort *ebuf = lod.ebuf;
1024 int lastlm = -1, lastxs = -1, lastys = -1, lastl = -1, lasto = -1, lastenvmap = -1, envmapped = 0;
1025 bool mtglow = false, shadowmapped = false;
1026 float lastscale = -1;
1027 Slot *lastslot = NULL;
1028 Shader *lastshader = NULL;
1029 loopi(lod.texs)
1031 const elementset &es = lod.eslist[i];
1032 Slot &slot = lookuptexture(es.texture);
1033 Texture *tex = slot.sts[0].t;
1034 Shader *s = slot.shader;
1036 extern vector<GLuint> lmtexids;
1037 int lmid = es.lmid, curlm = pass==RENDERPASS_LIGHTMAP ? (int)lmtexids[lmid] : -1;
1038 if(s && renderpath!=R_FIXEDFUNCTION && pass==RENDERPASS_LIGHTMAP)
1040 int tmu = cur.lightmaptmu+1;
1041 if(s->type&SHADER_NORMALSLMS)
1043 if((!lastslot || s->type!=lastslot->shader->type || curlm!=lastlm) && (lmid<LMID_RESERVED || lightmaps[lmid-LMID_RESERVED].type==LM_BUMPMAP0))
1045 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1046 glBindTexture(GL_TEXTURE_2D, lmtexids[lmid+1]);
1048 tmu++;
1050 if(s->type&SHADER_ENVMAP)
1052 int envmap = es.envmap;
1053 if((!lastslot || s->type!=lastslot->shader->type || (envmap==EMID_CUSTOM ? &slot!=lastslot : envmap!=lastenvmap)) && hasCM)
1055 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1056 if(!(envmapped & (1<<tmu)))
1058 glEnable(GL_TEXTURE_CUBE_MAP_ARB);
1059 envmapped |= 1<<tmu;
1061 GLuint emtex = 0;
1062 if(envmap==EMID_CUSTOM) loopvj(slot.sts)
1064 Slot::Tex &t = slot.sts[j];
1065 if(t.type==TEX_ENVMAP && t.t) { emtex = t.t->gl; break; }
1067 if(!emtex) emtex = lookupenvmap(envmap);
1068 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, emtex);
1069 lastenvmap = envmap;
1071 tmu++;
1073 glActiveTexture_(GL_TEXTURE0_ARB);
1075 if(curlm!=lastlm && pass==RENDERPASS_LIGHTMAP)
1077 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1078 glBindTexture(GL_TEXTURE_2D, curlm);
1079 lastlm = curlm;
1080 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1082 if(&slot!=lastslot)
1084 if(pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_COLOR) glBindTexture(GL_TEXTURE_2D, tex->gl);
1085 if(renderpath==R_FIXEDFUNCTION)
1087 bool noglow = true;
1088 if(pass==RENDERPASS_GLOW || cur.glowtmu>=0) loopvj(slot.sts)
1090 Slot::Tex &t = slot.sts[j];
1091 if(t.type==TEX_GLOW && t.combined<0)
1093 if(cur.glowtmu>=0)
1095 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1096 if(!mtglow) { glEnable(GL_TEXTURE_2D); mtglow = true; }
1098 glBindTexture(GL_TEXTURE_2D, t.t->gl);
1099 noglow = false;
1102 if(pass==RENDERPASS_GLOW && noglow)
1104 ebuf += es.length[5];
1105 continue;
1107 else if(mtglow)
1109 if(noglow) { glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu); glDisable(GL_TEXTURE_2D); mtglow = false; }
1110 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1113 else if(pass==RENDERPASS_LIGHTMAP && s)
1115 int tmu = cur.lightmaptmu+1;
1116 if(s->type&SHADER_NORMALSLMS) tmu++;
1117 if(s->type&SHADER_ENVMAP) tmu++;
1118 loopvj(slot.sts)
1120 Slot::Tex &t = slot.sts[j];
1121 if(t.type==TEX_DIFFUSE || t.type==TEX_ENVMAP || t.combined>=0) continue;
1122 glActiveTexture_(GL_TEXTURE0_ARB+tmu++);
1123 glBindTexture(GL_TEXTURE_2D, t.t->gl);
1125 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1127 lastshader = NULL;
1129 lastslot = &slot;
1132 float scale = slot.sts[0].scale;
1133 if(!scale) scale = 1;
1134 loopk(shadowmapreceiver ? 2 : 1) loopl(3)
1136 int dim = 2*l+k;
1137 ushort offset = dim>0 ? es.length[dim-1] : 0,
1138 len = es.length[dim + (shadowmapreceiver ? 0 : 1)] - offset;
1139 if(!len) continue;
1141 if(pass==RENDERPASS_LIGHTMAP && s && (lastshader!=s || shadowmapped!=(k!=0)))
1143 if(refracting && hasFBO && waterrefract && waterfade)
1145 if(k) s->variant(min(s->variants[3].length()-1, visibledynlights.length()), 3)->set(&slot);
1146 else s->variant(min(s->variants[2].length()-1, visibledynlights.length()), 2)->set(&slot);
1148 else if(k) s->variant(min(s->variants[1].length()-1, visibledynlights.length()), 1)->set(&slot);
1149 else if(visibledynlights.empty()) s->set(&slot);
1150 else s->variant(min(s->variants[0].length()-1, visibledynlights.length()-1))->set(&slot);
1151 shadowmapped = k!=0;
1152 lastshader = s;
1155 if(lastl!=l || lastxs!=tex->xs || lastys!=tex->ys || lastscale!=scale || (s && s->type&SHADER_GLSLANG))
1157 static const int si[] = { 1, 0, 0 };
1158 static const int ti[] = { 2, 2, 1 };
1160 GLfloat sgen[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1161 sgen[si[l]] = 8.0f/scale/(tex->xs<<VVEC_FRAC);
1162 GLfloat tgen[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1163 tgen[ti[l]] = (l <= 1 ? -8.0f : 8.0f)/scale/(tex->ys<<VVEC_FRAC);
1165 if(renderpath==R_FIXEDFUNCTION)
1167 glTexGenfv(GL_S, GL_OBJECT_PLANE, sgen);
1168 glTexGenfv(GL_T, GL_OBJECT_PLANE, tgen);
1169 // KLUGE: workaround for buggy nvidia drivers
1170 // object planes are somehow invalid unless texgen is toggled
1171 extern int nvidia_texgen_bug;
1172 if(nvidia_texgen_bug)
1174 glDisable(GL_TEXTURE_GEN_S);
1175 glDisable(GL_TEXTURE_GEN_T);
1176 glEnable(GL_TEXTURE_GEN_S);
1177 glEnable(GL_TEXTURE_GEN_T);
1180 if(mtglow)
1182 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1183 glTexGenfv(GL_S, GL_OBJECT_PLANE, sgen);
1184 glTexGenfv(GL_T, GL_OBJECT_PLANE, tgen);
1185 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1188 else
1190 // have to pass in env, otherwise same problem as fixed function
1191 setlocalparamfv("texgenS", SHPARAM_VERTEX, 0, sgen);
1192 setlocalparamfv("texgenT", SHPARAM_VERTEX, 1, tgen);
1195 lastxs = tex->xs;
1196 lastys = tex->ys;
1197 lastl = l;
1198 lastscale = scale;
1201 if(renderpath!=R_FIXEDFUNCTION && pass==RENDERPASS_LIGHTMAP && s && s->type&SHADER_NORMALSLMS && (lasto!=l || s->type&SHADER_GLSLANG))
1203 setlocalparamfv("orienttangent", SHPARAM_VERTEX, 2, orientation_tangent[l]);
1204 setlocalparamfv("orientbinormal", SHPARAM_VERTEX, 3, orientation_binormal[l]);
1205 lasto = l;
1208 ushort minvert = es.minvert[dim], maxvert = es.maxvert[dim];
1209 if(!shadowmapreceiver) { minvert = min(minvert, es.minvert[dim+1]); maxvert = max(maxvert, es.maxvert[dim+1]); }
1210 drawvatris(va, len, &ebuf[offset], minvert, maxvert);
1212 ebuf += es.length[5];
1215 if(mtglow)
1217 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1218 glDisable(GL_TEXTURE_2D);
1220 if(envmapped)
1222 loopi(4) if(envmapped&(1<<i))
1224 glActiveTexture_(GL_TEXTURE0_ARB+i);
1225 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1228 if(mtglow || envmapped) glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1230 vtris += lod.tris;
1231 vverts += va->verts;
1234 VAR(oqdist, 0, 256, 1024);
1235 VAR(zpass, 0, 1, 1);
1236 VAR(glowpass, 0, 1, 1);
1238 extern int ati_texgen_bug;
1240 static void setuptexgen(int dims = 2)
1242 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1243 glEnable(GL_TEXTURE_GEN_S);
1244 if(dims>=2)
1246 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1247 glEnable(GL_TEXTURE_GEN_T);
1248 if(ati_texgen_bug) glEnable(GL_TEXTURE_GEN_R); // should not be needed, but apparently makes some ATI drivers happy
1252 static void disabletexgen(int dims = 2)
1254 glDisable(GL_TEXTURE_GEN_S);
1255 if(dims>=2)
1257 glDisable(GL_TEXTURE_GEN_T);
1258 if(ati_texgen_bug) glDisable(GL_TEXTURE_GEN_R);
1262 GLuint fogtex = 0;
1264 void createfogtex()
1266 glGenTextures(1, &fogtex);
1267 uchar buf[4] = { 255, 0, 255, 255 };
1268 createtexture(fogtex, 2, 1, buf, 3, false, GL_LUMINANCE_ALPHA, GL_TEXTURE_1D);
1271 #define NUMCAUSTICS 32
1273 VAR(causticscale, 0, 100, 10000);
1274 VAR(causticmillis, 0, 75, 1000);
1275 VARP(caustics, 0, 1, 1);
1277 static Texture *caustictex[NUMCAUSTICS] = { NULL };
1279 void loadcaustics()
1281 if(caustictex[0]) return;
1282 loopi(NUMCAUSTICS)
1284 s_sprintfd(name)("<mad:0.6,0.4>packages/caustics/caust%.2d.png", i);
1285 caustictex[i] = textureload(name);
1289 void setupcaustics(int tmu, GLfloat *color = NULL)
1291 if(!caustictex[0]) loadcaustics();
1293 GLfloat s[4] = { 0.011f, 0, 0.0066f, 0 };
1294 GLfloat t[4] = { 0, 0.011f, 0.0066f, 0 };
1295 loopk(3)
1297 s[k] *= 100.0f/(causticscale<<VVEC_FRAC);
1298 t[k] *= 100.0f/(causticscale<<VVEC_FRAC);
1300 int tex = (lastmillis/causticmillis)%NUMCAUSTICS;
1301 float frac = float(lastmillis%causticmillis)/causticmillis;
1302 if(color) color[3] = frac;
1303 else glColor4f(1, 1, 1, frac);
1304 loopi(2)
1306 glActiveTexture_(GL_TEXTURE0_ARB+tmu+i);
1307 glEnable(GL_TEXTURE_2D);
1308 glBindTexture(GL_TEXTURE_2D, caustictex[(tex+i)%NUMCAUSTICS]->gl);
1309 if(renderpath==R_FIXEDFUNCTION || !i)
1311 setuptexgen();
1312 setuptmu(tmu+i, !i ? "= T" : "T , P @ Ca");
1313 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
1314 glTexGenfv(GL_T, GL_OBJECT_PLANE, t);
1317 if(renderpath!=R_FIXEDFUNCTION)
1319 static Shader *causticshader = NULL;
1320 if(!causticshader) causticshader = lookupshaderbyname("caustic");
1321 causticshader->set();
1322 setlocalparamf("frameoffset", SHPARAM_PIXEL, 0, frac, frac, frac);
1326 void setupTMUs(renderstate &cur, bool causticspass, bool fogpass)
1328 extern GLuint shadowmapfb;
1329 if(!reflecting && !refracting && !envmapping && shadowmap && shadowmapfb)
1331 glDisableClientState(GL_VERTEX_ARRAY);
1333 if(hasVBO)
1335 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1336 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1339 rendershadowmap();
1341 glEnableClientState(GL_VERTEX_ARRAY);
1344 if(renderpath==R_FIXEDFUNCTION)
1346 if(nolights) cur.lightmaptmu = -1;
1347 else if(maxtmus>=3)
1349 if(maxtmus>=4 && causticspass)
1351 cur.causticstmu = 0;
1352 cur.diffusetmu = 2;
1353 cur.lightmaptmu = 3;
1354 if(maxtmus>=5)
1356 if(fogpass) cur.fogtmu = 4;
1357 else if(glowpass) cur.glowtmu = 4;
1360 else if(fogpass && !causticspass) cur.fogtmu = 2;
1361 else if(glowpass) cur.glowtmu = 2;
1363 if(cur.glowtmu>=0)
1365 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1366 setuptexgen();
1367 setuptmu(cur.glowtmu, "P + T");
1369 if(cur.fogtmu>=0)
1371 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
1372 glEnable(GL_TEXTURE_1D);
1373 setuptexgen(1);
1374 setuptmu(cur.fogtmu, "C , P @ Ta");
1375 if(!fogtex) createfogtex();
1376 glBindTexture(GL_TEXTURE_1D, fogtex);
1377 uchar wcol[3];
1378 getwatercolour(wcol);
1379 loopk(3) cur.color[k] = wcol[k]/255.0f;
1381 if(cur.causticstmu>=0) setupcaustics(cur.causticstmu, cur.color);
1383 else
1385 glEnableClientState(GL_COLOR_ARRAY);
1386 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glEnable(GL_TEXTURE_2D); }
1387 glActiveTexture_(GL_TEXTURE0_ARB);
1388 setenvparamf("ambient", SHPARAM_PIXEL, 5, hdr.ambient/255.0f, hdr.ambient/255.0f, hdr.ambient/255.0f);
1389 setenvparamf("millis", SHPARAM_VERTEX, 6, lastmillis/1000.0f, lastmillis/1000.0f, lastmillis/1000.0f);
1392 glColor4fv(cur.color);
1394 if(cur.lightmaptmu>=0)
1396 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1397 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1399 setuptmu(cur.lightmaptmu, "P * T x 2");
1400 glEnable(GL_TEXTURE_2D);
1401 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1402 glMatrixMode(GL_TEXTURE);
1403 glLoadIdentity();
1404 glScalef(1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f);
1405 glMatrixMode(GL_MODELVIEW);
1407 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1408 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1409 glEnable(GL_TEXTURE_2D);
1410 setuptmu(cur.diffusetmu, cur.diffusetmu>0 ? "P * T" : "= T");
1413 setuptexgen();
1416 void cleanupTMUs(renderstate &cur)
1418 if(cur.lightmaptmu>=0)
1420 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1421 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1423 resettmu(cur.lightmaptmu);
1424 glDisable(GL_TEXTURE_2D);
1425 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1426 glMatrixMode(GL_TEXTURE);
1427 glLoadIdentity();
1428 glMatrixMode(GL_MODELVIEW);
1430 if(cur.glowtmu>=0)
1432 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1433 resettmu(cur.glowtmu);
1434 disabletexgen();
1435 glDisable(GL_TEXTURE_2D);
1437 if(cur.fogtmu>=0)
1439 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
1440 resettmu(cur.fogtmu);
1441 disabletexgen(1);
1442 glDisable(GL_TEXTURE_1D);
1444 if(cur.causticstmu>=0) loopi(2)
1446 glActiveTexture_(GL_TEXTURE0_ARB+cur.causticstmu+i);
1447 resettmu(cur.causticstmu+i);
1448 disabletexgen();
1449 glDisable(GL_TEXTURE_2D);
1452 if(cur.lightmaptmu>=0)
1454 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1455 resettmu(cur.diffusetmu);
1456 glDisable(GL_TEXTURE_2D);
1459 disabletexgen();
1461 if(renderpath!=R_FIXEDFUNCTION)
1463 glDisableClientState(GL_COLOR_ARRAY);
1464 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glDisable(GL_TEXTURE_2D); }
1467 if(cur.lightmaptmu>=0)
1469 glActiveTexture_(GL_TEXTURE0_ARB);
1470 glClientActiveTexture_(GL_TEXTURE0_ARB);
1471 glEnable(GL_TEXTURE_2D);
1475 #define FIRSTVA (reflecting && !refracting && camera1->o.z >= reflecting ? reflectedva : visibleva)
1476 #define NEXTVA (reflecting && !refracting && camera1->o.z >= reflecting ? va->rnext : va->next)
1478 void rendergeommultipass(renderstate &cur, int pass, bool fogpass)
1480 cur.vbufGL = cur.ebufGL = 0;
1481 for(vtxarray *va = FIRSTVA; va; va = NEXTVA)
1483 lodlevel &lod = va->curlod ? va->l1 : va->l0;
1484 if(!lod.texs || va->occluded >= OCCLUDE_GEOM) continue;
1485 if(refracting || (reflecting && camera1->o.z < reflecting))
1487 if(va->curvfc == VFC_FOGGED || (refracting && camera1->o.z >= refracting ? va->min.z > refracting : va->max.z <= refracting)) continue;
1488 if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
1490 else if(reflecting)
1492 if(va->max.z <= reflecting || (va->rquery && checkquery(va->rquery))) continue;
1493 if(va->rquery && checkquery(va->rquery)) continue;
1495 if(fogpass ? va->z+va->size<=refracting-waterfog : va->curvfc==VFC_FOGGED) continue;
1496 renderva(cur, va, lod, pass, fogpass);
1500 void rendergeom(bool causticspass, bool fogpass)
1502 renderstate cur;
1504 if(causticspass && ((renderpath==R_FIXEDFUNCTION && maxtmus<2) || !causticscale || !causticmillis)) causticspass = false;
1506 glEnableClientState(GL_VERTEX_ARRAY);
1508 if(!reflecting && !refracting)
1510 flipqueries();
1511 vtris = vverts = 0;
1514 bool doOQ = !refracting && (reflecting ? camera1->o.z >= reflecting && hasOQ && oqfrags && oqreflect : zpass!=0);
1515 if(!doOQ)
1517 setupTMUs(cur, causticspass, fogpass);
1518 if(shadowmap) pushshadowmap();
1521 limitdynlights();
1523 glPushMatrix();
1525 resetorigin();
1527 for(vtxarray *va = FIRSTVA; va; va = NEXTVA)
1529 lodlevel &lod = va->curlod ? va->l1 : va->l0;
1530 if(!lod.texs) continue;
1531 if(refracting || (reflecting && camera1->o.z < reflecting))
1533 if(va->curvfc == VFC_FOGGED || (refracting && camera1->o.z >= refracting ? va->min.z > refracting : va->max.z <= reflecting) || va->occluded >= OCCLUDE_GEOM) continue;
1534 if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
1536 else if(reflecting)
1538 if(va->max.z <= reflecting) continue;
1539 if(doOQ)
1541 va->rquery = newquery(&va->rquery);
1542 if(!va->rquery) continue;
1543 if(va->occluded >= OCCLUDE_BB || va->curvfc == VFC_NOT_VISIBLE)
1545 renderquery(cur, va->rquery, va);
1546 continue;
1550 else if(hasOQ && oqfrags && (zpass || va->distance > oqdist) && !insideva(va, camera1->o))
1552 if(!zpass && va->query && va->query->owner == va)
1553 va->occluded = checkquery(va->query) ? min(va->occluded+1, OCCLUDE_BB) : OCCLUDE_NOTHING;
1554 if(zpass && va->parent &&
1555 (va->parent->occluded == OCCLUDE_PARENT ||
1556 (va->parent->occluded >= OCCLUDE_BB &&
1557 va->parent->query && va->parent->query->owner == va->parent && va->parent->query->fragments < 0)))
1559 va->query = NULL;
1560 if(va->occluded >= OCCLUDE_GEOM)
1562 va->occluded = OCCLUDE_PARENT;
1563 continue;
1566 else if(va->occluded >= OCCLUDE_GEOM)
1568 va->query = newquery(va);
1569 if(va->query) renderquery(cur, va->query, va);
1570 continue;
1572 else va->query = newquery(va);
1574 else
1576 va->query = NULL;
1577 va->occluded = OCCLUDE_NOTHING;
1580 if(!refracting)
1582 if(!reflecting) { if(va->query) startquery(va->query); }
1583 else if(camera1->o.z >= reflecting && va->rquery) startquery(va->rquery);
1586 renderva(cur, va, lod, doOQ ? RENDERPASS_Z : (nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP), fogpass);
1588 if(!refracting)
1590 if(!reflecting) { if(va->query) endquery(va->query); }
1591 else if(camera1->o.z >= reflecting && va->rquery) endquery(va->rquery);
1595 if(!cur.colormask) { cur.colormask = true; glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); }
1596 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
1598 if(doOQ)
1600 setupTMUs(cur, causticspass, fogpass);
1601 if(shadowmap)
1603 pushshadowmap();
1604 resetorigin();
1606 glDepthFunc(GL_LEQUAL);
1607 cur.vbufGL = cur.ebufGL = 0;
1608 cur.texture = 0;
1609 for(vtxarray **prevva = &FIRSTVA, *va = FIRSTVA; va; prevva = &NEXTVA, va = NEXTVA)
1611 lodlevel &lod = va->curlod ? va->l1 : va->l0;
1612 if(!lod.texs) continue;
1613 if(reflecting)
1615 if(va->max.z <= reflecting) continue;
1616 if(va->rquery && checkquery(va->rquery))
1618 if(va->occluded >= OCCLUDE_BB || va->curvfc == VFC_NOT_VISIBLE) *prevva = va->rnext;
1619 continue;
1622 else if(va->parent && va->parent->occluded >= OCCLUDE_BB && (!va->parent->query || va->parent->query->fragments >= 0))
1624 va->query = NULL;
1625 va->occluded = OCCLUDE_BB;
1626 continue;
1628 else if(va->query)
1630 va->occluded = checkquery(va->query) ? min(va->occluded+1, OCCLUDE_BB) : OCCLUDE_NOTHING;
1631 if(va->occluded >= OCCLUDE_GEOM) continue;
1633 else if(va->occluded == OCCLUDE_PARENT) va->occluded = OCCLUDE_NOTHING;
1635 renderva(cur, va, lod, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP, fogpass);
1637 glDepthFunc(GL_LESS);
1640 if(shadowmap) popshadowmap();
1642 cleanupTMUs(cur);
1644 if((causticspass && cur.causticstmu<0) || (renderpath==R_FIXEDFUNCTION && ((glowpass && cur.glowtmu<0) || (fogpass && cur.fogtmu<0))))
1646 glDepthFunc(GL_LEQUAL);
1647 glDepthMask(GL_FALSE);
1648 glEnable(GL_BLEND);
1649 static GLfloat zerofog[4] = { 0, 0, 0, 1 }, onefog[4] = { 1, 1, 1, 1 };
1650 GLfloat oldfogc[4];
1651 glGetFloatv(GL_FOG_COLOR, oldfogc);
1653 if(renderpath==R_FIXEDFUNCTION && glowpass && cur.glowtmu<0)
1655 glBlendFunc(GL_ONE, GL_ONE);
1656 glFogfv(GL_FOG_COLOR, zerofog);
1657 setuptexgen();
1658 if(cur.fogtmu>=0)
1660 setuptmu(0, "= T");
1661 glActiveTexture_(GL_TEXTURE1_ARB);
1662 glEnable(GL_TEXTURE_1D);
1663 setuptexgen(1);
1664 setuptmu(1, "C , P @ Ta");
1665 if(!fogtex) createfogtex();
1666 glBindTexture(GL_TEXTURE_1D, fogtex);
1667 glColor3f(0, 0, 0);
1668 glActiveTexture_(GL_TEXTURE0_ARB);
1670 else glColor3f(1, 1, 1);
1671 rendergeommultipass(cur, RENDERPASS_GLOW, fogpass);
1672 disabletexgen();
1673 if(cur.fogtmu>=0)
1675 resettmu(0);
1676 glActiveTexture_(GL_TEXTURE1_ARB);
1677 resettmu(1);
1678 disabletexgen();
1679 glDisable(GL_TEXTURE_1D);
1680 glActiveTexture_(GL_TEXTURE0_ARB);
1684 if(causticspass && cur.causticstmu<0)
1686 setupcaustics(0);
1687 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
1688 glFogfv(GL_FOG_COLOR, onefog);
1689 if(renderpath!=R_FIXEDFUNCTION && refracting) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
1690 rendergeommultipass(cur, RENDERPASS_CAUSTICS, fogpass);
1691 if(renderpath!=R_FIXEDFUNCTION && refracting) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1692 loopi(2)
1694 glActiveTexture_(GL_TEXTURE0_ARB+i);
1695 resettmu(i);
1696 if(renderpath==R_FIXEDFUNCTION || !i)
1698 resettmu(i);
1699 disabletexgen();
1701 if(i) glDisable(GL_TEXTURE_2D);
1703 glActiveTexture_(GL_TEXTURE0_ARB);
1706 if(renderpath==R_FIXEDFUNCTION && fogpass && cur.fogtmu<0)
1708 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1709 glDisable(GL_TEXTURE_2D);
1710 glEnable(GL_TEXTURE_1D);
1711 setuptexgen(1);
1712 if(!fogtex) createfogtex();
1713 glBindTexture(GL_TEXTURE_1D, fogtex);
1714 setuptexgen(1);
1715 uchar wcol[3];
1716 getwatercolour(wcol);
1717 glColor3ubv(wcol);
1718 rendergeommultipass(cur, RENDERPASS_FOG, fogpass);
1719 disabletexgen(1);
1720 glDisable(GL_TEXTURE_1D);
1721 glEnable(GL_TEXTURE_2D);
1724 glFogfv(GL_FOG_COLOR, oldfogc);
1725 glDisable(GL_BLEND);
1726 glDepthFunc(GL_LESS);
1727 glDepthMask(GL_TRUE);
1730 glPopMatrix();
1732 if(hasVBO)
1734 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1735 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1737 glDisableClientState(GL_VERTEX_ARRAY);
1740 void findreflectedvas(vector<vtxarray *> &vas, float z, bool refract, bool vfc = true)
1742 bool doOQ = hasOQ && oqfrags && oqreflect;
1743 loopv(vas)
1745 vtxarray *va = vas[i];
1746 if(!vfc) va->curvfc = VFC_NOT_VISIBLE;
1747 if(va->curvfc == VFC_FOGGED || va->z+va->size <= z || isvisiblecube(vec(va->x, va->y, va->z), va->size) >= VFC_FOGGED) continue;
1748 bool render = true;
1749 if(va->curvfc == VFC_FULL_VISIBLE)
1751 if(va->occluded >= OCCLUDE_BB) continue;
1752 if(va->occluded >= OCCLUDE_GEOM) render = false;
1754 if(render)
1756 if(va->curvfc == VFC_NOT_VISIBLE) va->distance = (int)vadist(va, camera1->o);
1757 if(!doOQ && va->distance > reflectdist) continue;
1758 va->rquery = NULL;
1759 vtxarray **vprev = &reflectedva, *vcur = reflectedva;
1760 while(vcur && va->distance > vcur->distance)
1762 vprev = &vcur->rnext;
1763 vcur = vcur->rnext;
1765 va->rnext = *vprev;
1766 *vprev = va;
1768 if(va->children->length()) findreflectedvas(*va->children, z, refract, va->curvfc != VFC_NOT_VISIBLE);
1772 void renderreflectedgeom(float z, bool refract, bool causticspass, bool fogpass)
1774 if(!refract && camera1->o.z >= z)
1776 reflectvfcP(z);
1777 reflectedva = NULL;
1778 findreflectedvas(varoot, z, refract);
1779 rendergeom(causticspass, fogpass);
1780 restorevfcP();
1782 else rendergeom(causticspass, fogpass);
1785 static GLuint skyvbufGL, skyebufGL;
1787 void renderskyva(vtxarray *va, lodlevel &lod, bool explicitonly = false)
1789 setorigin(va);
1791 bool vbufchanged = true;
1792 if(hasVBO)
1794 if(skyvbufGL == va->vbufGL) vbufchanged = false;
1795 else
1797 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbufGL);
1798 skyvbufGL = va->vbufGL;
1800 if(skyebufGL != lod.skybufGL)
1802 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, lod.skybufGL);
1803 skyebufGL = lod.skybufGL;
1806 if(vbufchanged) glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &(va->vbuf[0].x));
1808 drawvatris(va, explicitonly ? lod.explicitsky : lod.sky+lod.explicitsky, explicitonly ? lod.skybuf+lod.sky : lod.skybuf);
1810 if(!explicitonly) xtraverts += lod.sky/3;
1811 xtraverts += lod.explicitsky/3;
1814 int renderreflectedskyvas(vector<vtxarray *> &vas, float z, bool vfc = true)
1816 int rendered = 0;
1817 loopv(vas)
1819 vtxarray *va = vas[i];
1820 lodlevel &lod = va->curlod ? va->l1 : va->l0;
1821 if((vfc && va->curvfc == VFC_FULL_VISIBLE) && va->occluded >= OCCLUDE_BB) continue;
1822 if(va->z+va->size <= z || isvisiblecube(vec(va->x, va->y, va->z), va->size) == VFC_NOT_VISIBLE) continue;
1823 if(lod.sky+lod.explicitsky)
1825 renderskyva(va, lod);
1826 rendered++;
1828 if(va->children->length()) rendered += renderreflectedskyvas(*va->children, z, vfc && va->curvfc != VFC_NOT_VISIBLE);
1830 return rendered;
1833 bool rendersky(bool explicitonly, float zreflect)
1835 glEnableClientState(GL_VERTEX_ARRAY);
1837 glPushMatrix();
1839 resetorigin();
1841 skyvbufGL = skyebufGL = 0;
1843 int rendered = 0;
1844 if(zreflect)
1846 reflectvfcP(zreflect);
1847 rendered = renderreflectedskyvas(varoot, zreflect);
1848 restorevfcP();
1850 else for(vtxarray *va = visibleva; va; va = va->next)
1852 lodlevel &lod = va->curlod ? va->l1 : va->l0;
1853 if(va->occluded >= OCCLUDE_BB || !(explicitonly ? lod.explicitsky : lod.sky+lod.explicitsky)) continue;
1855 renderskyva(va, lod, explicitonly);
1856 rendered++;
1859 glPopMatrix();
1861 if(skyvbufGL) glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1862 if(skyebufGL) glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1864 glDisableClientState(GL_VERTEX_ARRAY);
1866 return rendered>0;