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 : Texture *caustictex[numcaustics] = {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 : VARP(watersubdiv, 0, 3, 3); //gridpower of water geometry
135 : VARP(waterlod, 0, 1, 3); //larger means that geometry is finer for longer distances
136 0 : VARFP(vertwater, 0, 1, 1, rootworld.allchanged());
137 :
138 : namespace
139 : {
140 : int wx1, wy1, wx2, wy2, wsize;
141 :
142 : float wxscale = 1.0f,
143 : wyscale = 1.0f;
144 :
145 0 : void defvertwt()
146 : {
147 0 : gle::defvertex();
148 0 : gle::deftexcoord0();
149 0 : }
150 :
151 0 : void vertwt(float v1, float v2, float v3, float whscale, float whoffset)
152 : {
153 0 : float angle = (v1 - wx1) * (v2 - wy1) * (v1 - wx2) * (v2 - wy2) * whscale + whoffset;
154 0 : float s = angle - static_cast<int>(angle) - 0.5f; s *= 8 - std::fabs(s)*16;
155 0 : float h = wateramplitude*s-wateroffset;
156 0 : gle::attribf(v1, v2, v3+h);
157 0 : gle::attribf(wxscale*v1, wyscale*v2);
158 0 : }
159 :
160 0 : void defvertwtn()
161 : {
162 0 : gle::defvertex();
163 0 : gle::deftexcoord0();
164 0 : }
165 :
166 0 : void vertwtn(float v1, float v2, float v3)
167 : {
168 0 : float h = -wateroffset;
169 0 : gle::attribf(v1, v2, v3+h);
170 0 : gle::attribf(wxscale*v1, wyscale*v2);
171 0 : }
172 :
173 0 : void rendervertwater(int subdiv, int xo, int yo, int z, int size, int mat)
174 : {
175 0 : wx1 = xo;
176 0 : wy1 = yo;
177 0 : wx2 = wx1 + size,
178 0 : wy2 = wy1 + size;
179 0 : wsize = size;
180 0 : float whscale = 59.0f/(23.0f*wsize*wsize)/(2*M_PI); //59, 23 magic numbers
181 0 : if(mat == Mat_Water)
182 : {
183 0 : float whoffset = std::fmod(static_cast<float>(lastmillis/600.0f/(2*M_PI)), 1.0f);
184 0 : defvertwt();
185 0 : gle::begin(GL_TRIANGLE_STRIP, 2*(wy2-wy1 + 1)*(wx2-wx1)/subdiv);
186 0 : for(int x = wx1; x<wx2; x += subdiv)
187 : {
188 0 : vertwt(x, wy1, z, whscale, whoffset);
189 0 : vertwt(x+subdiv, wy1, z, whscale, whoffset);
190 0 : for(int y = wy1; y<wy2; y += subdiv)
191 : {
192 0 : vertwt(x, y+subdiv, z, whscale, whoffset);
193 0 : vertwt(x+subdiv, y+subdiv, z, whscale, whoffset);
194 : }
195 0 : gle::multidraw();
196 : }
197 0 : xtraverts += gle::end();
198 : }
199 0 : }
200 :
201 0 : int calcwatersubdiv(int x, int y, int z, int size)
202 : {
203 : float dist;
204 0 : if(camera1->o.x >= x && camera1->o.x < x + size &&
205 0 : camera1->o.y >= y && camera1->o.y < y + size)
206 : {
207 0 : dist = std::fabs(camera1->o.z - static_cast<float>(z));
208 : }
209 : else
210 : {
211 0 : dist = vec(x + size/2, y + size/2, z + size/2).dist(camera1->o) - size*1.42f/2;
212 : }
213 0 : int subdiv = watersubdiv + static_cast<int>(dist) / (32 << waterlod);
214 0 : return subdiv >= 31 ? INT_MAX : 1<<subdiv;
215 : }
216 :
217 0 : int renderwaterlod(int x, int y, int z, int size, int mat)
218 : {
219 0 : if(size <= (32 << waterlod))
220 : {
221 0 : int subdiv = calcwatersubdiv(x, y, z, size);
222 0 : if(subdiv < size * 2)
223 : {
224 0 : rendervertwater(std::min(subdiv, size), x, y, z, size, mat);
225 : }
226 0 : return subdiv;
227 : }
228 : else
229 : {
230 0 : int subdiv = calcwatersubdiv(x, y, z, size);
231 0 : if(subdiv >= size)
232 : {
233 0 : if(subdiv < size * 2)
234 : {
235 0 : rendervertwater(size, x, y, z, size, mat);
236 : }
237 0 : return subdiv;
238 : }
239 0 : int childsize = size / 2,
240 0 : subdiv1 = renderwaterlod(x, y, z, childsize, mat),
241 0 : subdiv2 = renderwaterlod(x + childsize, y, z, childsize, mat),
242 0 : subdiv3 = renderwaterlod(x + childsize, y + childsize, z, childsize, mat),
243 0 : subdiv4 = renderwaterlod(x, y + childsize, z, childsize, mat),
244 0 : minsubdiv = subdiv1;
245 0 : minsubdiv = std::min(minsubdiv, subdiv2);
246 0 : minsubdiv = std::min(minsubdiv, subdiv3);
247 0 : minsubdiv = std::min(minsubdiv, subdiv4);
248 0 : if(minsubdiv < size * 2)
249 : {
250 0 : if(minsubdiv >= size)
251 : {
252 0 : rendervertwater(size, x, y, z, size, mat);
253 : }
254 : else
255 : {
256 0 : if(subdiv1 >= size)
257 : {
258 0 : rendervertwater(childsize, x, y, z, childsize, mat);
259 : }
260 0 : if(subdiv2 >= size)
261 : {
262 0 : rendervertwater(childsize, x + childsize, y, z, childsize, mat);
263 : }
264 0 : if(subdiv3 >= size)
265 : {
266 0 : rendervertwater(childsize, x + childsize, y + childsize, z, childsize, mat);
267 : }
268 0 : if(subdiv4 >= size)
269 : {
270 0 : rendervertwater(childsize, x, y + childsize, z, childsize, mat);
271 : }
272 : }
273 : }
274 0 : return minsubdiv;
275 : }
276 : }
277 :
278 : /* renderflatwater: renders water with no vertex water subdivision
279 : */
280 0 : void renderflatwater(int x, int y, int z, int rsize, int csize, int mat)
281 : {
282 0 : if(mat == Mat_Water)
283 : {
284 0 : if(gle::attribbuf.empty())
285 : {
286 0 : defvertwtn();
287 0 : gle::begin(GL_TRIANGLE_FAN);
288 : }
289 0 : vertwtn(x, y, z);
290 0 : vertwtn(x+rsize, y, z);
291 0 : vertwtn(x+rsize, y+csize, z);
292 0 : vertwtn(x, y+csize, z);
293 0 : xtraverts += 4;
294 : }
295 0 : }
296 :
297 0 : void renderwater(const materialsurface &m, int mat = Mat_Water)
298 : {
299 0 : if(!vertwater || drawtex == Draw_TexMinimap)
300 : {
301 0 : renderflatwater(m.o.x, m.o.y, m.o.z, m.rsize, m.csize, mat);
302 : }
303 0 : else if(renderwaterlod(m.o.x, m.o.y, m.o.z, m.csize, mat) >= static_cast<int>(m.csize) * 2)
304 : {
305 0 : rendervertwater(m.csize, m.o.x, m.o.y, m.o.z, m.csize, mat);
306 : }
307 0 : }
308 :
309 : //==================================================================== WATERVARS
310 : #define WATERVARS(name) \
311 : CVAR0R(name##color, 0x01212C); \
312 : CVAR0R(name##deepcolor, 0x010A10); \
313 : CVAR0R(name##deepfade, 0x60BFFF); \
314 : CVAR0R(name##refractcolor, 0xFFFFFF); \
315 : VARR(name##fog, 0, 30, 10000); \
316 : VARR(name##deep, 0, 50, 10000); \
317 : VARR(name##spec, 0, 150, 200); \
318 : FVARR(name##refract, 0, 0.1f, 1e3f); \
319 : CVARR(name##fallcolor, 0); \
320 : CVARR(name##fallrefractcolor, 0); \
321 : VARR(name##fallspec, 0, 150, 200); \
322 : FVARR(name##fallrefract, 0, 0.1f, 1e3f);
323 :
324 0 : WATERVARS(water)
325 0 : WATERVARS(water2)
326 0 : WATERVARS(water3)
327 0 : WATERVARS(water4)
328 :
329 : #undef WATERVARS
330 : //==============================================================================
331 :
332 0 : VARFP(waterreflect, 0, 1, 1, { preloadwatershaders(); });
333 : }
334 :
335 0 : GETMATIDXVAR(water, color, const bvec &)
336 0 : GETMATIDXVAR(water, deepcolor, const bvec &)
337 0 : GETMATIDXVAR(water, deepfade, const bvec &)
338 0 : GETMATIDXVAR(water, refractcolor, const bvec &)
339 0 : GETMATIDXVAR(water, fallcolor, const bvec &)
340 0 : GETMATIDXVAR(water, fallrefractcolor, const bvec &)
341 0 : GETMATIDXVAR(water, fog, int)
342 0 : GETMATIDXVAR(water, deep, int)
343 0 : GETMATIDXVAR(water, spec, int)
344 0 : GETMATIDXVAR(water, refract, float)
345 0 : GETMATIDXVAR(water, fallspec, int)
346 0 : GETMATIDXVAR(water, fallrefract, float)
347 :
348 : VARR(waterreflectstep, 1, 32, 10000);
349 :
350 0 : void GBuffer::renderwaterfog(int mat, float surface)
351 : {
352 0 : glDepthFunc(GL_NOTEQUAL);
353 0 : glDepthMask(GL_FALSE);
354 0 : glDepthRange(1, 1);
355 :
356 0 : glEnable(GL_BLEND);
357 :
358 0 : glActiveTexture(GL_TEXTURE9);
359 0 : if(msaalight)
360 : {
361 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
362 : }
363 : else
364 : {
365 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
366 : }
367 0 : glActiveTexture(GL_TEXTURE0);
368 :
369 0 : matrix4 invcamprojmatrix = camprojmatrix.inverse();
370 : vec p[4] =
371 : {
372 0 : invcamprojmatrix.perspectivetransform(vec(-1, -1, -1)),
373 0 : invcamprojmatrix.perspectivetransform(vec(-1, 1, -1)),
374 0 : invcamprojmatrix.perspectivetransform(vec(1, -1, -1)),
375 0 : invcamprojmatrix.perspectivetransform(vec(1, 1, -1))
376 0 : };
377 0 : float bz = surface + camera1->o.z + (vertwater ? wateramplitude : 0),
378 0 : syl = (p[1].z > p[0].z) ? (2*(bz - p[0].z)/(p[1].z - p[0].z) - 1) : 1,
379 0 : syr = (p[3].z > p[2].z) ? (2*(bz - p[2].z)/(p[3].z - p[2].z) - 1) : 1;
380 :
381 0 : if((mat&MatFlag_Volume) == Mat_Water)
382 : {
383 0 : const bvec &deepcolor = getwaterdeepcolor(mat);
384 0 : int deep = getwaterdeep(mat);
385 0 : GLOBALPARAMF(waterdeepcolor, deepcolor.x*ldrscaleb(), deepcolor.y*ldrscaleb(), deepcolor.z*ldrscaleb());
386 0 : vec deepfade = getwaterdeepfade(mat).tocolor().mul(deep);
387 0 : GLOBALPARAMF(waterdeepfade,
388 : deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
389 : deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
390 : deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
391 : deep ? calcfogdensity(deep) : -1e4f);
392 :
393 0 : rendercaustics(surface, syl, syr);
394 : }
395 : else
396 : {
397 0 : GLOBALPARAMF(waterdeepcolor, 0, 0, 0);
398 0 : GLOBALPARAMF(waterdeepfade, -1e4f, -1e4f, -1e4f, -1e4f);
399 : }
400 :
401 0 : GLOBALPARAMF(waterheight, bz);
402 :
403 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
404 :
405 0 : SETSHADER(waterfog);
406 0 : gle::defvertex(3);
407 0 : gle::begin(GL_TRIANGLE_STRIP);
408 0 : gle::attribf( 1, -1, 1);
409 0 : gle::attribf(-1, -1, 1);
410 0 : gle::attribf( 1, syr, 1);
411 0 : gle::attribf(-1, syl, 1);
412 0 : gle::end();
413 :
414 0 : glDisable(GL_BLEND);
415 :
416 0 : glDepthFunc(GL_LESS);
417 0 : glDepthMask(GL_TRUE);
418 0 : glDepthRange(0, 1);
419 0 : }
420 :
421 0 : void preloadwatershaders(bool force)
422 : {
423 : static bool needwater = false;
424 0 : if(force)
425 : {
426 0 : needwater = true;
427 : }
428 0 : if(!needwater)
429 : {
430 0 : return;
431 : }
432 0 : if(caustics && causticscale && causticmillis)
433 : {
434 0 : if(waterreflect)
435 : {
436 0 : useshaderbyname("waterreflectcaustics");
437 : }
438 : else
439 : {
440 0 : useshaderbyname("watercaustics");
441 : }
442 : }
443 : else
444 : {
445 0 : if(waterreflect)
446 : {
447 0 : useshaderbyname("waterreflect");
448 : }
449 : else
450 : {
451 0 : useshaderbyname("water");
452 : }
453 : }
454 0 : useshaderbyname("underwater");
455 0 : useshaderbyname("waterfall");
456 0 : useshaderbyname("waterfog");
457 0 : useshaderbyname("waterminimap");
458 : }
459 :
460 : static float wfwave = 0.0f, //waterfall wave
461 : wfscroll = 0.0f, //waterfall scroll
462 : wfxscale = 1.0f, //waterfall x scale
463 : wfyscale = 1.0f; //waterfall y scale
464 :
465 : //"waterfall" refers to any rendered side of water material
466 0 : static void renderwaterfall(const materialsurface &m, float offset, vec normal = vec(0,0,0))
467 : {
468 0 : if(gle::attribbuf.empty())
469 : {
470 0 : gle::defvertex();
471 0 : if(normal != vec(0,0,0))
472 : {
473 0 : gle::defnormal();
474 : }
475 0 : gle::deftexcoord0();
476 : }
477 0 : float x = m.o.x,
478 0 : y = m.o.y,
479 0 : zmin = m.o.z,
480 0 : zmax = zmin;
481 0 : if(m.ends&1)
482 : {
483 0 : zmin += -wateroffset-wateramplitude;
484 : }
485 0 : if(m.ends&2)
486 : {
487 0 : zmax += wfwave;
488 : }
489 0 : int csize = m.csize,
490 0 : rsize = m.rsize;
491 0 : if(normal != vec(0,0,0))
492 : {
493 0 : vec n = normal;
494 0 : switch(m.orient)
495 : {
496 0 : case 0:
497 : {
498 0 : gle::begin(GL_TRIANGLE_FAN);
499 : {
500 0 : vec v(x + offset, y + rsize, zmax + csize);
501 0 : gle::attribf(v.x, v.y, v.z);
502 0 : gle::attribf(n.x, n.y, n.z);
503 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
504 : }
505 : {
506 0 : vec v(x + offset, y + rsize, zmin );
507 0 : gle::attribf(v.x, v.y, v.z);
508 0 : gle::attribf(n.x, n.y, n.z);
509 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
510 : }
511 : {
512 0 : vec v(x + offset, y , zmin );
513 0 : gle::attribf(v.x, v.y, v.z);
514 0 : gle::attribf(n.x, n.y, n.z);
515 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
516 : }
517 : {
518 0 : vec v(x + offset, y , zmax + csize);
519 0 : gle::attribf(v.x, v.y, v.z);
520 0 : gle::attribf(n.x, n.y, n.z);
521 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
522 : }
523 0 : gle::end();
524 0 : break;
525 : }
526 0 : case 1:
527 : {
528 0 : gle::begin(GL_TRIANGLE_FAN);
529 : {
530 0 : vec v(x - offset, y + rsize, zmax + csize);
531 0 : gle::attribf(v.x, v.y, v.z);
532 0 : gle::attribf(n.x, n.y, n.z);
533 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
534 : }
535 : {
536 0 : vec v(x - offset, y , zmax + csize);
537 0 : gle::attribf(v.x, v.y, v.z);
538 0 : gle::attribf(n.x, n.y, n.z);
539 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
540 : }
541 : {
542 0 : vec v(x - offset, y , zmin );
543 0 : gle::attribf(v.x, v.y, v.z);
544 0 : gle::attribf(n.x, n.y, n.z);
545 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
546 : }
547 : {
548 0 : vec v(x - offset, y + rsize, zmin );
549 0 : gle::attribf(v.x, v.y, v.z);
550 0 : gle::attribf(n.x, n.y, n.z);
551 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
552 : }
553 0 : gle::end();
554 0 : break;
555 : }
556 0 : case 2:
557 : {
558 0 : gle::begin(GL_TRIANGLE_FAN);
559 : {
560 0 : vec v(x + csize, y + offset, zmax + rsize);
561 0 : gle::attribf(v.x, v.y, v.z);
562 0 : gle::attribf(n.x, n.y, n.z);
563 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
564 : }
565 : {
566 0 : vec v(x , y + offset, zmax + rsize);
567 0 : gle::attribf(v.x, v.y, v.z);
568 0 : gle::attribf(n.x, n.y, n.z);
569 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
570 : }
571 : {
572 0 : vec v(x , y + offset, zmin );
573 0 : gle::attribf(v.x, v.y, v.z);
574 0 : gle::attribf(n.x, n.y, n.z);
575 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
576 : }
577 : {
578 0 : vec v(x + csize, y + offset, zmin );
579 0 : gle::attribf(v.x, v.y, v.z);
580 0 : gle::attribf(n.x, n.y, n.z);
581 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
582 : }
583 0 : gle::end();
584 0 : break;
585 : }
586 0 : case 3:
587 : {
588 0 : gle::begin(GL_TRIANGLE_FAN);
589 : {
590 0 : vec v(x , y - offset, zmin );
591 0 : gle::attribf(v.x, v.y, v.z);
592 0 : gle::attribf(n.x, n.y, n.z);
593 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
594 : }
595 : {
596 0 : vec v(x , y - offset, zmax + rsize);
597 0 : gle::attribf(v.x, v.y, v.z);
598 0 : gle::attribf(n.x, n.y, n.z);
599 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
600 : }
601 : {
602 0 : vec v(x + csize, y - offset, zmax + rsize);
603 0 : gle::attribf(v.x, v.y, v.z);
604 0 : gle::attribf(n.x, n.y, n.z);
605 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
606 : }
607 : {
608 0 : vec v(x + csize, y - offset, zmin );
609 0 : gle::attribf(v.x, v.y, v.z);
610 0 : gle::attribf(n.x, n.y, n.z);
611 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
612 : }
613 0 : gle::end();
614 0 : break;
615 : }
616 : }
617 : }
618 : else
619 : {
620 0 : switch(m.orient)
621 : {
622 0 : case 0:
623 : {
624 0 : gle::begin(GL_TRIANGLE_FAN);
625 : {
626 0 : vec v(x + offset, y + rsize, zmax + csize);
627 0 : gle::attribf(v.x, v.y, v.z);
628 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
629 : }
630 : {
631 0 : vec v(x + offset, y + rsize, zmin );
632 0 : gle::attribf(v.x, v.y, v.z);
633 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
634 : }
635 : {
636 0 : vec v(x + offset, y , zmin );
637 0 : gle::attribf(v.x, v.y, v.z);
638 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
639 : }
640 : {
641 0 : vec v(x + offset, y , zmax + csize);
642 0 : gle::attribf(v.x, v.y, v.z);
643 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
644 : }
645 0 : gle::end();
646 0 : break;
647 : }
648 0 : case 1:
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 , zmax + csize);
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 + rsize, zmin );
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 2:
675 : {
676 0 : gle::begin(GL_TRIANGLE_FAN);
677 : {
678 0 : vec v(x + csize, y + offset, zmax + rsize);
679 0 : gle::attribf(v.x, v.y, v.z);
680 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
681 : }
682 : {
683 0 : vec v(x , y + offset, zmax + rsize);
684 0 : gle::attribf(v.x, v.y, v.z);
685 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
686 : }
687 : {
688 0 : vec v(x , y + offset, zmin);
689 0 : gle::attribf(v.x, v.y, v.z);
690 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
691 : }
692 : {
693 0 : vec v(x + csize, y + offset, zmin);
694 0 : gle::attribf(v.x, v.y, v.z);
695 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
696 : }
697 0 : gle::end();
698 0 : break;
699 : }
700 0 : case 3:
701 : {
702 0 : gle::begin(GL_TRIANGLE_FAN);
703 : {
704 0 : vec v(x , y - offset, zmin);
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 + csize, y - offset, zmax + rsize);
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 : }
727 : }
728 0 : }
729 :
730 0 : void renderwaterfalls()
731 : {
732 0 : for(int k = 0; k < 4; ++k)
733 : {
734 0 : const std::vector<materialsurface> &surfs = waterfallsurfs[k];
735 0 : if(surfs.empty())
736 : {
737 0 : continue;
738 : }
739 0 : const MatSlot &wslot = lookupmaterialslot(Mat_Water+k);
740 :
741 0 : const Texture *tex = wslot.sts.size() > 2 ? wslot.sts[2].t : (wslot.sts.size() ? wslot.sts[0].t : notexture);
742 0 : float angle = std::fmod(static_cast<float>(lastmillis/600.0f/(2*M_PI)), 1.0f),
743 0 : s = angle - static_cast<int>(angle) - 0.5f;
744 0 : s *= 8 - std::fabs(s)*16;
745 0 : wfwave = vertwater ? wateramplitude*s-wateroffset : -wateroffset;
746 0 : wfscroll = 16.0f*lastmillis/1000.0f;
747 0 : wfxscale = defaulttexscale/(tex->xs*wslot.scale);
748 0 : wfyscale = defaulttexscale/(tex->ys*wslot.scale);
749 : //waterfall color vectors
750 0 : bvec color = getwaterfallcolor(k),
751 0 : refractcolor = getwaterfallrefractcolor(k);
752 0 : if(color.iszero())
753 : {
754 0 : color = getwatercolor(k);
755 : }
756 0 : if(refractcolor.iszero())
757 : {
758 0 : refractcolor = getwaterrefractcolor(k);
759 : }
760 0 : float colorscale = (0.5f/255),
761 0 : refractscale = colorscale/ldrscale,
762 0 : refract = getwaterfallrefract(k);
763 0 : int spec = getwaterfallspec(k);
764 0 : GLOBALPARAMF(waterfallcolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
765 0 : GLOBALPARAMF(waterfallrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
766 0 : GLOBALPARAMF(waterfallspec, spec/100.0f);
767 :
768 0 : SETSHADER(waterfall);
769 :
770 0 : glBindTexture(GL_TEXTURE_2D, tex->id);
771 0 : glActiveTexture(GL_TEXTURE1);
772 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));
773 0 : glActiveTexture(GL_TEXTURE0);
774 0 : for(const materialsurface& m : surfs)
775 : {
776 0 : renderwaterfall(m, 0.1f, matnormals(m.orient));
777 : }
778 0 : xtraverts += gle::end();
779 : }
780 0 : }
781 :
782 0 : void renderwater()
783 : {
784 0 : for(int k = 0; k < 4; ++k) //four types of water hardcoded
785 : {
786 0 : const std::vector<materialsurface> &surfs = watersurfs[k];
787 0 : if(surfs.empty())
788 : {
789 0 : continue;
790 : }
791 0 : const MatSlot &wslot = lookupmaterialslot(Mat_Water+k);
792 :
793 0 : const Texture *tex = wslot.sts.size() ? wslot.sts[0].t: notexture;
794 0 : wxscale = defaulttexscale/(tex->xs*wslot.scale);
795 0 : wyscale = defaulttexscale/(tex->ys*wslot.scale);
796 :
797 0 : glBindTexture(GL_TEXTURE_2D, tex->id);
798 0 : glActiveTexture(GL_TEXTURE1);
799 0 : glBindTexture(GL_TEXTURE_2D, wslot.sts.size() > 1 ? wslot.sts[1].t->id : notexture->id);
800 0 : if(caustics && causticscale && causticmillis)
801 : {
802 0 : setupcaustics(2);
803 : }
804 0 : glActiveTexture(GL_TEXTURE0);
805 :
806 0 : float colorscale = 0.5f/255,
807 0 : refractscale = colorscale/ldrscale,
808 0 : reflectscale = 0.5f/ldrscale;
809 0 : const bvec &color = getwatercolor(k),
810 0 : &deepcolor = getwaterdeepcolor(k),
811 0 : &refractcolor = getwaterrefractcolor(k);
812 0 : int fog = getwaterfog(k),
813 0 : deep = getwaterdeep(k),
814 0 : spec = getwaterspec(k);
815 0 : float refract = getwaterrefract(k);
816 0 : GLOBALPARAMF(watercolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
817 0 : GLOBALPARAMF(waterdeepcolor, deepcolor.x*colorscale, deepcolor.y*colorscale, deepcolor.z*colorscale);
818 0 : float fogdensity = fog ? calcfogdensity(fog) : -1e4f;
819 0 : GLOBALPARAMF(waterfog, fogdensity);
820 0 : vec deepfade = getwaterdeepfade(k).tocolor().mul(deep);
821 0 : GLOBALPARAMF(waterdeepfade,
822 : deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
823 : deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
824 : deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
825 : deep ? calcfogdensity(deep) : -1e4f);
826 0 : GLOBALPARAMF(waterspec, spec/100.0f);
827 0 : GLOBALPARAMF(waterreflect, reflectscale, reflectscale, reflectscale, waterreflectstep);
828 0 : GLOBALPARAMF(waterrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
829 :
830 : //======================================================= SETWATERSHADER
831 : #define SETWATERSHADER(which, name) \
832 : do { \
833 : static Shader *name##shader = nullptr; \
834 : if(!name##shader) \
835 : { \
836 : name##shader = lookupshaderbyname(#name); \
837 : } \
838 : which##shader = name##shader; \
839 : } while(0)
840 :
841 0 : Shader *aboveshader = nullptr;
842 : //this if tree will select which shader is the water aboveshader depending on settings
843 0 : if(drawtex == Draw_TexMinimap)
844 : {
845 0 : SETWATERSHADER(above, waterminimap);
846 : }
847 0 : else if(caustics && causticscale && causticmillis) //caustics
848 : {
849 0 : if(waterreflect)
850 : {
851 0 : SETWATERSHADER(above, waterreflectcaustics);
852 : }
853 : else
854 : {
855 0 : SETWATERSHADER(above, watercaustics);
856 : }
857 0 : }
858 : else //no caustics
859 : {
860 0 : if(waterreflect)
861 : {
862 0 : SETWATERSHADER(above, waterreflect);
863 : }
864 : else
865 : {
866 0 : SETWATERSHADER(above, water);
867 : }
868 : }
869 : //now select the water belowshader
870 0 : Shader *belowshader = nullptr;
871 0 : if(drawtex != Draw_TexMinimap)
872 : {
873 0 : SETWATERSHADER(below, underwater); //if rendering water, and not rendering a minimap, sets belowshader to non-null
874 : }
875 : #undef SETWATERSHADER
876 : //======================================================================
877 :
878 0 : aboveshader->set();
879 0 : for(const materialsurface &m: surfs)
880 : {
881 0 : if(camera1->o.z < m.o.z - wateroffset)
882 : {
883 0 : continue;
884 : }
885 0 : renderwater(m);
886 : }
887 0 : xtraverts += gle::end();
888 0 : if(belowshader)
889 : {
890 0 : belowshader->set();
891 0 : for(const materialsurface& m : surfs)
892 : {
893 0 : if(camera1->o.z >= m.o.z - wateroffset)
894 : {
895 0 : continue;
896 : }
897 0 : renderwater(m);
898 : }
899 0 : xtraverts += gle::end();
900 : }
901 : }
902 0 : }
903 :
|