LCOV - code coverage report
Current view: top level - engine/render - rendersky.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 0 212 0.0 %
Date: 2024-11-22 05:07:59 Functions: 0 15 0.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 1.14