LCOV - code coverage report
Current view: top level - engine/render - rendersky.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 0.0 % 212 0
Test Date: 2025-02-21 06:59:27 Functions: 0.0 % 15 0

            Line data    Source code
       1              : /* rendersky.cpp: skybox and sky environment rendering
       2              :  *
       3              :  * Libprimis supports standard static cubemap skyboxes as well as cloud layers,
       4              :  * which are both static (though capable of translation/rotation)
       5              :  *
       6              :  * as well as a parameterized sky generation system, referred to the code as the
       7              :  * atmo" functionality
       8              :  *
       9              :  * as expected for distant scenery, like the sky and clouds are, there is no support
      10              :  * for parallax (cloud layers do not move relative to background sky as the player
      11              :  * moves)
      12              :  */
      13              : #include "../libprimis-headers/cube.h"
      14              : #include "../../shared/geomexts.h"
      15              : #include "../../shared/glemu.h"
      16              : #include "../../shared/glexts.h"
      17              : #include "../../shared/stream.h"
      18              : 
      19              : #include "octarender.h"
      20              : #include "rendergl.h"
      21              : #include "renderlights.h"
      22              : #include "rendersky.h"
      23              : #include "renderva.h"
      24              : #include "shader.h"
      25              : #include "shaderparam.h"
      26              : #include "texture.h"
      27              : 
      28              : #include "interface/console.h"
      29              : #include "interface/control.h"
      30              : 
      31              : #include "world/light.h"
      32              : #include "world/octaedit.h"
      33              : #include "world/octaworld.h"
      34              : #include "world/raycube.h"
      35              : 
      36            0 : VARFR(skyshadow, 0, 0, 1, clearshadowcache());   //toggles rsm features in renderva.cpp
      37              : 
      38              : bool explicitsky = false;
      39              : 
      40              : // internally relevant functionality
      41              : namespace
      42              : {
      43              :     VARNR(skytexture, useskytexture, 0, 0, 1);       //toggles rendering sky texture instead of nothing on skytex'd geometry
      44              : 
      45              :     std::array<const Texture *, 6> sky = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
      46              : 
      47            0 :     void loadsky(const char *basename, std::array<const Texture *, 6> &texs)
      48              :     {
      49              : 
      50              :         struct cubemapside
      51              :         {
      52              :             GLenum target;
      53              :             const char *name;
      54              :             bool flipx, flipy, swapxy;
      55              :         };
      56              :         static const cubemapside cubemapsides[6] =
      57              :         {
      58              :             { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, "lf", false, true,  true  },
      59              :             { GL_TEXTURE_CUBE_MAP_POSITIVE_X, "rt", true,  false, true  },
      60              :             { GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, "bk", false, false, false },
      61              :             { GL_TEXTURE_CUBE_MAP_POSITIVE_Y, "ft", true,  true,  false },
      62              :             { GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, "dn", true,  false, true  },
      63              :             { GL_TEXTURE_CUBE_MAP_POSITIVE_Z, "up", true,  false, true  },
      64              :         };
      65              : 
      66            0 :         const char *wildcard = std::strchr(basename, '*');
      67            0 :         for(int i = 0; i < 6; ++i) //six sides for a cubemap
      68              :         {
      69            0 :             const char *side = cubemapsides[i].name;
      70              :             string name;
      71            0 :             copystring(name, makerelpath("media/sky", basename));
      72            0 :             if(wildcard)
      73              :             {
      74            0 :                 char *chop = std::strchr(name, '*');
      75            0 :                 if(chop)
      76              :                 {
      77            0 :                     *chop = '\0';
      78            0 :                     concatstring(name, side);
      79            0 :                     concatstring(name, wildcard+1);
      80              :                 }
      81            0 :                 texs[i] = textureload(name, 3, true, false);
      82              :             }
      83              :             else
      84              :             {
      85            0 :                 DEF_FORMAT_STRING(ext, "_%s.jpg", side);
      86            0 :                 concatstring(name, ext);
      87            0 :                 if((texs[i] = textureload(name, 3, true, false))==notexture)
      88              :                 {
      89            0 :                     std::strcpy(name+std::strlen(name)-3, "png");
      90            0 :                     texs[i] = textureload(name, 3, true, false);
      91              :                 }
      92              :             }
      93            0 :             if(texs[i]==notexture)
      94              :             {
      95            0 :                 conoutf(Console_Error, "could not load side %s of sky texture %s", side, basename);
      96              :             }
      97              :         }
      98            0 :     }
      99              : 
     100              :     Texture *cloudoverlay = nullptr;
     101              : 
     102            0 :     Texture *loadskyoverlay(const char *basename)
     103              :     {
     104            0 :         const char *ext = std::strrchr(basename, '.');
     105              :         string name;
     106            0 :         copystring(name, makerelpath("media/sky", basename));
     107            0 :         Texture *t = notexture;
     108            0 :         if(ext)
     109              :         {
     110            0 :             t = textureload(name, 0, true, false);
     111              :         }
     112              :         else
     113              :         {
     114            0 :             concatstring(name, ".jpg");
     115            0 :             if((t = textureload(name, 0, true, false)) == notexture)
     116              :             {
     117            0 :                 std::strcpy(name+std::strlen(name)-3, "png");
     118            0 :                 t = textureload(name, 0, true, false);
     119              :             }
     120              :         }
     121            0 :         if(t==notexture)
     122              :         {
     123            0 :             conoutf(Console_Error, "could not load sky overlay texture %s", basename);
     124              :         }
     125            0 :         return t;
     126              :     }
     127              : 
     128            0 :     SVARFR(skybox, "",
     129              :     {
     130              :         if(skybox[0])
     131              :         {
     132              :             loadsky(skybox, sky);
     133              :         }
     134              :     });                                             //path to skybox
     135            0 :     CVARR(skyboxcolor, 0xFFFFFF);                   //color to multiply skybox texture by
     136              :     FVARR(skyboxoverbright, 1, 2, 16);              //amount by which skybox can exceed 0xFFFFFF
     137              :     FVARR(skyboxoverbrightmin, 0, 1, 16);
     138              :     FVARR(skyboxoverbrightthreshold, 0, 0.7f, 1);
     139              :     FVARR(skyboxspin, -720, 0, 720);                //skybox spin rate in degrees per second
     140              :     VARR (skyboxyaw, 0, 0, 360);                    //skybox rotation offset in degrees
     141              : 
     142              :     //cloud layer variables
     143              :     FVARR(cloudclip, 0, 0.5f, 1);
     144            0 :     SVARFR(cloudlayer, "",
     145              :     {
     146              :         if(cloudlayer[0])
     147              :         {
     148              :             cloudoverlay = loadskyoverlay(cloudlayer);
     149              :         }
     150              :     });
     151              :     FVARR(cloudoffsetx, 0, 0, 1); //offset of cloud texture: 1 is equal to 1 tex-width x
     152              :     FVARR(cloudoffsety, 0, 0, 1); //offset of cloud texture: 1 is equal to 1 tex-width y
     153              :     FVARR(cloudscrollx, -16, 0, 16);
     154              :     FVARR(cloudscrolly, -16, 0, 16);
     155              :     FVARR(cloudscale, 0.001, 1, 64);
     156              :     FVARR(cloudspin, -720, 0, 720);
     157              :     VARR (cloudyaw, 0, 0, 360);
     158              :     FVARR(cloudheight, -1, 0.2f, 1);
     159              :     FVARR(cloudfade, 0, 0.2f, 1);
     160              :     FVARR(cloudalpha, 0, 1, 1);
     161              :     VARR (cloudsubdiv, 4, 16, 64);
     162            0 :     CVARR(cloudcolor, 0xFFFFFF);
     163              : 
     164            0 :     void drawenvboxface(float s0, float t0, int x0, int y0, int z0,
     165              :                         float s1, float t1, int x1, int y1, int z1,
     166              :                         float s2, float t2, int x2, int y2, int z2,
     167              :                         float s3, float t3, int x3, int y3, int z3,
     168              :                         const Texture *tex)
     169              :     {
     170            0 :         glBindTexture(GL_TEXTURE_2D, (tex ? tex : notexture)->id);
     171            0 :         gle::begin(GL_TRIANGLE_STRIP);
     172            0 :         gle::attribf(x3, y3, z3); gle::attribf(s3, t3);
     173            0 :         gle::attribf(x2, y2, z2); gle::attribf(s2, t2);
     174            0 :         gle::attribf(x0, y0, z0); gle::attribf(s0, t0);
     175            0 :         gle::attribf(x1, y1, z1); gle::attribf(s1, t1);
     176            0 :         xtraverts += gle::end();
     177            0 :     }
     178              : 
     179            0 :     void drawenvbox(const std::array<const Texture *, 6> &sky, float z1clip = 0.0f, float z2clip = 1.0f, int faces = 0x3F)
     180              :     {
     181            0 :         if(z1clip >= z2clip)
     182              :         {
     183            0 :             return;
     184              :         }
     185            0 :         float v1 = 1-z1clip,
     186            0 :               v2 = 1-z2clip;
     187            0 :         int w  = farplane/2,
     188            0 :             z1 = static_cast<int>(std::ceil(2*w*(z1clip-0.5f))),
     189            0 :             z2 = static_cast<int>(std::ceil(2*w*(z2clip-0.5f)));
     190              : 
     191            0 :         gle::defvertex();
     192            0 :         gle::deftexcoord0();
     193              : 
     194              :         //daw the six faces of the skybox's cubemap
     195            0 :         if(faces&0x01)
     196              :         {
     197            0 :             drawenvboxface(1.0f, v2,  -w, -w, z2,
     198              :                            0.0f, v2,  -w,  w, z2,
     199              :                            0.0f, v1,  -w,  w, z1,
     200            0 :                            1.0f, v1,  -w, -w, z1, sky[0]);
     201              :         }
     202            0 :         if(faces&0x02)
     203              :         {
     204            0 :             drawenvboxface(0.0f, v1, w, -w, z1,
     205              :                            1.0f, v1, w,  w, z1,
     206              :                            1.0f, v2, w,  w, z2,
     207            0 :                            0.0f, v2, w, -w, z2, sky[1]);
     208              :         }
     209            0 :         if(faces&0x04)
     210              :         {
     211            0 :             drawenvboxface(0.0f, v1, -w, -w, z1,
     212              :                            1.0f, v1,  w, -w, z1,
     213              :                            1.0f, v2,  w, -w, z2,
     214            0 :                            0.0f, v2, -w, -w, z2, sky[2]);
     215              :         }
     216            0 :         if(faces&0x08)
     217              :         {
     218            0 :             drawenvboxface(0.0f, v1,  w,  w, z1,
     219              :                            1.0f, v1, -w,  w, z1,
     220              :                            1.0f, v2, -w,  w, z2,
     221            0 :                            0.0f, v2,  w,  w, z2, sky[3]);
     222              :         }
     223            0 :         if(z1clip <= 0 && faces&0x10)
     224              :         {
     225            0 :             drawenvboxface(1.0f, 1.0f, -w,  w,  -w,
     226              :                            1.0f, 0.0f,  w,  w,  -w,
     227              :                            0.0f, 0.0f,  w, -w,  -w,
     228            0 :                            0.0f, 1.0f, -w, -w,  -w, sky[4]);
     229              :         }
     230            0 :         if(z2clip >= 1 && faces&0x20)
     231              :         {
     232            0 :             drawenvboxface(1.0f, 1.0f,  w,  w, w,
     233              :                            1.0f, 0.0f, -w,  w, w,
     234              :                            0.0f, 0.0f, -w, -w, w,
     235            0 :                            0.0f, 1.0f,  w, -w, w, sky[5]);
     236              :         }
     237              :     }
     238              : 
     239            0 :     void drawenvoverlay(const Texture *overlay = nullptr, float tx = 0, float ty = 0)
     240              :     {
     241            0 :         int w = farplane/2;
     242            0 :         float z   = w*cloudheight,
     243            0 :               tsz = 0.5f*(1-cloudfade)/cloudscale,
     244            0 :               psz = w*(1-cloudfade);
     245            0 :         glBindTexture(GL_TEXTURE_2D, (overlay ? overlay : notexture)->id);
     246            0 :         vec color = cloudcolor.tocolor();
     247            0 :         gle::color(color, cloudalpha);
     248            0 :         gle::defvertex();
     249            0 :         gle::deftexcoord0();
     250            0 :         gle::begin(GL_TRIANGLE_FAN);
     251            0 :         for(int i = 0; i < cloudsubdiv+1; ++i)
     252              :         {
     253            0 :             vec p(1, 1, 0);
     254            0 :             p.rotate_around_z((-2.0f*M_PI*i)/cloudsubdiv);
     255            0 :             gle::attribf(p.x*psz, p.y*psz, z);
     256            0 :             gle::attribf(tx - p.x*tsz, ty + p.y*tsz);
     257              :         }
     258            0 :         xtraverts += gle::end();
     259            0 :         float tsz2 = 0.5f/cloudscale;
     260            0 :         gle::defvertex();
     261            0 :         gle::deftexcoord0();
     262            0 :         gle::defcolor(4);
     263            0 :         gle::begin(GL_TRIANGLE_STRIP);
     264            0 :         for(int i = 0; i < cloudsubdiv+1; ++i)
     265              :         {
     266            0 :             vec p(1, 1, 0);
     267            0 :             p.rotate_around_z((-2.0f*M_PI*i)/cloudsubdiv);
     268            0 :             gle::attribf(p.x*psz, p.y*psz, z);
     269            0 :             gle::attribf(tx - p.x*tsz, ty + p.y*tsz);
     270            0 :             gle::attrib(color, cloudalpha);
     271            0 :             gle::attribf(p.x*w, p.y*w, z);
     272            0 :             gle::attribf(tx - p.x*tsz2, ty + p.y*tsz2);
     273            0 :             gle::attrib(color, 0.0f);
     274              :         }
     275            0 :         xtraverts += gle::end();
     276            0 :     }
     277              : 
     278              :     /* === "atmo" parameterized, procedurally generated sky === */
     279              :     VARR(atmo, 0, 0, 1);
     280              :     FVARR(atmoplanetsize, 1e-3f, 8, 1e3f);
     281              :     FVARR(atmoheight, 1e-3f, 1, 1e3f);
     282              :     FVARR(atmobright, 0, 4, 16);
     283            0 :     CVAR1R(atmosunlight, 0);
     284              :     FVARR(atmosunlightscale, 0, 1, 16);
     285              :     FVARR(atmosundisksize, 0, 1, 10);
     286              :     FVARR(atmosundiskbright, 0, 1, 16);
     287              :     FVARR(atmohaze, 0, 0.03f, 1);
     288            0 :     CVAR0R(atmohazefade, 0xAEACA9);
     289              :     FVARR(atmohazefadescale, 0, 1, 1);
     290              :     FVARR(atmoclarity, 0, 0.2f, 10);
     291              :     FVARR(atmodensity, 1e-3f, 0.99f, 10);
     292              :     FVARR(atmoalpha, 0, 1, 1);
     293              : 
     294            0 :     void drawatmosphere()
     295              :     {
     296            0 :         SETSHADER(atmosphere,);
     297              : 
     298            0 :         matrix4 sunmatrix = cammatrix.inverse();
     299            0 :         sunmatrix.settranslation(0, 0, 0);
     300            0 :         sunmatrix.mul(projmatrix.inverse());
     301            0 :         LOCALPARAM(sunmatrix, sunmatrix);
     302              : 
     303            0 :         LOCALPARAM(sunlight, (!atmosunlight.iszero() ? atmosunlight.tocolor().mul(atmosunlightscale) : sunlight.tocolor().mul(sunlightscale)).mul(atmobright*ldrscale));
     304            0 :         LOCALPARAM(sundir, sunlightdir);
     305              : 
     306            0 :         vec sundiskparams;
     307            0 :         sundiskparams.y = -(1 - 0.0075f * atmosundisksize);
     308            0 :         sundiskparams.x = 1/(1 + sundiskparams.y);
     309            0 :         sundiskparams.y *= sundiskparams.x;
     310            0 :         sundiskparams.z = atmosundiskbright;
     311            0 :         LOCALPARAM(sundiskparams, sundiskparams);
     312              : 
     313            0 :         const float earthradius     = 6.371e6f, //radius of earth in meters
     314            0 :                     earthatmoheight = 100e3f; //atmospheric height (100km)
     315            0 :         float planetradius = earthradius*atmoplanetsize,
     316            0 :               atmoradius   = planetradius + earthatmoheight*atmoheight;
     317            0 :         LOCALPARAMF(atmoradius, planetradius, atmoradius*atmoradius, atmoradius*atmoradius - planetradius*planetradius);
     318              : 
     319            0 :         float gm = (1 - atmohaze)*0.2f + 0.75f;
     320            0 :         LOCALPARAMF(gm, gm);
     321              : 
     322            0 :         vec lambda(680e-9f, 550e-9f, 450e-9f),
     323            0 :             betar = vec(lambda).square().square().recip().mul(1.86e-31f / atmodensity),
     324            0 :             betam = vec(lambda).recip().mul(2*M_PI).square().mul(atmohazefade.tocolor().mul(atmohazefadescale)).mul(1.36e-19f * std::max(atmohaze, 1e-3f)),
     325            0 :             betarm = vec(betar).div(1+atmoclarity).add(betam);
     326            0 :         betar.div(betarm).mul(3/(16*M_PI));
     327            0 :         betam.div(betarm).mul((1-gm)*(1-gm)/(4*M_PI));
     328            0 :         LOCALPARAM(betar, betar);
     329            0 :         LOCALPARAM(betam, betam);
     330            0 :         LOCALPARAM(betarm, betarm.div(M_LN2));
     331              : 
     332            0 :         LOCALPARAMF(atmoalpha, atmoalpha);
     333              : 
     334            0 :         gle::defvertex();
     335            0 :         gle::begin(GL_TRIANGLE_STRIP);
     336            0 :         gle::attribf(-1, 1, 1);
     337            0 :         gle::attribf(1, 1, 1);
     338            0 :         gle::attribf(-1, -1, 1);
     339            0 :         gle::attribf(1, -1, 1);
     340            0 :         xtraverts += gle::end();
     341            0 :     }
     342              : 
     343              :     /* === general sky rendering === */
     344              :     VAR(showsky, 0, 1, 1);
     345              :     VAR(clampsky, 0, 1, 1);
     346              : }
     347              : 
     348              : // externally relevant functionality
     349              : 
     350            0 : bool limitsky()
     351              : {
     352            0 :     return explicitsky && (useskytexture || editmode);
     353              : }
     354              : 
     355            0 : void drawskybox(bool clear)
     356              : {
     357            0 :     bool limited = false;
     358            0 :     if(limitsky())
     359              :     {
     360            0 :         for(vtxarray *va = visibleva; va; va = va->next)
     361              :         {
     362            0 :             if(va->sky && va->occluded < Occlude_BB &&
     363            0 :                ((va->skymax.x >= 0 && view.isvisiblebb(va->skymin, ivec(va->skymax).sub(va->skymin)) != ViewFrustumCull_NotVisible) ||
     364            0 :                 !insideworld(camera1->o)))
     365              :             {
     366            0 :                 limited = true;
     367            0 :                 break;
     368              :             }
     369              :         }
     370              :     }
     371            0 :     if(limited)
     372              :     {
     373            0 :         glDisable(GL_DEPTH_TEST);
     374              :     }
     375              :     else
     376              :     {
     377            0 :         glDepthFunc(GL_LEQUAL);
     378            0 :         glDepthMask(GL_FALSE);
     379              :     }
     380            0 :     if(clampsky)
     381              :     {
     382            0 :         glDepthRange(1, 1); //set gl depth range min and max to 1 (all far away)
     383              :     }
     384            0 :     if(clear || (!skybox[0] && (!atmo || atmoalpha < 1)))
     385              :     {
     386            0 :         vec skyboxcol = skyboxcolor.tocolor().mul(ldrscale); //local skyboxcol was skyboxcolor before skyboxcolour -> skyboxcolor uniformity change
     387            0 :         glClearColor(skyboxcol.x, skyboxcol.y, skyboxcol.z, 0);
     388            0 :         glClear(GL_COLOR_BUFFER_BIT);
     389              :     }
     390            0 :     if(skybox[0])
     391              :     {
     392            0 :         if(ldrscale < 1 && (skyboxoverbrightmin != 1 || (skyboxoverbright > 1 && skyboxoverbrightthreshold < 1)))
     393              :         {
     394            0 :             SETSHADER(skyboxoverbright,);
     395            0 :             LOCALPARAMF(overbrightparams, skyboxoverbrightmin, std::max(skyboxoverbright, skyboxoverbrightmin), skyboxoverbrightthreshold);
     396            0 :         }
     397              :         else
     398              :         {
     399            0 :             SETSHADER(skybox,);
     400              :         }
     401            0 :         gle::color(skyboxcolor);
     402              : 
     403            0 :         matrix4 skymatrix = cammatrix,
     404            0 :                 skyprojmatrix;
     405            0 :         skymatrix.settranslation(0, 0, 0);
     406            0 :         skymatrix.rotate_around_z((skyboxspin*lastmillis/1000.0f+skyboxyaw)/RAD);
     407            0 :         skyprojmatrix.mul(projmatrix, skymatrix);
     408            0 :         LOCALPARAM(skymatrix, skyprojmatrix);
     409              : 
     410            0 :         drawenvbox(sky);
     411              :     }
     412            0 :     if(atmo && (!skybox[0] || atmoalpha < 1))
     413              :     {
     414            0 :         if(atmoalpha < 1)
     415              :         {
     416            0 :             glEnable(GL_BLEND);
     417            0 :             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     418              :         }
     419              : 
     420            0 :         drawatmosphere();
     421              : 
     422            0 :         if(atmoalpha < 1)
     423              :         {
     424            0 :             glDisable(GL_BLEND);
     425              :         }
     426              :     }
     427            0 :     if(cloudlayer[0] && cloudheight)
     428              :     {
     429            0 :         SETSHADER(skybox,);
     430              : 
     431            0 :         glDisable(GL_CULL_FACE);
     432              : 
     433            0 :         glEnable(GL_BLEND);
     434            0 :         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     435              : 
     436            0 :         matrix4 skymatrix = cammatrix,
     437            0 :                 skyprojmatrix;
     438            0 :         skymatrix.settranslation(0, 0, 0);
     439            0 :         skymatrix.rotate_around_z((cloudspin*lastmillis/1000.0f+cloudyaw)/RAD);
     440            0 :         skyprojmatrix.mul(projmatrix, skymatrix);
     441            0 :         LOCALPARAM(skymatrix, skyprojmatrix);
     442              : 
     443            0 :         drawenvoverlay(cloudoverlay, cloudoffsetx + cloudscrollx * lastmillis/1000.0f, cloudoffsety + cloudscrolly * lastmillis/1000.0f);
     444              : 
     445            0 :         glDisable(GL_BLEND);
     446              : 
     447            0 :         glEnable(GL_CULL_FACE);
     448              :     }
     449            0 :     if(clampsky)
     450              :     {
     451            0 :         glDepthRange(0, 1); //return depth range to normal
     452              :     }
     453            0 :     if(limited)
     454              :     {
     455            0 :         glEnable(GL_DEPTH_TEST);
     456              :     }
     457              :     else
     458              :     {
     459            0 :         glDepthMask(GL_TRUE);
     460            0 :         glDepthFunc(GL_LESS);
     461              :     }
     462            0 : }
        

Generated by: LCOV version 2.0-1