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

Generated by: LCOV version 2.0-1