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