Line data Source code
1 : /**
2 : * @brief Rendering of water special effects
3 : *
4 : * water is a special material to render because of its dynamic effects caused
5 : * by the surface moving over time, and as a result has its own implementations
6 : * for special water functionality
7 : *
8 : * implemented are caustics, (light/dark areas on underwater surfaces due to lensing)
9 : * screenspace reflection, to capture the reflective surface, dynamic water surface
10 : * geometry, and dynamic waterfalls
11 : */
12 : #include "../libprimis-headers/cube.h"
13 : #include "../../shared/geomexts.h"
14 : #include "../../shared/glemu.h"
15 : #include "../../shared/glexts.h"
16 :
17 : #include "octarender.h"
18 : #include "rendergl.h"
19 : #include "renderlights.h"
20 : #include "shader.h"
21 : #include "shaderparam.h"
22 : #include "texture.h"
23 : #include "water.h"
24 :
25 : #include "interface/control.h"
26 :
27 : #include "world/material.h"
28 : #include "world/octaworld.h"
29 : #include "world/world.h"
30 :
31 : // ======================= caustics ===================== //
32 :
33 : //caustics: lightening on surfaces underwater due to lensing effects from an
34 : // uneven water surface
35 :
36 : namespace
37 : {
38 : constexpr int numcaustics = 32; //number of separate caustics textures to load
39 : std::array<const Texture *, numcaustics> caustictex = {nullptr};
40 0 : VARFR(causticscale, 0, 50, 10000, preloadwatershaders());
41 0 : VARFR(causticmillis, 0, 75, 1000, preloadwatershaders()); //milliseconds between caustics frames
42 : FVARR(causticcontrast, 0, 0.6f, 2);
43 : FVARR(causticoffset, 0, 0.7f, 1);
44 :
45 0 : void setupcaustics(int tmu, float surface = -1e16f)
46 : {
47 0 : if(!caustictex[0])
48 : {
49 0 : loadcaustics(true);
50 : }
51 0 : vec s = vec(0.011f, 0, 0.0066f).mul(100.0f/causticscale),
52 0 : t = vec(0, 0.011f, 0.0066f).mul(100.0f/causticscale);
53 0 : int tex = (lastmillis/causticmillis)%numcaustics;
54 0 : float frac = static_cast<float>(lastmillis%causticmillis)/causticmillis;
55 0 : for(int i = 0; i < 2; ++i)
56 : {
57 0 : glActiveTexture(GL_TEXTURE0+tmu+i);
58 0 : glBindTexture(GL_TEXTURE_2D, caustictex[(tex+i)%numcaustics]->id);
59 : }
60 0 : glActiveTexture(GL_TEXTURE0);
61 0 : float blendscale = causticcontrast,
62 0 : blendoffset = 1;
63 0 : if(surface > -1e15f)
64 : {
65 0 : float bz = surface + camera1->o.z + (vertwater ? wateramplitude : 0);
66 0 : matrix4 m(vec4<float>(s.x, t.x, 0, 0),
67 0 : vec4<float>(s.y, t.y, 0, 0),
68 0 : vec4<float>(s.z, t.z, -1, 0),
69 0 : vec4<float>( 0, 0, bz, 1));
70 0 : m.mul(worldmatrix);
71 0 : GLOBALPARAM(causticsmatrix, m);
72 0 : blendscale *= 0.5f;
73 0 : blendoffset = 0;
74 : }
75 : else
76 : {
77 0 : GLOBALPARAM(causticsS, s);
78 0 : GLOBALPARAM(causticsT, t);
79 : }
80 0 : GLOBALPARAMF(causticsblend, blendscale*(1-frac), blendscale*frac, blendoffset - causticoffset*blendscale);
81 0 : }
82 :
83 0 : VARFP(caustics, 0, 1, 1, { loadcaustics(false); preloadwatershaders(); });
84 :
85 0 : void rendercaustics(float surface, float syl, float syr)
86 : {
87 0 : if(!caustics || !causticscale || !causticmillis)
88 : {
89 0 : return;
90 : }
91 0 : glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
92 0 : setupcaustics(0, surface);
93 0 : SETSHADER(caustics);
94 0 : gle::defvertex(2);
95 0 : gle::begin(GL_TRIANGLE_STRIP);
96 0 : gle::attribf(1, -1);
97 0 : gle::attribf(-1, -1);
98 0 : gle::attribf(1, syr);
99 0 : gle::attribf(-1, syl);
100 0 : gle::end();
101 : }
102 : }
103 :
104 0 : void loadcaustics(bool force)
105 : {
106 : static bool needcaustics = false;
107 0 : if(force)
108 : {
109 0 : needcaustics = true;
110 : }
111 0 : if(!caustics || !needcaustics)
112 : {
113 0 : return;
114 : }
115 0 : useshaderbyname("caustics");
116 0 : if(caustictex[0])
117 : {
118 0 : return;
119 : }
120 0 : for(int i = 0; i < numcaustics; ++i)
121 : {
122 0 : DEF_FORMAT_STRING(name, "<grey><noswizzle>media/texture/mat_water/caustic/caust%.2d.png", i);
123 0 : caustictex[i] = textureload(name);
124 : }
125 : }
126 :
127 : /* vertex water */
128 :
129 : // vertex water refers to the ability for the engine to dynamically create geom
130 : // for the water material's surface, to simulate waviness directly by creating
131 : // 3d geometry
132 :
133 : //these variables control the vertex water geometry intensity
134 : //(nothing to do with any other rendering)
135 :
136 0 : VARFP(vertwater, 0, 1, 1, rootworld.allchanged()); //used in material
137 :
138 : namespace
139 : {
140 : VARP(watersubdiv, 0, 3, 3); //gridpower of water geometry
141 : VARP(waterlod, 0, 1, 3); //larger means that geometry is finer for longer distances
142 :
143 : int wx1, wy1, wx2, wy2, wsize;
144 :
145 : float wxscale = 1.0f,
146 : wyscale = 1.0f;
147 :
148 0 : void defvertwt()
149 : {
150 0 : gle::defvertex();
151 0 : gle::deftexcoord0();
152 0 : }
153 :
154 0 : void vertwt(float v1, float v2, float v3, float whscale, float whoffset)
155 : {
156 0 : float angle = (v1 - wx1) * (v2 - wy1) * (v1 - wx2) * (v2 - wy2) * whscale + whoffset;
157 0 : float s = angle - static_cast<int>(angle) - 0.5f; s *= 8 - std::fabs(s)*16;
158 0 : float h = wateramplitude*s-wateroffset;
159 0 : gle::attribf(v1, v2, v3+h);
160 0 : gle::attribf(wxscale*v1, wyscale*v2);
161 0 : }
162 :
163 0 : void defvertwtn()
164 : {
165 0 : gle::defvertex();
166 0 : gle::deftexcoord0();
167 0 : }
168 :
169 0 : void vertwtn(float v1, float v2, float v3)
170 : {
171 0 : float h = -wateroffset;
172 0 : gle::attribf(v1, v2, v3+h);
173 0 : gle::attribf(wxscale*v1, wyscale*v2);
174 0 : }
175 :
176 0 : void rendervertwater(int subdiv, int xo, int yo, int z, int size, int mat)
177 : {
178 0 : wx1 = xo;
179 0 : wy1 = yo;
180 0 : wx2 = wx1 + size,
181 0 : wy2 = wy1 + size;
182 0 : wsize = size;
183 0 : float whscale = 59.0f/(23.0f*wsize*wsize)/(2*M_PI); //59, 23 magic numbers
184 0 : if(mat == Mat_Water)
185 : {
186 0 : float whoffset = std::fmod(static_cast<float>(lastmillis/600.0f/(2*M_PI)), 1.0f);
187 0 : defvertwt();
188 0 : gle::begin(GL_TRIANGLE_STRIP, 2*(wy2-wy1 + 1)*(wx2-wx1)/subdiv);
189 0 : for(int x = wx1; x<wx2; x += subdiv)
190 : {
191 0 : vertwt(x, wy1, z, whscale, whoffset);
192 0 : vertwt(x+subdiv, wy1, z, whscale, whoffset);
193 0 : for(int y = wy1; y<wy2; y += subdiv)
194 : {
195 0 : vertwt(x, y+subdiv, z, whscale, whoffset);
196 0 : vertwt(x+subdiv, y+subdiv, z, whscale, whoffset);
197 : }
198 0 : gle::multidraw();
199 : }
200 0 : xtraverts += gle::end();
201 : }
202 0 : }
203 :
204 0 : int calcwatersubdiv(int x, int y, int z, int size)
205 : {
206 : float dist;
207 0 : if(camera1->o.x >= x && camera1->o.x < x + size &&
208 0 : camera1->o.y >= y && camera1->o.y < y + size)
209 : {
210 0 : dist = std::fabs(camera1->o.z - static_cast<float>(z));
211 : }
212 : else
213 : {
214 0 : dist = vec(x + size/2, y + size/2, z + size/2).dist(camera1->o) - size*1.42f/2;
215 : }
216 0 : int subdiv = watersubdiv + static_cast<int>(dist) / (32 << waterlod);
217 0 : return subdiv >= 31 ? INT_MAX : 1<<subdiv;
218 : }
219 :
220 0 : int renderwaterlod(int x, int y, int z, int size, int mat)
221 : {
222 0 : if(size <= (32 << waterlod))
223 : {
224 0 : int subdiv = calcwatersubdiv(x, y, z, size);
225 0 : if(subdiv < size * 2)
226 : {
227 0 : rendervertwater(std::min(subdiv, size), x, y, z, size, mat);
228 : }
229 0 : return subdiv;
230 : }
231 : else
232 : {
233 0 : int subdiv = calcwatersubdiv(x, y, z, size);
234 0 : if(subdiv >= size)
235 : {
236 0 : if(subdiv < size * 2)
237 : {
238 0 : rendervertwater(size, x, y, z, size, mat);
239 : }
240 0 : return subdiv;
241 : }
242 0 : int childsize = size / 2,
243 0 : subdiv1 = renderwaterlod(x, y, z, childsize, mat),
244 0 : subdiv2 = renderwaterlod(x + childsize, y, z, childsize, mat),
245 0 : subdiv3 = renderwaterlod(x + childsize, y + childsize, z, childsize, mat),
246 0 : subdiv4 = renderwaterlod(x, y + childsize, z, childsize, mat),
247 0 : minsubdiv = subdiv1;
248 0 : minsubdiv = std::min(minsubdiv, subdiv2);
249 0 : minsubdiv = std::min(minsubdiv, subdiv3);
250 0 : minsubdiv = std::min(minsubdiv, subdiv4);
251 0 : if(minsubdiv < size * 2)
252 : {
253 0 : if(minsubdiv >= size)
254 : {
255 0 : rendervertwater(size, x, y, z, size, mat);
256 : }
257 : else
258 : {
259 0 : if(subdiv1 >= size)
260 : {
261 0 : rendervertwater(childsize, x, y, z, childsize, mat);
262 : }
263 0 : if(subdiv2 >= size)
264 : {
265 0 : rendervertwater(childsize, x + childsize, y, z, childsize, mat);
266 : }
267 0 : if(subdiv3 >= size)
268 : {
269 0 : rendervertwater(childsize, x + childsize, y + childsize, z, childsize, mat);
270 : }
271 0 : if(subdiv4 >= size)
272 : {
273 0 : rendervertwater(childsize, x, y + childsize, z, childsize, mat);
274 : }
275 : }
276 : }
277 0 : return minsubdiv;
278 : }
279 : }
280 :
281 :
282 : /**
283 : * @brief renders water with no vertex water subdivision
284 : *
285 : * If `mat` is not Mat_Water, this function has no effect. Otherwise, draws
286 : * water at the position `o` and size `rsize`/`csize`.
287 : *
288 : * @param o the position to draw at
289 : * @param rsize x size of the water
290 : * @param csize y size of the water
291 : * @param mat check that appropriate material is being used
292 : */
293 0 : void renderflatwater(ivec o, int rsize, int csize, int mat)
294 : {
295 0 : if(mat == Mat_Water)
296 : {
297 0 : if(gle::attribbuf.empty())
298 : {
299 0 : defvertwtn();
300 0 : gle::begin(GL_TRIANGLE_FAN);
301 : }
302 0 : vertwtn(o.x, o.y, o.z);
303 0 : vertwtn(o.x+rsize, o.y, o.z);
304 0 : vertwtn(o.x+rsize, o.y+csize, o.z);
305 0 : vertwtn(o.x, o.y+csize, o.z);
306 0 : xtraverts += 4;
307 : }
308 0 : }
309 :
310 0 : void renderwater(const materialsurface &m, int mat = Mat_Water)
311 : {
312 0 : if(!vertwater || drawtex == Draw_TexMinimap)
313 : {
314 0 : renderflatwater(m.o, m.rsize, m.csize, mat);
315 : }
316 0 : else if(renderwaterlod(m.o.x, m.o.y, m.o.z, m.csize, mat) >= static_cast<int>(m.csize) * 2)
317 : {
318 0 : rendervertwater(m.csize, m.o.x, m.o.y, m.o.z, m.csize, mat);
319 : }
320 0 : }
321 :
322 : //==================================================================== WATERVARS
323 : #define WATERVARS(name) \
324 : CVAR0R(name##color, 0x01212C); \
325 : CVAR0R(name##deepcolor, 0x010A10); \
326 : CVAR0R(name##deepfade, 0x60BFFF); \
327 : CVAR0R(name##refractcolor, 0xFFFFFF); \
328 : VARR(name##fog, 0, 30, 10000); \
329 : VARR(name##deep, 0, 50, 10000); \
330 : VARR(name##spec, 0, 150, 200); \
331 : FVARR(name##refract, 0, 0.1f, 1e3f); \
332 : CVARR(name##fallcolor, 0); \
333 : CVARR(name##fallrefractcolor, 0); \
334 : VARR(name##fallspec, 0, 150, 200); \
335 : FVARR(name##fallrefract, 0, 0.1f, 1e3f);
336 :
337 0 : WATERVARS(water)
338 0 : WATERVARS(water2)
339 0 : WATERVARS(water3)
340 0 : WATERVARS(water4)
341 :
342 : #undef WATERVARS
343 : //==============================================================================
344 :
345 0 : VARFP(waterreflect, 0, 1, 1, { preloadwatershaders(); });
346 : VARR(waterreflectstep, 1, 32, 10000);
347 : }
348 :
349 0 : GETMATIDXVAR(water, color, const bvec &)
350 0 : GETMATIDXVAR(water, deepcolor, const bvec &)
351 0 : GETMATIDXVAR(water, deepfade, const bvec &)
352 0 : GETMATIDXVAR(water, refractcolor, const bvec &)
353 0 : GETMATIDXVAR(water, fallcolor, const bvec &)
354 0 : GETMATIDXVAR(water, fallrefractcolor, const bvec &)
355 0 : GETMATIDXVAR(water, fog, int)
356 0 : GETMATIDXVAR(water, deep, int)
357 0 : GETMATIDXVAR(water, spec, int)
358 0 : GETMATIDXVAR(water, refract, float)
359 0 : GETMATIDXVAR(water, fallspec, int)
360 0 : GETMATIDXVAR(water, fallrefract, float)
361 :
362 :
363 0 : void GBuffer::renderwaterfog(int mat, float surface)
364 : {
365 0 : glDepthFunc(GL_NOTEQUAL);
366 0 : glDepthMask(GL_FALSE);
367 0 : glDepthRange(1, 1);
368 :
369 0 : glEnable(GL_BLEND);
370 :
371 0 : glActiveTexture(GL_TEXTURE9);
372 0 : if(msaalight)
373 : {
374 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
375 : }
376 : else
377 : {
378 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
379 : }
380 0 : glActiveTexture(GL_TEXTURE0);
381 :
382 0 : matrix4 invcamprojmatrix = camprojmatrix.inverse();
383 : std::array<vec, 4> p =
384 : {
385 0 : invcamprojmatrix.perspectivetransform(vec(-1, -1, -1)),
386 0 : invcamprojmatrix.perspectivetransform(vec(-1, 1, -1)),
387 0 : invcamprojmatrix.perspectivetransform(vec(1, -1, -1)),
388 0 : invcamprojmatrix.perspectivetransform(vec(1, 1, -1))
389 : };
390 0 : float bz = surface + camera1->o.z + (vertwater ? wateramplitude : 0),
391 0 : syl = (p[1].z > p[0].z) ? (2*(bz - p[0].z)/(p[1].z - p[0].z) - 1) : 1,
392 0 : syr = (p[3].z > p[2].z) ? (2*(bz - p[2].z)/(p[3].z - p[2].z) - 1) : 1;
393 :
394 0 : if((mat&MatFlag_Volume) == Mat_Water)
395 : {
396 0 : const bvec &deepcolor = getwaterdeepcolor(mat);
397 0 : int deep = getwaterdeep(mat);
398 0 : GLOBALPARAMF(waterdeepcolor, deepcolor.x*ldrscaleb(), deepcolor.y*ldrscaleb(), deepcolor.z*ldrscaleb());
399 0 : vec deepfade = getwaterdeepfade(mat).tocolor().mul(deep);
400 0 : GLOBALPARAMF(waterdeepfade,
401 : deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
402 : deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
403 : deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
404 : deep ? calcfogdensity(deep) : -1e4f);
405 :
406 0 : rendercaustics(surface, syl, syr);
407 : }
408 : else
409 : {
410 0 : GLOBALPARAMF(waterdeepcolor, 0, 0, 0);
411 0 : GLOBALPARAMF(waterdeepfade, -1e4f, -1e4f, -1e4f, -1e4f);
412 : }
413 :
414 0 : GLOBALPARAMF(waterheight, bz);
415 :
416 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
417 :
418 0 : SETSHADER(waterfog);
419 0 : gle::defvertex(3);
420 0 : gle::begin(GL_TRIANGLE_STRIP);
421 0 : gle::attribf( 1, -1, 1);
422 0 : gle::attribf(-1, -1, 1);
423 0 : gle::attribf( 1, syr, 1);
424 0 : gle::attribf(-1, syl, 1);
425 0 : gle::end();
426 :
427 0 : glDisable(GL_BLEND);
428 :
429 0 : glDepthFunc(GL_LESS);
430 0 : glDepthMask(GL_TRUE);
431 0 : glDepthRange(0, 1);
432 0 : }
433 :
434 0 : void preloadwatershaders(bool force)
435 : {
436 : static bool needwater = false;
437 0 : if(force)
438 : {
439 0 : needwater = true;
440 : }
441 0 : if(!needwater)
442 : {
443 0 : return;
444 : }
445 0 : if(caustics && causticscale && causticmillis)
446 : {
447 0 : if(waterreflect)
448 : {
449 0 : useshaderbyname("waterreflectcaustics");
450 : }
451 : else
452 : {
453 0 : useshaderbyname("watercaustics");
454 : }
455 : }
456 : else
457 : {
458 0 : if(waterreflect)
459 : {
460 0 : useshaderbyname("waterreflect");
461 : }
462 : else
463 : {
464 0 : useshaderbyname("water");
465 : }
466 : }
467 0 : useshaderbyname("underwater");
468 0 : useshaderbyname("waterfall");
469 0 : useshaderbyname("waterfog");
470 0 : useshaderbyname("waterminimap");
471 : }
472 :
473 : static float wfwave = 0.0f, //waterfall wave
474 : wfscroll = 0.0f, //waterfall scroll
475 : wfxscale = 1.0f, //waterfall x scale
476 : wfyscale = 1.0f; //waterfall y scale
477 :
478 : //"waterfall" refers to any rendered side of water material
479 0 : static void renderwaterfall(const materialsurface &m, float offset, vec normal = vec(0,0,0))
480 : {
481 0 : if(gle::attribbuf.empty())
482 : {
483 0 : gle::defvertex();
484 0 : if(normal != vec(0,0,0))
485 : {
486 0 : gle::defnormal();
487 : }
488 0 : gle::deftexcoord0();
489 : }
490 0 : float x = m.o.x,
491 0 : y = m.o.y,
492 0 : zmin = m.o.z,
493 0 : zmax = zmin;
494 0 : if(m.ends&1)
495 : {
496 0 : zmin += -wateroffset-wateramplitude;
497 : }
498 0 : if(m.ends&2)
499 : {
500 0 : zmax += wfwave;
501 : }
502 0 : int csize = m.csize,
503 0 : rsize = m.rsize;
504 0 : if(normal != vec(0,0,0))
505 : {
506 0 : vec n = normal;
507 0 : switch(m.orient)
508 : {
509 0 : case 0:
510 : {
511 0 : gle::begin(GL_TRIANGLE_FAN);
512 : {
513 0 : vec v(x + offset, y + rsize, zmax + csize);
514 0 : gle::attribf(v.x, v.y, v.z);
515 0 : gle::attribf(n.x, n.y, n.z);
516 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
517 : }
518 : {
519 0 : vec v(x + offset, y + rsize, zmin );
520 0 : gle::attribf(v.x, v.y, v.z);
521 0 : gle::attribf(n.x, n.y, n.z);
522 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
523 : }
524 : {
525 0 : vec v(x + offset, y , zmin );
526 0 : gle::attribf(v.x, v.y, v.z);
527 0 : gle::attribf(n.x, n.y, n.z);
528 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
529 : }
530 : {
531 0 : vec v(x + offset, y , zmax + csize);
532 0 : gle::attribf(v.x, v.y, v.z);
533 0 : gle::attribf(n.x, n.y, n.z);
534 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
535 : }
536 0 : gle::end();
537 0 : break;
538 : }
539 0 : case 1:
540 : {
541 0 : gle::begin(GL_TRIANGLE_FAN);
542 : {
543 0 : vec v(x - offset, y + rsize, zmax + csize);
544 0 : gle::attribf(v.x, v.y, v.z);
545 0 : gle::attribf(n.x, n.y, n.z);
546 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
547 : }
548 : {
549 0 : vec v(x - offset, y , zmax + csize);
550 0 : gle::attribf(v.x, v.y, v.z);
551 0 : gle::attribf(n.x, n.y, n.z);
552 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
553 : }
554 : {
555 0 : vec v(x - offset, y , zmin );
556 0 : gle::attribf(v.x, v.y, v.z);
557 0 : gle::attribf(n.x, n.y, n.z);
558 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
559 : }
560 : {
561 0 : vec v(x - offset, y + rsize, zmin );
562 0 : gle::attribf(v.x, v.y, v.z);
563 0 : gle::attribf(n.x, n.y, n.z);
564 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
565 : }
566 0 : gle::end();
567 0 : break;
568 : }
569 0 : case 2:
570 : {
571 0 : gle::begin(GL_TRIANGLE_FAN);
572 : {
573 0 : vec v(x + csize, y + offset, zmax + rsize);
574 0 : gle::attribf(v.x, v.y, v.z);
575 0 : gle::attribf(n.x, n.y, n.z);
576 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
577 : }
578 : {
579 0 : vec v(x , y + offset, zmax + rsize);
580 0 : gle::attribf(v.x, v.y, v.z);
581 0 : gle::attribf(n.x, n.y, n.z);
582 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
583 : }
584 : {
585 0 : vec v(x , y + offset, zmin );
586 0 : gle::attribf(v.x, v.y, v.z);
587 0 : gle::attribf(n.x, n.y, n.z);
588 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
589 : }
590 : {
591 0 : vec v(x + csize, y + offset, zmin );
592 0 : gle::attribf(v.x, v.y, v.z);
593 0 : gle::attribf(n.x, n.y, n.z);
594 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
595 : }
596 0 : gle::end();
597 0 : break;
598 : }
599 0 : case 3:
600 : {
601 0 : gle::begin(GL_TRIANGLE_FAN);
602 : {
603 0 : vec v(x , y - offset, zmin );
604 0 : gle::attribf(v.x, v.y, v.z);
605 0 : gle::attribf(n.x, n.y, n.z);
606 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
607 : }
608 : {
609 0 : vec v(x , y - offset, zmax + rsize);
610 0 : gle::attribf(v.x, v.y, v.z);
611 0 : gle::attribf(n.x, n.y, n.z);
612 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
613 : }
614 : {
615 0 : vec v(x + csize, y - offset, zmax + rsize);
616 0 : gle::attribf(v.x, v.y, v.z);
617 0 : gle::attribf(n.x, n.y, n.z);
618 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
619 : }
620 : {
621 0 : vec v(x + csize, y - offset, zmin );
622 0 : gle::attribf(v.x, v.y, v.z);
623 0 : gle::attribf(n.x, n.y, n.z);
624 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
625 : }
626 0 : gle::end();
627 0 : break;
628 : }
629 : }
630 : }
631 : else
632 : {
633 0 : switch(m.orient)
634 : {
635 0 : case 0:
636 : {
637 0 : gle::begin(GL_TRIANGLE_FAN);
638 : {
639 0 : vec v(x + offset, y + rsize, zmax + csize);
640 0 : gle::attribf(v.x, v.y, v.z);
641 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
642 : }
643 : {
644 0 : vec v(x + offset, y + rsize, zmin );
645 0 : gle::attribf(v.x, v.y, v.z);
646 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
647 : }
648 : {
649 0 : vec v(x + offset, y , zmin );
650 0 : gle::attribf(v.x, v.y, v.z);
651 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
652 : }
653 : {
654 0 : vec v(x + offset, y , zmax + csize);
655 0 : gle::attribf(v.x, v.y, v.z);
656 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
657 : }
658 0 : gle::end();
659 0 : break;
660 : }
661 0 : case 1:
662 : {
663 0 : gle::begin(GL_TRIANGLE_FAN);
664 : {
665 0 : vec v(x - offset, y + rsize, zmax + csize);
666 0 : gle::attribf(v.x, v.y, v.z);
667 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
668 : }
669 : {
670 0 : vec v(x - offset, y , zmax + csize);
671 0 : gle::attribf(v.x, v.y, v.z);
672 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
673 : }
674 : {
675 0 : vec v(x - offset, y , zmin );
676 0 : gle::attribf(v.x, v.y, v.z);
677 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
678 : }
679 : {
680 0 : vec v(x - offset, y + rsize, zmin );
681 0 : gle::attribf(v.x, v.y, v.z);
682 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
683 : }
684 0 : gle::end();
685 0 : break;
686 : }
687 0 : case 2:
688 : {
689 0 : gle::begin(GL_TRIANGLE_FAN);
690 : {
691 0 : vec v(x + csize, y + offset, zmax + rsize);
692 0 : gle::attribf(v.x, v.y, v.z);
693 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
694 : }
695 : {
696 0 : vec v(x , y + offset, zmax + rsize);
697 0 : gle::attribf(v.x, v.y, v.z);
698 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
699 : }
700 : {
701 0 : vec v(x , y + offset, zmin);
702 0 : gle::attribf(v.x, v.y, v.z);
703 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
704 : }
705 : {
706 0 : vec v(x + csize, y + offset, zmin);
707 0 : gle::attribf(v.x, v.y, v.z);
708 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
709 : }
710 0 : gle::end();
711 0 : break;
712 : }
713 0 : case 3:
714 : {
715 0 : gle::begin(GL_TRIANGLE_FAN);
716 : {
717 0 : vec v(x , y - offset, zmin);
718 0 : gle::attribf(v.x, v.y, v.z);
719 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
720 : }
721 : {
722 0 : vec v(x , y - offset, zmax + rsize);
723 0 : gle::attribf(v.x, v.y, v.z);
724 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
725 : }
726 : {
727 0 : vec v(x + csize, y - offset, zmax + rsize);
728 0 : gle::attribf(v.x, v.y, v.z);
729 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
730 : }
731 : {
732 0 : vec v(x + csize, y - offset, zmin);
733 0 : gle::attribf(v.x, v.y, v.z);
734 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
735 : }
736 0 : gle::end();
737 0 : break;
738 : }
739 : }
740 : }
741 0 : }
742 :
743 0 : void renderwaterfalls()
744 : {
745 0 : for(int k = 0; k < 4; ++k)
746 : {
747 0 : const std::vector<materialsurface> &surfs = waterfallsurfs[k];
748 0 : if(surfs.empty())
749 : {
750 0 : continue;
751 : }
752 0 : const MatSlot &wslot = lookupmaterialslot(Mat_Water+k);
753 :
754 0 : const Texture *tex = wslot.sts.size() > 2 ? wslot.sts[2].t : (wslot.sts.size() ? wslot.sts[0].t : notexture);
755 0 : float angle = std::fmod(static_cast<float>(lastmillis/600.0f/(2*M_PI)), 1.0f),
756 0 : s = angle - static_cast<int>(angle) - 0.5f;
757 0 : s *= 8 - std::fabs(s)*16;
758 0 : wfwave = vertwater ? wateramplitude*s-wateroffset : -wateroffset;
759 0 : wfscroll = 16.0f*lastmillis/1000.0f;
760 0 : wfxscale = defaulttexscale/(tex->xs*wslot.scale);
761 0 : wfyscale = defaulttexscale/(tex->ys*wslot.scale);
762 : //waterfall color vectors
763 0 : bvec color = getwaterfallcolor(k),
764 0 : refractcolor = getwaterfallrefractcolor(k);
765 0 : if(color.iszero())
766 : {
767 0 : color = getwatercolor(k);
768 : }
769 0 : if(refractcolor.iszero())
770 : {
771 0 : refractcolor = getwaterrefractcolor(k);
772 : }
773 0 : float colorscale = (0.5f/255),
774 0 : refractscale = colorscale/ldrscale,
775 0 : refract = getwaterfallrefract(k);
776 0 : int spec = getwaterfallspec(k);
777 0 : GLOBALPARAMF(waterfallcolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
778 0 : GLOBALPARAMF(waterfallrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
779 0 : GLOBALPARAMF(waterfallspec, spec/100.0f);
780 :
781 0 : SETSHADER(waterfall);
782 :
783 0 : glBindTexture(GL_TEXTURE_2D, tex->id);
784 0 : glActiveTexture(GL_TEXTURE1);
785 0 : glBindTexture(GL_TEXTURE_2D, wslot.sts.size() > 2 ? (wslot.sts.size() > 3 ? wslot.sts[3].t->id : notexture->id) : (wslot.sts.size() > 1 ? wslot.sts[1].t->id : notexture->id));
786 0 : glActiveTexture(GL_TEXTURE0);
787 0 : for(const materialsurface& m : surfs)
788 : {
789 0 : renderwaterfall(m, 0.1f, matnormals(m.orient));
790 : }
791 0 : xtraverts += gle::end();
792 : }
793 0 : }
794 :
795 0 : void renderwater()
796 : {
797 0 : for(int k = 0; k < 4; ++k) //four types of water hardcoded
798 : {
799 0 : const std::vector<materialsurface> &surfs = watersurfs[k];
800 0 : if(surfs.empty())
801 : {
802 0 : continue;
803 : }
804 0 : const MatSlot &wslot = lookupmaterialslot(Mat_Water+k);
805 :
806 0 : const Texture *tex = wslot.sts.size() ? wslot.sts[0].t: notexture;
807 0 : wxscale = defaulttexscale/(tex->xs*wslot.scale);
808 0 : wyscale = defaulttexscale/(tex->ys*wslot.scale);
809 :
810 0 : glBindTexture(GL_TEXTURE_2D, tex->id);
811 0 : glActiveTexture(GL_TEXTURE1);
812 0 : glBindTexture(GL_TEXTURE_2D, wslot.sts.size() > 1 ? wslot.sts[1].t->id : notexture->id);
813 0 : if(caustics && causticscale && causticmillis)
814 : {
815 0 : setupcaustics(2);
816 : }
817 0 : glActiveTexture(GL_TEXTURE0);
818 :
819 0 : float colorscale = 0.5f/255,
820 0 : refractscale = colorscale/ldrscale,
821 0 : reflectscale = 0.5f/ldrscale;
822 0 : const bvec &color = getwatercolor(k),
823 0 : &deepcolor = getwaterdeepcolor(k),
824 0 : &refractcolor = getwaterrefractcolor(k);
825 0 : int fog = getwaterfog(k),
826 0 : deep = getwaterdeep(k),
827 0 : spec = getwaterspec(k);
828 0 : float refract = getwaterrefract(k);
829 0 : GLOBALPARAMF(watercolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
830 0 : GLOBALPARAMF(waterdeepcolor, deepcolor.x*colorscale, deepcolor.y*colorscale, deepcolor.z*colorscale);
831 0 : float fogdensity = fog ? calcfogdensity(fog) : -1e4f;
832 0 : GLOBALPARAMF(waterfog, fogdensity);
833 0 : vec deepfade = getwaterdeepfade(k).tocolor().mul(deep);
834 0 : GLOBALPARAMF(waterdeepfade,
835 : deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
836 : deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
837 : deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
838 : deep ? calcfogdensity(deep) : -1e4f);
839 0 : GLOBALPARAMF(waterspec, spec/100.0f);
840 0 : GLOBALPARAMF(waterreflect, reflectscale, reflectscale, reflectscale, waterreflectstep);
841 0 : GLOBALPARAMF(waterrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
842 :
843 : //======================================================= SETWATERSHADER
844 : #define SETWATERSHADER(which, name) \
845 : do { \
846 : static Shader *name##shader = nullptr; \
847 : if(!name##shader) \
848 : { \
849 : name##shader = lookupshaderbyname(#name); \
850 : } \
851 : which##shader = name##shader; \
852 : } while(0)
853 :
854 0 : Shader *aboveshader = nullptr;
855 : //this if tree will select which shader is the water aboveshader depending on settings
856 0 : if(drawtex == Draw_TexMinimap)
857 : {
858 0 : SETWATERSHADER(above, waterminimap);
859 : }
860 0 : else if(caustics && causticscale && causticmillis) //caustics
861 : {
862 0 : if(waterreflect)
863 : {
864 0 : SETWATERSHADER(above, waterreflectcaustics);
865 : }
866 : else
867 : {
868 0 : SETWATERSHADER(above, watercaustics);
869 : }
870 0 : }
871 : else //no caustics
872 : {
873 0 : if(waterreflect)
874 : {
875 0 : SETWATERSHADER(above, waterreflect);
876 : }
877 : else
878 : {
879 0 : SETWATERSHADER(above, water);
880 : }
881 : }
882 : //now select the water belowshader
883 0 : Shader *belowshader = nullptr;
884 0 : if(drawtex != Draw_TexMinimap)
885 : {
886 0 : SETWATERSHADER(below, underwater); //if rendering water, and not rendering a minimap, sets belowshader to non-null
887 : }
888 : #undef SETWATERSHADER
889 : //======================================================================
890 :
891 0 : aboveshader->set();
892 0 : for(const materialsurface &m: surfs)
893 : {
894 0 : if(camera1->o.z < m.o.z - wateroffset)
895 : {
896 0 : continue;
897 : }
898 0 : renderwater(m);
899 : }
900 0 : xtraverts += gle::end();
901 0 : if(belowshader)
902 : {
903 0 : belowshader->set();
904 0 : for(const materialsurface& m : surfs)
905 : {
906 0 : if(camera1->o.z >= m.o.z - wateroffset)
907 : {
908 0 : continue;
909 : }
910 0 : renderwater(m);
911 : }
912 0 : xtraverts += gle::end();
913 : }
914 : }
915 0 : }
916 :
|