1 // renderva.cpp: handles the occlusion and rendering of vertex arrays
2
3 #include "engine.h"
4
drawtris(GLsizei numindices,const GLvoid * indices,ushort minvert,ushort maxvert)5 static inline void drawtris(GLsizei numindices, const GLvoid *indices, ushort minvert, ushort maxvert)
6 {
7 if(hasDRE) glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, numindices, GL_UNSIGNED_SHORT, indices);
8 else glDrawElements(GL_TRIANGLES, numindices, GL_UNSIGNED_SHORT, indices);
9 glde++;
10 }
11
drawvatris(vtxarray * va,GLsizei numindices,const GLvoid * indices)12 static inline void drawvatris(vtxarray *va, GLsizei numindices, const GLvoid *indices)
13 {
14 drawtris(numindices, indices, va->minvert, va->maxvert);
15 }
16
17 ///////// view frustrum culling ///////////////////////
18
19 plane vfcP[5]; // perpindictular vectors to view frustrum bounding planes
20 float vfcDfog; // far plane culling distance (fog limit).
21 float vfcDnear[5], vfcDfar[5];
22 float vfcfov, vfcfovy;
23
24 vtxarray *visibleva;
25
isfoggedsphere(float rad,const vec & cv)26 bool isfoggedsphere(float rad, const vec &cv)
27 {
28 loopi(4) if(vfcP[i].dist(cv) < -rad) return true;
29 float dist = vfcP[4].dist(cv);
30 return dist < -rad || dist > vfcDfog + rad;
31 }
32
isvisiblesphere(float rad,const vec & cv)33 int isvisiblesphere(float rad, const vec &cv)
34 {
35 int v = VFC_FULL_VISIBLE;
36 float dist;
37
38 loopi(5)
39 {
40 dist = vfcP[i].dist(cv);
41 if(dist < -rad) return VFC_NOT_VISIBLE;
42 if(dist < rad) v = VFC_PART_VISIBLE;
43 }
44
45 dist -= vfcDfog;
46 if(dist > rad) return VFC_FOGGED; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM
47 if(dist > -rad) v = VFC_PART_VISIBLE;
48
49 return v;
50 }
51
ishiddencube(const ivec & o,int size)52 static inline int ishiddencube(const ivec &o, int size)
53 {
54 loopi(5) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true;
55 return false;
56 }
57
isfoggedcube(const ivec & o,int size)58 static inline int isfoggedcube(const ivec &o, int size)
59 {
60 loopi(4) if(o.dist(vfcP[i]) < -vfcDfar[i]*size) return true;
61 float dist = o.dist(vfcP[4]);
62 return dist < -vfcDfar[4]*size || dist > vfcDfog - vfcDnear[4]*size;
63 }
64
isvisiblecube(const ivec & o,int size)65 int isvisiblecube(const ivec &o, int size)
66 {
67 int v = VFC_FULL_VISIBLE;
68 float dist;
69
70 loopi(5)
71 {
72 dist = o.dist(vfcP[i]);
73 if(dist < -vfcDfar[i]*size) return VFC_NOT_VISIBLE;
74 if(dist < -vfcDnear[i]*size) v = VFC_PART_VISIBLE;
75 }
76
77 dist -= vfcDfog;
78 if(dist > -vfcDnear[4]*size) return VFC_FOGGED;
79 if(dist > -vfcDfar[4]*size) v = VFC_PART_VISIBLE;
80
81 return v;
82 }
83
vadist(vtxarray * va,const vec & p)84 float vadist(vtxarray *va, const vec &p)
85 {
86 return p.dist_to_bb(va->bbmin, va->bbmax);
87 }
88
89 #define VASORTSIZE 64
90
91 static vtxarray *vasort[VASORTSIZE];
92
addvisibleva(vtxarray * va)93 void addvisibleva(vtxarray *va)
94 {
95 float dist = vadist(va, camera1->o);
96 va->distance = int(dist); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
97
98 int hash = min(int(dist*VASORTSIZE/hdr.worldsize), VASORTSIZE-1);
99 vtxarray **prev = &vasort[hash], *cur = vasort[hash];
100
101 while(cur && va->distance >= cur->distance)
102 {
103 prev = &cur->next;
104 cur = cur->next;
105 }
106
107 va->next = *prev;
108 *prev = va;
109 }
110
sortvisiblevas()111 void sortvisiblevas()
112 {
113 visibleva = NULL;
114 vtxarray **last = &visibleva;
115 loopi(VASORTSIZE) if(vasort[i])
116 {
117 vtxarray *va = vasort[i];
118 *last = va;
119 while(va->next) va = va->next;
120 last = &va->next;
121 }
122 }
123
findvisiblevas(vector<vtxarray * > & vas,bool resetocclude=false)124 void findvisiblevas(vector<vtxarray *> &vas, bool resetocclude = false)
125 {
126 loopv(vas)
127 {
128 vtxarray &v = *vas[i];
129 int prevvfc = resetocclude ? VFC_NOT_VISIBLE : v.curvfc;
130 v.curvfc = isvisiblecube(v.o, v.size);
131 if(v.curvfc!=VFC_NOT_VISIBLE)
132 {
133 if(pvsoccluded(v.o, v.size))
134 {
135 v.curvfc += PVS_FULL_VISIBLE - VFC_FULL_VISIBLE;
136 continue;
137 }
138 addvisibleva(&v);
139 if(v.children.length()) findvisiblevas(v.children, prevvfc>=VFC_NOT_VISIBLE);
140 if(prevvfc>=VFC_NOT_VISIBLE)
141 {
142 v.occluded = !v.texs || pvsoccluded(v.geommin, v.geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
143 v.query = NULL;
144 }
145 }
146 }
147 }
148
calcvfcD()149 void calcvfcD()
150 {
151 loopi(5)
152 {
153 plane &p = vfcP[i];
154 vfcDnear[i] = vfcDfar[i] = 0;
155 loopk(3) if(p[k] > 0) vfcDfar[i] += p[k];
156 else vfcDnear[i] += p[k];
157 }
158 }
159
setvfcP(float yaw,float pitch,const vec & camera,float minyaw=-M_PI,float maxyaw=M_PI,float minpitch=-M_PI,float maxpitch=M_PI)160 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)
161 {
162 yaw *= RAD;
163 pitch *= RAD;
164 vfcP[0].toplane(vec(yaw + M_PI/2 - min(vfcfov, -minyaw), pitch), camera); // left plane
165 vfcP[1].toplane(vec(yaw - M_PI/2 + min(vfcfov, maxyaw), pitch), camera); // right plane
166 vfcP[2].toplane(vec(yaw, pitch + M_PI/2 - min(vfcfovy, -minpitch)), camera); // top plane
167 vfcP[3].toplane(vec(yaw, pitch - M_PI/2 + min(vfcfovy, maxpitch)), camera); // bottom plane
168 vfcP[4].toplane(vec(yaw, pitch), camera); // near/far planes
169 extern int fog;
170 vfcDfog = fog;
171 calcvfcD();
172 }
173
174 plane oldvfcP[5];
175
reflectvfcP(float z,float minyaw,float maxyaw,float minpitch,float maxpitch)176 void reflectvfcP(float z, float minyaw, float maxyaw, float minpitch, float maxpitch)
177 {
178 memcpy(oldvfcP, vfcP, sizeof(vfcP));
179
180 if(z < 0) setvfcP(camera1->yaw, camera1->pitch, camera1->o, minyaw, maxyaw, minpitch, maxpitch);
181 else
182 {
183 vec o(camera1->o);
184 o.z = z-(camera1->o.z-z);
185 setvfcP(camera1->yaw, -camera1->pitch, o, minyaw, maxyaw, -maxpitch, -minpitch);
186 }
187 }
188
restorevfcP()189 void restorevfcP()
190 {
191 memcpy(vfcP, oldvfcP, sizeof(vfcP));
192 calcvfcD();
193 }
194
195 extern vector<vtxarray *> varoot;
196
visiblecubes(float fov,float fovy)197 void visiblecubes(float fov, float fovy)
198 {
199 memset(vasort, 0, sizeof(vasort));
200
201 vfcfov = fov*0.5f*RAD;
202 vfcfovy = fovy*0.5f*RAD;
203
204 // Calculate view frustrum: Only changes if resize, but...
205 setvfcP(camera1->yaw, camera1->pitch, camera1->o);
206
207 findvisiblevas(varoot);
208 sortvisiblevas();
209 }
210
insideva(const vtxarray * va,const vec & v,int margin=1)211 static inline bool insideva(const vtxarray *va, const vec &v, int margin = 1)
212 {
213 int size = va->size + margin;
214 return v.x>=va->o.x-margin && v.y>=va->o.y-margin && v.z>=va->o.z-margin &&
215 v.x<=va->o.x+size && v.y<=va->o.y+size && v.z<=va->o.z+size;
216 }
217
218 static ivec vaorigin;
219
resetorigin()220 static void resetorigin()
221 {
222 vaorigin = ivec(-1, -1, -1);
223 }
224
setorigin(vtxarray * va,bool shadowmatrix=false)225 static bool setorigin(vtxarray *va, bool shadowmatrix = false)
226 {
227 ivec o = floatvtx ? ivec(0, 0, 0) : ivec(va->o).mask(~VVEC_INT_MASK).add(0x8000>>VVEC_FRAC);
228 if(o != vaorigin)
229 {
230 vaorigin = o;
231 glPopMatrix();
232 glPushMatrix();
233 glTranslatef(o.x, o.y, o.z);
234 static const float scale = 1.0f / (1<<VVEC_FRAC);
235 glScalef(scale, scale, scale);
236
237 if(shadowmatrix) adjustshadowmatrix(o, scale);
238 return true;
239 }
240 return false;
241 }
242
243 ///////// occlusion queries /////////////
244
245 #define MAXQUERY 2048
246
247 struct queryframe
248 {
249 int cur, max;
250 occludequery queries[MAXQUERY];
251 };
252
253 static queryframe queryframes[2] = {{0, 0}, {0, 0}};
254 static uint flipquery = 0;
255
getnumqueries()256 int getnumqueries()
257 {
258 return queryframes[flipquery].cur;
259 }
260
flipqueries()261 void flipqueries()
262 {
263 flipquery = (flipquery + 1) % 2;
264 queryframe &qf = queryframes[flipquery];
265 loopi(qf.cur) qf.queries[i].owner = NULL;
266 qf.cur = 0;
267 }
268
newquery(void * owner)269 occludequery *newquery(void *owner)
270 {
271 queryframe &qf = queryframes[flipquery];
272 if(qf.cur >= qf.max)
273 {
274 if(qf.max >= MAXQUERY) return NULL;
275 glGenQueries_(1, &qf.queries[qf.max++].id);
276 }
277 occludequery *query = &qf.queries[qf.cur++];
278 query->owner = owner;
279 query->fragments = -1;
280 return query;
281 }
282
resetqueries()283 void resetqueries()
284 {
285 loopi(2) loopj(queryframes[i].max) queryframes[i].queries[j].owner = NULL;
286 }
287
clearqueries()288 void clearqueries()
289 {
290 loopi(2)
291 {
292 queryframe &qf = queryframes[i];
293 loopj(qf.max)
294 {
295 glDeleteQueries_(1, &qf.queries[j].id);
296 qf.queries[j].owner = NULL;
297 }
298 qf.cur = qf.max = 0;
299 }
300 }
301
302 VAR(oqfrags, 0, 8, 64);
303 VAR(oqreflect, 0, 4, 64);
304
checkquery(occludequery * query,bool nowait)305 bool checkquery(occludequery *query, bool nowait)
306 {
307 GLuint fragments;
308 if(query->fragments >= 0) fragments = query->fragments;
309 else
310 {
311 if(nowait)
312 {
313 GLint avail;
314 glGetQueryObjectiv_(query->id, GL_QUERY_RESULT_AVAILABLE, &avail);
315 if(!avail) return false;
316 }
317 glGetQueryObjectuiv_(query->id, GL_QUERY_RESULT_ARB, &fragments);
318 query->fragments = fragments;
319 }
320 return fragments < (uint)(reflecting || refracting ? oqreflect : oqfrags);
321 }
322
drawbb(const ivec & bo,const ivec & br,const vec & camera,int scale,const ivec & origin)323 void drawbb(const ivec &bo, const ivec &br, const vec &camera, int scale, const ivec &origin)
324 {
325 glBegin(GL_QUADS);
326
327 loopi(6)
328 {
329 int dim = dimension(i), coord = dimcoord(i);
330
331 if(coord)
332 {
333 if(camera[dim] < bo[dim] + br[dim]) continue;
334 }
335 else if(camera[dim] > bo[dim]) continue;
336
337 loopj(4)
338 {
339 const ivec &cc = cubecoords[fv[i][j]];
340 glVertex3f(((cc.x ? bo.x+br.x : bo.x) - origin.x) << scale,
341 ((cc.y ? bo.y+br.y : bo.y) - origin.y) << scale,
342 ((cc.z ? bo.z+br.z : bo.z) - origin.z) << scale);
343 }
344
345 xtraverts += 4;
346 }
347
348 glEnd();
349 }
350
351 extern int octaentsize;
352
353 static octaentities *visiblemms, **lastvisiblemms;
354
findvisiblemms(const vector<extentity * > & ents)355 void findvisiblemms(const vector<extentity *> &ents)
356 {
357 for(vtxarray *va = visibleva; va; va = va->next)
358 {
359 if(!va->mapmodels || va->curvfc >= VFC_FOGGED || va->occluded >= OCCLUDE_BB) continue;
360 loopv(*va->mapmodels)
361 {
362 octaentities *oe = (*va->mapmodels)[i];
363 if(isfoggedcube(oe->o, oe->size) || pvsoccluded(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin))) continue;
364
365 bool occluded = oe->query && oe->query->owner == oe && checkquery(oe->query);
366 if(occluded)
367 {
368 oe->distance = -1;
369
370 oe->next = NULL;
371 *lastvisiblemms = oe;
372 lastvisiblemms = &oe->next;
373 }
374 else
375 {
376 int visible = 0;
377 loopv(oe->mapmodels)
378 {
379 extentity &e = *ents[oe->mapmodels[i]];
380 if(e.lastemit && e.spawned && e.attrs[5]&MMT_HIDE) continue;
381 e.visible = true;
382 ++visible;
383 }
384 if(!visible) continue;
385
386 oe->distance = int(camera1->o.dist_to_bb(oe->o, oe->size));
387
388 octaentities **prev = &visiblemms, *cur = visiblemms;
389 while(cur && cur->distance >= 0 && oe->distance > cur->distance)
390 {
391 prev = &cur->next;
392 cur = cur->next;
393 }
394
395 if(*prev == NULL) lastvisiblemms = &oe->next;
396 oe->next = *prev;
397 *prev = oe;
398 }
399 }
400 }
401 }
402
403 VAR(oqmm, 0, 4, 8);
404
405 extern bool getentboundingbox(extentity &e, ivec &o, ivec &r);
406
rendermapmodel(extentity & e)407 void rendermapmodel(extentity &e)
408 {
409 int anim = ANIM_MAPMODEL|ANIM_LOOP, basetime = 0, flags = MDL_CULL_VFC|MDL_CULL_DIST|MDL_DYNLIGHT;
410 if(e.lastemit)
411 {
412 if(e.attrs[5]&MMT_HIDE && e.spawned) return;
413 anim = e.spawned ? ANIM_TRIGGER_ON : ANIM_TRIGGER_OFF;
414 if(e.lastemit > 0 && lastmillis-e.lastemit < entities::triggertime(e)) basetime = e.lastemit;
415 else anim |= ANIM_END;
416 }
417 if((e.lastemit || e.attrs[5]&MMT_NOSHADOW) && !(e.attrs[5]&MMT_NODYNSHADOW)) flags |= MDL_SHADOW;
418 mapmodelinfo &mmi = getmminfo(e.attrs[0]);
419 if(&mmi) rendermodel(&e.light, mmi.name, anim, e.o, (float)(e.attrs[1]%360), 0, (float)(e.attrs[2]%360), flags, NULL, NULL, basetime, 0, e.attrs[3] ? min(e.attrs[3]/100.f, 1.f) : 1.f, e.attrs[4] ? max(e.attrs[4]/100.f, 1e-3f) : 1.f);
420 }
421
422 extern int reflectdist;
423
424 vtxarray *reflectedva;
425
renderreflectedmapmodels()426 void renderreflectedmapmodels()
427 {
428 const vector<extentity *> &ents = entities::getents();
429
430 octaentities *mms = visiblemms;
431 if(reflecting)
432 {
433 octaentities **lastmms = &mms;
434 for(vtxarray *va = reflectedva; va; va = va->rnext)
435 {
436 if(!va->mapmodels || va->distance > reflectdist) continue;
437 loopv(*va->mapmodels)
438 {
439 octaentities *oe = (*va->mapmodels)[i];
440 *lastmms = oe;
441 lastmms = &oe->rnext;
442 }
443 }
444 *lastmms = NULL;
445 }
446 for(octaentities *oe = mms; oe; oe = reflecting ? oe->rnext : oe->next)
447 {
448 if(reflecting || refracting>0 ? oe->bbmax.z <= reflectz : oe->bbmin.z >= reflectz) continue;
449 if(isfoggedcube(oe->o, oe->size)) continue;
450 loopv(oe->mapmodels)
451 {
452 extentity &e = *ents[oe->mapmodels[i]];
453 if(e.visible || (e.lastemit && e.spawned && e.attrs[4]&MMT_HIDE)) continue;
454 e.visible = true;
455 }
456 }
457 if(mms)
458 {
459 startmodelbatches();
460 for(octaentities *oe = mms; oe; oe = reflecting ? oe->rnext : oe->next)
461 {
462 loopv(oe->mapmodels)
463 {
464 extentity &e = *ents[oe->mapmodels[i]];
465 if(!e.visible) continue;
466 rendermapmodel(e);
467 e.visible = false;
468 }
469 }
470 endmodelbatches();
471 }
472 }
473
rendermapmodels()474 void rendermapmodels()
475 {
476 const vector<extentity *> &ents = entities::getents();
477
478 visiblemms = NULL;
479 lastvisiblemms = &visiblemms;
480 findvisiblemms(ents);
481
482 static int skipoq = 0;
483 bool doquery = hasOQ && oqfrags && oqmm;
484
485 startmodelbatches();
486 for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance>=0)
487 {
488 bool rendered = false;
489 loopv(oe->mapmodels)
490 {
491 extentity &e = *ents[oe->mapmodels[i]];
492 if(!e.visible) continue;
493 if(!rendered)
494 {
495 rendered = true;
496 oe->query = doquery && oe->distance>0 && !(++skipoq%oqmm) ? newquery(oe) : NULL;
497 if(oe->query) startmodelquery(oe->query);
498 }
499 rendermapmodel(e);
500 e.visible = false;
501 }
502 if(rendered && oe->query) endmodelquery();
503 }
504 endmodelbatches();
505
506 bool queried = false;
507 for(octaentities *oe = visiblemms; oe; oe = oe->next) if(oe->distance<0)
508 {
509 oe->query = doquery ? newquery(oe) : NULL;
510 if(!oe->query) continue;
511 if(!queried)
512 {
513 glDepthMask(GL_FALSE);
514 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
515 nocolorshader->set();
516 queried = true;
517 }
518 startquery(oe->query);
519 drawbb(oe->bbmin, ivec(oe->bbmax).sub(oe->bbmin));
520 endquery(oe->query);
521 }
522 if(queried)
523 {
524 glDepthMask(GL_TRUE);
525 glColorMask(COLORMASK, fading ? GL_FALSE : GL_TRUE);
526 }
527 }
528
bbinsideva(const ivec & bo,const ivec & br,vtxarray * va)529 static inline bool bbinsideva(const ivec &bo, const ivec &br, vtxarray *va)
530 {
531 return bo.x >= va->bbmin.x && bo.y >= va->bbmin.y && va->o.z >= va->bbmin.z &&
532 bo.x + br.x <= va->bbmax.x && bo.y + br.y <= va->bbmax.y && bo.z + br.z <= va->bbmax.z;
533 }
534
bboccluded(const ivec & bo,const ivec & br,cube * c,const ivec & o,int size)535 static inline bool bboccluded(const ivec &bo, const ivec &br, cube *c, const ivec &o, int size)
536 {
537 loopoctabox(o, size, bo, br)
538 {
539 ivec co(i, o.x, o.y, o.z, size);
540 if(c[i].ext && c[i].ext->va)
541 {
542 vtxarray *va = c[i].ext->va;
543 if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) continue;
544 }
545 if(c[i].children && bboccluded(bo, br, c[i].children, co, size>>1)) continue;
546 return false;
547 }
548 return true;
549 }
550
bboccluded(const ivec & bo,const ivec & br)551 bool bboccluded(const ivec &bo, const ivec &br)
552 {
553 int diff = (bo.x^(bo.x+br.x)) | (bo.y^(bo.y+br.y)) | (bo.z^(bo.z+br.z));
554 if(diff&~((1<<worldscale)-1)) return false;
555 int scale = worldscale-1;
556 if(diff&(1<<scale)) return bboccluded(bo, br, worldroot, ivec(0, 0, 0), 1<<scale);
557 cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)];
558 if(c->ext && c->ext->va)
559 {
560 vtxarray *va = c->ext->va;
561 if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) return true;
562 }
563 scale--;
564 while(c->children && !(diff&(1<<scale)))
565 {
566 c = &c->children[octastep(bo.x, bo.y, bo.z, scale)];
567 if(c->ext && c->ext->va)
568 {
569 vtxarray *va = c->ext->va;
570 if(va->curvfc >= VFC_FOGGED || (va->occluded >= OCCLUDE_BB && bbinsideva(bo, br, va))) return true;
571 }
572 scale--;
573 }
574 if(c->children) return bboccluded(bo, br, c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale);
575 return false;
576 }
577
578 extern int ati_texgen_bug;
579
setuptexgen(int dims=2)580 static void setuptexgen(int dims = 2)
581 {
582 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
583 glEnable(GL_TEXTURE_GEN_S);
584 if(dims>=2)
585 {
586 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
587 glEnable(GL_TEXTURE_GEN_T);
588 if(ati_texgen_bug) glEnable(GL_TEXTURE_GEN_R); // should not be needed, but apparently makes some ATI drivers happy
589 }
590 }
591
disabletexgen(int dims=2)592 static void disabletexgen(int dims = 2)
593 {
594 glDisable(GL_TEXTURE_GEN_S);
595 if(dims>=2)
596 {
597 glDisable(GL_TEXTURE_GEN_T);
598 if(ati_texgen_bug) glDisable(GL_TEXTURE_GEN_R);
599 }
600 }
601
602 HVARP(outline, 0, 1, 0xFFFFFF);
603 VAR(dtoutline, 0, 1, 1);
604
renderoutline()605 void renderoutline()
606 {
607 notextureshader->set();
608
609 glDisable(GL_TEXTURE_2D);
610 glEnableClientState(GL_VERTEX_ARRAY);
611
612 glPushMatrix();
613
614 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
615 glColor3ub((outline>>16)&0xFF, (outline>>8)&0xFF, outline&0xFF);
616
617 enablepolygonoffset(GL_POLYGON_OFFSET_LINE);
618
619 if(!dtoutline) glDisable(GL_DEPTH_TEST);
620
621 resetorigin();
622 vtxarray *prev = NULL;
623 for(vtxarray *va = visibleva; va; va = va->next)
624 {
625 if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue;
626
627 if(!prev || va->vbuf != prev->vbuf)
628 {
629 setorigin(va);
630 if(hasVBO)
631 {
632 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
633 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
634 }
635 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
636 }
637
638 drawvatris(va, 3*va->tris, va->edata);
639 xtravertsva += va->verts;
640
641 prev = va;
642 }
643
644 if(!dtoutline) glEnable(GL_DEPTH_TEST);
645
646 disablepolygonoffset(GL_POLYGON_OFFSET_LINE);
647
648 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
649
650 glPopMatrix();
651
652 if(hasVBO)
653 {
654 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
655 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
656 }
657 glDisableClientState(GL_VERTEX_ARRAY);
658 glEnable(GL_TEXTURE_2D);
659
660 defaultshader->set();
661 }
662
663 HVAR(blendbrushcolor, 0, 0x0000C0, 0xFFFFFF);
664
renderblendbrush(GLuint tex,float x,float y,float w,float h)665 void renderblendbrush(GLuint tex, float x, float y, float w, float h)
666 {
667 static Shader *blendbrushshader = NULL;
668 if(!blendbrushshader) blendbrushshader = lookupshaderbyname("blendbrush");
669 blendbrushshader->set();
670
671 glEnableClientState(GL_VERTEX_ARRAY);
672
673 glPushMatrix();
674
675 glDepthFunc(GL_LEQUAL);
676
677 glEnable(GL_BLEND);
678 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
679
680 glEnable(GL_TEXTURE_2D);
681 glBindTexture(GL_TEXTURE_2D, tex);
682 glColor4ub((blendbrushcolor>>16)&0xFF, (blendbrushcolor>>8)&0xFF, blendbrushcolor&0xFF, 0x40);
683
684 GLfloat s[4] = { 0, 0, 0, 0 }, t[4] = { 0, 0, 0, 0 };
685 if(renderpath==R_FIXEDFUNCTION) setuptexgen();
686
687 resetorigin();
688 vtxarray *prev = NULL;
689 for(vtxarray *va = visibleva; va; va = va->next)
690 {
691 if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue;
692 if(va->o.x + va->size <= x || va->o.y + va->size <= y || va->o.x >= x + w || va->o.y >= y + h) continue;
693
694 if(!prev || va->vbuf != prev->vbuf)
695 {
696 if(setorigin(va))
697 {
698 s[0] = 1.0f / (w*(1<<VVEC_FRAC));
699 s[3] = (vaorigin.x - x) / w;
700 t[1] = 1.0f / (h*(1<<VVEC_FRAC));
701 t[3] = (vaorigin.y - y) / h;
702 if(renderpath==R_FIXEDFUNCTION)
703 {
704 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
705 glTexGenfv(GL_T, GL_OBJECT_PLANE, t);
706 }
707 else
708 {
709 setlocalparamfv("texgenS", SHPARAM_VERTEX, 0, s);
710 setlocalparamfv("texgenT", SHPARAM_VERTEX, 1, t);
711 }
712 }
713
714 if(hasVBO)
715 {
716 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
717 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
718 }
719 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
720 }
721
722 drawvatris(va, 3*va->tris, va->edata);
723 xtravertsva += va->verts;
724
725 prev = va;
726 }
727
728 if(renderpath==R_FIXEDFUNCTION) disabletexgen();
729
730 glDisable(GL_TEXTURE_2D);
731 glDisable(GL_BLEND);
732
733 glDepthFunc(GL_LESS);
734
735 glPopMatrix();
736
737 if(hasVBO)
738 {
739 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
740 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
741 }
742 glDisableClientState(GL_VERTEX_ARRAY);
743
744 notextureshader->set();
745 }
746
rendershadowmapreceivers()747 void rendershadowmapreceivers()
748 {
749 if(!hasBE) return;
750
751 static Shader *shadowmapshader = NULL;
752 if(!shadowmapshader) shadowmapshader = lookupshaderbyname("shadowmapreceiver");
753 shadowmapshader->set();
754
755 glDisable(GL_TEXTURE_2D);
756 glEnableClientState(GL_VERTEX_ARRAY);
757
758 glCullFace(GL_BACK);
759 glDepthMask(GL_FALSE);
760 glDepthFunc(GL_GREATER);
761
762 extern int ati_minmax_bug;
763 if(!ati_minmax_bug) glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
764
765 glEnable(GL_BLEND);
766 glBlendEquation_(GL_MAX_EXT);
767 glBlendFunc(GL_ONE, GL_ONE);
768
769 glPushMatrix();
770
771 resetorigin();
772 vtxarray *prev = NULL;
773 for(vtxarray *va = visibleva; va; va = va->next)
774 {
775 if(!va->texs || va->curvfc >= VFC_FOGGED || !isshadowmapreceiver(va)) continue;
776
777 if(!prev || va->vbuf != prev->vbuf)
778 {
779 setorigin(va);
780 if(hasVBO)
781 {
782 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
783 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
784 }
785 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
786 }
787
788 drawvatris(va, 3*va->tris, va->edata);
789 xtravertsva += va->verts;
790
791 prev = va;
792 }
793
794 glPopMatrix();
795
796 glDisable(GL_BLEND);
797 glBlendEquation_(GL_FUNC_ADD_EXT);
798
799 glCullFace(GL_FRONT);
800 glDepthMask(GL_TRUE);
801 glDepthFunc(GL_LESS);
802
803 if(!ati_minmax_bug) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
804
805 if(hasVBO)
806 {
807 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
808 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
809 }
810 glDisableClientState(GL_VERTEX_ARRAY);
811 glEnable(GL_TEXTURE_2D);
812 }
813
renderdepthobstacles(const vec & bbmin,const vec & bbmax,float scale,float * ranges,int numranges)814 void renderdepthobstacles(const vec &bbmin, const vec &bbmax, float scale, float *ranges, int numranges)
815 {
816 float scales[4] = { 0, 0, 0, 0 }, offsets[4] = { 0, 0, 0, 0 };
817 if(numranges < 0)
818 {
819 SETSHADER(depthfxsplitworld);
820
821 loopi(-numranges)
822 {
823 if(!i) scales[i] = 1.0f/scale;
824 else scales[i] = scales[i-1]*256;
825 }
826 }
827 else
828 {
829 SETSHADER(depthfxworld);
830
831 if(!numranges) loopi(4) scales[i] = 1.0f/scale;
832 else loopi(numranges)
833 {
834 scales[i] = 1.0f/scale;
835 offsets[i] = -ranges[i]/scale;
836 }
837 }
838 setlocalparamfv("depthscale", SHPARAM_VERTEX, 0, scales);
839 setlocalparamfv("depthoffsets", SHPARAM_VERTEX, 1, offsets);
840
841 glDisable(GL_TEXTURE_2D);
842 glEnableClientState(GL_VERTEX_ARRAY);
843
844 glPushMatrix();
845
846 resetorigin();
847 vtxarray *prev = NULL;
848 for(vtxarray *va = visibleva; va; va = va->next)
849 {
850 if(!va->texs || va->occluded >= OCCLUDE_GEOM ||
851 va->o.x > bbmax.x || va->o.y > bbmax.y || va->o.z > bbmax.z ||
852 va->o.x + va->size < bbmin.x || va->o.y + va->size < bbmin.y || va->o.z + va->size < bbmin.z)
853 continue;
854
855 if(!prev || va->vbuf != prev->vbuf)
856 {
857 setorigin(va);
858 if(hasVBO)
859 {
860 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
861 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
862 }
863 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
864 }
865
866 drawvatris(va, 3*va->tris, va->edata);
867 xtravertsva += va->verts;
868
869 prev = va;
870 }
871 glPopMatrix();
872
873 if(hasVBO)
874 {
875 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
876 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
877 }
878 glDisableClientState(GL_VERTEX_ARRAY);
879 glEnable(GL_TEXTURE_2D);
880
881 defaultshader->set();
882 }
883
884 // [rotation][dimension] = vec4
885 float orientation_tangent [6][3][4] =
886 {
887 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
888 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
889 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
890 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
891 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
892 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
893 };
894 float orientation_binormal[6][3][4] =
895 {
896 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
897 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
898 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
899 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
900 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
901 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
902 };
903
904 struct renderstate
905 {
906 bool colormask, depthmask, blending, mtglow, skippedglow;
907 GLuint vbuf;
908 float fogplane;
909 int diffusetmu, lightmaptmu, glowtmu, fogtmu, causticstmu;
910 GLfloat color[4];
911 vec glowcolor;
912 GLuint textures[8];
913 Slot *slot;
914 float texgenSk, texgenSoff, texgenTk, texgenToff;
915 int texgendim;
916 bool mttexgen;
917 int visibledynlights;
918 uint dynlightmask;
919 vec dynlightpos;
920 float dynlightradius;
921
renderstaterenderstate922 renderstate() : colormask(true), depthmask(true), blending(false), 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)
923 {
924 loopk(4) color[k] = 1;
925 loopk(8) textures[k] = 0;
926 }
927 };
928
renderquery(renderstate & cur,occludequery * query,vtxarray * va)929 void renderquery(renderstate &cur, occludequery *query, vtxarray *va)
930 {
931 nocolorshader->set();
932 if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
933 if(cur.depthmask) { cur.depthmask = false; glDepthMask(GL_FALSE); }
934
935 vec camera(camera1->o);
936 if(reflecting) camera.z = reflectz;
937
938 startquery(query);
939
940 drawbb(va->bbmin, ivec(va->bbmax).sub(va->bbmin), camera, vaorigin.x >= 0 ? VVEC_FRAC : 0, vaorigin.x >= 0 ? vaorigin : ivec(0, 0, 0));
941
942 endquery(query);
943 }
944
945 enum
946 {
947 RENDERPASS_LIGHTMAP = 0,
948 RENDERPASS_COLOR,
949 RENDERPASS_Z,
950 RENDERPASS_GLOW,
951 RENDERPASS_CAUSTICS,
952 RENDERPASS_FOG,
953 RENDERPASS_SHADOWMAP,
954 RENDERPASS_DYNLIGHT,
955 RENDERPASS_LIGHTMAP_BLEND
956 };
957
958 struct geombatch
959 {
960 const elementset &es;
961 Slot &slot;
962 ushort *edata;
963 vtxarray *va;
964 int next, batch;
965
geombatchgeombatch966 geombatch(const elementset &es, ushort *edata, vtxarray *va)
967 : es(es), slot(lookuptexture(es.texture)), edata(edata), va(va),
968 next(-1), batch(-1)
969 {}
970
comparegeombatch971 int compare(const geombatch &b) const
972 {
973 if(va->vbuf < b.va->vbuf) return -1;
974 if(va->vbuf > b.va->vbuf) return 1;
975 if(renderpath!=R_FIXEDFUNCTION)
976 {
977 if(va->dynlightmask < b.va->dynlightmask) return -1;
978 if(va->dynlightmask > b.va->dynlightmask) return 1;
979 if(slot.shader < b.slot.shader) return -1;
980 if(slot.shader > b.slot.shader) return 1;
981 if(slot.params.length() < b.slot.params.length()) return -1;
982 if(slot.params.length() > b.slot.params.length()) return 1;
983 }
984 if(es.texture < b.es.texture) return -1;
985 if(es.texture > b.es.texture) return 1;
986 if(es.lmid < b.es.lmid) return -1;
987 if(es.lmid > b.es.lmid) return 1;
988 if(es.envmap < b.es.envmap) return -1;
989 if(es.envmap > b.es.envmap) return 1;
990 return 0;
991 }
992 };
993
994 static vector<geombatch> geombatches;
995 static int firstbatch = -1, numbatches = 0;
996
mergetexs(vtxarray * va,elementset * texs=NULL,int numtexs=0,ushort * edata=NULL)997 static void mergetexs(vtxarray *va, elementset *texs = NULL, int numtexs = 0, ushort *edata = NULL)
998 {
999 if(!texs)
1000 {
1001 texs = va->eslist;
1002 numtexs = va->texs;
1003 edata = va->edata;
1004 }
1005
1006 if(firstbatch < 0)
1007 {
1008 firstbatch = geombatches.length();
1009 numbatches = numtexs;
1010 loopi(numtexs-1)
1011 {
1012 geombatches.add(geombatch(texs[i], edata, va)).next = i+1;
1013 edata += texs[i].length[5];
1014 }
1015 geombatches.add(geombatch(texs[numtexs-1], edata, va));
1016 return;
1017 }
1018
1019 int prevbatch = -1, curbatch = firstbatch, curtex = 0;
1020 do
1021 {
1022 geombatch &b = geombatches.add(geombatch(texs[curtex], edata, va));
1023 edata += texs[curtex].length[5];
1024 int dir = -1;
1025 while(curbatch >= 0)
1026 {
1027 dir = b.compare(geombatches[curbatch]);
1028 if(dir <= 0) break;
1029 prevbatch = curbatch;
1030 curbatch = geombatches[curbatch].next;
1031 }
1032 if(!dir)
1033 {
1034 int last = curbatch, next;
1035 for(;;)
1036 {
1037 next = geombatches[last].batch;
1038 if(next < 0) break;
1039 last = next;
1040 }
1041 if(last==curbatch)
1042 {
1043 b.batch = curbatch;
1044 b.next = geombatches[curbatch].next;
1045 if(prevbatch < 0) firstbatch = geombatches.length()-1;
1046 else geombatches[prevbatch].next = geombatches.length()-1;
1047 curbatch = geombatches.length()-1;
1048 }
1049 else
1050 {
1051 b.batch = next;
1052 geombatches[last].batch = geombatches.length()-1;
1053 }
1054 }
1055 else
1056 {
1057 numbatches++;
1058 b.next = curbatch;
1059 if(prevbatch < 0) firstbatch = geombatches.length()-1;
1060 else geombatches[prevbatch].next = geombatches.length()-1;
1061 prevbatch = geombatches.length()-1;
1062 }
1063 }
1064 while(++curtex < numtexs);
1065 }
1066
mergeglowtexs(vtxarray * va)1067 static void mergeglowtexs(vtxarray *va)
1068 {
1069 int start = -1;
1070 ushort *edata = va->edata, *startdata = NULL;
1071 loopi(va->texs)
1072 {
1073 elementset &es = va->eslist[i];
1074 Slot &slot = lookuptexture(es.texture, false);
1075 if(slot.texmask&(1<<TEX_GLOW) && !slot.mtglowed)
1076 {
1077 if(start<0) { start = i; startdata = edata; }
1078 }
1079 else if(start>=0)
1080 {
1081 mergetexs(va, &va->eslist[start], i-start, startdata);
1082 start = -1;
1083 }
1084 edata += es.length[5];
1085 }
1086 if(start>=0) mergetexs(va, &va->eslist[start], va->texs-start, startdata);
1087 }
1088
changefogplane(renderstate & cur,int pass,vtxarray * va)1089 static void changefogplane(renderstate &cur, int pass, vtxarray *va)
1090 {
1091 if(renderpath!=R_FIXEDFUNCTION)
1092 {
1093 if((fading && !cur.blending) || fogging)
1094 {
1095 float fogplane = reflectz - vaorigin.z;
1096 if(cur.fogplane!=fogplane)
1097 {
1098 cur.fogplane = fogplane;
1099 if(fogging) setfogplane(1.0f/(1<<VVEC_FRAC), fogplane, false, -0.25f/(1<<VVEC_FRAC), 0.5f + 0.25f*fogplane);
1100 else setfogplane(0, 0, false, 0.25f/(1<<VVEC_FRAC), 0.5f - 0.25f*fogplane);
1101 }
1102 }
1103 }
1104 else if(pass==RENDERPASS_FOG || (cur.fogtmu>=0 && (pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_GLOW || pass==RENDERPASS_SHADOWMAP)))
1105 {
1106 if(pass==RENDERPASS_LIGHTMAP) glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
1107 else if(pass==RENDERPASS_GLOW || pass==RENDERPASS_SHADOWMAP) glActiveTexture_(GL_TEXTURE1_ARB);
1108 GLfloat s[4] = { 0, 0, -1.0f/(waterfog<<VVEC_FRAC), (reflectz - vaorigin.z)/waterfog };
1109 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
1110 if(pass==RENDERPASS_LIGHTMAP) glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1111 else if(pass==RENDERPASS_GLOW || pass==RENDERPASS_SHADOWMAP) glActiveTexture_(GL_TEXTURE0_ARB);
1112 }
1113 }
1114
changedynlightpos(renderstate & cur,vtxarray * va)1115 static void changedynlightpos(renderstate &cur, vtxarray *va)
1116 {
1117 GLfloat tx[4] = { 0.5f/(cur.dynlightradius * (1<<VVEC_FRAC)), 0, 0, 0.5f + 0.5f*(vaorigin.x - cur.dynlightpos.x)/cur.dynlightradius },
1118 ty[4] = { 0, 0.5f/(cur.dynlightradius * (1<<VVEC_FRAC)), 0, 0.5f + 0.5f*(vaorigin.y - cur.dynlightpos.y)/cur.dynlightradius },
1119 tz[4] = { 0, 0, 0.5f/(cur.dynlightradius * (1<<VVEC_FRAC)), 0.5f + 0.5f*(vaorigin.z - cur.dynlightpos.z)/cur.dynlightradius };
1120 glActiveTexture_(GL_TEXTURE0_ARB);
1121 glTexGenfv(GL_S, GL_OBJECT_PLANE, tx);
1122 glTexGenfv(GL_T, GL_OBJECT_PLANE, ty);
1123 glActiveTexture_(GL_TEXTURE1_ARB);
1124 glTexGenfv(GL_S, GL_OBJECT_PLANE, tz);
1125 glActiveTexture_(GL_TEXTURE2_ARB);
1126 }
1127
changevbuf(renderstate & cur,int pass,vtxarray * va)1128 static void changevbuf(renderstate &cur, int pass, vtxarray *va)
1129 {
1130 if(setorigin(va, renderpath!=R_FIXEDFUNCTION ? pass==RENDERPASS_LIGHTMAP && !envmapping && !glaring : pass==RENDERPASS_SHADOWMAP))
1131 {
1132 cur.visibledynlights = 0;
1133 cur.dynlightmask = 0;
1134 }
1135 if(hasVBO)
1136 {
1137 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
1138 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->ebuf);
1139 }
1140 cur.vbuf = va->vbuf;
1141
1142 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
1143
1144 if(pass==RENDERPASS_LIGHTMAP)
1145 {
1146 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1147 glTexCoordPointer(2, GL_SHORT, VTXSIZE, floatvtx ? &((fvertex *)va->vdata)[0].u : &va->vdata[0].u);
1148 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1149
1150 if(renderpath!=R_FIXEDFUNCTION)
1151 {
1152 glColorPointer(3, GL_UNSIGNED_BYTE, VTXSIZE, floatvtx ? &((fvertex *)va->vdata)[0].n : &va->vdata[0].n);
1153 setenvparamf("camera", SHPARAM_VERTEX, 4,
1154 (camera1->o.x - vaorigin.x)*(1<<VVEC_FRAC),
1155 (camera1->o.y - vaorigin.y)*(1<<VVEC_FRAC),
1156 (camera1->o.z - vaorigin.z)*(1<<VVEC_FRAC),
1157 1);
1158 }
1159 }
1160 }
1161
changebatchtmus(renderstate & cur,int pass,geombatch & b)1162 static void changebatchtmus(renderstate &cur, int pass, geombatch &b)
1163 {
1164 bool changed = false;
1165 extern bool brightengeom;
1166 int lmid = brightengeom && (b.es.lmid < LMID_RESERVED || fullbright) ? LMID_BRIGHT : b.es.lmid;
1167 if(cur.textures[cur.lightmaptmu]!=lightmaptexs[lmid].id)
1168 {
1169 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1170 glBindTexture(GL_TEXTURE_2D, cur.textures[cur.lightmaptmu] = lightmaptexs[lmid].id);
1171 changed = true;
1172 }
1173 if(renderpath!=R_FIXEDFUNCTION)
1174 {
1175 int tmu = cur.lightmaptmu+1;
1176 if(b.slot.shader->type&SHADER_NORMALSLMS)
1177 {
1178 if(cur.textures[tmu]!=lightmaptexs[lmid+1].id)
1179 {
1180 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1181 glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = lightmaptexs[lmid+1].id);
1182 changed = true;
1183 }
1184 tmu++;
1185 }
1186 if(b.slot.shader->type&SHADER_ENVMAP && b.es.envmap!=EMID_CUSTOM)
1187 {
1188 GLuint emtex = lookupenvmap(b.es.envmap);
1189 if(cur.textures[tmu]!=emtex)
1190 {
1191 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1192 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cur.textures[tmu] = emtex);
1193 changed = true;
1194 }
1195 }
1196 }
1197 if(changed) glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1198 }
1199
changeglow(renderstate & cur,int pass,Slot & slot)1200 static void changeglow(renderstate &cur, int pass, Slot &slot)
1201 {
1202 vec color = slot.glowcolor;
1203 if(slot.pulseglowspeed)
1204 {
1205 float k = lastmillis*slot.pulseglowspeed;
1206 k -= floor(k);
1207 k = fabs(k*2 - 1);
1208 color.lerp(color, slot.pulseglowcolor, k);
1209 }
1210 if(pass==RENDERPASS_GLOW)
1211 {
1212 if(cur.glowcolor!=color) glColor3fv(color.v);
1213 }
1214 else
1215 {
1216 if(cur.glowcolor!=color)
1217 {
1218 if(color==vec(1, 1, 1))
1219 {
1220 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1221 setuptmu(cur.glowtmu, "P + T", "= Pa");
1222 }
1223 else if(hasTE3 || hasTE4)
1224 {
1225 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1226 if(cur.glowcolor==vec(1, 1, 1))
1227 {
1228 if(hasTE3) setuptmu(cur.glowtmu, "TPK3", "= Pa");
1229 else if(hasTE4) setuptmu(cur.glowtmu, "TKP14", "= Pa");
1230 }
1231 colortmu(cur.glowtmu, color.x, color.y, color.z);
1232 }
1233 else
1234 {
1235 slot.mtglowed = false;
1236 cur.skippedglow = true;
1237 return;
1238 }
1239 }
1240 else glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1241 if(!cur.mtglow) { glEnable(GL_TEXTURE_2D); cur.mtglow = true; }
1242 slot.mtglowed = true;
1243 }
1244 loopvj(slot.sts)
1245 {
1246 Slot::Tex &t = slot.sts[j];
1247 if(t.type==TEX_GLOW && t.combined<0)
1248 {
1249 if(cur.textures[cur.glowtmu]!=t.t->id)
1250 glBindTexture(GL_TEXTURE_2D, cur.textures[cur.glowtmu] = t.t->id);
1251 break;
1252 }
1253 }
1254 cur.glowcolor = color;
1255 }
1256
1257 VAR(blankgeom, 0, 0, 1);
1258
changeslottmus(renderstate & cur,int pass,Slot & slot)1259 static void changeslottmus(renderstate &cur, int pass, Slot &slot)
1260 {
1261 if(pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_COLOR || pass==RENDERPASS_DYNLIGHT)
1262 {
1263 GLuint diffusetex = blankgeom ? blanktexture->id : (slot.sts.empty() ? notexture->id : slot.sts[0].t->id);
1264 if(cur.textures[cur.diffusetmu]!=diffusetex)
1265 glBindTexture(GL_TEXTURE_2D, cur.textures[cur.diffusetmu] = diffusetex);
1266 }
1267
1268 if(renderpath==R_FIXEDFUNCTION)
1269 {
1270 if(slot.texmask&(1<<TEX_GLOW))
1271 {
1272 if(pass==RENDERPASS_LIGHTMAP || pass==RENDERPASS_COLOR)
1273 {
1274 if(cur.glowtmu<0) { slot.mtglowed = false; cur.skippedglow = true; }
1275 else changeglow(cur, pass, slot);
1276 }
1277 else if(pass==RENDERPASS_GLOW && !slot.mtglowed) changeglow(cur, pass, slot);
1278 }
1279 if(cur.mtglow)
1280 {
1281 if(!(slot.texmask&(1<<TEX_GLOW)) || !slot.mtglowed)
1282 {
1283 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1284 glDisable(GL_TEXTURE_2D);
1285 cur.mtglow = false;
1286 }
1287 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1288 }
1289 }
1290 else
1291 {
1292 int tmu = cur.lightmaptmu+1, envmaptmu = -1;
1293 if(slot.shader->type&SHADER_NORMALSLMS) tmu++;
1294 if(slot.shader->type&SHADER_ENVMAP) envmaptmu = tmu++;
1295 loopvj(slot.sts)
1296 {
1297 Slot::Tex &t = slot.sts[j];
1298 Texture *u = slot.sts[j].t;
1299 if(t.type==TEX_DIFFUSE || t.combined>=0) continue;
1300 if(t.type==TEX_DIFFUSE && blankgeom) u = blanktexture;
1301 if(t.type==TEX_ENVMAP)
1302 {
1303 if(envmaptmu>=0 && cur.textures[envmaptmu]!=u->id)
1304 {
1305 glActiveTexture_(GL_TEXTURE0_ARB+envmaptmu);
1306 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cur.textures[envmaptmu] = u->id);
1307 }
1308 continue;
1309 }
1310 else if(cur.textures[tmu]!=u->id)
1311 {
1312 glActiveTexture_(GL_TEXTURE0_ARB+tmu);
1313 glBindTexture(GL_TEXTURE_2D, cur.textures[tmu] = u->id);
1314 }
1315 tmu++;
1316 }
1317 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1318 }
1319
1320 Texture *curtex = blankgeom ? blanktexture :
1321 (!cur.slot || cur.slot->sts.empty() ? notexture : cur.slot->sts[0].t),
1322 *tex = blankgeom ? blanktexture : (slot.sts.empty() ? notexture : slot.sts[0].t);
1323 if(!cur.slot || slot.sts.empty() ||
1324 (curtex->xs != tex->xs || curtex->ys != tex->ys ||
1325 cur.slot->rotation != slot.rotation || cur.slot->scale != slot.scale ||
1326 cur.slot->xoffset != slot.xoffset || cur.slot->yoffset != slot.yoffset ||
1327 cur.slot->scrollS != slot.scrollS || cur.slot->scrollT != slot.scrollT))
1328 {
1329 float k = 8.0f/slot.scale/(1<<VVEC_FRAC),
1330 xs = slot.rotation>=2 && slot.rotation<=4 ? -tex->xs : tex->xs,
1331 ys = (slot.rotation>=1 && slot.rotation<=2) || slot.rotation==5 ? -tex->ys : tex->ys;
1332 if((slot.rotation&5)==1)
1333 {
1334 cur.texgenSk = k/xs; cur.texgenSoff = (slot.scrollT*lastmillis*tex->xs - slot.yoffset)/xs;
1335 cur.texgenTk = k/ys; cur.texgenToff = (slot.scrollS*lastmillis*tex->ys - slot.xoffset)/ys;
1336 }
1337 else
1338 {
1339 cur.texgenSk = k/xs; cur.texgenSoff = (slot.scrollS*lastmillis*tex->xs - slot.xoffset)/xs;
1340 cur.texgenTk = k/ys; cur.texgenToff = (slot.scrollT*lastmillis*tex->ys - slot.yoffset)/ys;
1341 }
1342 cur.texgendim = -1;
1343 }
1344
1345 cur.slot = &slot;
1346 }
1347
changeshader(renderstate & cur,Shader * s,Slot & slot,bool shadowed)1348 static void changeshader(renderstate &cur, Shader *s, Slot &slot, bool shadowed)
1349 {
1350 if(glaring)
1351 {
1352 static Shader *noglareshader = NULL, *noglareblendshader = NULL;
1353 if(!noglareshader) noglareshader = lookupshaderbyname("noglareworld");
1354 if(!noglareblendshader) noglareblendshader = lookupshaderbyname("noglareblendworld");
1355 if(s->hasoption(4)) s->setvariant(cur.visibledynlights, 4, &slot, cur.blending ? noglareblendshader : noglareshader);
1356 else s->setvariant(cur.blending ? 1 : 0, 4, &slot, cur.blending ? noglareblendshader : noglareshader);
1357 }
1358 else if(fading && !cur.blending)
1359 {
1360 if(shadowed) s->setvariant(cur.visibledynlights, 3, &slot);
1361 else s->setvariant(cur.visibledynlights, 2, &slot);
1362 }
1363 else if(shadowed) s->setvariant(cur.visibledynlights, 1, &slot);
1364 else if(!cur.visibledynlights) s->set(&slot);
1365 else s->setvariant(cur.visibledynlights-1, 0, &slot);
1366 if(s->type&SHADER_GLSLANG) cur.texgendim = -1;
1367 }
1368
changetexgen(renderstate & cur,Slot & slot,int dim)1369 static void changetexgen(renderstate &cur, Slot &slot, int dim)
1370 {
1371 static const int si[] = { 1, 0, 0 };
1372 static const int ti[] = { 2, 2, 1 };
1373
1374 GLfloat sgen[4] = { 0.0f, 0.0f, 0.0f, cur.texgenSoff },
1375 tgen[4] = { 0.0f, 0.0f, 0.0f, cur.texgenToff };
1376 int sdim = si[dim], tdim = ti[dim];
1377 if((slot.rotation&5)==1)
1378 {
1379 sgen[tdim] = (dim <= 1 ? -cur.texgenSk : cur.texgenSk);
1380 sgen[3] += (vaorigin[tdim]<<VVEC_FRAC)*sgen[tdim];
1381 tgen[sdim] = cur.texgenTk;
1382 tgen[3] += (vaorigin[sdim]<<VVEC_FRAC)*tgen[sdim];
1383 }
1384 else
1385 {
1386 sgen[sdim] = cur.texgenSk;
1387 sgen[3] += (vaorigin[sdim]<<VVEC_FRAC)*sgen[sdim];
1388 tgen[tdim] = (dim <= 1 ? -cur.texgenTk : cur.texgenTk);
1389 tgen[3] += (vaorigin[tdim]<<VVEC_FRAC)*tgen[tdim];
1390 }
1391
1392 if(renderpath==R_FIXEDFUNCTION)
1393 {
1394 if(cur.texgendim!=dim)
1395 {
1396 glTexGenfv(GL_S, GL_OBJECT_PLANE, sgen);
1397 glTexGenfv(GL_T, GL_OBJECT_PLANE, tgen);
1398 // KLUGE: workaround for buggy nvidia drivers
1399 // object planes are somehow invalid unless texgen is toggled
1400 extern int nvidia_texgen_bug;
1401 if(nvidia_texgen_bug)
1402 {
1403 glDisable(GL_TEXTURE_GEN_S);
1404 glDisable(GL_TEXTURE_GEN_T);
1405 glEnable(GL_TEXTURE_GEN_S);
1406 glEnable(GL_TEXTURE_GEN_T);
1407 }
1408 }
1409
1410 if(cur.mtglow)
1411 {
1412 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1413 glTexGenfv(GL_S, GL_OBJECT_PLANE, sgen);
1414 glTexGenfv(GL_T, GL_OBJECT_PLANE, tgen);
1415 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1416 }
1417 cur.mttexgen = cur.mtglow;
1418 }
1419 else
1420 {
1421 // have to pass in env, otherwise same problem as fixed function
1422 setlocalparamfv("texgenS", SHPARAM_VERTEX, 0, sgen);
1423 setlocalparamfv("texgenT", SHPARAM_VERTEX, 1, tgen);
1424 setlocalparamfv("orienttangent", SHPARAM_VERTEX, 2, orientation_tangent[slot.rotation][dim]);
1425 setlocalparamfv("orientbinormal", SHPARAM_VERTEX, 3, orientation_binormal[slot.rotation][dim]);
1426 }
1427
1428 cur.texgendim = dim;
1429 }
1430
1431 struct batchdrawinfo
1432 {
1433 ushort *edata;
1434 ushort len, minvert, maxvert;
1435
batchdrawinfobatchdrawinfo1436 batchdrawinfo(geombatch &b, int dim, ushort offset, ushort len)
1437 : edata(b.edata + offset), len(len),
1438 minvert(b.va->shadowed ? b.es.minvert[dim] : min(b.es.minvert[dim], b.es.minvert[dim+1])),
1439 maxvert(b.va->shadowed ? b.es.maxvert[dim] : max(b.es.maxvert[dim], b.es.maxvert[dim+1]))
1440 {}
1441 };
1442
renderbatch(renderstate & cur,int pass,geombatch & b)1443 static void renderbatch(renderstate &cur, int pass, geombatch &b)
1444 {
1445 static vector<batchdrawinfo> draws[6];
1446 for(geombatch *curbatch = &b;; curbatch = &geombatches[curbatch->batch])
1447 {
1448 int dim = 0;
1449 ushort offset = 0, len = 0;
1450 loopi(3)
1451 {
1452 offset += len;
1453 len = curbatch->es.length[dim + (curbatch->va->shadowed ? 0 : 1)] - offset;
1454 if(len) draws[dim].add(batchdrawinfo(*curbatch, dim, offset, len));
1455 dim++;
1456
1457 if(curbatch->va->shadowed)
1458 {
1459 offset += len;
1460 len = curbatch->es.length[dim] - offset;
1461 if(len) draws[dim].add(batchdrawinfo(*curbatch, dim, offset, len));
1462 }
1463 dim++;
1464 }
1465 if(curbatch->batch < 0) break;
1466 }
1467 loop(shadowed, 2)
1468 {
1469 bool rendered = false;
1470 loop(dim, 3)
1471 {
1472 vector<batchdrawinfo> &draw = draws[2*dim + shadowed];
1473 if(draw.empty()) continue;
1474
1475 if(!rendered)
1476 {
1477 if(renderpath!=R_FIXEDFUNCTION) changeshader(cur, b.slot.shader, b.slot, shadowed!=0);
1478 rendered = true;
1479 }
1480 if(cur.texgendim!=dim || cur.mtglow>cur.mttexgen)
1481 changetexgen(cur, b.slot, dim);
1482
1483 gbatches++;
1484 loopv(draw)
1485 {
1486 batchdrawinfo &info = draw[i];
1487 drawtris(info.len, info.edata, info.minvert, info.maxvert);
1488 vtris += info.len/3;
1489 }
1490 draw.setsizenodelete(0);
1491 }
1492 }
1493 }
1494
resetbatches()1495 static void resetbatches()
1496 {
1497 geombatches.setsizenodelete(0);
1498 firstbatch = -1;
1499 numbatches = 0;
1500 }
1501
renderbatches(renderstate & cur,int pass)1502 static void renderbatches(renderstate &cur, int pass)
1503 {
1504 cur.slot = NULL;
1505 int curbatch = firstbatch;
1506 if(curbatch >= 0)
1507 {
1508 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
1509 if(!cur.colormask) { cur.colormask = true; glColorMask(COLORMASK, GL_TRUE); }
1510 }
1511 while(curbatch >= 0)
1512 {
1513 geombatch &b = geombatches[curbatch];
1514 curbatch = b.next;
1515
1516 if(cur.vbuf != b.va->vbuf)
1517 {
1518 changevbuf(cur, pass, b.va);
1519 if(pass == RENDERPASS_DYNLIGHT) changedynlightpos(cur, b.va);
1520 else changefogplane(cur, pass, b.va);
1521 }
1522 if(pass == RENDERPASS_LIGHTMAP)
1523 {
1524 changebatchtmus(cur, pass, b);
1525 if(cur.dynlightmask != b.va->dynlightmask)
1526 {
1527 cur.visibledynlights = setdynlights(b.va, vaorigin);
1528 cur.dynlightmask = b.va->dynlightmask;
1529 }
1530 }
1531 if(cur.slot != &b.slot) changeslottmus(cur, pass, b.slot);
1532
1533 renderbatch(cur, pass, b);
1534 }
1535
1536 if(pass == RENDERPASS_LIGHTMAP && cur.mtglow)
1537 {
1538 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1539 glDisable(GL_TEXTURE_2D);
1540 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1541 cur.mtglow = false;
1542 }
1543
1544 resetbatches();
1545 }
1546
renderzpass(renderstate & cur,vtxarray * va)1547 void renderzpass(renderstate &cur, vtxarray *va)
1548 {
1549 if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_Z, va);
1550 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
1551 if(cur.colormask) { cur.colormask = false; glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); }
1552
1553 extern int apple_glsldepth_bug;
1554 if(renderpath!=R_GLSLANG || !apple_glsldepth_bug)
1555 {
1556 nocolorshader->set();
1557 drawvatris(va, 3*va->tris, va->edata);
1558 }
1559 else
1560 {
1561 static Shader *nocolorglslshader = NULL;
1562 if(!nocolorglslshader) nocolorglslshader = lookupshaderbyname("nocolorglsl");
1563 Slot *lastslot = NULL;
1564 int lastdraw = 0, offset = 0;
1565 loopi(va->texs)
1566 {
1567 Slot &slot = lookuptexture(va->eslist[i].texture);
1568 if(lastslot && (slot.shader->type&SHADER_GLSLANG) != (lastslot->shader->type&SHADER_GLSLANG) && offset > lastdraw)
1569 {
1570 (lastslot->shader->type&SHADER_GLSLANG ? nocolorglslshader : nocolorshader)->set();
1571 drawvatris(va, offset-lastdraw, va->edata+lastdraw);
1572 lastdraw = offset;
1573 }
1574 lastslot = &slot;
1575 offset += va->eslist[i].length[5];
1576 }
1577 if(offset > lastdraw)
1578 {
1579 (lastslot->shader->type&SHADER_GLSLANG ? nocolorglslshader : nocolorshader)->set();
1580 drawvatris(va, offset-lastdraw, va->edata+lastdraw);
1581 }
1582 }
1583 xtravertsva += va->verts;
1584 }
1585
1586 vector<vtxarray *> foggedvas;
1587
1588 #define startvaquery(va, flush) \
1589 do { \
1590 if(!refracting) \
1591 { \
1592 occludequery *query = reflecting ? va->rquery : va->query; \
1593 if(query) \
1594 { \
1595 flush; \
1596 startquery(query); \
1597 } \
1598 } \
1599 } while(0)
1600
1601
1602 #define endvaquery(va, flush) \
1603 do { \
1604 if(!refracting) \
1605 { \
1606 occludequery *query = reflecting ? va->rquery : va->query; \
1607 if(query) \
1608 { \
1609 flush; \
1610 endquery(query); \
1611 } \
1612 } \
1613 } while(0)
1614
renderfoggedvas(renderstate & cur,bool doquery=false)1615 void renderfoggedvas(renderstate &cur, bool doquery = false)
1616 {
1617 static Shader *fogshader = NULL;
1618 if(!fogshader) fogshader = lookupshaderbyname("fogworld");
1619 fogshader->set();
1620
1621 glDisable(GL_TEXTURE_2D);
1622
1623 glColor3ubv(watercol.v);
1624
1625 loopv(foggedvas)
1626 {
1627 vtxarray *va = foggedvas[i];
1628 if(cur.vbuf!=va->vbuf) changevbuf(cur, RENDERPASS_FOG, va);
1629
1630 if(doquery) startvaquery(va, );
1631 drawvatris(va, 3*va->tris, va->edata);
1632 vtris += va->tris;
1633 if(doquery) endvaquery(va, );
1634 }
1635
1636 glEnable(GL_TEXTURE_2D);
1637
1638 foggedvas.setsizenodelete(0);
1639 }
1640
rendershadowmappass(renderstate & cur,vtxarray * va)1641 void rendershadowmappass(renderstate &cur, vtxarray *va)
1642 {
1643 if(cur.vbuf!=va->vbuf)
1644 {
1645 changevbuf(cur, RENDERPASS_SHADOWMAP, va);
1646 changefogplane(cur, RENDERPASS_SHADOWMAP, va);
1647 }
1648
1649 elementset *texs = va->eslist;
1650 ushort *edata = va->edata;
1651 loopi(va->texs)
1652 {
1653 elementset &es = texs[i];
1654 int len = es.length[1] - es.length[0];
1655 if(len > 0)
1656 {
1657 drawtris(len, &edata[es.length[0]], es.minvert[1], es.maxvert[1]);
1658 vtris += len/3;
1659 }
1660 len = es.length[3] - es.length[2];
1661 if(len > 0)
1662 {
1663 drawtris(len, &edata[es.length[2]], es.minvert[3], es.maxvert[3]);
1664 vtris += len/3;
1665 }
1666 len = es.length[5] - es.length[4];
1667 if(len > 0)
1668 {
1669 drawtris(len, &edata[es.length[4]], es.minvert[5], es.maxvert[5]);
1670 vtris += len/3;
1671 }
1672 edata += es.length[5];
1673 }
1674 }
1675
1676 VAR(batchgeom, 0, 1, 1);
1677
renderva(renderstate & cur,vtxarray * va,int pass=RENDERPASS_LIGHTMAP,bool fogpass=false,bool doquery=false)1678 void renderva(renderstate &cur, vtxarray *va, int pass = RENDERPASS_LIGHTMAP, bool fogpass = false, bool doquery = false)
1679 {
1680 switch(pass)
1681 {
1682 case RENDERPASS_GLOW:
1683 if(!(va->texmask&(1<<TEX_GLOW))) return;
1684 mergeglowtexs(va);
1685 if(!batchgeom && geombatches.length()) renderbatches(cur, pass);
1686 break;
1687
1688 case RENDERPASS_COLOR:
1689 case RENDERPASS_LIGHTMAP:
1690 vverts += va->verts;
1691 va->shadowed = false;
1692 va->dynlightmask = 0;
1693 if(fogpass ? va->geommax.z<=reflectz-waterfog : va->curvfc==VFC_FOGGED)
1694 {
1695 foggedvas.add(va);
1696 break;
1697 }
1698 if(renderpath!=R_FIXEDFUNCTION && !envmapping && !glaring)
1699 {
1700 va->shadowed = isshadowmapreceiver(va);
1701 calcdynlightmask(va);
1702 }
1703 if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); });
1704 mergetexs(va);
1705 if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, pass); });
1706 else if(!batchgeom && geombatches.length()) renderbatches(cur, pass);
1707 break;
1708
1709 case RENDERPASS_LIGHTMAP_BLEND:
1710 {
1711 if(doquery) startvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); });
1712 ushort *edata = va->edata;
1713 loopi(va->texs) edata += va->eslist[i].length[5];
1714 mergetexs(va, &va->eslist[va->texs], va->blends, edata);
1715 if(doquery) endvaquery(va, { if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP); });
1716 else if(!batchgeom && geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
1717 break;
1718 }
1719
1720 case RENDERPASS_DYNLIGHT:
1721 if(cur.dynlightpos.dist_to_bb(va->geommin, va->geommax) >= cur.dynlightradius) break;
1722 vverts += va->verts;
1723 mergetexs(va);
1724 if(!batchgeom && geombatches.length()) renderbatches(cur, pass);
1725 break;
1726
1727 case RENDERPASS_FOG:
1728 if(cur.vbuf!=va->vbuf)
1729 {
1730 changevbuf(cur, pass, va);
1731 changefogplane(cur, pass, va);
1732 }
1733 drawvatris(va, 3*va->tris, va->edata);
1734 xtravertsva += va->verts;
1735 break;
1736
1737 case RENDERPASS_SHADOWMAP:
1738 if(isshadowmapreceiver(va)) rendershadowmappass(cur, va);
1739 break;
1740
1741 case RENDERPASS_CAUSTICS:
1742 if(cur.vbuf!=va->vbuf) changevbuf(cur, pass, va);
1743 drawvatris(va, 3*va->tris, va->edata);
1744 xtravertsva += va->verts;
1745 break;
1746
1747 case RENDERPASS_Z:
1748 if(doquery) startvaquery(va, );
1749 renderzpass(cur, va);
1750 if(doquery) endvaquery(va, );
1751 break;
1752 }
1753 }
1754
1755 VAR(oqdist, 0, 256, 1024);
1756 VAR(zpass, 0, 1, 1);
1757 VAR(glowpass, 0, 1, 1);
1758
1759 GLuint fogtex = 0;
1760
createfogtex()1761 void createfogtex()
1762 {
1763 extern int bilinear;
1764 uchar buf[2*256] = { 255, 0, 255, 255 };
1765 if(!bilinear) loopi(256) { buf[2*i] = 255; buf[2*i+1] = i; }
1766 glGenTextures(1, &fogtex);
1767 createtexture(fogtex, bilinear ? 2 : 256, 1, buf, 3, 1, GL_LUMINANCE_ALPHA, GL_TEXTURE_1D);
1768 }
1769
1770 GLuint attenxytex = 0, attenztex = 0;
1771
createattenxytex(int size)1772 static GLuint createattenxytex(int size)
1773 {
1774 uchar *data = new uchar[size*size], *dst = data;
1775 loop(y, size) loop(x, size)
1776 {
1777 float dx = 2*float(x)/(size-1) - 1, dy = 2*float(y)/(size-1) - 1;
1778 float atten = max(0.0f, 1.0f - dx*dx - dy*dy);
1779 *dst++ = uchar(atten*255);
1780 }
1781 GLuint tex = 0;
1782 glGenTextures(1, &tex);
1783 createtexture(tex, size, size, data, 3, 1, GL_ALPHA);
1784 delete[] data;
1785 return tex;
1786 }
1787
createattenztex(int size)1788 static GLuint createattenztex(int size)
1789 {
1790 uchar *data = new uchar[size], *dst = data;
1791 loop(z, size)
1792 {
1793 float dz = 2*float(z)/(size-1) - 1;
1794 float atten = dz*dz;
1795 *dst++ = uchar(atten*255);
1796 }
1797 GLuint tex = 0;
1798 glGenTextures(1, &tex);
1799 createtexture(tex, size, 1, data, 3, 1, GL_ALPHA, GL_TEXTURE_1D);
1800 delete[] data;
1801 return tex;
1802 }
1803
1804 Texture *caustic = NULL;
loadcaustic(const char * name)1805 void loadcaustic(const char *name)
1806 {
1807 if(*name)
1808 {
1809 defformatstring(s)("%s%s", renderpath==R_FIXEDFUNCTION ? "<mad:0.6,0.4>" : "<mad:-0.6,0.6>", name);
1810 caustic = textureload(s);
1811 }
1812 else caustic = notexture;
1813 }
1814 SVARFW(caustictex, "<anim:75>textures/caustics", loadcaustic(caustictex));
1815
loadcaustics(bool force)1816 void loadcaustics(bool force)
1817 {
1818 static bool needcaustics = false;
1819 if(force) needcaustics = true;
1820 if(!caustics || !needcaustics) return;
1821 useshaderbyname("caustic");
1822 loadcaustic(caustictex);
1823 }
1824
1825 VARW(causticscale, 0, 100, 10000);
1826 VARFP(caustics, 0, 1, 1, loadcaustics());
1827
cleanupva()1828 void cleanupva()
1829 {
1830 clearvas(worldroot);
1831 clearqueries();
1832 if(fogtex) { glDeleteTextures(1, &fogtex); fogtex = 0; }
1833 if(attenxytex) { glDeleteTextures(1, &attenxytex); attenxytex = 0; }
1834 if(attenztex) { glDeleteTextures(1, &attenztex); attenztex = 0; }
1835 caustic = NULL;
1836 }
1837
setupcaustics(int tmu,float blend,GLfloat * color=NULL)1838 void setupcaustics(int tmu, float blend, GLfloat *color = NULL)
1839 {
1840 if(!caustictex[0]) loadcaustics(true);
1841
1842 GLfloat s[4] = { 0.011f, 0, 0.0066f, 0 };
1843 GLfloat t[4] = { 0, 0.011f, 0.0066f, 0 };
1844 loopk(3)
1845 {
1846 s[k] *= 100.0f/(causticscale<<VVEC_FRAC);
1847 t[k] *= 100.0f/(causticscale<<VVEC_FRAC);
1848 }
1849 int tex = (lastmillis/caustic->delay)%caustic->frames.length();
1850 float frac = float(lastmillis%caustic->delay)/caustic->delay;
1851 if(color) color[3] = frac;
1852 else glColor4f(1, 1, 1, frac);
1853 loopi(2)
1854 {
1855 glActiveTexture_(GL_TEXTURE0_ARB+tmu+i);
1856 glEnable(GL_TEXTURE_2D);
1857 glBindTexture(GL_TEXTURE_2D, caustic->frames[(tex+i)%caustic->frames.length()]);
1858 if(renderpath==R_FIXEDFUNCTION)
1859 {
1860 setuptexgen();
1861 setuptmu(tmu+i, !i ? "= T" : "T , P @ Ca");
1862 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
1863 glTexGenfv(GL_T, GL_OBJECT_PLANE, t);
1864 }
1865 }
1866 if(renderpath!=R_FIXEDFUNCTION)
1867 {
1868 static Shader *causticshader = NULL;
1869 if(!causticshader) causticshader = lookupshaderbyname("caustic");
1870 causticshader->set();
1871 setlocalparamfv("texgenS", SHPARAM_VERTEX, 0, s);
1872 setlocalparamfv("texgenT", SHPARAM_VERTEX, 1, t);
1873 setlocalparamf("frameoffset", SHPARAM_PIXEL, 0, blend*(1-frac), blend*frac, blend);
1874 }
1875 }
1876
setupTMUs(renderstate & cur,float causticspass,bool fogpass)1877 void setupTMUs(renderstate &cur, float causticspass, bool fogpass)
1878 {
1879 if(!reflecting && !refracting && !envmapping && shadowmap && hasFBO)
1880 {
1881 glDisableClientState(GL_VERTEX_ARRAY);
1882
1883 if(hasVBO)
1884 {
1885 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1886 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1887 }
1888
1889 rendershadowmap();
1890
1891 glEnableClientState(GL_VERTEX_ARRAY);
1892 }
1893
1894 if(renderpath==R_FIXEDFUNCTION)
1895 {
1896 if(nolights) cur.lightmaptmu = -1;
1897 else if(maxtmus>=3)
1898 {
1899 if(maxtmus>=4 && causticspass>=1)
1900 {
1901 cur.causticstmu = 0;
1902 cur.diffusetmu = 2;
1903 cur.lightmaptmu = 3;
1904 if(maxtmus>=5)
1905 {
1906 if(fogpass)
1907 {
1908 if(glowpass && maxtmus>=6)
1909 {
1910 cur.fogtmu = 5;
1911 cur.glowtmu = 4;
1912 }
1913 else cur.fogtmu = 4;
1914 }
1915 else if(glowpass) cur.glowtmu = 4;
1916 }
1917 }
1918 else if(fogpass && causticspass<1) cur.fogtmu = 2;
1919 else if(glowpass) cur.glowtmu = 2;
1920 }
1921 if(cur.glowtmu>=0)
1922 {
1923 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1924 setuptexgen();
1925 setuptmu(cur.glowtmu, "P + T", "= Pa");
1926 }
1927 if(cur.fogtmu>=0)
1928 {
1929 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
1930 glEnable(GL_TEXTURE_1D);
1931 setuptexgen(1);
1932 setuptmu(cur.fogtmu, "C , P @ Ta", "= Pa");
1933 if(!fogtex) createfogtex();
1934 glBindTexture(GL_TEXTURE_1D, fogtex);
1935 loopk(3) cur.color[k] = watercol[k]/255.0f;
1936 }
1937 if(cur.causticstmu>=0) setupcaustics(cur.causticstmu, causticspass, cur.color);
1938 }
1939 else
1940 {
1941 // need to invalidate vertex params in case they were used somewhere else for streaming params
1942 invalidateenvparams(SHPARAM_VERTEX, 10, RESERVEDSHADERPARAMS + MAXSHADERPARAMS - 10);
1943 glEnableClientState(GL_COLOR_ARRAY);
1944 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glEnable(GL_TEXTURE_2D); }
1945 glActiveTexture_(GL_TEXTURE0_ARB);
1946 setenvparamf("ambient", SHPARAM_PIXEL, 5, ambientcolor[0]/255.0f, ambientcolor[1]/255.0f, ambientcolor[2]/255.0f);
1947 setenvparamf("millis", SHPARAM_VERTEX, 6, lastmillis/1000.0f, lastmillis/1000.0f, lastmillis/1000.0f);
1948 }
1949
1950 glColor4fv(cur.color);
1951
1952 if(cur.lightmaptmu>=0)
1953 {
1954 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1955 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1956
1957 setuptmu(cur.lightmaptmu, "P * T x 2", "= Ta");
1958 glEnable(GL_TEXTURE_2D);
1959 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1960 glMatrixMode(GL_TEXTURE);
1961 glLoadIdentity();
1962 glScalef(1.0f/SHRT_MAX, 1.0f/SHRT_MAX, 1.0f);
1963 glMatrixMode(GL_MODELVIEW);
1964
1965 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1966 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
1967 glEnable(GL_TEXTURE_2D);
1968 setuptmu(cur.diffusetmu, cur.diffusetmu>0 ? "P * T" : "= T");
1969 }
1970
1971 if(renderpath==R_FIXEDFUNCTION) setuptexgen();
1972 }
1973
cleanupTMUs(renderstate & cur)1974 void cleanupTMUs(renderstate &cur)
1975 {
1976 if(cur.lightmaptmu>=0)
1977 {
1978 glActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1979 glClientActiveTexture_(GL_TEXTURE0_ARB+cur.lightmaptmu);
1980
1981 resettmu(cur.lightmaptmu);
1982 glDisable(GL_TEXTURE_2D);
1983 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1984 glMatrixMode(GL_TEXTURE);
1985 glLoadIdentity();
1986 glMatrixMode(GL_MODELVIEW);
1987 }
1988 if(cur.glowtmu>=0)
1989 {
1990 glActiveTexture_(GL_TEXTURE0_ARB+cur.glowtmu);
1991 resettmu(cur.glowtmu);
1992 disabletexgen();
1993 glDisable(GL_TEXTURE_2D);
1994 }
1995 if(cur.fogtmu>=0)
1996 {
1997 glActiveTexture_(GL_TEXTURE0_ARB+cur.fogtmu);
1998 resettmu(cur.fogtmu);
1999 disabletexgen(1);
2000 glDisable(GL_TEXTURE_1D);
2001 }
2002 if(cur.causticstmu>=0) loopi(2)
2003 {
2004 glActiveTexture_(GL_TEXTURE0_ARB+cur.causticstmu+i);
2005 resettmu(cur.causticstmu+i);
2006 disabletexgen();
2007 glDisable(GL_TEXTURE_2D);
2008 }
2009
2010 if(cur.lightmaptmu>=0)
2011 {
2012 glActiveTexture_(GL_TEXTURE0_ARB+cur.diffusetmu);
2013 resettmu(cur.diffusetmu);
2014 glDisable(GL_TEXTURE_2D);
2015 }
2016
2017 if(renderpath==R_FIXEDFUNCTION) disabletexgen();
2018 else
2019 {
2020 glDisableClientState(GL_COLOR_ARRAY);
2021 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB+i); glDisable(GL_TEXTURE_2D); }
2022 }
2023
2024 if(cur.lightmaptmu>=0)
2025 {
2026 glActiveTexture_(GL_TEXTURE0_ARB);
2027 glClientActiveTexture_(GL_TEXTURE0_ARB);
2028 glEnable(GL_TEXTURE_2D);
2029 }
2030 }
2031
2032 #define FIRSTVA (reflecting ? reflectedva : visibleva)
2033 #define NEXTVA (reflecting ? va->rnext : va->next)
2034
rendergeommultipass(renderstate & cur,int pass,bool fogpass)2035 static void rendergeommultipass(renderstate &cur, int pass, bool fogpass)
2036 {
2037 cur.vbuf = 0;
2038 for(vtxarray *va = FIRSTVA; va; va = NEXTVA)
2039 {
2040 if(!va->texs || va->occluded >= OCCLUDE_GEOM) continue;
2041 if(refracting)
2042 {
2043 if(refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) continue;
2044 if(ishiddencube(va->o, va->size)) continue;
2045 if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
2046 }
2047 else if(reflecting)
2048 {
2049 if(va->geommax.z <= reflectz || (va->rquery && checkquery(va->rquery))) continue;
2050 }
2051 if(fogpass ? va->geommax.z <= reflectz-waterfog : va->curvfc==VFC_FOGGED) continue;
2052 renderva(cur, va, pass, fogpass);
2053 }
2054 if(geombatches.length()) renderbatches(cur, pass);
2055 }
2056
2057 VAR(oqgeom, 0, 1, 1);
2058 VAR(oqbatch, 0, 1, 1);
2059
2060 VAR(dbgffsm, 0, 0, 1);
2061 VAR(dbgffdl, 0, 0, 1);
2062 VAR(ffdlscissor, 0, 1, 1);
2063
rendergeom(float causticspass,bool fogpass)2064 void rendergeom(float causticspass, bool fogpass)
2065 {
2066 renderstate cur;
2067
2068 if(causticspass && ((renderpath==R_FIXEDFUNCTION && maxtmus<2) || !causticscale)) causticspass = 0;
2069
2070 glEnableClientState(GL_VERTEX_ARRAY);
2071
2072 if(!reflecting && !refracting)
2073 {
2074 flipqueries();
2075 vtris = vverts = 0;
2076 }
2077
2078 bool doOQ = reflecting ? hasOQ && oqfrags && oqreflect : !refracting && zpass!=0;
2079 if(!doOQ)
2080 {
2081 setupTMUs(cur, causticspass, fogpass);
2082 if(shadowmap && !envmapping && !glaring && renderpath!=R_FIXEDFUNCTION) pushshadowmap();
2083 }
2084
2085 int hasdynlights = finddynlights();
2086
2087 glPushMatrix();
2088
2089 resetorigin();
2090
2091 resetbatches();
2092
2093 int blends = 0;
2094 for(vtxarray *va = FIRSTVA; va; va = NEXTVA)
2095 {
2096 if(!va->texs) continue;
2097 if(refracting)
2098 {
2099 if((refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) || va->occluded >= OCCLUDE_GEOM) continue;
2100 if(ishiddencube(va->o, va->size)) continue;
2101 if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
2102 }
2103 else if(reflecting)
2104 {
2105 if(va->geommax.z <= reflectz) continue;
2106 if(doOQ)
2107 {
2108 va->rquery = newquery(&va->rquery);
2109 if(!va->rquery) continue;
2110 if(va->occluded >= OCCLUDE_BB || va->curvfc >= VFC_NOT_VISIBLE)
2111 {
2112 renderquery(cur, va->rquery, va);
2113 continue;
2114 }
2115 }
2116 }
2117 else if(hasOQ && oqfrags && (zpass || va->distance > oqdist) && !insideva(va, camera1->o) && oqgeom)
2118 {
2119 if(!zpass && va->query && va->query->owner == va)
2120 {
2121 if(checkquery(va->query)) va->occluded = min(va->occluded+1, int(OCCLUDE_BB));
2122 else va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
2123 }
2124 if(zpass && oqbatch)
2125 {
2126 if(va->parent && va->parent->occluded >= OCCLUDE_BB)
2127 {
2128 va->query = NULL;
2129 va->occluded = OCCLUDE_PARENT;
2130 continue;
2131 }
2132 bool succeeded = false;
2133 if(va->query && va->query->owner == va && checkquery(va->query))
2134 {
2135 va->occluded = min(va->occluded+1, int(OCCLUDE_BB));
2136 succeeded = true;
2137 }
2138 va->query = newquery(va);
2139 if(!va->query || !succeeded)
2140 va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
2141 if(va->occluded >= OCCLUDE_GEOM)
2142 {
2143 if(va->query) renderquery(cur, va->query, va);
2144 continue;
2145 }
2146 }
2147 else if(zpass && va->parent &&
2148 (va->parent->occluded == OCCLUDE_PARENT ||
2149 (va->parent->occluded >= OCCLUDE_BB &&
2150 va->parent->query && va->parent->query->owner == va->parent && va->parent->query->fragments < 0)))
2151 {
2152 va->query = NULL;
2153 if(va->occluded >= OCCLUDE_GEOM || pvsoccluded(va->geommin, va->geommax))
2154 {
2155 va->occluded = OCCLUDE_PARENT;
2156 continue;
2157 }
2158 }
2159 else if(va->occluded >= OCCLUDE_GEOM)
2160 {
2161 va->query = newquery(va);
2162 if(va->query) renderquery(cur, va->query, va);
2163 continue;
2164 }
2165 else va->query = newquery(va);
2166 }
2167 else
2168 {
2169 va->query = NULL;
2170 va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
2171 if(va->occluded >= OCCLUDE_GEOM) continue;
2172 }
2173
2174 if(!doOQ) blends += va->blends;
2175 renderva(cur, va, doOQ ? RENDERPASS_Z : (nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP), fogpass, true);
2176 }
2177
2178 if(geombatches.length()) renderbatches(cur, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP);
2179
2180 if(!cur.colormask) { cur.colormask = true; glColorMask(COLORMASK, GL_TRUE); }
2181 if(!cur.depthmask) { cur.depthmask = true; glDepthMask(GL_TRUE); }
2182
2183 if(doOQ)
2184 {
2185 setupTMUs(cur, causticspass, fogpass);
2186 if(shadowmap && !envmapping && !glaring && renderpath!=R_FIXEDFUNCTION)
2187 {
2188 glPopMatrix();
2189 glPushMatrix();
2190 pushshadowmap();
2191 resetorigin();
2192 }
2193 glDepthFunc(GL_LEQUAL);
2194 cur.vbuf = 0;
2195
2196 for(vtxarray **prevva = &FIRSTVA, *va = FIRSTVA; va; prevva = &NEXTVA, va = NEXTVA)
2197 {
2198 if(!va->texs) continue;
2199 if(reflecting)
2200 {
2201 if(va->geommax.z <= reflectz) continue;
2202 if(va->rquery && checkquery(va->rquery))
2203 {
2204 if(va->occluded >= OCCLUDE_BB || va->curvfc >= VFC_NOT_VISIBLE) *prevva = va->rnext;
2205 continue;
2206 }
2207 }
2208 else if(oqbatch)
2209 {
2210 if(va->occluded >= OCCLUDE_GEOM) continue;
2211 }
2212 else if(va->parent && va->parent->occluded >= OCCLUDE_BB && (!va->parent->query || va->parent->query->fragments >= 0))
2213 {
2214 va->query = NULL;
2215 va->occluded = OCCLUDE_BB;
2216 continue;
2217 }
2218 else
2219 {
2220 if(va->query && checkquery(va->query)) va->occluded = min(va->occluded+1, int(OCCLUDE_BB));
2221 else va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
2222 if(va->occluded >= OCCLUDE_GEOM) continue;
2223 }
2224
2225 blends += va->blends;
2226 renderva(cur, va, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP, fogpass);
2227 }
2228 if(geombatches.length()) renderbatches(cur, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP);
2229 if(oqbatch && !reflecting) for(vtxarray **prevva = &FIRSTVA, *va = FIRSTVA; va; prevva = &NEXTVA, va = NEXTVA)
2230 {
2231 if(!va->texs || va->occluded < OCCLUDE_GEOM) continue;
2232 else if(va->query && checkquery(va->query)) continue;
2233 else if(va->parent && (va->parent->occluded >= OCCLUDE_BB ||
2234 (va->parent->occluded >= OCCLUDE_GEOM && va->parent->query && checkquery(va->parent->query))))
2235 {
2236 va->occluded = OCCLUDE_BB;
2237 continue;
2238 }
2239 else
2240 {
2241 va->occluded = pvsoccluded(va->geommin, va->geommax) ? OCCLUDE_GEOM : OCCLUDE_NOTHING;
2242 if(va->occluded >= OCCLUDE_GEOM) continue;
2243 }
2244
2245 blends += va->blends;
2246 renderva(cur, va, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP, fogpass);
2247 }
2248 if(geombatches.length()) renderbatches(cur, nolights ? RENDERPASS_COLOR : RENDERPASS_LIGHTMAP);
2249
2250 if(foggedvas.empty()) glDepthFunc(GL_LESS);
2251 }
2252
2253 if(blends && (renderpath!=R_FIXEDFUNCTION || !nolights))
2254 {
2255 if(shadowmap && !envmapping && !glaring && renderpath!=R_FIXEDFUNCTION)
2256 {
2257 glPopMatrix();
2258 glPushMatrix();
2259 resetorigin();
2260 }
2261 if(foggedvas.empty()) glDepthFunc(GL_LEQUAL);
2262 glDepthMask(GL_FALSE);
2263 glEnable(GL_BLEND);
2264 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2265 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
2266
2267 cur.vbuf = 0;
2268 cur.blending = true;
2269 for(vtxarray **prevva = &FIRSTVA, *va = FIRSTVA; va; prevva = &NEXTVA, va = NEXTVA)
2270 {
2271 if(!va->blends || va->occluded >= OCCLUDE_GEOM) continue;
2272 if(refracting)
2273 {
2274 if(refracting < 0 ? va->geommin.z > reflectz : va->geommax.z <= reflectz) continue;
2275 if(ishiddencube(va->o, va->size)) continue;
2276 if((!hasOQ || !oqfrags) && va->distance > reflectdist) break;
2277 }
2278 else if(reflecting)
2279 {
2280 if(va->geommax.z <= reflectz || (va->rquery && checkquery(va->rquery))) continue;
2281 }
2282 if(fogpass ? va->geommax.z <= reflectz-waterfog : va->curvfc==VFC_FOGGED) continue;
2283 renderva(cur, va, RENDERPASS_LIGHTMAP_BLEND, fogpass);
2284 }
2285 if(geombatches.length()) renderbatches(cur, RENDERPASS_LIGHTMAP);
2286 cur.blending = false;
2287
2288 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2289 glDisable(GL_BLEND);
2290 glDepthMask(GL_TRUE);
2291 if(foggedvas.empty()) glDepthFunc(GL_LESS);
2292 }
2293
2294 if(shadowmap && !envmapping && !glaring && renderpath!=R_FIXEDFUNCTION) popshadowmap();
2295
2296 cleanupTMUs(cur);
2297
2298 if(foggedvas.length())
2299 {
2300 renderfoggedvas(cur, !doOQ);
2301 if(doOQ) glDepthFunc(GL_LESS);
2302 }
2303
2304 if(renderpath==R_FIXEDFUNCTION ? (glowpass && cur.skippedglow) || (causticspass>=1 && cur.causticstmu<0) || (fogpass && cur.fogtmu<0) || (shadowmap && shadowmapcasters) || hasdynlights : causticspass)
2305 {
2306 glDepthFunc(GL_LEQUAL);
2307 glDepthMask(GL_FALSE);
2308 glEnable(GL_BLEND);
2309 static GLfloat zerofog[4] = { 0, 0, 0, 1 }, onefog[4] = { 1, 1, 1, 1 };
2310 GLfloat oldfogc[4];
2311 glGetFloatv(GL_FOG_COLOR, oldfogc);
2312
2313 if(renderpath==R_FIXEDFUNCTION && glowpass && cur.skippedglow)
2314 {
2315 glBlendFunc(GL_ONE, GL_ONE);
2316 glFogfv(GL_FOG_COLOR, zerofog);
2317 setuptexgen();
2318 if(cur.fogtmu>=0)
2319 {
2320 setuptmu(0, "C * T");
2321 glActiveTexture_(GL_TEXTURE1_ARB);
2322 glEnable(GL_TEXTURE_1D);
2323 setuptexgen(1);
2324 setuptmu(1, "P * T~a");
2325 if(!fogtex) createfogtex();
2326 glBindTexture(GL_TEXTURE_1D, fogtex);
2327 glActiveTexture_(GL_TEXTURE0_ARB);
2328 }
2329 cur.glowcolor = vec(-1, -1, -1);
2330 cur.glowtmu = 0;
2331 rendergeommultipass(cur, RENDERPASS_GLOW, fogpass);
2332 disabletexgen();
2333 if(cur.fogtmu>=0)
2334 {
2335 resettmu(0);
2336 glActiveTexture_(GL_TEXTURE1_ARB);
2337 resettmu(1);
2338 disabletexgen(1);
2339 glDisable(GL_TEXTURE_1D);
2340 glActiveTexture_(GL_TEXTURE0_ARB);
2341 }
2342 }
2343
2344 if(renderpath==R_FIXEDFUNCTION ? causticspass>=1 && cur.causticstmu<0 : causticspass)
2345 {
2346 setupcaustics(0, causticspass);
2347 glBlendFunc(GL_ZERO, renderpath==R_FIXEDFUNCTION ? GL_SRC_COLOR : GL_ONE_MINUS_SRC_COLOR);
2348 glFogfv(GL_FOG_COLOR, renderpath==R_FIXEDFUNCTION ? onefog : zerofog);
2349 if(fading) glColorMask(COLORMASK, GL_FALSE);
2350 rendergeommultipass(cur, RENDERPASS_CAUSTICS, fogpass);
2351 if(fading) glColorMask(COLORMASK, GL_TRUE);
2352 loopi(2)
2353 {
2354 glActiveTexture_(GL_TEXTURE0_ARB+i);
2355 resettmu(i);
2356 if(renderpath==R_FIXEDFUNCTION || !i)
2357 {
2358 resettmu(i);
2359 disabletexgen();
2360 }
2361 if(i) glDisable(GL_TEXTURE_2D);
2362 }
2363 glActiveTexture_(GL_TEXTURE0_ARB);
2364 }
2365
2366 if(renderpath==R_FIXEDFUNCTION && shadowmap && shadowmapcasters)
2367 {
2368 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
2369 glFogfv(GL_FOG_COLOR, zerofog);
2370 glPopMatrix();
2371 glPushMatrix();
2372 pushshadowmap();
2373 resetorigin();
2374 if(cur.fogtmu>=0)
2375 {
2376 setuptmu(0, "C * T");
2377 glActiveTexture_(GL_TEXTURE1_ARB);
2378 glEnable(GL_TEXTURE_1D);
2379 setuptexgen(1);
2380 setuptmu(1, "P * T~a");
2381 if(!fogtex) createfogtex();
2382 glBindTexture(GL_TEXTURE_1D, fogtex);
2383 glActiveTexture_(GL_TEXTURE0_ARB);
2384 }
2385 if(dbgffsm) { glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); glColor3f(1, 0, 1); }
2386 rendergeommultipass(cur, RENDERPASS_SHADOWMAP, fogpass);
2387 if(dbgffsm) { glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); }
2388 popshadowmap();
2389 if(cur.fogtmu>=0)
2390 {
2391 resettmu(0);
2392 glActiveTexture_(GL_TEXTURE1_ARB);
2393 resettmu(1);
2394 disabletexgen();
2395 glDisable(GL_TEXTURE_1D);
2396 glActiveTexture_(GL_TEXTURE0_ARB);
2397 }
2398 }
2399
2400 if(renderpath==R_FIXEDFUNCTION && hasdynlights)
2401 {
2402 glBlendFunc(GL_SRC_ALPHA, dbgffdl ? GL_ZERO : GL_ONE);
2403 glFogfv(GL_FOG_COLOR, zerofog);
2404
2405 if(!attenxytex) attenxytex = createattenxytex(64);
2406 glBindTexture(GL_TEXTURE_2D, attenxytex);
2407
2408 setuptmu(0, "= C", "= Ta");
2409 setuptexgen();
2410
2411 glActiveTexture_(GL_TEXTURE1_ARB);
2412 setuptmu(1, "= P", "Pa - Ta");
2413 setuptexgen(1);
2414 if(!attenztex) attenztex = createattenztex(64);
2415 glBindTexture(GL_TEXTURE_1D, attenztex);
2416 glEnable(GL_TEXTURE_1D);
2417
2418 glActiveTexture_(GL_TEXTURE2_ARB);
2419 cur.diffusetmu = 2;
2420 setuptmu(2, "P * T x 4", "= Pa");
2421 setuptexgen();
2422 glEnable(GL_TEXTURE_2D);
2423
2424 vec lightcolor;
2425 for(int n = 0; getdynlight(n, cur.dynlightpos, cur.dynlightradius, lightcolor); n++)
2426 {
2427 lightcolor.mul(0.5f);
2428 if(fogpass && cur.fogtmu>=0)
2429 {
2430 float fog = (reflectz - cur.dynlightpos.z)/waterfog;
2431 if(fog >= 1.0f) continue;
2432 lightcolor.mul(1.0f - max(fog, 0.0f));
2433 }
2434 glColor3f(lightcolor.x, lightcolor.y, lightcolor.z);
2435 if(ffdlscissor)
2436 {
2437 float sx1, sy1, sx2, sy2;
2438 calcspherescissor(cur.dynlightpos, cur.dynlightradius, sx1, sy1, sx2, sy2);
2439 pushscissor(sx1, sy1, sx2, sy2);
2440 }
2441 resetorigin();
2442 rendergeommultipass(cur, RENDERPASS_DYNLIGHT, fogpass);
2443 if(ffdlscissor) popscissor();
2444 }
2445
2446 glDisable(GL_TEXTURE_2D);
2447 disabletexgen();
2448 resettmu(2);
2449
2450 glActiveTexture_(GL_TEXTURE1_ARB);
2451 glDisable(GL_TEXTURE_1D);
2452 resettmu(1);
2453 disabletexgen(1);
2454
2455 glActiveTexture_(GL_TEXTURE0_ARB);
2456 resettmu(0);
2457 disabletexgen();
2458 }
2459
2460 if(renderpath==R_FIXEDFUNCTION && fogpass && cur.fogtmu<0)
2461 {
2462 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2463 glDisable(GL_TEXTURE_2D);
2464 glEnable(GL_TEXTURE_1D);
2465 setuptexgen(1);
2466 if(!fogtex) createfogtex();
2467 glBindTexture(GL_TEXTURE_1D, fogtex);
2468 setuptexgen(1);
2469 glColor3ubv(watercol.v);
2470 rendergeommultipass(cur, RENDERPASS_FOG, fogpass);
2471 disabletexgen(1);
2472 glDisable(GL_TEXTURE_1D);
2473 glEnable(GL_TEXTURE_2D);
2474 }
2475
2476 glFogfv(GL_FOG_COLOR, oldfogc);
2477 glDisable(GL_BLEND);
2478 glDepthFunc(GL_LESS);
2479 glDepthMask(GL_TRUE);
2480 }
2481
2482 glPopMatrix();
2483
2484 if(hasVBO)
2485 {
2486 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
2487 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
2488 }
2489 glDisableClientState(GL_VERTEX_ARRAY);
2490 }
2491
findreflectedvas(vector<vtxarray * > & vas,int prevvfc=VFC_PART_VISIBLE)2492 void findreflectedvas(vector<vtxarray *> &vas, int prevvfc = VFC_PART_VISIBLE)
2493 {
2494 bool doOQ = hasOQ && oqfrags && oqreflect;
2495 loopv(vas)
2496 {
2497 vtxarray *va = vas[i];
2498 if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc;
2499 if(va->curvfc == VFC_FOGGED || va->curvfc == PVS_FOGGED || va->o.z+va->size <= reflectz || isfoggedcube(va->o, va->size)) continue;
2500 bool render = true;
2501 if(va->curvfc == VFC_FULL_VISIBLE)
2502 {
2503 if(va->occluded >= OCCLUDE_BB) continue;
2504 if(va->occluded >= OCCLUDE_GEOM) render = false;
2505 }
2506 else if(va->curvfc == PVS_FULL_VISIBLE) continue;
2507 if(render)
2508 {
2509 if(va->curvfc >= VFC_NOT_VISIBLE) va->distance = (int)vadist(va, camera1->o);
2510 if(!doOQ && va->distance > reflectdist) continue;
2511 va->rquery = NULL;
2512 vtxarray **vprev = &reflectedva, *vcur = reflectedva;
2513 while(vcur && va->distance > vcur->distance)
2514 {
2515 vprev = &vcur->rnext;
2516 vcur = vcur->rnext;
2517 }
2518 va->rnext = *vprev;
2519 *vprev = va;
2520 }
2521 if(va->children.length()) findreflectedvas(va->children, va->curvfc);
2522 }
2523 }
2524
renderreflectedgeom(bool causticspass,bool fogpass)2525 void renderreflectedgeom(bool causticspass, bool fogpass)
2526 {
2527 if(reflecting)
2528 {
2529 reflectedva = NULL;
2530 findreflectedvas(varoot);
2531 rendergeom(causticspass ? 1 : 0, fogpass);
2532 }
2533 else rendergeom(causticspass ? 1 : 0, fogpass);
2534 }
2535
2536 static vtxarray *prevskyva = NULL;
2537
renderskyva(vtxarray * va,bool explicitonly=false)2538 void renderskyva(vtxarray *va, bool explicitonly = false)
2539 {
2540 if(!prevskyva || va->vbuf != prevskyva->vbuf)
2541 {
2542 if(!prevskyva)
2543 {
2544 glEnableClientState(GL_VERTEX_ARRAY);
2545 glPushMatrix();
2546 resetorigin();
2547 }
2548
2549 setorigin(va);
2550 if(hasVBO)
2551 {
2552 glBindBuffer_(GL_ARRAY_BUFFER_ARB, va->vbuf);
2553 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, va->skybuf);
2554 }
2555 glVertexPointer(3, floatvtx ? GL_FLOAT : GL_SHORT, VTXSIZE, &va->vdata[0].x);
2556 }
2557
2558 drawvatris(va, explicitonly ? va->explicitsky : va->sky+va->explicitsky, explicitonly ? va->skydata+va->sky : va->skydata);
2559
2560 if(!explicitonly) xtraverts += va->sky/3;
2561 xtraverts += va->explicitsky/3;
2562
2563 prevskyva = va;
2564 }
2565
2566 int renderedsky = 0, renderedexplicitsky = 0, renderedskyfaces = 0, renderedskyclip = INT_MAX;
2567
updateskystats(vtxarray * va)2568 static inline void updateskystats(vtxarray *va)
2569 {
2570 renderedsky += va->sky;
2571 renderedexplicitsky += va->explicitsky;
2572 renderedskyfaces |= va->skyfaces&0x3F;
2573 if(!(va->skyfaces&0x1F) || camera1->o.z < va->skyclip) renderedskyclip = min(renderedskyclip, va->skyclip);
2574 else renderedskyclip = 0;
2575 }
2576
renderreflectedskyvas(vector<vtxarray * > & vas,int prevvfc=VFC_PART_VISIBLE)2577 void renderreflectedskyvas(vector<vtxarray *> &vas, int prevvfc = VFC_PART_VISIBLE)
2578 {
2579 loopv(vas)
2580 {
2581 vtxarray *va = vas[i];
2582 if(prevvfc >= VFC_NOT_VISIBLE) va->curvfc = prevvfc;
2583 if((va->curvfc == VFC_FULL_VISIBLE && va->occluded >= OCCLUDE_BB) || va->curvfc==PVS_FULL_VISIBLE) continue;
2584 if(va->o.z+va->size <= reflectz || ishiddencube(va->o, va->size)) continue;
2585 if(va->sky+va->explicitsky)
2586 {
2587 updateskystats(va);
2588 renderskyva(va);
2589 }
2590 if(va->children.length()) renderreflectedskyvas(va->children, va->curvfc);
2591 }
2592 }
2593
rendersky(bool explicitonly)2594 bool rendersky(bool explicitonly)
2595 {
2596 prevskyva = NULL;
2597 renderedsky = renderedexplicitsky = renderedskyfaces = 0;
2598 renderedskyclip = INT_MAX;
2599
2600 if(reflecting)
2601 {
2602 renderreflectedskyvas(varoot);
2603 }
2604 else for(vtxarray *va = visibleva; va; va = va->next)
2605 {
2606 if((va->occluded >= OCCLUDE_BB && va->skyfaces&0x80) || !(va->sky+va->explicitsky)) continue;
2607
2608 // count possibly visible sky even if not actually rendered
2609 updateskystats(va);
2610 if(explicitonly && !va->explicitsky) continue;
2611 renderskyva(va, explicitonly);
2612 }
2613
2614 if(prevskyva)
2615 {
2616 glPopMatrix();
2617 glDisableClientState(GL_VERTEX_ARRAY);
2618 if(hasVBO)
2619 {
2620 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
2621 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
2622 }
2623 }
2624
2625 return renderedsky+renderedexplicitsky > 0;
2626 }
2627
2628