LCOV - code coverage report
Current view: top level - engine/render - radiancehints.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 1.3 % 602 8
Test Date: 2025-08-24 05:32:49 Functions: 4.2 % 48 2

            Line data    Source code
       1              : /*
       2              :  * radiancehints.cpp: radiance hints global illumination
       3              :  *
       4              :  * Libprimis supports global illumination via the Radiance Hints algorithm. This
       5              :  * global illumination is rendered using a reflective shadow map mapped from the
       6              :  * sun's location.
       7              :  *
       8              :  * For performance reasons, the radiance hints algorithm is only run on the global
       9              :  * sunlight. Running radiance hints on point lights would require complex, expensive
      10              :  * shadowmapping similar to standard lighting, and not perform particularly well.
      11              :  *
      12              :  * By only allowing the sunlight to be lit, Libprimis' global illumination only
      13              :  * has to worry about a single RSM (reflective shadow map) rather than 6 sided cube
      14              :  * maps (as point lights would require).
      15              :  */
      16              : #include "../libprimis-headers/cube.h"
      17              : #include "../../shared/geomexts.h"
      18              : #include "../../shared/glemu.h"
      19              : #include "../../shared/glexts.h"
      20              : 
      21              : #include "csm.h"
      22              : #include "hdr.h"
      23              : #include "octarender.h"
      24              : #include "radiancehints.h"
      25              : #include "rendergl.h"
      26              : #include "renderlights.h"
      27              : #include "rendermodel.h"
      28              : #include "rendertimers.h"
      29              : #include "renderva.h"
      30              : #include "renderwindow.h"
      31              : #include "shader.h"
      32              : #include "shaderparam.h"
      33              : #include "texture.h"
      34              : 
      35              : #include "interface/control.h"
      36              : 
      37              : #include "world/light.h"
      38              : #include "world/world.h"
      39              : 
      40              : std::array<GLuint, 8> rhtex = { 0, 0, 0, 0, 0, 0, 0, 0 };
      41              : GLuint rhfbo = 0;
      42              : 
      43              : //radiance hints (global illumination) vars
      44            0 : VARF(rhsplits, 1, 2, rhmaxsplits, { cleardeferredlightshaders(); cleanupradiancehints(); }); //`r`adiance `h`ints `splits`: number of radiance hints subdivisions
      45            0 : VARF(rhrect, 0, 0, 1, cleanupradiancehints());
      46            0 : VARF(rhborder, 0, 1, 1, cleanupradiancehints());
      47            0 : VARF(rsmsize, 64, 512, 2048, cleanupradiancehints());                           //`r`eflective `s`hadow `m`ap `size`: resolution (squared) of global illumination
      48            0 : VARF(rhnearplane, 1, 1, 16, clearradiancehintscache());                         //`r`adiance `h`ints `near plane`: distance in gridpower 0 cubes before global illumination gets rendered
      49            0 : VARF(rhfarplane, 64, 1024, 16384, clearradiancehintscache());                   //`r`adiance `h`ints `far plane`: distance in gridpower 0 cubes whereafter global illumination no longer gets calculated
      50            0 : FVARF(rsmpradiustweak, 1e-3f, 1, 1e3f, clearradiancehintscache());              //`r`eflective `s`hadow `m`ap `p`robe `radius tweak`
      51            0 : FVARF(rhpradiustweak, 1e-3f, 1, 1e3f, clearradiancehintscache());               //`r`adiance `h`ints `p`robe `radius tweak`
      52            0 : FVARF(rsmdepthrange, 0, 1024, 1e6f, clearradiancehintscache());                 //`r`eflective `s`hadow `m`ap `depth range`
      53            0 : FVARF(rsmdepthmargin, 0, 0.1f, 1e3f, clearradiancehintscache());                //`r`eflective `s`hadow `m`ap `depth margin`
      54            0 : VARFP(rhprec, 0, 0, 1, cleanupradiancehints());                                 //`r`adiance `h`ints `prec`ision: toggles between rgba16 or rgba8 map for radiance hints
      55            0 : VARFP(rsmprec, 0, 0, 3, cleanupradiancehints());                                //`r`eflective `s`hadow `m`ap `prec`ision: toggles the rsm bit depth between rgb8 (0,1) , r11g11b10 (rgb 32bit) (2), or rgb16 (3)
      56            0 : VARFP(rsmdepthprec, 0, 0, 2, cleanupradiancehints());                           //`r`eflective `s`hadow `m`ap `depth` `prec`ision: toggles the rsm depth map (buffer) between 16b, 24b, or 32b
      57              : FVAR(rhnudge, 0, 0.5f, 4);                                                      //`r`adiance `h`ints `nudge`: (minor) factor for rsmsplits offset
      58            0 : FVARF(rhworldbias, 0, 0.5f, 10, clearradiancehintscache());                     //`r`adiance `h`ints `worldbias`: (minor) factor for radiance hints nudge
      59            0 : FVARF(rhsplitweight, 0.20f, 0.6f, 0.95f, clearradiancehintscache());            //`r`adiance `h`ints `split weight`
      60            0 : VARF(rhgrid, 3, 27, rhmaxgrid, cleanupradiancehints());                         //`r`adiance `h`ints `grid`: subdivisions for the radiance hints to calculate
      61            0 : FVARF(rsmspread, 0, 0.35f, 1, clearradiancehintscache());                       //smoothness of `r`adiance hints `s`hadow `m`ap: higher is more blurred
      62              : VAR(rhclipgrid, 0, 1, 1);                                                       //`r`adiance `h`ints `clip` `grid`: determines whether the radiance hints clips to grid
      63            0 : VARF(rhcache, 0, 1, 1, cleanupradiancehints());                                 //`r`adiance `h`ints `cache`: determines whether to create cache textures and use the cache shader
      64            0 : VARF(rhforce, 0, 0, 1, cleanupradiancehints());
      65              : VAR(rsmcull, 0, 1, 1);                                                          //`r`eflective `s`hadow `m`ap `cull`ing
      66            0 : VARFP(rhtaps, 0, 20, 32, cleanupradiancehints());                               //`r`adiance `h`ints `taps`: number of sample points for global illumination
      67              : VAR(rhdyntex, 0, 0, 1);                                                         //`r`adiance `h`ints `dyn`amic `tex`tures
      68              : VAR(rhdynmm, 0, 0, 1);                                                          //`r`adiance `h`ints `dyn`amic `m`ap `m`odels
      69              : 
      70              : //distance at which to render global illumination in cubits
      71            0 : VARFR(gidist, 0, 384, 1024,
      72              : {
      73              :     clearradiancehintscache();
      74              :     cleardeferredlightshaders();
      75              :     if(!gidist)
      76              :     {
      77              :         cleanupradiancehints();
      78              :     }
      79              : });
      80              : 
      81            0 : FVARFR(giscale, 0, 1.5f, 1e3f,
      82              : {
      83              :     cleardeferredlightshaders();
      84              :     if(!giscale)
      85              :     {
      86              :         cleanupradiancehints();
      87              :     }
      88              : }); //`g`lobal `i`llumination `scale`
      89              : 
      90              : FVARR(giaoscale, 0, 3, 1e3f);                                                   //`g`lobal `i`llumination `a`mbient `o`cclusion `scale`: scale of ambient occlusion (corner darkening) on globally illuminated surfaces
      91            0 : VARFP(gi, 0, 1, 1, { cleardeferredlightshaders(); cleanupradiancehints(); });   //`g`lobal `i`llumination toggle: 0 disables global illumination
      92              : 
      93              : //debugrsm/rh used extern in renderlights
      94              : VAR(debugrsm, 0, 0, 2);                                                         //displays the `r`adiance hints `s`hadow `m`ap in the bottom right of the screen; 1 for view from sun pos, 2 for view from sun pos, normal map
      95              : VAR(debugrh, -1, 0, rhmaxsplits*(rhmaxgrid + 2));
      96              : 
      97              : reflectiveshadowmap rsm;
      98              : radiancehints rh;
      99              : Shader *rsmworldshader = nullptr;
     100              : 
     101              : 
     102              : namespace //internal functionality
     103              : {
     104              :     uint rhclearmasks[2][rhmaxsplits][(rhmaxgrid+2+31)/32];
     105              :     //reflective shadow map buffers, rendered from sun location
     106              :     GLuint rsmdepthtex = 0,
     107              :            rsmcolortex = 0,
     108              :            rsmnormaltex = 0,
     109              :            rsmfbo = 0;
     110              :     std::array<GLuint, 4> rhrb = {0, 0, 0, 0};
     111              : 
     112              :     Shader *radiancehintsshader = nullptr;
     113              : 
     114            0 :     Shader *loadradiancehintsshader()
     115              :     {
     116            0 :         std::string name = std::string("radiancehints").append(std::to_string(rhtaps));
     117            0 :         return generateshader(name, "radiancehintsshader %d", rhtaps);
     118            0 :     }
     119              : 
     120            0 :     void loadrhshaders()
     121              :     {
     122            0 :         if(rhborder)
     123              :         {
     124            0 :             useshaderbyname("radiancehintsborder");
     125              :         }
     126            0 :         if(rhcache)
     127              :         {
     128            0 :             useshaderbyname("radiancehintscached");
     129              :         }
     130            0 :         useshaderbyname("radiancehintsdisable");
     131            0 :         radiancehintsshader = loadradiancehintsshader();
     132            0 :         rsmworldshader = useshaderbyname("rsmworld");
     133            0 :         useshaderbyname("rsmsky");
     134            0 :     }
     135              : 
     136            0 :     void clearrhshaders()
     137              :     {
     138            0 :         radiancehintsshader = nullptr;
     139            0 :         rsmworldshader = nullptr;
     140            0 :     }
     141              : 
     142              :     //defines a rectangle with corners at x1...y2
     143            0 :     void rhquad(float x1, float y1, float x2, float y2, float tx1, float ty1, float tx2, float ty2, float tz)
     144              :     {
     145            0 :         gle::begin(GL_TRIANGLE_STRIP);
     146            0 :         gle::attribf(x2, y1); gle::attribf(tx2, ty1, tz);
     147            0 :         gle::attribf(x1, y1); gle::attribf(tx1, ty1, tz);
     148            0 :         gle::attribf(x2, y2); gle::attribf(tx2, ty2, tz);
     149            0 :         gle::attribf(x1, y2); gle::attribf(tx1, ty2, tz);
     150            0 :         gle::end();
     151            0 :     }
     152              : 
     153            0 :     void rhquad(float dx1, float dy1, float dx2, float dy2, float dtx1, float dty1, float dtx2, float dty2, float dtz,
     154              :                 float px1, float py1, float px2, float py2, float ptx1, float pty1, float ptx2, float pty2, float ptz)
     155              :     {
     156            0 :         gle::begin(GL_TRIANGLE_STRIP);
     157            0 :         gle::attribf(dx2, dy1); gle::attribf(dtx2, dty1, dtz);
     158            0 :         gle::attribf(px2, py1); gle::attribf(ptx2, pty1, ptz);
     159              : 
     160            0 :         gle::attribf(dx1, dy1); gle::attribf(dtx1, dty1, dtz);
     161            0 :         gle::attribf(px1, py1); gle::attribf(ptx1, pty1, ptz);
     162              : 
     163            0 :         gle::attribf(dx1, dy2); gle::attribf(dtx1, dty2, dtz);
     164            0 :         gle::attribf(px1, py2); gle::attribf(ptx1, pty2, ptz);
     165              : 
     166            0 :         gle::attribf(dx2, dy2); gle::attribf(dtx2, dty2, dtz);
     167            0 :         gle::attribf(px2, py2); gle::attribf(ptx2, pty2, ptz);
     168              : 
     169            0 :         gle::attribf(dx2, dy1); gle::attribf(dtx2, dty1, dtz);
     170            0 :         gle::attribf(px2, py1); gle::attribf(ptx2, pty1, ptz);
     171            0 :         gle::end();
     172            0 :     }
     173              : }
     174              : 
     175              : //externally relevant functionality
     176              : 
     177            0 : void viewrsm()
     178              : {
     179            0 :     int w = std::min(hudw(), hudh())/2,
     180            0 :         h = (w*hudh())/hudw(),
     181            0 :         x = hudw()-w,
     182            0 :         y = hudh()-h;
     183            0 :     SETSHADER(hudrect);
     184            0 :     gle::colorf(1, 1, 1);
     185            0 :     glBindTexture(GL_TEXTURE_RECTANGLE, debugrsm == 2 ? rsmnormaltex : rsmcolortex);
     186            0 :     debugquad(x, y, w, h, 0, 0, rsmsize, rsmsize);
     187            0 : }
     188              : 
     189            0 : void setupradiancehints()
     190              : {
     191            0 :     GLenum rhformat = rhprec >= 1 ? GL_RGBA16F : GL_RGBA8;
     192            0 :     for(int i = 0; i < (!rhrect && rhcache ? 8 : 4); ++i)
     193              :     {
     194            0 :         if(!rhtex[i])
     195              :         {
     196            0 :             glGenTextures(1, &rhtex[i]);
     197              :         }
     198            0 :         create3dtexture(rhtex[i], rhgrid+2*rhborder, rhgrid+2*rhborder, (rhgrid+2*rhborder)*rhsplits, nullptr, 7, 1, rhformat);
     199            0 :         if(rhborder)
     200              :         {
     201            0 :             glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
     202            0 :             glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
     203            0 :             glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
     204            0 :             GLfloat border[4] = { 0.5f, 0.5f, 0.5f, 0 };
     205            0 :             glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, border);
     206              :         }
     207              :     }
     208            0 :     if(!rhfbo)
     209              :     {
     210            0 :         glGenFramebuffers(1, &rhfbo);
     211              :     }
     212            0 :     glBindFramebuffer(GL_FRAMEBUFFER, rhfbo);
     213              : 
     214            0 :     if(rhrect)
     215              :     {
     216            0 :         for(size_t i = 0; i < rhrb.size(); ++i)
     217              :         {
     218            0 :             if(!rhrb[i])
     219              :             {
     220            0 :                 glGenRenderbuffers(1, &rhrb[i]);
     221              :             }
     222            0 :             glBindRenderbuffer(GL_RENDERBUFFER, rhrb[i]);
     223            0 :             glRenderbufferStorage(GL_RENDERBUFFER, rhformat, (rhgrid + 2*rhborder)*(rhgrid + 2*rhborder), (rhgrid + 2*rhborder)*rhsplits);
     224            0 :             glBindRenderbuffer(GL_RENDERBUFFER, 0);
     225            0 :             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, rhrb[i]);
     226              :         }
     227              :     }
     228              :     else
     229              :     {
     230            0 :         for(int i = 0; i < 4; ++i)
     231              :         {
     232            0 :             glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_3D, rhtex[i], 0, 0);
     233              :         }
     234              :     }
     235              : 
     236              :     static const std::array<GLenum, 4> drawbufs =
     237              :     {
     238              :         GL_COLOR_ATTACHMENT0,
     239              :         GL_COLOR_ATTACHMENT1,
     240              :         GL_COLOR_ATTACHMENT2,
     241              :         GL_COLOR_ATTACHMENT3
     242              :     };
     243            0 :     glDrawBuffers(4, drawbufs.data());
     244              : 
     245            0 :     if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
     246              :     {
     247            0 :         fatal("failed allocating radiance hints buffer!");
     248              :     }
     249              : 
     250            0 :     if(!rsmdepthtex)
     251              :     {
     252            0 :         glGenTextures(1, &rsmdepthtex);
     253              :     }
     254            0 :     if(!rsmcolortex)
     255              :     {
     256            0 :         glGenTextures(1, &rsmcolortex);
     257              :     }
     258            0 :     if(!rsmnormaltex)
     259              :     {
     260            0 :         glGenTextures(1, &rsmnormaltex);
     261              :     }
     262            0 :     if(!rsmfbo)
     263              :     {
     264            0 :         glGenFramebuffers(1, &rsmfbo);
     265              :     }
     266              : 
     267            0 :     glBindFramebuffer(GL_FRAMEBUFFER, rsmfbo);
     268            0 :     GLenum rsmformat = gethdrformat(rsmprec, GL_RGBA8);
     269              : 
     270            0 :     createtexture(rsmdepthtex, rsmsize, rsmsize, nullptr, 3, 0, rsmdepthprec > 1 ? GL_DEPTH_COMPONENT32 : (rsmdepthprec ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16), GL_TEXTURE_RECTANGLE);
     271            0 :     createtexture(rsmcolortex, rsmsize, rsmsize, nullptr, 3, 0, rsmformat, GL_TEXTURE_RECTANGLE);
     272            0 :     createtexture(rsmnormaltex, rsmsize, rsmsize, nullptr, 3, 0, rsmformat, GL_TEXTURE_RECTANGLE);
     273              : 
     274            0 :     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, rsmdepthtex, 0);
     275            0 :     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, rsmcolortex, 0);
     276            0 :     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE, rsmnormaltex, 0);
     277              : 
     278            0 :     glDrawBuffers(2, drawbufs.data());
     279              : 
     280            0 :     if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
     281              :     {
     282            0 :         fatal("failed allocating RSM buffer!");
     283              :     }
     284            0 :     glBindFramebuffer(GL_FRAMEBUFFER, 0);
     285            0 :     loadrhshaders();
     286            0 :     clearradiancehintscache();
     287            0 : }
     288              : 
     289            0 : void cleanupradiancehints()
     290              : {
     291            0 :     clearradiancehintscache();
     292              : 
     293            0 :     for(GLuint &i : rhtex)
     294              :     {
     295            0 :         if(i)
     296              :         {
     297            0 :             glDeleteTextures(1, &i);
     298            0 :             i = 0;
     299              :         }
     300              :     }
     301            0 :     for(GLuint &i : rhrb)
     302              :     {
     303            0 :         if(i)
     304              :         {
     305            0 :             glDeleteRenderbuffers(1, &i);
     306            0 :             i = 0;
     307              :         }
     308              :     }
     309            0 :     if(rhfbo)
     310              :     {
     311            0 :         glDeleteFramebuffers(1, &rhfbo);
     312            0 :         rhfbo = 0;
     313              :     }
     314            0 :     if(rsmdepthtex)
     315              :     {
     316            0 :         glDeleteTextures(1, &rsmdepthtex);
     317            0 :         rsmdepthtex = 0;
     318              :     }
     319            0 :     if(rsmcolortex)
     320              :     {
     321            0 :         glDeleteTextures(1, &rsmcolortex);
     322            0 :         rsmcolortex = 0;
     323              :     }
     324            0 :     if(rsmnormaltex)
     325              :     {
     326            0 :         glDeleteTextures(1, &rsmnormaltex);
     327            0 :         rsmnormaltex = 0;
     328              :     }
     329            0 :     if(rsmfbo)
     330              :     {
     331            0 :         glDeleteFramebuffers(1, &rsmfbo);
     332            0 :         rsmfbo = 0;
     333              :     }
     334              : 
     335            0 :     clearrhshaders();
     336            0 : }
     337              : 
     338            0 : void viewrh()
     339              : {
     340            0 :     int w = std::min(hudw(), hudh())/2,
     341            0 :         h = (w*hudh())/hudw(),
     342            0 :         x = hudw()-w,
     343            0 :         y = hudh()-h;
     344            0 :     gle::colorf(1, 1, 1);
     345            0 :     if(debugrh < 0 && rhrect)
     346              :     {
     347            0 :         SETSHADER(hudrect);
     348            0 :         glBindTexture(GL_TEXTURE_RECTANGLE, rhtex[5]);
     349            0 :         float tw = (rhgrid+2*rhborder)*(rhgrid+2*rhborder),
     350            0 :               th = (rhgrid+2*rhborder)*rhsplits;
     351            0 :         gle::defvertex(2);
     352            0 :         gle::deftexcoord0(2);
     353            0 :         gle::begin(GL_TRIANGLE_STRIP);
     354            0 :         gle::attribf(x,   y);   gle::attribf(0,  0);
     355            0 :         gle::attribf(x+w, y);   gle::attribf(tw, 0);
     356            0 :         gle::attribf(x,   y+h); gle::attribf(0,  th);
     357            0 :         gle::attribf(x+w, y+h); gle::attribf(tw, th);
     358            0 :         gle::end();
     359            0 :     }
     360              :     else
     361              :     {
     362            0 :         SETSHADER(hud3d);
     363            0 :         glBindTexture(GL_TEXTURE_3D, rhtex[1]);
     364            0 :         float z = (std::max(debugrh, 1)-1+0.5f)/static_cast<float>((rhgrid+2*rhborder)*rhsplits);
     365            0 :         gle::defvertex(2);
     366            0 :         gle::deftexcoord0(3);
     367            0 :         gle::begin(GL_TRIANGLE_STRIP);
     368            0 :         gle::attribf(x,   y);   gle::attribf(0, 0, z);
     369            0 :         gle::attribf(x+w, y);   gle::attribf(1, 0, z);
     370            0 :         gle::attribf(x,   y+h); gle::attribf(0, 1, z);
     371            0 :         gle::attribf(x+w, y+h); gle::attribf(1, 1, z);
     372            0 :         gle::end();
     373              :     }
     374            0 : }
     375              : 
     376            1 : void clearradiancehintscache()
     377              : {
     378            1 :     rh.clearcache();
     379            1 :     std::memset(rhclearmasks, 0, sizeof(rhclearmasks));
     380            1 : }
     381              : 
     382            0 : bool useradiancehints()
     383              : {
     384            0 :     return !sunlight.iszero() && csm.getcsmproperty(cascadedshadowmap::ShadowMap) && gi && giscale && gidist;
     385              : }
     386              : 
     387              : //============================= radiance hints object ==========================//
     388              : 
     389            0 : void radiancehints::updatesplitdist()
     390              : {
     391            0 :     const float lambda = rhsplitweight,
     392            0 :                 nd = rhnearplane,
     393            0 :                 fd = rhfarplane,
     394            0 :                 ratio = fd/nd;
     395            0 :     splits[0].nearplane = nd;
     396            0 :     for(int i = 1; i < rhsplits; ++i)
     397              :     {
     398            0 :         const float si = i / static_cast<float>(rhsplits);
     399            0 :         splits[i].nearplane = lambda*(nd*std::pow(ratio, si)) + (1-lambda)*(nd + (fd - nd)*si);
     400            0 :         splits[i-1].farplane = splits[i].nearplane * 1.005f;
     401              :     }
     402            0 :     splits[rhsplits-1].farplane = fd;
     403            0 : }
     404              : 
     405            0 : void radiancehints::setup()
     406              : {
     407            0 :     updatesplitdist();
     408              : 
     409            0 :     for(int i = 0; i < rhsplits; ++i)
     410              :     {
     411            0 :         splitinfo &split = splits[i];
     412              : 
     413            0 :         vec c;
     414            0 :         const float radius = calcfrustumboundsphere(split.nearplane, split.farplane, camera1->o, camdir(), c);
     415              : 
     416              :         // compute the projected bounding box of the sphere
     417            0 :         const float pradius = std::ceil(radius * rhpradiustweak),
     418            0 :                     step = (2*pradius) / rhgrid;
     419            0 :         vec offset = vec(c).sub(pradius).div(step);
     420            0 :         offset.x = std::floor(offset.x);
     421            0 :         offset.y = std::floor(offset.y);
     422            0 :         offset.z = std::floor(offset.z);
     423            0 :         split.cached = split.bounds == pradius ? split.center : vec(-1e16f, -1e16f, -1e16f);
     424            0 :         split.center = vec(offset).mul(step).add(pradius);
     425            0 :         split.bounds = pradius;
     426              : 
     427              :         // modify mvp with a scale and offset
     428              :         // now compute the update model view matrix for this split
     429            0 :         split.scale = vec(1/(step*(rhgrid+2*rhborder)), 1/(step*(rhgrid+2*rhborder)), 1/(step*(rhgrid+2*rhborder)*rhsplits));
     430            0 :         split.offset = vec(-(offset.x-rhborder)/(rhgrid+2*rhborder), -(offset.y-rhborder)/(rhgrid+2*rhborder), (i - (offset.z-rhborder)/(rhgrid+2*rhborder))/static_cast<float>(rhsplits));
     431              :     }
     432            0 : }
     433              : 
     434            0 : void radiancehints::bindparams() const
     435              : {
     436            0 :     float step = 2*splits[0].bounds/rhgrid;
     437            0 :     GLOBALPARAMF(rhnudge, rhnudge*step);
     438            0 :     static GlobalShaderParam rhtc("rhtc");
     439            0 :     vec4<float> *rhtcv = rhtc.reserve<vec4<float>>();
     440            0 :     for(int i = 0; i < rhsplits; ++i)
     441              :     {
     442            0 :         const splitinfo &split = splits[i];
     443            0 :         rhtcv[i] = vec4<float>(vec(split.center).mul(-split.scale.x), split.scale.x);//split.bounds*(1 + rhborder*2*0.5f/rhgrid));
     444              :     }
     445            0 :     GLOBALPARAMF(rhbounds, 0.5f*(rhgrid + rhborder)/static_cast<float>(rhgrid + 2*rhborder));
     446            0 : }
     447              : 
     448            1 : void radiancehints::clearcache()
     449              : {
     450            5 :     for(splitinfo &i : splits)
     451              :     {
     452            4 :         i.clearcache();
     453              :     }
     454            1 : }
     455              : 
     456            0 : bool radiancehints::allcached() const
     457              : {
     458            0 :     for(const splitinfo &i : splits)
     459              :     {
     460            0 :         if(i.cached != i.center)
     461              :         {
     462            0 :             return false;
     463              :         }
     464              :     }
     465            0 :     return true;
     466              : }
     467              : 
     468            0 : void radiancehints::rotatedynlimits()
     469              : {
     470            0 :     prevdynmin = dynmin;
     471            0 :     prevdynmax = dynmax;
     472            0 : }
     473              : 
     474            0 : bool radiancehints::checkprevbounds()
     475              : {
     476            0 :     return prevdynmin.z < rh.prevdynmax.z;
     477              : }
     478              : 
     479            0 : static void bindslice(int sx, int sy, int sw, int sh, int i, int j)
     480              : {
     481            0 :     if(rhrect)
     482              :     {
     483            0 :         glViewport(sx, sy, sw, sh);
     484            0 :         glScissor(sx, sy, sw, sh);
     485              :     }
     486              :     else
     487              :     {
     488            0 :         glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, rhtex[0], 0, i*sh + j);
     489            0 :         glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_3D, rhtex[1], 0, i*sh + j);
     490            0 :         glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_3D, rhtex[2], 0, i*sh + j);
     491            0 :         glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_3D, rhtex[3], 0, i*sh + j);
     492              :     }
     493            0 : }
     494              : 
     495            0 : void radiancehints::renderslices()
     496              : {
     497            0 :     int sw = rhgrid+2*rhborder,
     498            0 :         sh = rhgrid+2*rhborder;
     499            0 :     glBindFramebuffer(GL_FRAMEBUFFER, rhfbo);
     500            0 :     if(!rhrect)
     501              :     {
     502            0 :         glViewport(0, 0, sw, sh);
     503            0 :         if(rhcache)
     504              :         {
     505            0 :             for(size_t i = 0; i < rhtex.size()/2; ++i)
     506              :             {
     507            0 :                 std::swap(rhtex[i], rhtex[i+rhtex.size()/2]);
     508              :             }
     509              :             uint clearmasks[rhmaxsplits][(rhmaxgrid+2+31)/32];
     510            0 :             std::memcpy(clearmasks, rhclearmasks[0], sizeof(clearmasks));
     511            0 :             std::memcpy(rhclearmasks[0], rhclearmasks[1], sizeof(clearmasks));
     512            0 :             std::memcpy(rhclearmasks[1], clearmasks, sizeof(clearmasks));
     513              :         }
     514              :     }
     515              : 
     516            0 :     GLOBALPARAMF(rhatten, 1.0f/(gidist*gidist));
     517            0 :     GLOBALPARAMF(rsmspread, gidist*rsmspread*rsm.scale.x, gidist*rsmspread*rsm.scale.y);
     518            0 :     GLOBALPARAMF(rhaothreshold, splits[0].bounds/rhgrid);
     519            0 :     GLOBALPARAMF(rhaoatten, 1.0f/(gidist*rsmspread));
     520            0 :     GLOBALPARAMF(rhaoheight, gidist*rsmspread);
     521              : 
     522            0 :     matrix4 rsmtcmatrix;
     523            0 :     rsmtcmatrix.identity();
     524            0 :     rsmtcmatrix.settranslation(rsm.offset);
     525            0 :     rsmtcmatrix.setscale(rsm.scale);
     526            0 :     rsmtcmatrix.mul(rsm.model);
     527            0 :     GLOBALPARAM(rsmtcmatrix, rsmtcmatrix);
     528              : 
     529            0 :     matrix4 rsmworldmatrix;
     530            0 :     rsmworldmatrix.invert(rsmtcmatrix);
     531            0 :     GLOBALPARAM(rsmworldmatrix, rsmworldmatrix);
     532              : 
     533            0 :     glBindTexture(GL_TEXTURE_RECTANGLE, rsmdepthtex);
     534            0 :     glActiveTexture(GL_TEXTURE1);
     535            0 :     glBindTexture(GL_TEXTURE_RECTANGLE, rsmcolortex);
     536            0 :     glActiveTexture(GL_TEXTURE2);
     537            0 :     glBindTexture(GL_TEXTURE_RECTANGLE, rsmnormaltex);
     538            0 :     if(rhborder)
     539              :     {
     540            0 :         for(size_t i = 0; i < rhtex.size()/2; ++i)
     541              :         {
     542            0 :             glActiveTexture(GL_TEXTURE3 + i);
     543            0 :             glBindTexture(GL_TEXTURE_3D, rhtex[i]);
     544              :         }
     545              :     }
     546            0 :     if(rhcache)
     547              :     {
     548            0 :         for(size_t i = 0; i < rhtex.size()/2; ++i)
     549              :         {
     550            0 :             glActiveTexture(GL_TEXTURE7 + i);
     551            0 :             glBindTexture(GL_TEXTURE_3D, rhtex[rhrect ? i :  rhtex.size()/2+i]);
     552              :         }
     553              :     }
     554            0 :     glActiveTexture(GL_TEXTURE0);
     555            0 :     glClearColor(0.5f, 0.5f, 0.5f, 0);
     556            0 :     if(rhrect)
     557              :     {
     558            0 :         glEnable(GL_SCISSOR_TEST);
     559              :     }
     560            0 :     gle::defvertex(2);
     561            0 :     gle::deftexcoord0(3);
     562              : 
     563            0 :     bool prevcached = true;
     564            0 :     int cx = -1,
     565            0 :         cy = -1;
     566            0 :     for(int i = rhsplits; --i >= 0;) //reverse iterate through rhsplits
     567              :     {
     568            0 :         splitinfo &split = splits[i];
     569            0 :         float cellradius = split.bounds/rhgrid,
     570            0 :               step       = 2*cellradius,
     571            0 :               nudge      = rhnudge*2*splits[0].bounds/rhgrid + rhworldbias*step;
     572            0 :         vec cmin, cmax,
     573            0 :             dmin( 1e16f,  1e16f,  1e16f),
     574            0 :             dmax(-1e16f, -1e16f, -1e16f),
     575            0 :             bmin( 1e16f,  1e16f,  1e16f),
     576            0 :             bmax(-1e16f, -1e16f, -1e16f);
     577            0 :         for(int k = 0; k < 3; ++k)
     578              :         {
     579            0 :             cmin[k] = std::floor((worldmin[k] - nudge - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
     580            0 :             cmax[k] = std::ceil((worldmax[k] + nudge - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
     581              :         }
     582            0 :         if(prevdynmin.z < prevdynmax.z)
     583              :         {
     584            0 :             for(int k = 0; k < 3; ++k)
     585              :             {
     586            0 :                 dmin[k] = std::min(dmin[k], static_cast<float>(std::floor((prevdynmin[k] - gidist - cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
     587            0 :                 dmax[k] = std::max(dmax[k], static_cast<float>(std::ceil((prevdynmax[k] + gidist + cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
     588              :             }
     589              :         }
     590            0 :         if(dynmin.z < dynmax.z)
     591              :         {
     592            0 :             for(int k = 0; k < 3; ++k)
     593              :             {
     594            0 :                 dmin[k] = std::min(dmin[k], static_cast<float>(std::floor((dynmin[k] - gidist - cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
     595            0 :                 dmax[k] = std::max(dmax[k], static_cast<float>(std::ceil((dynmax[k] + gidist + cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds));
     596              :             }
     597              :         }
     598            0 :         if((rhrect || !rhcache || hasCI) && split.cached == split.center && (!rhborder || prevcached) && !rhforce &&
     599            0 :            (dmin.x > split.center.x + split.bounds || dmax.x < split.center.x - split.bounds ||
     600            0 :             dmin.y > split.center.y + split.bounds || dmax.y < split.center.y - split.bounds ||
     601            0 :             dmin.z > split.center.z + split.bounds || dmax.z < split.center.z - split.bounds))
     602              :         {
     603            0 :             if(rhrect || !rhcache || split.copied)
     604              :             {
     605            0 :                 continue;
     606              :             }
     607            0 :             split.copied = true;
     608            0 :             for(size_t k = 0; k <  rhtex.size()/2; ++k)
     609              :             {
     610            0 :                 glCopyImageSubData_(rhtex[rhtex.size()/2+k], GL_TEXTURE_3D, 0, 0, 0, i*sh, rhtex[k], GL_TEXTURE_3D, 0, 0, 0, i*sh, sw, sh, sh);
     611              :             }
     612            0 :             continue;
     613            0 :         }
     614              : 
     615            0 :         prevcached = false;
     616            0 :         split.copied = false;
     617              : 
     618            0 :         GLOBALPARAM(rhcenter, split.center);
     619            0 :         GLOBALPARAMF(rhbounds, split.bounds);
     620            0 :         GLOBALPARAMF(rhspread, cellradius);
     621              : 
     622            0 :         if(rhborder && i + 1 < rhsplits)
     623              :         {
     624            0 :             GLOBALPARAMF(bordercenter, 0.5f, 0.5f, static_cast<float>(i+1 + 0.5f)/rhsplits);
     625            0 :             GLOBALPARAMF(borderrange, 0.5f - 0.5f/(rhgrid+2), 0.5f - 0.5f/(rhgrid+2), (0.5f - 0.5f/(rhgrid+2))/rhsplits);
     626            0 :             GLOBALPARAMF(borderscale, rhgrid+2, rhgrid+2, (rhgrid+2)*rhsplits);
     627              : 
     628            0 :             splitinfo &next = splits[i+1];
     629            0 :             for(int k = 0; k < 3; ++k)
     630              :             {
     631            0 :                 bmin[k] = std::floor((std::max(static_cast<float>(worldmin[k] - nudge), next.center[k] - next.bounds) - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
     632            0 :                 bmax[k] = std::ceil((std::min(static_cast<float>(worldmax[k] + nudge), next.center[k] + next.bounds) - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
     633              :             }
     634              :         }
     635              : 
     636              :         std::array<uint, (rhmaxgrid+2+31)/32> clearmasks;
     637            0 :         std::memset(clearmasks.data(), 0xFF, clearmasks.size()*sizeof(uint));
     638              : 
     639            0 :         int sy = rhrect ? i*sh : 0;
     640            0 :         for(int j = sh; --j >= 0;) //note reverse iteration
     641              :         {
     642            0 :             int sx = rhrect ? j*sw : 0;
     643              : 
     644            0 :             float x1  = split.center.x - split.bounds,
     645            0 :                   x2  = split.center.x + split.bounds,
     646            0 :                   y1  = split.center.y - split.bounds,
     647            0 :                   y2  = split.center.y + split.bounds,
     648            0 :                   z   = split.center.z - split.bounds + (j-rhborder+0.5f)*step,
     649            0 :                   vx1 = -1 + rhborder*2.0f/(rhgrid+2),
     650            0 :                   vx2 = 1 - rhborder*2.0f/(rhgrid+2),
     651            0 :                   vy1 = -1 + rhborder*2.0f/(rhgrid+2),
     652            0 :                   vy2 = 1 - rhborder*2.0f/(rhgrid+2),
     653            0 :                   tx1 = x1,
     654            0 :                   tx2 = x2,
     655            0 :                   ty1 = y1,
     656            0 :                   ty2 = y2;
     657            0 :             bool clipped = false;
     658              : 
     659            0 :             if(rhborder && i + 1 < rhsplits)
     660              :             {
     661            0 :                 const splitinfo &next = splits[i+1];
     662            0 :                 float bx1  = x1-step,
     663            0 :                       bx2  = x2+step,
     664            0 :                       by1  = y1-step,
     665            0 :                       by2  = y2+step,
     666            0 :                       bz   = z,
     667            0 :                       bvx1 = -1,
     668            0 :                       bvx2 = 1,
     669            0 :                       bvy1 = -1,
     670            0 :                       bvy2 = 1,
     671            0 :                       btx1 = bx1,
     672            0 :                       btx2 = bx2,
     673            0 :                       bty1 = by1,
     674            0 :                       bty2 = by2;
     675              : 
     676            0 :                 if(rhclipgrid)
     677              :                 {
     678            0 :                     if(bz < bmin.z || bz > bmax.z)
     679              :                     {
     680            0 :                         goto noborder;
     681              :                     }
     682            0 :                     if(bx1 < bmin.x || bx2 > bmax.x || by1 < bmin.y || by2 > bmax.y)
     683              :                     {
     684            0 :                         btx1 = std::max(bx1, bmin.x);
     685            0 :                         btx2 = std::min(bx2, bmax.x);
     686            0 :                         bty1 = std::max(by1, bmin.y);
     687            0 :                         bty2 = std::min(by2, bmax.y);
     688            0 :                         if(btx1 > tx2 || bty1 > bty2)
     689              :                         {
     690            0 :                             goto noborder;
     691              :                         }
     692            0 :                         bvx1 += 2*(btx1 - bx1)/(bx2 - bx1);
     693            0 :                         bvx2 += 2*(btx2 - bx2)/(bx2 - bx1);
     694            0 :                         bvy1 += 2*(bty1 - by1)/(by2 - by1);
     695            0 :                         bvy2 += 2*(bty2 - by2)/(by2 - by1);
     696            0 :                         clipped = true;
     697              :                     }
     698              :                 }
     699            0 :                 btx1 = btx1*next.scale.x + next.offset.x;
     700            0 :                 btx2 = btx2*next.scale.x + next.offset.x;
     701            0 :                 bty1 = bty1*next.scale.y + next.offset.y;
     702            0 :                 bty2 = bty2*next.scale.y + next.offset.y;
     703            0 :                 bz = bz*next.scale.z + next.offset.z;
     704            0 :                 bindslice(sx, sy, sw, sh, i, j);
     705            0 :                 if(clipped)
     706              :                 {
     707            0 :                     glClear(GL_COLOR_BUFFER_BIT);
     708              :                 }
     709            0 :                 SETSHADER(radiancehintsborder);
     710            0 :                 rhquad(bvx1, bvy1, bvx2, bvy2, btx1, bty1, btx2, bty2, bz);
     711            0 :                 clearmasks[j/32] &= ~(1 << (j%32));
     712              :             }
     713              : 
     714            0 :         noborder:
     715            0 :             if(j < rhborder || j >= rhgrid + rhborder)
     716              :             {
     717            0 :             skipped:
     718            0 :                 if(clearmasks[j/32] & (1 << (j%32)) && (!rhrect || cx < 0) && !(rhclearmasks[0][i][j/32] & (1 << (j%32))))
     719              :                 {
     720            0 :                     bindslice(sx, sy, sw, sh, i, j);
     721            0 :                     glClear(GL_COLOR_BUFFER_BIT);
     722            0 :                     cx = sx;
     723            0 :                     cy = sy;
     724              :                 }
     725            0 :                 continue;
     726              :             }
     727              : 
     728            0 :             if(rhclipgrid)
     729              :             {
     730            0 :                 if(z < cmin.z || z > cmax.z)
     731              :                 {
     732            0 :                     goto skipped;
     733              :                 }
     734            0 :                 if(x1 < cmin.x || x2 > cmax.x || y1 < cmin.y || y2 > cmax.y)
     735              :                 {
     736            0 :                     tx1 = std::max(x1, cmin.x);
     737            0 :                     tx2 = std::min(x2, cmax.x);
     738            0 :                     ty1 = std::max(y1, cmin.y);
     739            0 :                     ty2 = std::min(y2, cmax.y);
     740            0 :                     if(tx1 > tx2 || ty1 > ty2)
     741              :                     {
     742            0 :                         goto skipped;
     743              :                     }
     744            0 :                     vx1 += 2*rhgrid/static_cast<float>(sw)*(tx1 - x1)/(x2 - x1);
     745            0 :                     vx2 += 2*rhgrid/static_cast<float>(sw)*(tx2 - x2)/(x2 - x1);
     746            0 :                     vy1 += 2*rhgrid/static_cast<float>(sh)*(ty1 - y1)/(y2 - y1);
     747            0 :                     vy2 += 2*rhgrid/static_cast<float>(sh)*(ty2 - y2)/(y2 - y1);
     748            0 :                     clipped = true;
     749              :                 }
     750              :             }
     751            0 :             if(clearmasks[j/32] & (1 << (j%32)))
     752              :             {
     753            0 :                 bindslice(sx, sy, sw, sh, i, j);
     754            0 :                 if(clipped || (rhborder && i + 1 >= rhsplits))
     755              :                 {
     756            0 :                     glClear(GL_COLOR_BUFFER_BIT);
     757              :                 }
     758            0 :                 clearmasks[j/32] &= ~(1 << (j%32));
     759              :             }
     760              : 
     761            0 :             if(rhcache && z > split.cached.z - split.bounds && z < split.cached.z + split.bounds)
     762              :             {
     763            0 :                 float px1 = std::max(tx1, split.cached.x - split.bounds),
     764            0 :                       px2 = std::min(tx2, split.cached.x + split.bounds),
     765            0 :                       py1 = std::max(ty1, split.cached.y - split.bounds),
     766            0 :                       py2 = std::min(ty2, split.cached.y + split.bounds);
     767            0 :                 if(px1 < px2 && py1 < py2)
     768              :                 {
     769            0 :                     float pvx1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(px1 - x1)/(x2 - x1),
     770            0 :                           pvx2 =  1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(px2 - x2)/(x2 - x1),
     771            0 :                           pvy1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(py1 - y1)/(y2 - y1),
     772            0 :                           pvy2 =  1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(py2 - y2)/(y2 - y1),
     773            0 :                           ptx1 = (px1 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
     774            0 :                           ptx2 = (px2 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
     775            0 :                           pty1 = (py1 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
     776            0 :                           pty2 = (py2 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
     777            0 :                           pz = (z + split.center.z - split.cached.z)*split.scale.z + split.offset.z;
     778            0 :                     if(px1 != tx1 || px2 != tx2 || py1 != ty1 || py2 != ty2)
     779              :                     {
     780            0 :                         radiancehintsshader->set();
     781            0 :                         rhquad(pvx1, pvy1, pvx2, pvy2, px1, py1, px2, py2, z,
     782              :                                 vx1,  vy1,  vx2,  vy2, tx1, ty1, tx2, ty2, z);
     783              :                     }
     784            0 :                     if(z > dmin.z && z < dmax.z)
     785              :                     {
     786            0 :                         float dx1 = std::max(px1, dmin.x),
     787            0 :                               dx2 = std::min(px2, dmax.x),
     788            0 :                               dy1 = std::max(py1, dmin.y),
     789            0 :                               dy2 = std::min(py2, dmax.y);
     790            0 :                         if(dx1 < dx2 && dy1 < dy2)
     791              :                         {
     792            0 :                             float dvx1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(dx1 - x1)/(x2 - x1),
     793            0 :                                   dvx2 =  1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sw)*(dx2 - x2)/(x2 - x1),
     794            0 :                                   dvy1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(dy1 - y1)/(y2 - y1),
     795            0 :                                   dvy2 =  1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/static_cast<float>(sh)*(dy2 - y2)/(y2 - y1),
     796            0 :                                   dtx1 = (dx1 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
     797            0 :                                   dtx2 = (dx2 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
     798            0 :                                   dty1 = (dy1 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
     799            0 :                                   dty2 = (dy2 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
     800            0 :                                   dz = (z + split.center.z - split.cached.z)*split.scale.z + split.offset.z;
     801            0 :                             if(dx1 != px1 || dx2 != px2 || dy1 != py1 || dy2 != py2)
     802              :                             {
     803            0 :                                 SETSHADER(radiancehintscached);
     804            0 :                                 rhquad(dvx1, dvy1, dvx2, dvy2, dtx1, dty1, dtx2, dty2, dz,
     805              :                                        pvx1, pvy1, pvx2, pvy2, ptx1, pty1, ptx2, pty2, pz);
     806              :                             }
     807            0 :                             radiancehintsshader->set();
     808            0 :                             rhquad(dvx1, dvy1, dvx2, dvy2, dx1, dy1, dx2, dy2, z);
     809            0 :                             goto maskslice;
     810              :                         }
     811              :                     }
     812            0 :                     SETSHADER(radiancehintscached);
     813            0 :                     rhquad(pvx1, pvy1, pvx2, pvy2, ptx1, pty1, ptx2, pty2, pz);
     814            0 :                     goto maskslice;
     815              :                 }
     816              :             }
     817            0 :             radiancehintsshader->set();
     818            0 :             rhquad(vx1, vy1, vx2, vy2, tx1, ty1, tx2, ty2, z);
     819            0 :         maskslice:
     820            0 :             if(i)
     821              :             {
     822            0 :                 continue;
     823              :             }
     824            0 :             if(gle::attribbuf.empty())
     825              :             {
     826            0 :                 continue;
     827              :             }
     828            0 :             SETSHADER(radiancehintsdisable);
     829            0 :             if(rhborder)
     830              :             {
     831            0 :                 glScissor(sx + rhborder, sy + rhborder, sw - 2*rhborder, sh - 2*rhborder);
     832            0 :                 if(!rhrect)
     833              :                 {
     834            0 :                     glEnable(GL_SCISSOR_TEST);
     835              :                 }
     836              :             }
     837            0 :             gle::defvertex(2);
     838            0 :             gle::begin(GL_TRIANGLES);
     839            0 :             gle::end();
     840            0 :             if(rhborder && !rhrect)
     841              :             {
     842            0 :                 glDisable(GL_SCISSOR_TEST);
     843              :             }
     844            0 :             gle::defvertex(2);
     845            0 :             gle::deftexcoord0(3);
     846              :         }
     847            0 :         if(rhrect)
     848              :         {
     849            0 :             for(int k = 0; k < 4; ++k)
     850              :             {
     851            0 :                 glReadBuffer(GL_COLOR_ATTACHMENT0+k);
     852            0 :                 glBindTexture(GL_TEXTURE_3D, rhtex[k]);
     853            0 :                 for(int j = 0; j < sh; ++j)
     854              :                 {
     855            0 :                     if(clearmasks[j/32] & (1 << (j%32)))
     856              :                     {
     857            0 :                         if(!(rhclearmasks[0][i][j/32] & (1 << (j%32))))
     858              :                         {
     859            0 :                             glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, sy+j, cx, cy, sw, sh);
     860              :                         }
     861            0 :                         continue;
     862              :                     }
     863            0 :                     glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, sy+j, j*sw, sy, sw, sh);
     864              :                 }
     865              :             }
     866              :         }
     867            0 :         std::memcpy(rhclearmasks[0][i], clearmasks.data(), clearmasks.size()*sizeof(uint));
     868              :     }
     869            0 :     if(rhrect)
     870              :     {
     871            0 :         glDisable(GL_SCISSOR_TEST);
     872              :     }
     873            0 : }
     874              : 
     875            0 : void GBuffer::renderradiancehints() const
     876              : {
     877            0 :     if(rhinoq && !inoq && shouldworkinoq())
     878              :     {
     879            0 :         return;
     880              :     }
     881            0 :     if(!useradiancehints())
     882              :     {
     883            0 :         return;
     884              :     }
     885            0 :     timer *rhcputimer = begintimer("radiance hints", false),
     886            0 :           *rhtimer = begintimer("radiance hints"); //implicit true
     887              : 
     888            0 :     rh.setup();
     889            0 :     rsm.setup();
     890              : 
     891            0 :     shadowmapping = ShadowMap_Reflect;
     892            0 :     shadowside = 0;
     893            0 :     shadoworigin = vec(0, 0, 0);
     894            0 :     shadowdir = rsm.lightview;
     895            0 :     shadowbias = rsm.lightview.project_bb(worldmin, worldmax);
     896            0 :     shadowradius = std::fabs(rsm.lightview.project_bb(worldmax, worldmin));
     897              : 
     898            0 :     findshadowvas();
     899            0 :     findshadowmms();
     900              : 
     901            0 :     batching::shadowmaskbatchedmodels(false);
     902            0 :     batchshadowmapmodels();
     903              : 
     904            0 :     rh.rotatedynlimits();
     905            0 :     rh.dynmin = vec(1e16f, 1e16f, 1e16f);
     906            0 :     rh.dynmax = vec(-1e16f, -1e16f, -1e16f);
     907            0 :     if(rhdyntex)
     908              :     {
     909            0 :         dynamicshadowvabounds(1<<shadowside, rh.dynmin, rh.dynmax);
     910              :     }
     911            0 :     if(rhdynmm)
     912              :     {
     913            0 :         batching::batcheddynamicmodelbounds(1<<shadowside, rh.dynmin, rh.dynmax);
     914              :     }
     915            0 :     if(rhforce || rh.checkprevbounds() || rh.dynmin.z < rh.dynmax.z || !rh.allcached())
     916              :     {
     917            0 :         if(inoq)
     918              :         {
     919            0 :             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
     920            0 :             glDepthMask(GL_TRUE);
     921              :         }
     922            0 :         glBindFramebuffer(GL_FRAMEBUFFER, rsmfbo);
     923            0 :         shadowmatrix.mul(rsm.proj, rsm.model);
     924            0 :         GLOBALPARAM(rsmmatrix, shadowmatrix);
     925            0 :         GLOBALPARAMF(rsmdir, -rsm.lightview.x, -rsm.lightview.y, -rsm.lightview.z);
     926              : 
     927            0 :         glViewport(0, 0, rsmsize, rsmsize);
     928            0 :         glClearColor(0, 0, 0, 0);
     929            0 :         glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
     930              : 
     931            0 :         renderrsmgeom(rhdyntex!=0);
     932            0 :         batching::rendershadowmodelbatches(rhdynmm!=0);
     933            0 :         rh.renderslices();
     934            0 :         if(inoq)
     935              :         {
     936            0 :             glBindFramebuffer(GL_FRAMEBUFFER, msaasamples ? msfbo : gfbo);
     937            0 :             glViewport(0, 0, vieww, viewh);
     938              : 
     939            0 :             glFlush();
     940              :         }
     941              :     }
     942              : 
     943            0 :     batching::clearbatchedmapmodels();
     944            0 :     shadowmapping = 0;
     945            0 :     endtimer(rhtimer);
     946            0 :     endtimer(rhcputimer);
     947              : }
     948              : 
     949              : // ============================ reflective shadow map =========================//
     950              : //the reflective shadow map caches the terrain albedo for use by the radiance
     951              : //hints algorithm: it needs to know how bright the surfaces the sun is shining on
     952            0 : void reflectiveshadowmap::setup()
     953              : {
     954            0 :     getmodelmatrix();
     955            0 :     getprojmatrix();
     956            0 :     gencullplanes();
     957            0 : }
     958              : 
     959              : // sets the reflectiveshadowmap's model to the global viewmatrix, then points it
     960              : // to be oriented like the sun
     961            0 : void reflectiveshadowmap::getmodelmatrix()
     962              : {
     963            0 :     model = viewmatrix;                             //copy global view matrix
     964            0 :     model.rotate_around_x(sunlightpitch/RAD);       //orient camera in same yaw as sunlight
     965            0 :     model.rotate_around_z((180-sunlightyaw)/RAD);   //orient camera in same pitch as sunlight
     966            0 : }
     967              : 
     968            0 : void reflectiveshadowmap::getprojmatrix()
     969              : {
     970            0 :     lightview = vec(sunlightdir).neg();
     971              :     // find z extent
     972            0 :     float minz = lightview.project_bb(worldmin, worldmax),
     973            0 :           maxz = lightview.project_bb(worldmax, worldmin),
     974            0 :           zmargin = std::max((maxz - minz)*rsmdepthmargin, 0.5f*(rsmdepthrange - (maxz - minz)));
     975            0 :     minz -= zmargin;
     976            0 :     maxz += zmargin;
     977            0 :     vec c;
     978            0 :     const float radius = calcfrustumboundsphere(rhnearplane, rhfarplane, camera1->o, camdir(), c);
     979              :     // compute the projected bounding box of the sphere
     980            0 :     vec tc;
     981            0 :     model.transform(c, tc);
     982            0 :     const float pradius = std::ceil((radius + gidist) * rsmpradiustweak),
     983            0 :                 step = (2*pradius) / rsmsize;
     984            0 :     vec2 tcoff = vec2(tc).sub(pradius).div(step);
     985            0 :     tcoff.x = std::floor(tcoff.x);
     986            0 :     tcoff.y = std::floor(tcoff.y);
     987            0 :     center = vec(vec2(tcoff).mul(step).add(pradius), -0.5f*(minz + maxz));
     988            0 :     bounds = vec(pradius, pradius, 0.5f*(maxz - minz));
     989              : 
     990            0 :     scale = vec(1/step, 1/step, -1/(maxz - minz));
     991            0 :     offset = vec(-tcoff.x, -tcoff.y, -minz/(maxz - minz));
     992              : 
     993            0 :     proj.identity();
     994            0 :     proj.settranslation(2*offset.x/rsmsize - 1, 2*offset.y/rsmsize - 1, 2*offset.z - 1);
     995            0 :     proj.setscale(2*scale.x/rsmsize, 2*scale.y/rsmsize, 2*scale.z);
     996            0 : }
     997              : 
     998              : //sets the culling plane objects' location within the reflectiveshadowmap object
     999            0 : void reflectiveshadowmap::gencullplanes()
    1000              : {
    1001            0 :     matrix4 mvp;
    1002            0 :     mvp.mul(proj, model);
    1003            0 :     vec4<float> px = mvp.rowx(),
    1004            0 :                 py = mvp.rowy(),
    1005            0 :                 pw = mvp.roww();
    1006            0 :     cull[0] = plane(vec4<float>(pw).add(px)).normalize(); // left plane
    1007            0 :     cull[1] = plane(vec4<float>(pw).sub(px)).normalize(); // right plane
    1008            0 :     cull[2] = plane(vec4<float>(pw).add(py)).normalize(); // bottom plane
    1009            0 :     cull[3] = plane(vec4<float>(pw).sub(py)).normalize(); // top plane
    1010            0 : }
    1011              : 
    1012              : //=========================== end reflective shadow map =======================//
        

Generated by: LCOV version 2.0-1