LCOV - code coverage report
Current view: top level - engine/render - radiancehints.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 8 601 1.3 %
Date: 2024-11-22 05:07:59 Functions: 2 48 4.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(uint 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 1.14