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