1 #include "engine.h"
2
3 VARFP(waterreflect, 0, 1, 1, { cleanreflections(); preloadwatershaders(); });
4 VARFP(waterrefract, 0, 1, 1, { cleanreflections(); preloadwatershaders(); });
5 VARFP(waterenvmap, 0, 1, 1, { cleanreflections(); preloadwatershaders(); });
6 VARFP(waterfallrefract, 0, 0, 1, { cleanreflections(); preloadwatershaders(); });
7
8 /* vertex water */
9 VARP(watersubdiv, 0, 2, 3);
10 VARP(waterlod, 0, 1, 3);
11
12 static int wx1, wy1, wx2, wy2, wz, wsize, wsubdiv;
13 static float whoffset, whphase;
14
vertwangle(int v1,int v2)15 static inline float vertwangle(int v1, int v2)
16 {
17 static const float whscale = 59.0f/23.0f/(2*M_PI);
18 v1 &= wsize-1;
19 v2 &= wsize-1;
20 return v1*v2*whscale+whoffset;
21 }
22
vertwphase(float angle)23 static inline float vertwphase(float angle)
24 {
25 float s = angle - int(angle) - 0.5f;
26 s *= 8 - fabs(s)*16;
27 return WATER_AMPLITUDE*s-WATER_OFFSET;
28 }
29
vertw(int v1,int v2,int v3)30 static inline void vertw(int v1, int v2, int v3)
31 {
32 float h = vertwphase(vertwangle(v1, v2));
33 gle::attribf(v1, v2, v3+h);
34 }
35
vertwq(float v1,float v2,float v3)36 static inline void vertwq(float v1, float v2, float v3)
37 {
38 gle::attribf(v1, v2, v3+whphase);
39 }
40
vertwn(float v1,float v2,float v3)41 static inline void vertwn(float v1, float v2, float v3)
42 {
43 float h = -WATER_OFFSET;
44 gle::attribf(v1, v2, v3+h);
45 }
46
47 struct waterstrip
48 {
49 int x1, y1, x2, y2, z;
50 ushort size, subdiv;
51
numvertswaterstrip52 int numverts() const { return 2*((y2-y1)/subdiv + 1)*((x2-x1)/subdiv); }
53
savewaterstrip54 void save()
55 {
56 x1 = wx1;
57 y1 = wy1;
58 x2 = wx2;
59 y2 = wy2;
60 z = wz;
61 size = wsize;
62 subdiv = wsubdiv;
63 }
64
restorewaterstrip65 void restore()
66 {
67 wx1 = x1;
68 wy1 = y1;
69 wx2 = x2;
70 wy2 = y2;
71 wz = z;
72 wsize = size;
73 wsubdiv = subdiv;
74 }
75 };
76 vector<waterstrip> waterstrips;
77
flushwaterstrips()78 void flushwaterstrips()
79 {
80 if(gle::attribbuf.length()) xtraverts += gle::end();
81 gle::defvertex();
82 int numverts = 0;
83 loopv(waterstrips) numverts += waterstrips[i].numverts();
84 gle::begin(GL_TRIANGLE_STRIP, numverts);
85 loopv(waterstrips)
86 {
87 waterstrips[i].restore();
88 for(int x = wx1; x < wx2; x += wsubdiv)
89 {
90 for(int y = wy1; y <= wy2; y += wsubdiv)
91 {
92 vertw(x, y, wz);
93 vertw(x+wsubdiv, y, wz);
94 }
95 x += wsubdiv;
96 if(x >= wx2) break;
97 for(int y = wy2; y >= wy1; y -= wsubdiv)
98 {
99 vertw(x, y, wz);
100 vertw(x+wsubdiv, y, wz);
101 }
102 }
103 gle::multidraw();
104 }
105 waterstrips.setsize(0);
106 wsize = 0;
107 xtraverts += gle::end();
108 }
109
flushwater(int mat=MAT_WATER,bool force=true)110 void flushwater(int mat = MAT_WATER, bool force = true)
111 {
112 if(wsize)
113 {
114 if(wsubdiv >= wsize)
115 {
116 if(gle::attribbuf.empty()) { gle::defvertex(); gle::begin(GL_QUADS); }
117 vertwq(wx1, wy1, wz);
118 vertwq(wx2, wy1, wz);
119 vertwq(wx2, wy2, wz);
120 vertwq(wx1, wy2, wz);
121 }
122 else waterstrips.add().save();
123 wsize = 0;
124 }
125
126 if(force)
127 {
128 if(gle::attribbuf.length()) xtraverts += gle::end();
129 if(waterstrips.length()) flushwaterstrips();
130 }
131 }
132
rendervertwater(int subdiv,int xo,int yo,int z,int size,int mat)133 void rendervertwater(int subdiv, int xo, int yo, int z, int size, int mat)
134 {
135 if(wsize == size && wsubdiv == subdiv && wz == z)
136 {
137 if(wx2 == xo)
138 {
139 if(wy1 == yo && wy2 == yo + size) { wx2 += size; return; }
140 }
141 else if(wy2 == yo && wx1 == xo && wx2 == xo + size) { wy2 += size; return; }
142 }
143
144 flushwater(mat, false);
145
146 wx1 = xo;
147 wy1 = yo;
148 wx2 = xo + size,
149 wy2 = yo + size;
150 wz = z;
151 wsize = size;
152 wsubdiv = subdiv;
153
154 ASSERT((wx1 & (subdiv - 1)) == 0);
155 ASSERT((wy1 & (subdiv - 1)) == 0);
156 }
157
calcwatersubdiv(int x,int y,int z,int size)158 int calcwatersubdiv(int x, int y, int z, int size)
159 {
160 float dist;
161 if(camera1->o.x >= x && camera1->o.x < x + size &&
162 camera1->o.y >= y && camera1->o.y < y + size)
163 dist = fabs(camera1->o.z - float(z));
164 else
165 dist = vec(x + size/2, y + size/2, z + size/2).dist(camera1->o) - size*1.42f/2;
166 int subdiv = watersubdiv + int(dist) / (32 << waterlod);
167 return subdiv >= 31 ? INT_MAX : 1<<subdiv;
168 }
169
renderwaterlod(int x,int y,int z,int size,int mat)170 int renderwaterlod(int x, int y, int z, int size, int mat)
171 {
172 if(size <= (32 << waterlod))
173 {
174 int subdiv = calcwatersubdiv(x, y, z, size);
175 if(subdiv < size * 2) rendervertwater(min(subdiv, size), x, y, z, size, mat);
176 return subdiv;
177 }
178 else
179 {
180 int subdiv = calcwatersubdiv(x, y, z, size);
181 if(subdiv >= size)
182 {
183 if(subdiv < size * 2) rendervertwater(size, x, y, z, size, mat);
184 return subdiv;
185 }
186 int childsize = size / 2,
187 subdiv1 = renderwaterlod(x, y, z, childsize, mat),
188 subdiv2 = renderwaterlod(x + childsize, y, z, childsize, mat),
189 subdiv3 = renderwaterlod(x + childsize, y + childsize, z, childsize, mat),
190 subdiv4 = renderwaterlod(x, y + childsize, z, childsize, mat),
191 minsubdiv = subdiv1;
192 minsubdiv = min(minsubdiv, subdiv2);
193 minsubdiv = min(minsubdiv, subdiv3);
194 minsubdiv = min(minsubdiv, subdiv4);
195 if(minsubdiv < size * 2)
196 {
197 if(minsubdiv >= size) rendervertwater(size, x, y, z, size, mat);
198 else
199 {
200 if(subdiv1 >= size) rendervertwater(childsize, x, y, z, childsize, mat);
201 if(subdiv2 >= size) rendervertwater(childsize, x + childsize, y, z, childsize, mat);
202 if(subdiv3 >= size) rendervertwater(childsize, x + childsize, y + childsize, z, childsize, mat);
203 if(subdiv4 >= size) rendervertwater(childsize, x, y + childsize, z, childsize, mat);
204 }
205 }
206 return minsubdiv;
207 }
208 }
209
renderflatwater(int x,int y,int z,int rsize,int csize,int mat)210 void renderflatwater(int x, int y, int z, int rsize, int csize, int mat)
211 {
212 if(gle::attribbuf.empty()) { gle::defvertex(); gle::begin(GL_QUADS); }
213 vertwn(x, y, z);
214 vertwn(x+rsize, y, z);
215 vertwn(x+rsize, y+csize, z);
216 vertwn(x, y+csize, z);
217 }
218
219 VARFP(vertwater, 0, 1, 1, allchanged());
220
renderwater(const materialsurface & m,int mat=MAT_WATER)221 static inline void renderwater(const materialsurface &m, int mat = MAT_WATER)
222 {
223 if(!vertwater || drawtex == DRAWTEX_MINIMAP) renderflatwater(m.o.x, m.o.y, m.o.z, m.rsize, m.csize, mat);
224 else if(renderwaterlod(m.o.x, m.o.y, m.o.z, m.csize, mat) >= int(m.csize) * 2)
225 rendervertwater(m.csize, m.o.x, m.o.y, m.o.z, m.csize, mat);
226 }
227
setuplava(Texture * tex,float scale)228 void setuplava(Texture *tex, float scale)
229 {
230 float xk = TEX_SCALE/(tex->xs*scale);
231 float yk = TEX_SCALE/(tex->ys*scale);
232 float scroll = lastmillis/1000.0f;
233 LOCALPARAMF(lavatexgen, xk, yk, scroll, scroll);
234 gle::normal(vec(0, 0, 1));
235 whoffset = fmod(float(lastmillis/2000.0f/(2*M_PI)), 1.0f);
236 whphase = vertwphase(whoffset);
237 }
238
renderlava(const materialsurface & m)239 void renderlava(const materialsurface &m)
240 {
241 renderwater(m, MAT_LAVA);
242 }
243
flushlava()244 void flushlava()
245 {
246 flushwater(MAT_LAVA);
247 }
248
249 /* reflective/refractive water */
250
251 #define MAXREFLECTIONS 16
252
253 struct Reflection
254 {
255 GLuint tex, refracttex;
256 int material, height, depth, age;
257 bool init;
258 matrix4 projmat;
259 occludequery *query, *prevquery;
260 vector<materialsurface *> matsurfs;
261
ReflectionReflection262 Reflection() : tex(0), refracttex(0), material(-1), height(-1), depth(0), age(0), init(false), query(NULL), prevquery(NULL)
263 {}
264 };
265
266 VARP(reflectdist, 0, 2000, 10000);
267
268 #define WATERVARS(name) \
269 bvec name##color(0x14, 0x46, 0x50), name##fallcolor(0, 0, 0); \
270 HVARFR(name##colour, 0, 0x144650, 0xFFFFFF, \
271 { \
272 if(!name##colour) name##colour = 0x144650; \
273 name##color = bvec((name##colour>>16)&0xFF, (name##colour>>8)&0xFF, name##colour&0xFF); \
274 }); \
275 VARR(name##fog, 0, 150, 10000); \
276 VARR(name##spec, 0, 150, 1000); \
277 HVARFR(name##fallcolour, 0, 0, 0xFFFFFF, \
278 { \
279 name##fallcolor = bvec((name##fallcolour>>16)&0xFF, (name##fallcolour>>8)&0xFF, name##fallcolour&0xFF); \
280 });
281
282 WATERVARS(water)
WATERVARS(water2)283 WATERVARS(water2)
284 WATERVARS(water3)
285 WATERVARS(water4)
286
287 GETMATIDXVAR(water, colour, int)
288 GETMATIDXVAR(water, color, const bvec &)
289 GETMATIDXVAR(water, fallcolour, int)
290 GETMATIDXVAR(water, fallcolor, const bvec &)
291 GETMATIDXVAR(water, fog, int)
292 GETMATIDXVAR(water, spec, int)
293
294 #define LAVAVARS(name) \
295 bvec name##color(0xFF, 0x40, 0x00); \
296 HVARFR(name##colour, 0, 0xFF4000, 0xFFFFFF, \
297 { \
298 if(!name##colour) name##colour = 0xFF4000; \
299 name##color = bvec((name##colour>>16)&0xFF, (name##colour>>8)&0xFF, name##colour&0xFF); \
300 }); \
301 VARR(name##fog, 0, 50, 10000);
302
303 LAVAVARS(lava)
304 LAVAVARS(lava2)
305 LAVAVARS(lava3)
306 LAVAVARS(lava4)
307
308 GETMATIDXVAR(lava, colour, int)
309 GETMATIDXVAR(lava, color, const bvec &)
310 GETMATIDXVAR(lava, fog, int)
311
312 void setprojtexmatrix(Reflection &ref)
313 {
314 if(ref.init)
315 {
316 ref.init = false;
317 (ref.projmat = camprojmatrix).projective();
318 }
319
320 LOCALPARAM(watermatrix, ref.projmat);
321 }
322
323 Reflection reflections[MAXREFLECTIONS];
324 Reflection waterfallrefraction;
325 GLuint reflectionfb = 0, reflectiondb = 0;
326
getwaterfalltex()327 GLuint getwaterfalltex() { return waterfallrefraction.refracttex ? waterfallrefraction.refracttex : notexture->id; }
328
329 VAR(oqwater, 0, 2, 2);
330 VARFP(waterfade, 0, 1, 1, { cleanreflections(); preloadwatershaders(); });
331
preloadwatershaders(bool force)332 void preloadwatershaders(bool force)
333 {
334 static bool needwater = false;
335 if(force) needwater = true;
336 if(!needwater) return;
337
338 useshaderbyname("waterglare");
339
340 if(waterenvmap && !waterreflect)
341 useshaderbyname(waterrefract ? (waterfade ? "waterenvfade" : "waterenvrefract") : "waterenv");
342 else useshaderbyname(waterrefract ? (waterfade ? "waterfade" : "waterrefract") : (waterreflect ? "waterreflect" : "water"));
343
344 useshaderbyname(waterrefract ? (waterfade ? "underwaterfade" : "underwaterrefract") : "underwater");
345
346 extern int waterfallenv;
347 useshaderbyname(waterfallenv ? "waterfallenv" : "waterfall");
348 if(waterfallrefract) useshaderbyname(waterfallenv ? "waterfallenvrefract" : "waterfallrefract");
349 }
350
renderwater()351 void renderwater()
352 {
353 if(editmode && showmat && !drawtex) return;
354 if(!rplanes) return;
355
356 glDisable(GL_CULL_FACE);
357
358 if(!glaring && drawtex != DRAWTEX_MINIMAP)
359 {
360 if(waterrefract)
361 {
362 if(waterfade)
363 {
364 glEnable(GL_BLEND);
365 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
366 }
367 }
368 else
369 {
370 glDepthMask(GL_FALSE);
371 glEnable(GL_BLEND);
372 glBlendFunc(GL_ONE, GL_SRC_ALPHA);
373 }
374 }
375
376 GLOBALPARAM(camera, camera1->o);
377 GLOBALPARAMF(millis, lastmillis/1000.0f);
378
379 #define SETWATERSHADER(which, name) \
380 do { \
381 static Shader *name##shader = NULL; \
382 if(!name##shader) name##shader = lookupshaderbyname(#name); \
383 which##shader = name##shader; \
384 } while(0)
385
386 Shader *aboveshader = NULL;
387 if(glaring) SETWATERSHADER(above, waterglare);
388 else if(drawtex == DRAWTEX_MINIMAP) aboveshader = notextureshader;
389 else if(waterenvmap && !waterreflect)
390 {
391 if(waterrefract)
392 {
393 if(waterfade) SETWATERSHADER(above, waterenvfade);
394 else SETWATERSHADER(above, waterenvrefract);
395 }
396 else SETWATERSHADER(above, waterenv);
397 }
398 else if(waterrefract)
399 {
400 if(waterfade) SETWATERSHADER(above, waterfade);
401 else SETWATERSHADER(above, waterrefract);
402 }
403 else if(waterreflect) SETWATERSHADER(above, waterreflect);
404 else SETWATERSHADER(above, water);
405
406 Shader *belowshader = NULL;
407 if(!glaring && drawtex != DRAWTEX_MINIMAP)
408 {
409 if(waterrefract)
410 {
411 if(waterfade) SETWATERSHADER(below, underwaterfade);
412 else SETWATERSHADER(below, underwaterrefract);
413 }
414 else SETWATERSHADER(below, underwater);
415 }
416
417 vec ambient(max(skylightcolor[0], ambientcolor[0]), max(skylightcolor[1], ambientcolor[1]), max(skylightcolor[2], ambientcolor[2]));
418 float offset = -WATER_OFFSET;
419 loopi(MAXREFLECTIONS)
420 {
421 Reflection &ref = reflections[i];
422 if(ref.height<0 || ref.age || ref.matsurfs.empty()) continue;
423 if(!glaring && oqfrags && oqwater && ref.query && ref.query->owner==&ref)
424 {
425 if(!ref.prevquery || ref.prevquery->owner!=&ref || checkquery(ref.prevquery))
426 {
427 if(checkquery(ref.query)) continue;
428 }
429 }
430
431 bool below = camera1->o.z < ref.height+offset;
432 if(below)
433 {
434 if(!belowshader) continue;
435 belowshader->set();
436 }
437 else aboveshader->set();
438
439 if(!glaring && drawtex != DRAWTEX_MINIMAP)
440 {
441 if(waterreflect || waterrefract)
442 {
443 if(waterreflect || !waterenvmap) glBindTexture(GL_TEXTURE_2D, waterreflect ? ref.tex : ref.refracttex);
444 setprojtexmatrix(ref);
445 }
446
447 if(waterrefract)
448 {
449 glActiveTexture_(GL_TEXTURE3);
450 glBindTexture(GL_TEXTURE_2D, ref.refracttex);
451 if(waterfade)
452 {
453 float fadeheight = ref.height+offset+(below ? -2 : 2);
454 LOCALPARAMF(waterheight, fadeheight);
455 }
456 }
457 }
458
459 MSlot &mslot = lookupmaterialslot(ref.material);
460 glActiveTexture_(GL_TEXTURE1);
461 glBindTexture(GL_TEXTURE_2D, mslot.sts.inrange(2) ? mslot.sts[2].t->id : notexture->id);
462 glActiveTexture_(GL_TEXTURE2);
463 glBindTexture(GL_TEXTURE_2D, mslot.sts.inrange(3) ? mslot.sts[3].t->id : notexture->id);
464 glActiveTexture_(GL_TEXTURE0);
465 if(!glaring && waterenvmap && !waterreflect && drawtex != DRAWTEX_MINIMAP)
466 {
467 glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(mslot));
468 }
469
470 whoffset = fmod(float(lastmillis/600.0f/(2*M_PI)), 1.0f);
471 whphase = vertwphase(whoffset);
472
473 gle::color(getwatercolor(ref.material));
474 int wfog = getwaterfog(ref.material), wspec = getwaterspec(ref.material);
475
476 const entity *lastlight = (const entity *)-1;
477 int lastdepth = -1;
478 loopvj(ref.matsurfs)
479 {
480 materialsurface &m = *ref.matsurfs[j];
481
482 entity *light = (m.light && m.light->type==ET_LIGHT ? m.light : NULL);
483 if(light!=lastlight)
484 {
485 flushwater();
486 vec lightpos = light ? light->o : vec(worldsize/2, worldsize/2, worldsize);
487 float lightrad = light && light->attr1 ? light->attr1 : worldsize*8.0f;
488 vec lightcol = (light ? vec(light->attr2, light->attr3, light->attr4) : vec(ambient)).div(255.0f).mul(wspec/100.0f);
489 LOCALPARAM(lightpos, lightpos);
490 LOCALPARAM(lightcolor, lightcol);
491 LOCALPARAMF(lightradius, lightrad);
492 lastlight = light;
493 }
494
495 if(!glaring && !waterrefract && m.depth!=lastdepth)
496 {
497 flushwater();
498 float depth = !wfog ? 1.0f : min(0.75f*m.depth/wfog, 0.95f);
499 depth = max(depth, !below && (waterreflect || waterenvmap) ? 0.3f : 0.6f);
500 LOCALPARAMF(depth, depth, 1.0f-depth);
501 lastdepth = m.depth;
502 }
503
504 renderwater(m);
505 }
506 flushwater();
507 }
508
509 if(!glaring && drawtex != DRAWTEX_MINIMAP)
510 {
511 if(waterrefract)
512 {
513 if(waterfade) glDisable(GL_BLEND);
514 }
515 else
516 {
517 glDepthMask(GL_TRUE);
518 glDisable(GL_BLEND);
519 }
520 }
521
522 glEnable(GL_CULL_FACE);
523 }
524
setupwaterfallrefract()525 void setupwaterfallrefract()
526 {
527 glBindTexture(GL_TEXTURE_2D, waterfallrefraction.refracttex ? waterfallrefraction.refracttex : notexture->id);
528 setprojtexmatrix(waterfallrefraction);
529 }
530
cleanreflection(Reflection & ref)531 void cleanreflection(Reflection &ref)
532 {
533 ref.material = -1;
534 ref.height = -1;
535 ref.init = false;
536 ref.query = ref.prevquery = NULL;
537 ref.matsurfs.setsize(0);
538 if(ref.tex)
539 {
540 glDeleteTextures(1, &ref.tex);
541 ref.tex = 0;
542 }
543 if(ref.refracttex)
544 {
545 glDeleteTextures(1, &ref.refracttex);
546 ref.refracttex = 0;
547 }
548 }
549
cleanreflections()550 void cleanreflections()
551 {
552 loopi(MAXREFLECTIONS) cleanreflection(reflections[i]);
553 cleanreflection(waterfallrefraction);
554 if(reflectionfb)
555 {
556 glDeleteFramebuffers_(1, &reflectionfb);
557 reflectionfb = 0;
558 }
559 if(reflectiondb)
560 {
561 glDeleteRenderbuffers_(1, &reflectiondb);
562 reflectiondb = 0;
563 }
564 }
565
566 VARFP(reflectsize, 6, 8, 11, cleanreflections());
567
genwatertex(GLuint & tex,GLuint & fb,GLuint & db,bool refract=false)568 void genwatertex(GLuint &tex, GLuint &fb, GLuint &db, bool refract = false)
569 {
570 static const GLenum colorfmts[] = { GL_RGBA, GL_RGBA8, GL_RGB, GL_RGB8, GL_FALSE },
571 depthfmts[] = { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_FALSE };
572 static GLenum reflectfmt = GL_FALSE, refractfmt = GL_FALSE, depthfmt = GL_FALSE;
573 static bool usingalpha = false;
574 bool needsalpha = refract && waterrefract && waterfade;
575 if(refract && usingalpha!=needsalpha)
576 {
577 usingalpha = needsalpha;
578 refractfmt = GL_FALSE;
579 }
580 int size = 1<<reflectsize;
581 while(size>hwtexsize) size /= 2;
582
583 glGenTextures(1, &tex);
584 char *buf = new char[size*size*4];
585 memset(buf, 0, size*size*4);
586
587 GLenum &colorfmt = refract ? refractfmt : reflectfmt;
588 if(colorfmt && fb && db)
589 {
590 createtexture(tex, size, size, buf, 3, 1, colorfmt);
591 delete[] buf;
592 return;
593 }
594
595 if(!fb) glGenFramebuffers_(1, &fb);
596 int find = needsalpha ? 0 : 2;
597 do
598 {
599 createtexture(tex, size, size, buf, 3, 1, colorfmt ? colorfmt : colorfmts[find]);
600 glBindFramebuffer_(GL_FRAMEBUFFER, fb);
601 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
602 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_COMPLETE) break;
603 }
604 while(!colorfmt && colorfmts[++find]);
605 if(!colorfmt) colorfmt = colorfmts[find];
606
607 delete[] buf;
608
609 if(!db) { glGenRenderbuffers_(1, &db); depthfmt = GL_FALSE; }
610 if(!depthfmt) glBindRenderbuffer_(GL_RENDERBUFFER, db);
611 find = 0;
612 do
613 {
614 if(!depthfmt) glRenderbufferStorage_(GL_RENDERBUFFER, depthfmts[find], size, size);
615 glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, db);
616 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_COMPLETE) break;
617 }
618 while(!depthfmt && depthfmts[++find]);
619 if(!depthfmt)
620 {
621 glBindRenderbuffer_(GL_RENDERBUFFER, 0);
622 depthfmt = depthfmts[find];
623 }
624
625 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
626 }
627
addwaterfallrefraction(materialsurface & m)628 void addwaterfallrefraction(materialsurface &m)
629 {
630 Reflection &ref = waterfallrefraction;
631 if(ref.age>=0)
632 {
633 ref.age = -1;
634 ref.init = false;
635 ref.matsurfs.setsize(0);
636 ref.material = MAT_WATER;
637 ref.height = INT_MAX;
638 }
639 ref.matsurfs.add(&m);
640
641 if(!ref.refracttex) genwatertex(ref.refracttex, reflectionfb, reflectiondb);
642 }
643
addreflection(materialsurface & m)644 void addreflection(materialsurface &m)
645 {
646 int mat = m.material, height = m.o.z;
647 Reflection *ref = NULL, *oldest = NULL;
648 loopi(MAXREFLECTIONS)
649 {
650 Reflection &r = reflections[i];
651 if(r.height<0)
652 {
653 if(!ref) ref = &r;
654 }
655 else if(r.height==height && r.material==mat)
656 {
657 r.matsurfs.add(&m);
658 r.depth = max(r.depth, int(m.depth));
659 if(r.age<0) return;
660 ref = &r;
661 break;
662 }
663 else if(!oldest || r.age>oldest->age) oldest = &r;
664 }
665 if(!ref)
666 {
667 if(!oldest || oldest->age<0) return;
668 ref = oldest;
669 }
670 if(ref->height!=height || ref->material!=mat)
671 {
672 ref->material = mat;
673 ref->height = height;
674 ref->prevquery = NULL;
675 }
676 rplanes++;
677 ref->age = -1;
678 ref->init = false;
679 ref->matsurfs.setsize(0);
680 ref->matsurfs.add(&m);
681 ref->depth = m.depth;
682 if(drawtex == DRAWTEX_MINIMAP) return;
683
684 if(waterreflect && !ref->tex) genwatertex(ref->tex, reflectionfb, reflectiondb);
685 if(waterrefract && !ref->refracttex) genwatertex(ref->refracttex, reflectionfb, reflectiondb, true);
686 }
687
drawmaterialquery(const materialsurface & m,float offset,float border=0,float reflect=-1)688 static void drawmaterialquery(const materialsurface &m, float offset, float border = 0, float reflect = -1)
689 {
690 if(gle::attribbuf.empty())
691 {
692 gle::defvertex();
693 gle::begin(GL_QUADS);
694 }
695 float x = m.o.x, y = m.o.y, z = m.o.z, csize = m.csize + border, rsize = m.rsize + border;
696 if(reflect >= 0) z = 2*reflect - z;
697 switch(m.orient)
698 {
699 #define GENFACEORIENT(orient, v0, v1, v2, v3) \
700 case orient: v0 v1 v2 v3 break;
701 #define GENFACEVERT(orient, vert, mx,my,mz, sx,sy,sz) \
702 gle::attribf(mx sx, my sy, mz sz);
703 GENFACEVERTS(x, x, y, y, z, z, - border, + csize, - border, + rsize, + offset, - offset)
704 #undef GENFACEORIENT
705 #undef GENFACEVERT
706 }
707 }
708
709 extern void drawreflection(float z, bool refract, int fogdepth = -1, const bvec &col = bvec(0, 0, 0));
710
711 int rplanes = 0;
712
queryreflection(Reflection & ref,bool init)713 void queryreflection(Reflection &ref, bool init)
714 {
715 if(init)
716 {
717 nocolorshader->set();
718 glDepthMask(GL_FALSE);
719 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
720 glDisable(GL_CULL_FACE);
721 }
722 startquery(ref.query);
723 loopvj(ref.matsurfs)
724 {
725 materialsurface &m = *ref.matsurfs[j];
726 float offset = 0.1f;
727 if(m.orient==O_TOP)
728 {
729 offset = WATER_OFFSET +
730 (vertwater ? WATER_AMPLITUDE*(camera1->pitch > 0 || m.depth < WATER_AMPLITUDE+0.5f ? -1 : 1) : 0);
731 if(fabs(m.o.z-offset - camera1->o.z) < 0.5f && m.depth > WATER_AMPLITUDE+1.5f)
732 offset += camera1->pitch > 0 ? -1 : 1;
733 }
734 drawmaterialquery(m, offset);
735 }
736 xtraverts += gle::end();
737 endquery(ref.query);
738 }
739
queryreflections()740 void queryreflections()
741 {
742 rplanes = 0;
743
744 static int lastsize = 0;
745 int size = 1<<reflectsize;
746 while(size>hwtexsize) size /= 2;
747 if(size!=lastsize) { if(lastsize) cleanreflections(); lastsize = size; }
748
749 for(vtxarray *va = visibleva; va; va = va->next)
750 {
751 if(!va->matsurfs || va->occluded >= OCCLUDE_BB || va->curvfc >= VFC_FOGGED) continue;
752 int lastmat = -1;
753 loopi(va->matsurfs)
754 {
755 materialsurface &m = va->matbuf[i];
756 if(m.material != lastmat)
757 {
758 if((m.material&MATF_VOLUME) != MAT_WATER || m.orient == O_BOTTOM) { i += m.skip; continue; }
759 if(m.orient != O_TOP)
760 {
761 if(!waterfallrefract || !getwaterfog(m.material)) { i += m.skip; continue; }
762 }
763 lastmat = m.material;
764 }
765 if(m.orient==O_TOP) addreflection(m);
766 else addwaterfallrefraction(m);
767 }
768 }
769
770 loopi(MAXREFLECTIONS)
771 {
772 Reflection &ref = reflections[i];
773 ++ref.age;
774 if(ref.height>=0 && !ref.age && ref.matsurfs.length())
775 {
776 if(waterpvsoccluded(ref.height)) ref.matsurfs.setsize(0);
777 }
778 }
779 if(waterfallrefract)
780 {
781 Reflection &ref = waterfallrefraction;
782 ++ref.age;
783 if(ref.height>=0 && !ref.age && ref.matsurfs.length())
784 {
785 if(waterpvsoccluded(-1)) ref.matsurfs.setsize(0);
786 }
787 }
788
789 if((editmode && showmat && !drawtex) || !oqfrags || !oqwater || drawtex == DRAWTEX_MINIMAP) return;
790
791 int refs = 0;
792 if(waterreflect || waterrefract) loopi(MAXREFLECTIONS)
793 {
794 Reflection &ref = reflections[i];
795 ref.prevquery = oqwater > 1 ? ref.query : NULL;
796 ref.query = ref.height>=0 && !ref.age && ref.matsurfs.length() ? newquery(&ref) : NULL;
797 if(ref.query) queryreflection(ref, !refs++);
798 }
799 if(waterfallrefract)
800 {
801 Reflection &ref = waterfallrefraction;
802 ref.prevquery = oqwater > 1 ? ref.query : NULL;
803 ref.query = ref.height>=0 && !ref.age && ref.matsurfs.length() ? newquery(&ref) : NULL;
804 if(ref.query) queryreflection(ref, !refs++);
805 }
806
807 if(refs)
808 {
809 glDepthMask(GL_TRUE);
810 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
811 glEnable(GL_CULL_FACE);
812 }
813
814 glFlush();
815 }
816
817 VARP(maxreflect, 1, 2, 8);
818
819 int refracting = 0, refractfog = 0;
820 bvec refractcolor(0, 0, 0);
821 bool reflecting = false, fading = false, fogging = false;
822 float reflectz = 1e16f;
823
824 VAR(maskreflect, 0, 2, 16);
825
maskreflection(Reflection & ref,float offset,bool reflect,bool clear=false)826 void maskreflection(Reflection &ref, float offset, bool reflect, bool clear = false)
827 {
828 const bvec &wcol = getwatercolor(ref.material);
829 vec color = wcol.tocolor();
830 if(!maskreflect)
831 {
832 if(clear) glClearColor(color.r, color.g, color.b, 1);
833 glClear(GL_DEPTH_BUFFER_BIT | (clear ? GL_COLOR_BUFFER_BIT : 0));
834 return;
835 }
836 glClearDepth(0);
837 glClear(GL_DEPTH_BUFFER_BIT);
838 glClearDepth(1);
839 glDepthRange(1, 1);
840 glDepthFunc(GL_ALWAYS);
841 glDisable(GL_CULL_FACE);
842 if(clear)
843 {
844 notextureshader->set();
845 gle::color(color);
846 }
847 else
848 {
849 nocolorshader->set();
850 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
851 }
852 float reflectheight = reflect ? ref.height + offset : -1;
853 loopv(ref.matsurfs)
854 {
855 materialsurface &m = *ref.matsurfs[i];
856 drawmaterialquery(m, -offset, maskreflect, reflectheight);
857 }
858 xtraverts += gle::end();
859 if(!clear) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
860 glEnable(GL_CULL_FACE);
861 glDepthFunc(GL_LESS);
862 glDepthRange(0, 1);
863 }
864
865 VAR(reflectscissor, 0, 1, 1);
866 VAR(reflectvfc, 0, 1, 1);
867
calcscissorbox(Reflection & ref,int size,vec & clipmin,vec & clipmax,int & sx,int & sy,int & sw,int & sh)868 static bool calcscissorbox(Reflection &ref, int size, vec &clipmin, vec &clipmax, int &sx, int &sy, int &sw, int &sh)
869 {
870 materialsurface &m0 = *ref.matsurfs[0];
871 int dim = dimension(m0.orient), r = R[dim], c = C[dim];
872 ivec bbmin = m0.o, bbmax = bbmin;
873 bbmax[r] += m0.rsize;
874 bbmax[c] += m0.csize;
875 loopvj(ref.matsurfs)
876 {
877 materialsurface &m = *ref.matsurfs[j];
878 bbmin[r] = min(bbmin[r], m.o[r]);
879 bbmin[c] = min(bbmin[c], m.o[c]);
880 bbmax[r] = max(bbmax[r], m.o[r] + m.rsize);
881 bbmax[c] = max(bbmax[c], m.o[c] + m.csize);
882 bbmin[dim] = min(bbmin[dim], m.o[dim]);
883 bbmax[dim] = max(bbmax[dim], m.o[dim]);
884 }
885
886 vec4 v[8];
887 float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1;
888 loopi(8)
889 {
890 vec4 &p = v[i];
891 camprojmatrix.transform(vec(i&1 ? bbmax.x : bbmin.x, i&2 ? bbmax.y : bbmin.y, (i&4 ? bbmax.z + WATER_AMPLITUDE : bbmin.z - WATER_AMPLITUDE) - WATER_OFFSET), p);
892 if(p.z >= -p.w)
893 {
894 float x = p.x / p.w, y = p.y / p.w;
895 sx1 = min(sx1, x);
896 sy1 = min(sy1, y);
897 sx2 = max(sx2, x);
898 sy2 = max(sy2, y);
899 }
900 }
901 if(sx1 >= sx2 || sy1 >= sy2) return false;
902 loopi(8)
903 {
904 const vec4 &p = v[i];
905 if(p.z >= -p.w) continue;
906 loopj(3)
907 {
908 const vec4 &o = v[i^(1<<j)];
909 if(o.z <= -o.w) continue;
910 float t = (p.z + p.w)/(p.z + p.w - o.z - o.w),
911 w = p.w + t*(o.w - p.w),
912 x = (p.x + t*(o.x - p.x))/w,
913 y = (p.y + t*(o.y - p.y))/w;
914 sx1 = min(sx1, x);
915 sy1 = min(sy1, y);
916 sx2 = max(sx2, x);
917 sy2 = max(sy2, y);
918 }
919 }
920 if(sx1 <= -1 && sy1 <= -1 && sx2 >= 1 && sy2 >= 1) return false;
921 sx1 = max(sx1, -1.0f);
922 sy1 = max(sy1, -1.0f);
923 sx2 = min(sx2, 1.0f);
924 sy2 = min(sy2, 1.0f);
925 if(reflectvfc)
926 {
927 clipmin.x = clamp(clipmin.x, sx1, sx2);
928 clipmin.y = clamp(clipmin.y, sy1, sy2);
929 clipmax.x = clamp(clipmax.x, sx1, sx2);
930 clipmax.y = clamp(clipmax.y, sy1, sy2);
931 }
932 sx = int(floor((sx1+1)*0.5f*size));
933 sy = int(floor((sy1+1)*0.5f*size));
934 sw = max(int(ceil((sx2+1)*0.5f*size)) - sx, 0);
935 sh = max(int(ceil((sy2+1)*0.5f*size)) - sy, 0);
936 return true;
937 }
938
939 VARR(refractclear, 0, 0, 1);
940
drawreflections()941 void drawreflections()
942 {
943 if((editmode && showmat && !drawtex) || drawtex == DRAWTEX_MINIMAP) return;
944
945 static int lastdrawn = 0;
946 int refs = 0, n = lastdrawn;
947 float offset = -WATER_OFFSET;
948 int size = 1<<reflectsize;
949 while(size>hwtexsize) size /= 2;
950
951 if(waterreflect || waterrefract) loopi(MAXREFLECTIONS)
952 {
953 Reflection &ref = reflections[++n%MAXREFLECTIONS];
954 if(ref.height<0 || ref.age || ref.matsurfs.empty()) continue;
955 if(oqfrags && oqwater && ref.query && ref.query->owner==&ref)
956 {
957 if(!ref.prevquery || ref.prevquery->owner!=&ref || checkquery(ref.prevquery))
958 {
959 if(checkquery(ref.query)) continue;
960 }
961 }
962
963 if(!refs)
964 {
965 glViewport(0, 0, size, size);
966 glBindFramebuffer_(GL_FRAMEBUFFER, reflectionfb);
967 }
968 refs++;
969 ref.init = true;
970 lastdrawn = n;
971
972 vec clipmin(-1, -1, -1), clipmax(1, 1, 1);
973 int sx, sy, sw, sh;
974 bool scissor = reflectscissor && calcscissorbox(ref, size, clipmin, clipmax, sx, sy, sw, sh);
975 if(scissor) glScissor(sx, sy, sw, sh);
976 else
977 {
978 sx = sy = 0;
979 sw = sh = size;
980 }
981
982 const bvec &wcol = getwatercolor(ref.material);
983 int wfog = getwaterfog(ref.material);
984
985 if(waterreflect && ref.tex && camera1->o.z >= ref.height+offset)
986 {
987 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ref.tex, 0);
988 if(scissor) glEnable(GL_SCISSOR_TEST);
989 maskreflection(ref, offset, true);
990 savevfcP();
991 setvfcP(ref.height+offset, clipmin, clipmax);
992 drawreflection(ref.height+offset, false);
993 restorevfcP();
994 if(scissor) glDisable(GL_SCISSOR_TEST);
995 }
996
997 if(waterrefract && ref.refracttex)
998 {
999 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ref.refracttex, 0);
1000 if(scissor) glEnable(GL_SCISSOR_TEST);
1001 maskreflection(ref, offset, false, refractclear || !wfog || (ref.depth>=10000 && camera1->o.z >= ref.height + offset));
1002 if(wfog || waterfade)
1003 {
1004 savevfcP();
1005 setvfcP(-1, clipmin, clipmax);
1006 drawreflection(ref.height+offset, true, wfog, wcol);
1007 restorevfcP();
1008 }
1009 if(scissor) glDisable(GL_SCISSOR_TEST);
1010 }
1011
1012 if(refs>=maxreflect) break;
1013 }
1014
1015 if(waterfallrefract && waterfallrefraction.refracttex)
1016 {
1017 Reflection &ref = waterfallrefraction;
1018
1019 if(ref.height<0 || ref.age || ref.matsurfs.empty()) goto nowaterfall;
1020 if(oqfrags && oqwater && ref.query && ref.query->owner==&ref)
1021 {
1022 if(!ref.prevquery || ref.prevquery->owner!=&ref || checkquery(ref.prevquery))
1023 {
1024 if(checkquery(ref.query)) goto nowaterfall;
1025 }
1026 }
1027
1028 if(!refs)
1029 {
1030 glViewport(0, 0, size, size);
1031 glBindFramebuffer_(GL_FRAMEBUFFER, reflectionfb);
1032 }
1033 refs++;
1034 ref.init = true;
1035
1036 vec clipmin(-1, -1, -1), clipmax(1, 1, 1);
1037 int sx, sy, sw, sh;
1038 bool scissor = reflectscissor && calcscissorbox(ref, size, clipmin, clipmax, sx, sy, sw, sh);
1039 if(scissor) glScissor(sx, sy, sw, sh);
1040 else
1041 {
1042 sx = sy = 0;
1043 sw = sh = size;
1044 }
1045
1046 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ref.refracttex, 0);
1047 if(scissor) glEnable(GL_SCISSOR_TEST);
1048 maskreflection(ref, -0.1f, false);
1049 savevfcP();
1050 setvfcP(-1, clipmin, clipmax);
1051 drawreflection(-1, true);
1052 restorevfcP();
1053 if(scissor) glDisable(GL_SCISSOR_TEST);
1054 }
1055 nowaterfall:
1056
1057 if(!refs) return;
1058 glViewport(0, 0, screenw, screenh);
1059 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
1060 }
1061
1062