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(false); 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()); //used in material
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 :
281 : /**
282 : * @brief renders water with no vertex water subdivision
283 : *
284 : * If `mat` is not Mat_Water, this function has no effect. Otherwise, draws
285 : * water at the position `o` and size `rsize`/`csize`.
286 : *
287 : * @param o the position to draw at
288 : * @param rsize x size of the water
289 : * @param csize y size of the water
290 : * @param mat check that appropriate material is being used
291 : */
292 0 : void renderflatwater(ivec o, int rsize, int csize, int mat)
293 : {
294 0 : if(mat == Mat_Water)
295 : {
296 0 : if(gle::attribbuf.empty())
297 : {
298 0 : defvertwtn();
299 0 : gle::begin(GL_TRIANGLE_FAN);
300 : }
301 0 : vertwtn(o.x, o.y, o.z);
302 0 : vertwtn(o.x+rsize, o.y, o.z);
303 0 : vertwtn(o.x+rsize, o.y+csize, o.z);
304 0 : vertwtn(o.x, o.y+csize, o.z);
305 0 : xtraverts += 4;
306 : }
307 0 : }
308 :
309 0 : void renderwater(const materialsurface &m, int mat = Mat_Water)
310 : {
311 0 : if(!vertwater || drawtex == Draw_TexMinimap)
312 : {
313 0 : renderflatwater(m.o, m.rsize, m.csize, mat);
314 : }
315 0 : else if(renderwaterlod(m.o.x, m.o.y, m.o.z, m.csize, mat) >= static_cast<int>(m.csize) * 2)
316 : {
317 0 : rendervertwater(m.csize, m.o.x, m.o.y, m.o.z, m.csize, mat);
318 : }
319 0 : }
320 :
321 : //==================================================================== WATERVARS
322 : #define WATERVARS(name) \
323 : CVAR0R(name##color, 0x01212C); \
324 : CVAR0R(name##deepcolor, 0x010A10); \
325 : CVAR0R(name##deepfade, 0x60BFFF); \
326 : CVAR0R(name##refractcolor, 0xFFFFFF); \
327 : VARR(name##fog, 0, 30, 10000); \
328 : VARR(name##deep, 0, 50, 10000); \
329 : VARR(name##spec, 0, 150, 200); \
330 : FVARR(name##refract, 0, 0.1f, 1e3f); \
331 : CVARR(name##fallcolor, 0); \
332 : CVARR(name##fallrefractcolor, 0); \
333 : VARR(name##fallspec, 0, 150, 200); \
334 : FVARR(name##fallrefract, 0, 0.1f, 1e3f);
335 :
336 0 : WATERVARS(water)
337 0 : WATERVARS(water2)
338 0 : WATERVARS(water3)
339 0 : WATERVARS(water4)
340 :
341 : #undef WATERVARS
342 : //==============================================================================
343 :
344 0 : VARFP(waterreflect, 0, 1, 1, { preloadwatershaders(); });
345 : }
346 :
347 0 : GETMATIDXVAR(water, color, const bvec &)
348 0 : GETMATIDXVAR(water, deepcolor, const bvec &)
349 0 : GETMATIDXVAR(water, deepfade, const bvec &)
350 0 : GETMATIDXVAR(water, refractcolor, const bvec &)
351 0 : GETMATIDXVAR(water, fallcolor, const bvec &)
352 0 : GETMATIDXVAR(water, fallrefractcolor, const bvec &)
353 0 : GETMATIDXVAR(water, fog, int)
354 0 : GETMATIDXVAR(water, deep, int)
355 0 : GETMATIDXVAR(water, spec, int)
356 0 : GETMATIDXVAR(water, refract, float)
357 0 : GETMATIDXVAR(water, fallspec, int)
358 0 : GETMATIDXVAR(water, fallrefract, float)
359 :
360 : static VARR(waterreflectstep, 1, 32, 10000);
361 :
362 0 : void GBuffer::renderwaterfog(int mat, float surface)
363 : {
364 0 : glDepthFunc(GL_NOTEQUAL);
365 0 : glDepthMask(GL_FALSE);
366 0 : glDepthRange(1, 1);
367 :
368 0 : glEnable(GL_BLEND);
369 :
370 0 : glActiveTexture(GL_TEXTURE9);
371 0 : if(msaalight)
372 : {
373 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
374 : }
375 : else
376 : {
377 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
378 : }
379 0 : glActiveTexture(GL_TEXTURE0);
380 :
381 0 : matrix4 invcamprojmatrix = camprojmatrix.inverse();
382 : std::array<vec, 4> p =
383 : {
384 0 : invcamprojmatrix.perspectivetransform(vec(-1, -1, -1)),
385 0 : invcamprojmatrix.perspectivetransform(vec(-1, 1, -1)),
386 0 : invcamprojmatrix.perspectivetransform(vec(1, -1, -1)),
387 0 : invcamprojmatrix.perspectivetransform(vec(1, 1, -1))
388 : };
389 0 : float bz = surface + camera1->o.z + (vertwater ? wateramplitude : 0),
390 0 : syl = (p[1].z > p[0].z) ? (2*(bz - p[0].z)/(p[1].z - p[0].z) - 1) : 1,
391 0 : syr = (p[3].z > p[2].z) ? (2*(bz - p[2].z)/(p[3].z - p[2].z) - 1) : 1;
392 :
393 0 : if((mat&MatFlag_Volume) == Mat_Water)
394 : {
395 0 : const bvec &deepcolor = getwaterdeepcolor(mat);
396 0 : int deep = getwaterdeep(mat);
397 0 : GLOBALPARAMF(waterdeepcolor, deepcolor.x*ldrscaleb(), deepcolor.y*ldrscaleb(), deepcolor.z*ldrscaleb());
398 0 : vec deepfade = getwaterdeepfade(mat).tocolor().mul(deep);
399 0 : GLOBALPARAMF(waterdeepfade,
400 : deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
401 : deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
402 : deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
403 : deep ? calcfogdensity(deep) : -1e4f);
404 :
405 0 : rendercaustics(surface, syl, syr);
406 : }
407 : else
408 : {
409 0 : GLOBALPARAMF(waterdeepcolor, 0, 0, 0);
410 0 : GLOBALPARAMF(waterdeepfade, -1e4f, -1e4f, -1e4f, -1e4f);
411 : }
412 :
413 0 : GLOBALPARAMF(waterheight, bz);
414 :
415 0 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
416 :
417 0 : SETSHADER(waterfog);
418 0 : gle::defvertex(3);
419 0 : gle::begin(GL_TRIANGLE_STRIP);
420 0 : gle::attribf( 1, -1, 1);
421 0 : gle::attribf(-1, -1, 1);
422 0 : gle::attribf( 1, syr, 1);
423 0 : gle::attribf(-1, syl, 1);
424 0 : gle::end();
425 :
426 0 : glDisable(GL_BLEND);
427 :
428 0 : glDepthFunc(GL_LESS);
429 0 : glDepthMask(GL_TRUE);
430 0 : glDepthRange(0, 1);
431 0 : }
432 :
433 0 : void preloadwatershaders(bool force)
434 : {
435 : static bool needwater = false;
436 0 : if(force)
437 : {
438 0 : needwater = true;
439 : }
440 0 : if(!needwater)
441 : {
442 0 : return;
443 : }
444 0 : if(caustics && causticscale && causticmillis)
445 : {
446 0 : if(waterreflect)
447 : {
448 0 : useshaderbyname("waterreflectcaustics");
449 : }
450 : else
451 : {
452 0 : useshaderbyname("watercaustics");
453 : }
454 : }
455 : else
456 : {
457 0 : if(waterreflect)
458 : {
459 0 : useshaderbyname("waterreflect");
460 : }
461 : else
462 : {
463 0 : useshaderbyname("water");
464 : }
465 : }
466 0 : useshaderbyname("underwater");
467 0 : useshaderbyname("waterfall");
468 0 : useshaderbyname("waterfog");
469 0 : useshaderbyname("waterminimap");
470 : }
471 :
472 : static float wfwave = 0.0f, //waterfall wave
473 : wfscroll = 0.0f, //waterfall scroll
474 : wfxscale = 1.0f, //waterfall x scale
475 : wfyscale = 1.0f; //waterfall y scale
476 :
477 : //"waterfall" refers to any rendered side of water material
478 0 : static void renderwaterfall(const materialsurface &m, float offset, vec normal = vec(0,0,0))
479 : {
480 0 : if(gle::attribbuf.empty())
481 : {
482 0 : gle::defvertex();
483 0 : if(normal != vec(0,0,0))
484 : {
485 0 : gle::defnormal();
486 : }
487 0 : gle::deftexcoord0();
488 : }
489 0 : float x = m.o.x,
490 0 : y = m.o.y,
491 0 : zmin = m.o.z,
492 0 : zmax = zmin;
493 0 : if(m.ends&1)
494 : {
495 0 : zmin += -wateroffset-wateramplitude;
496 : }
497 0 : if(m.ends&2)
498 : {
499 0 : zmax += wfwave;
500 : }
501 0 : int csize = m.csize,
502 0 : rsize = m.rsize;
503 0 : if(normal != vec(0,0,0))
504 : {
505 0 : vec n = normal;
506 0 : switch(m.orient)
507 : {
508 0 : case 0:
509 : {
510 0 : gle::begin(GL_TRIANGLE_FAN);
511 : {
512 0 : vec v(x + offset, y + rsize, zmax + csize);
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 + rsize, zmin );
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 : {
524 0 : vec v(x + offset, y , zmin );
525 0 : gle::attribf(v.x, v.y, v.z);
526 0 : gle::attribf(n.x, n.y, n.z);
527 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
528 : }
529 : {
530 0 : vec v(x + offset, y , 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 0 : gle::end();
536 0 : break;
537 : }
538 0 : case 1:
539 : {
540 0 : gle::begin(GL_TRIANGLE_FAN);
541 : {
542 0 : vec v(x - offset, y + rsize, zmax + csize);
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 , zmax + csize);
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 : {
554 0 : vec v(x - offset, y , zmin );
555 0 : gle::attribf(v.x, v.y, v.z);
556 0 : gle::attribf(n.x, n.y, n.z);
557 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
558 : }
559 : {
560 0 : vec v(x - offset, y + rsize, zmin );
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.y, -wfyscale*(v.z+wfscroll));
564 : }
565 0 : gle::end();
566 0 : break;
567 : }
568 0 : case 2:
569 : {
570 0 : gle::begin(GL_TRIANGLE_FAN);
571 : {
572 0 : vec v(x + csize, y + offset, zmax + rsize);
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 , y + offset, zmax + rsize);
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 : {
584 0 : vec v(x , y + offset, zmin );
585 0 : gle::attribf(v.x, v.y, v.z);
586 0 : gle::attribf(n.x, n.y, n.z);
587 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
588 : }
589 : {
590 0 : vec v(x + csize, 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 0 : gle::end();
596 0 : break;
597 : }
598 0 : case 3:
599 : {
600 0 : gle::begin(GL_TRIANGLE_FAN);
601 : {
602 0 : vec v(x , y - offset, zmin );
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 , y - offset, zmax + rsize);
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 : {
614 0 : vec v(x + csize, y - offset, zmax + rsize);
615 0 : gle::attribf(v.x, v.y, v.z);
616 0 : gle::attribf(n.x, n.y, n.z);
617 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
618 : }
619 : {
620 0 : vec v(x + csize, y - offset, zmin );
621 0 : gle::attribf(v.x, v.y, v.z);
622 0 : gle::attribf(n.x, n.y, n.z);
623 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
624 : }
625 0 : gle::end();
626 0 : break;
627 : }
628 : }
629 : }
630 : else
631 : {
632 0 : switch(m.orient)
633 : {
634 0 : case 0:
635 : {
636 0 : gle::begin(GL_TRIANGLE_FAN);
637 : {
638 0 : vec v(x + offset, y + rsize, zmax + csize);
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 + rsize, zmin );
644 0 : gle::attribf(v.x, v.y, v.z);
645 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
646 : }
647 : {
648 0 : vec v(x + offset, y , zmin );
649 0 : gle::attribf(v.x, v.y, v.z);
650 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
651 : }
652 : {
653 0 : vec v(x + offset, y , zmax + csize);
654 0 : gle::attribf(v.x, v.y, v.z);
655 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
656 : }
657 0 : gle::end();
658 0 : break;
659 : }
660 0 : case 1:
661 : {
662 0 : gle::begin(GL_TRIANGLE_FAN);
663 : {
664 0 : vec v(x - offset, y + rsize, zmax + csize);
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 , zmax + csize);
670 0 : gle::attribf(v.x, v.y, v.z);
671 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
672 : }
673 : {
674 0 : vec v(x - offset, y , zmin );
675 0 : gle::attribf(v.x, v.y, v.z);
676 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
677 : }
678 : {
679 0 : vec v(x - offset, y + rsize, zmin );
680 0 : gle::attribf(v.x, v.y, v.z);
681 0 : gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll));
682 : }
683 0 : gle::end();
684 0 : break;
685 : }
686 0 : case 2:
687 : {
688 0 : gle::begin(GL_TRIANGLE_FAN);
689 : {
690 0 : vec v(x + csize, y + offset, zmax + rsize);
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 , y + offset, zmax + rsize);
696 0 : gle::attribf(v.x, v.y, v.z);
697 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
698 : }
699 : {
700 0 : vec v(x , y + offset, zmin);
701 0 : gle::attribf(v.x, v.y, v.z);
702 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
703 : }
704 : {
705 0 : vec v(x + csize, y + offset, zmin);
706 0 : gle::attribf(v.x, v.y, v.z);
707 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
708 : }
709 0 : gle::end();
710 0 : break;
711 : }
712 0 : case 3:
713 : {
714 0 : gle::begin(GL_TRIANGLE_FAN);
715 : {
716 0 : vec v(x , y - offset, zmin);
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 , y - offset, zmax + rsize);
722 0 : gle::attribf(v.x, v.y, v.z);
723 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
724 : }
725 : {
726 0 : vec v(x + csize, y - offset, zmax + rsize);
727 0 : gle::attribf(v.x, v.y, v.z);
728 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
729 : }
730 : {
731 0 : vec v(x + csize, y - offset, zmin);
732 0 : gle::attribf(v.x, v.y, v.z);
733 0 : gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll));
734 : }
735 0 : gle::end();
736 0 : break;
737 : }
738 : }
739 : }
740 0 : }
741 :
742 0 : void renderwaterfalls()
743 : {
744 0 : for(int k = 0; k < 4; ++k)
745 : {
746 0 : const std::vector<materialsurface> &surfs = waterfallsurfs[k];
747 0 : if(surfs.empty())
748 : {
749 0 : continue;
750 : }
751 0 : const MatSlot &wslot = lookupmaterialslot(Mat_Water+k);
752 :
753 0 : const Texture *tex = wslot.sts.size() > 2 ? wslot.sts[2].t : (wslot.sts.size() ? wslot.sts[0].t : notexture);
754 0 : float angle = std::fmod(static_cast<float>(lastmillis/600.0f/(2*M_PI)), 1.0f),
755 0 : s = angle - static_cast<int>(angle) - 0.5f;
756 0 : s *= 8 - std::fabs(s)*16;
757 0 : wfwave = vertwater ? wateramplitude*s-wateroffset : -wateroffset;
758 0 : wfscroll = 16.0f*lastmillis/1000.0f;
759 0 : wfxscale = defaulttexscale/(tex->xs*wslot.scale);
760 0 : wfyscale = defaulttexscale/(tex->ys*wslot.scale);
761 : //waterfall color vectors
762 0 : bvec color = getwaterfallcolor(k),
763 0 : refractcolor = getwaterfallrefractcolor(k);
764 0 : if(color.iszero())
765 : {
766 0 : color = getwatercolor(k);
767 : }
768 0 : if(refractcolor.iszero())
769 : {
770 0 : refractcolor = getwaterrefractcolor(k);
771 : }
772 0 : float colorscale = (0.5f/255),
773 0 : refractscale = colorscale/ldrscale,
774 0 : refract = getwaterfallrefract(k);
775 0 : int spec = getwaterfallspec(k);
776 0 : GLOBALPARAMF(waterfallcolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
777 0 : GLOBALPARAMF(waterfallrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
778 0 : GLOBALPARAMF(waterfallspec, spec/100.0f);
779 :
780 0 : SETSHADER(waterfall);
781 :
782 0 : glBindTexture(GL_TEXTURE_2D, tex->id);
783 0 : glActiveTexture(GL_TEXTURE1);
784 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));
785 0 : glActiveTexture(GL_TEXTURE0);
786 0 : for(const materialsurface& m : surfs)
787 : {
788 0 : renderwaterfall(m, 0.1f, matnormals(m.orient));
789 : }
790 0 : xtraverts += gle::end();
791 : }
792 0 : }
793 :
794 0 : void renderwater()
795 : {
796 0 : for(int k = 0; k < 4; ++k) //four types of water hardcoded
797 : {
798 0 : const std::vector<materialsurface> &surfs = watersurfs[k];
799 0 : if(surfs.empty())
800 : {
801 0 : continue;
802 : }
803 0 : const MatSlot &wslot = lookupmaterialslot(Mat_Water+k);
804 :
805 0 : const Texture *tex = wslot.sts.size() ? wslot.sts[0].t: notexture;
806 0 : wxscale = defaulttexscale/(tex->xs*wslot.scale);
807 0 : wyscale = defaulttexscale/(tex->ys*wslot.scale);
808 :
809 0 : glBindTexture(GL_TEXTURE_2D, tex->id);
810 0 : glActiveTexture(GL_TEXTURE1);
811 0 : glBindTexture(GL_TEXTURE_2D, wslot.sts.size() > 1 ? wslot.sts[1].t->id : notexture->id);
812 0 : if(caustics && causticscale && causticmillis)
813 : {
814 0 : setupcaustics(2);
815 : }
816 0 : glActiveTexture(GL_TEXTURE0);
817 :
818 0 : float colorscale = 0.5f/255,
819 0 : refractscale = colorscale/ldrscale,
820 0 : reflectscale = 0.5f/ldrscale;
821 0 : const bvec &color = getwatercolor(k),
822 0 : &deepcolor = getwaterdeepcolor(k),
823 0 : &refractcolor = getwaterrefractcolor(k);
824 0 : int fog = getwaterfog(k),
825 0 : deep = getwaterdeep(k),
826 0 : spec = getwaterspec(k);
827 0 : float refract = getwaterrefract(k);
828 0 : GLOBALPARAMF(watercolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
829 0 : GLOBALPARAMF(waterdeepcolor, deepcolor.x*colorscale, deepcolor.y*colorscale, deepcolor.z*colorscale);
830 0 : float fogdensity = fog ? calcfogdensity(fog) : -1e4f;
831 0 : GLOBALPARAMF(waterfog, fogdensity);
832 0 : vec deepfade = getwaterdeepfade(k).tocolor().mul(deep);
833 0 : GLOBALPARAMF(waterdeepfade,
834 : deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
835 : deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
836 : deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
837 : deep ? calcfogdensity(deep) : -1e4f);
838 0 : GLOBALPARAMF(waterspec, spec/100.0f);
839 0 : GLOBALPARAMF(waterreflect, reflectscale, reflectscale, reflectscale, waterreflectstep);
840 0 : GLOBALPARAMF(waterrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
841 :
842 : //======================================================= SETWATERSHADER
843 : #define SETWATERSHADER(which, name) \
844 : do { \
845 : static Shader *name##shader = nullptr; \
846 : if(!name##shader) \
847 : { \
848 : name##shader = lookupshaderbyname(#name); \
849 : } \
850 : which##shader = name##shader; \
851 : } while(0)
852 :
853 0 : Shader *aboveshader = nullptr;
854 : //this if tree will select which shader is the water aboveshader depending on settings
855 0 : if(drawtex == Draw_TexMinimap)
856 : {
857 0 : SETWATERSHADER(above, waterminimap);
858 : }
859 0 : else if(caustics && causticscale && causticmillis) //caustics
860 : {
861 0 : if(waterreflect)
862 : {
863 0 : SETWATERSHADER(above, waterreflectcaustics);
864 : }
865 : else
866 : {
867 0 : SETWATERSHADER(above, watercaustics);
868 : }
869 0 : }
870 : else //no caustics
871 : {
872 0 : if(waterreflect)
873 : {
874 0 : SETWATERSHADER(above, waterreflect);
875 : }
876 : else
877 : {
878 0 : SETWATERSHADER(above, water);
879 : }
880 : }
881 : //now select the water belowshader
882 0 : Shader *belowshader = nullptr;
883 0 : if(drawtex != Draw_TexMinimap)
884 : {
885 0 : SETWATERSHADER(below, underwater); //if rendering water, and not rendering a minimap, sets belowshader to non-null
886 : }
887 : #undef SETWATERSHADER
888 : //======================================================================
889 :
890 0 : aboveshader->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 0 : if(belowshader)
901 : {
902 0 : belowshader->set();
903 0 : for(const materialsurface& m : surfs)
904 : {
905 0 : if(camera1->o.z >= m.o.z - wateroffset)
906 : {
907 0 : continue;
908 : }
909 0 : renderwater(m);
910 : }
911 0 : xtraverts += gle::end();
912 : }
913 : }
914 0 : }
915 :
|