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,
84 : {
85 : loadcaustics(false);
86 : preloadwatershaders();
87 : });
88 :
89 0 : void rendercaustics(float surface, float syl, float syr)
90 : {
91 0 : if(!caustics || !causticscale || !causticmillis)
92 : {
93 0 : return;
94 : }
95 0 : glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
96 0 : setupcaustics(0, surface);
97 0 : SETSHADER(caustics);
98 0 : gle::defvertex(2);
99 0 : gle::begin(GL_TRIANGLE_STRIP);
100 0 : gle::attribf(1, -1);
101 0 : gle::attribf(-1, -1);
102 0 : gle::attribf(1, syr);
103 0 : gle::attribf(-1, syl);
104 0 : gle::end();
105 : }
106 : }
107 :
108 0 : void loadcaustics(bool force)
109 : {
110 : static bool needcaustics = false;
111 0 : if(force)
112 : {
113 0 : needcaustics = true;
114 : }
115 0 : if(!caustics || !needcaustics)
116 : {
117 0 : return;
118 : }
119 0 : useshaderbyname("caustics");
120 0 : if(caustictex[0])
121 : {
122 0 : return;
123 : }
124 0 : for(int i = 0; i < numcaustics; ++i)
125 : {
126 0 : DEF_FORMAT_STRING(name, "<grey><noswizzle>media/texture/mat_water/caustic/caust%.2d.png", i);
127 0 : caustictex[i] = textureload(name);
128 : }
129 : }
130 :
131 : /* vertex water */
132 :
133 : // vertex water refers to the ability for the engine to dynamically create geom
134 : // for the water material's surface, to simulate waviness directly by creating
135 : // 3d geometry
136 :
137 : //these variables control the vertex water geometry intensity
138 : //(nothing to do with any other rendering)
139 :
140 0 : VARFP(vertwater, 0, 1, 1, rootworld.allchanged()); //used in material
141 :
142 : namespace
143 : {
144 : VARP(watersubdiv, 0, 3, 3); //gridpower of water geometry
145 : VARP(waterlod, 0, 1, 3); //larger means that geometry is finer for longer distances
146 :
147 : int wx1, wy1, wx2, wy2, wsize;
148 :
149 : float wxscale = 1.0f,
150 : wyscale = 1.0f;
151 :
152 0 : void defvertwt()
153 : {
154 0 : gle::defvertex();
155 0 : gle::deftexcoord0();
156 0 : }
157 :
158 0 : void vertwt(float v1, float v2, float v3, float whscale, float whoffset)
159 : {
160 0 : float angle = (v1 - wx1) * (v2 - wy1) * (v1 - wx2) * (v2 - wy2) * whscale + whoffset;
161 0 : float s = angle - static_cast<int>(angle) - 0.5f; s *= 8 - std::fabs(s)*16;
162 0 : float h = wateramplitude*s-wateroffset;
163 0 : gle::attribf(v1, v2, v3+h);
164 0 : gle::attribf(wxscale*v1, wyscale*v2);
165 0 : }
166 :
167 0 : void defvertwtn()
168 : {
169 0 : gle::defvertex();
170 0 : gle::deftexcoord0();
171 0 : }
172 :
173 0 : void vertwtn(float v1, float v2, float v3)
174 : {
175 0 : float h = -wateroffset;
176 0 : gle::attribf(v1, v2, v3+h);
177 0 : gle::attribf(wxscale*v1, wyscale*v2);
178 0 : }
179 :
180 0 : void rendervertwater(int subdiv, int xo, int yo, int z, int size, int mat)
181 : {
182 0 : wx1 = xo;
183 0 : wy1 = yo;
184 0 : wx2 = wx1 + size,
185 0 : wy2 = wy1 + size;
186 0 : wsize = size;
187 0 : float whscale = 59.0f/(23.0f*wsize*wsize)/(2*M_PI); //59, 23 magic numbers
188 0 : if(mat == Mat_Water)
189 : {
190 0 : float whoffset = std::fmod(static_cast<float>(lastmillis/600.0f/(2*M_PI)), 1.0f);
191 0 : defvertwt();
192 0 : gle::begin(GL_TRIANGLE_STRIP, 2*(wy2-wy1 + 1)*(wx2-wx1)/subdiv);
193 0 : for(int x = wx1; x<wx2; x += subdiv)
194 : {
195 0 : vertwt(x, wy1, z, whscale, whoffset);
196 0 : vertwt(x+subdiv, wy1, z, whscale, whoffset);
197 0 : for(int y = wy1; y<wy2; y += subdiv)
198 : {
199 0 : vertwt(x, y+subdiv, z, whscale, whoffset);
200 0 : vertwt(x+subdiv, y+subdiv, z, whscale, whoffset);
201 : }
202 0 : gle::multidraw();
203 : }
204 0 : xtraverts += gle::end();
205 : }
206 0 : }
207 :
208 0 : int calcwatersubdiv(int x, int y, int z, int size)
209 : {
210 : float dist;
211 0 : if(camera1->o.x >= x && camera1->o.x < x + size &&
212 0 : camera1->o.y >= y && camera1->o.y < y + size)
213 : {
214 0 : dist = std::fabs(camera1->o.z - static_cast<float>(z));
215 : }
216 : else
217 : {
218 0 : dist = vec(x + size/2, y + size/2, z + size/2).dist(camera1->o) - size*1.42f/2;
219 : }
220 0 : int subdiv = watersubdiv + static_cast<int>(dist) / (32 << waterlod);
221 0 : return subdiv >= 31 ? INT_MAX : 1<<subdiv;
222 : }
223 :
224 0 : int renderwaterlod(int x, int y, int z, int size, int mat)
225 : {
226 0 : if(size <= (32 << waterlod))
227 : {
228 0 : int subdiv = calcwatersubdiv(x, y, z, size);
229 0 : if(subdiv < size * 2)
230 : {
231 0 : rendervertwater(std::min(subdiv, size), x, y, z, size, mat);
232 : }
233 0 : return subdiv;
234 : }
235 : else
236 : {
237 0 : int subdiv = calcwatersubdiv(x, y, z, size);
238 0 : if(subdiv >= size)
239 : {
240 0 : if(subdiv < size * 2)
241 : {
242 0 : rendervertwater(size, x, y, z, size, mat);
243 : }
244 0 : return subdiv;
245 : }
246 0 : int childsize = size / 2,
247 0 : subdiv1 = renderwaterlod(x, y, z, childsize, mat),
248 0 : subdiv2 = renderwaterlod(x + childsize, y, z, childsize, mat),
249 0 : subdiv3 = renderwaterlod(x + childsize, y + childsize, z, childsize, mat),
250 0 : subdiv4 = renderwaterlod(x, y + childsize, z, childsize, mat),
251 0 : minsubdiv = subdiv1;
252 0 : minsubdiv = std::min(minsubdiv, subdiv2);
253 0 : minsubdiv = std::min(minsubdiv, subdiv3);
254 0 : minsubdiv = std::min(minsubdiv, subdiv4);
255 0 : if(minsubdiv < size * 2)
256 : {
257 0 : if(minsubdiv >= size)
258 : {
259 0 : rendervertwater(size, x, y, z, size, mat);
260 : }
261 : else
262 : {
263 0 : if(subdiv1 >= size)
264 : {
265 0 : rendervertwater(childsize, x, y, z, childsize, mat);
266 : }
267 0 : if(subdiv2 >= size)
268 : {
269 0 : rendervertwater(childsize, x + childsize, y, z, childsize, mat);
270 : }
271 0 : if(subdiv3 >= size)
272 : {
273 0 : rendervertwater(childsize, x + childsize, y + childsize, z, childsize, mat);
274 : }
275 0 : if(subdiv4 >= size)
276 : {
277 0 : rendervertwater(childsize, x, y + childsize, z, childsize, mat);
278 : }
279 : }
280 : }
281 0 : return minsubdiv;
282 : }
283 : }
284 :
285 :
286 : /**
287 : * @brief renders water with no vertex water subdivision
288 : *
289 : * If `mat` is not Mat_Water, this function has no effect. Otherwise, draws
290 : * water at the position `o` and size `rsize`/`csize`.
291 : *
292 : * @param o the position to draw at
293 : * @param rsize x size of the water
294 : * @param csize y size of the water
295 : * @param mat check that appropriate material is being used
296 : */
297 0 : void renderflatwater(ivec o, int rsize, int csize, int mat)
298 : {
299 0 : if(mat == Mat_Water)
300 : {
301 0 : if(gle::attribbuf.empty())
302 : {
303 0 : defvertwtn();
304 0 : gle::begin(GL_TRIANGLE_FAN);
305 : }
306 0 : vertwtn(o.x, o.y, o.z);
307 0 : vertwtn(o.x+rsize, o.y, o.z);
308 0 : vertwtn(o.x+rsize, o.y+csize, o.z);
309 0 : vertwtn(o.x, o.y+csize, o.z);
310 0 : xtraverts += 4;
311 : }
312 0 : }
313 :
314 : /**
315 : * @brief Draws type of water appropriate to conditions.
316 : *
317 : * Draws vertex water if drawing water in the world and within the LOD distance.
318 : * Otherwise, draws flat water with no dynamic effects.
319 : *
320 : * @param m the material surface to use
321 : * @param mat the type of water to draw
322 : */
323 0 : void renderwater(const materialsurface &m, int mat = Mat_Water)
324 : {
325 0 : if(!vertwater || drawtex == Draw_TexMinimap)
326 : {
327 0 : renderflatwater(m.o, m.rsize, m.csize, mat);
328 : }
329 0 : else if(renderwaterlod(m.o.x, m.o.y, m.o.z, m.csize, mat) >= static_cast<int>(m.csize) * 2)
330 : {
331 0 : rendervertwater(m.csize, m.o.x, m.o.y, m.o.z, m.csize, mat);
332 : }
333 0 : }
334 :
335 : //==================================================================== WATERVARS
336 : #define WATERVARS(name) \
337 : CVAR0R(name##color, 0x01212C); \
338 : CVAR0R(name##deepcolor, 0x010A10); \
339 : CVAR0R(name##deepfade, 0x60BFFF); \
340 : CVAR0R(name##refractcolor, 0xFFFFFF); \
341 : VARR(name##fog, 0, 30, 10000); \
342 : VARR(name##deep, 0, 50, 10000); \
343 : VARR(name##spec, 0, 150, 200); \
344 : FVARR(name##refract, 0, 0.1f, 1e3f); \
345 : CVARR(name##fallcolor, 0); \
346 : CVARR(name##fallrefractcolor, 0); \
347 : VARR(name##fallspec, 0, 150, 200); \
348 : FVARR(name##fallrefract, 0, 0.1f, 1e3f);
349 :
350 0 : WATERVARS(water)
351 0 : WATERVARS(water2)
352 0 : WATERVARS(water3)
353 0 : WATERVARS(water4)
354 :
355 : #undef WATERVARS
356 : //==============================================================================
357 :
358 0 : VARFP(waterreflect, 0, 1, 1, { preloadwatershaders(); });
359 : VARR(waterreflectstep, 1, 32, 10000);
360 : }
361 :
362 0 : GETMATIDXVAR(water, color, const bvec &)
363 0 : GETMATIDXVAR(water, deepcolor, const bvec &)
364 0 : GETMATIDXVAR(water, deepfade, const bvec &)
365 0 : GETMATIDXVAR(water, refractcolor, const bvec &)
366 0 : GETMATIDXVAR(water, fallcolor, const bvec &)
367 0 : GETMATIDXVAR(water, fallrefractcolor, const bvec &)
368 0 : GETMATIDXVAR(water, fog, int)
369 0 : GETMATIDXVAR(water, deep, int)
370 0 : GETMATIDXVAR(water, spec, int)
371 0 : GETMATIDXVAR(water, refract, float)
372 0 : GETMATIDXVAR(water, fallspec, int)
373 0 : GETMATIDXVAR(water, fallrefract, float)
374 :
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 :
|