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