LCOV - code coverage report
Current view: top level - engine/render - water.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 0.0 % 489 0
Test Date: 2026-05-09 04:28:55 Functions: 0.0 % 58 0

            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              : 
        

Generated by: LCOV version 2.0-1