LCOV - code coverage report
Current view: top level - engine/world - light.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 15.1 % 403 61
Test Date: 2026-08-20 06:51:03 Functions: 32.3 % 31 10

            Line data    Source code
       1              : /**
       2              :  * @file world light interaction functions
       3              :  *
       4              :  * while renderlights in /render handles the deferred rendering of point lights
       5              :  * on the world, light.cpp handles how lights behave in the world
       6              :  *
       7              :  * includes sunlight variables (direction/color of no-parallax sun lighting)
       8              :  * world light entity packing for the renderer to use
       9              :  */
      10              : #include "../libprimis-headers/cube.h"
      11              : #include "../../shared/geomexts.h"
      12              : #include "../../shared/glexts.h"
      13              : 
      14              : #include "light.h"
      15              : #include "octaworld.h"
      16              : #include "raycube.h"
      17              : #include "world.h"
      18              : 
      19              : #include "interface/console.h"
      20              : #include "interface/input.h"
      21              : 
      22              : #include "render/radiancehints.h"
      23              : #include "render/renderlights.h"
      24              : #include "render/normal.h"
      25              : #include "render/octarender.h"
      26              : #include "render/shaderparam.h"
      27              : #include "render/texture.h"
      28              : 
      29              : namespace
      30              : {
      31              :     /**
      32              :      * @brief Sets the sunlight direction from the sunlightyaw/pitch variables.
      33              :      *
      34              :      * Clears the radiance hints cache after resetting the sunlight directory, so
      35              :      * old GI buffers are cleared and new dynamic sunlight can be calculated
      36              :      */
      37            0 :     void setsunlightdir()
      38              :     {
      39            0 :         sunlightdir = vec(sunlightyaw/RAD, sunlightpitch/RAD);
      40            0 :         for(int k = 0; k < 3; ++k)
      41              :         {
      42            0 :             if(std::fabs(sunlightdir[k]) < 1e-5f)
      43              :             {
      44            0 :                 sunlightdir[k] = 0;
      45              :             }
      46              :         }
      47            0 :         sunlightdir.normalize();
      48            0 :         clearradiancehintscache();
      49            0 :     }
      50              : 
      51            0 :     void setsurfaces(cube &c, std::array<surfaceinfo, 6> surfs, const vertinfo *verts, int numverts)
      52              :     {
      53            0 :         if(!c.ext || c.ext->maxverts < numverts)
      54              :         {
      55            0 :             newcubeext(c, numverts, false);
      56              :         }
      57            0 :         std::copy(c.ext->surfaces.begin(), c.ext->surfaces.end(), surfs.begin());
      58            0 :         std::memcpy(c.ext->verts(), verts, numverts*sizeof(vertinfo));
      59            0 :     }
      60              : 
      61            0 :     void clearsurfaces(std::array<cube, 8> &c)
      62              :     {
      63            0 :         for(int i = 0; i < 8; ++i)
      64              :         {
      65            0 :             if(c[i].ext)
      66              :             {
      67            0 :                 for(int j = 0; j < 6; ++j)
      68              :                 {
      69            0 :                     surfaceinfo &surf = c[i].ext->surfaces[j];
      70            0 :                     if(!surf.used())
      71              :                     {
      72            0 :                         continue;
      73              :                     }
      74            0 :                     surf.clear();
      75            0 :                     int numverts = surf.numverts&Face_MaxVerts;
      76            0 :                     if(numverts)
      77              :                     {
      78            0 :                         if(!(c[i].merged&(1<<j)))
      79              :                         {
      80            0 :                             surf.numverts &= ~Face_MaxVerts;
      81            0 :                             continue;
      82              :                         }
      83            0 :                         vertinfo *verts = c[i].ext->verts() + surf.verts;
      84            0 :                         for(int k = 0; k < numverts; ++k)
      85              :                         {
      86            0 :                             vertinfo &v = verts[k];
      87            0 :                             v.norm = 0;
      88              :                         }
      89              :                     }
      90              :                 }
      91              :             }
      92            0 :             if(c[i].children)
      93              :             {
      94            0 :                 clearsurfaces(*(c[i].children));
      95              :             }
      96              :         }
      97            0 :     }
      98              : 
      99              :     constexpr int lightcacheentries = 1024;
     100              : 
     101              :     struct lightcacheentry final
     102              :     {
     103              :         int x, y;
     104              :     };
     105              : 
     106              :     std::array<lightcacheentry, lightcacheentries> lightcache;
     107              : 
     108            0 :     int lightcachehash(int x, int y)
     109              :     {
     110            0 :         return (((((x)^(y))<<5) + (((x)^(y))>>5)) & (lightcacheentries - 1));
     111              :     }
     112              : 
     113              :     /**
     114              :      * @brief Takes a 3d vec3 and transforms it into a packed ushort vector
     115              :      *
     116              :      * The output ushort is in base 360 and has yaw in the first place and pitch in the second place.
     117              :      * The second place has pitch as a range from 0 to 90; since this is a normal
     118              :      * vector, no magnitude is needed.
     119              :      *
     120              :      * @param n the normal to encode
     121              :      *
     122              :      * @return the packed normal vector
     123              :      */
     124            0 :     ushort encodenormal(const vec &n)
     125              :     {
     126            0 :         if(n.iszero())
     127              :         {
     128            0 :             return 0;
     129              :         }
     130            0 :         const int yaw = static_cast<int>(-std::atan2(n.x, n.y)*RAD), //arctangent in degrees
     131            0 :                   pitch = static_cast<int>(std::asin(n.z)*RAD); //arcsin in degrees
     132            0 :         return static_cast<ushort>(std::clamp(pitch + 90, 0, 180)*360 + (yaw < 0 ? yaw%360 + 360 : yaw%360) + 1);
     133              :     }
     134              : 
     135            0 :     void calcsurfaces(cube &c, const ivec &co, int size, int usefacemask, int preview = 0)
     136              :     {
     137            0 :         std::array<surfaceinfo, 6> surfaces;
     138              :         std::array<vertinfo, 6*2*Face_MaxVerts> litverts;
     139            0 :         int numlitverts = 0;
     140            0 :         surfaces.fill(surfaceinfo());
     141            0 :         for(int i = 0; i < 6; ++i) //for each face of the cube
     142              :         {
     143            0 :             int usefaces = usefacemask&0xF;
     144            0 :             usefacemask >>= 4;
     145            0 :             if(!usefaces)
     146              :             {
     147            0 :                 if(!c.ext)
     148              :                 {
     149            0 :                     continue;
     150              :                 }
     151            0 :                 surfaceinfo &surf = c.ext->surfaces[i];
     152            0 :                 int numverts = surf.totalverts();
     153            0 :                 if(numverts)
     154              :                 {
     155            0 :                     std::memcpy(&litverts[numlitverts], c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
     156            0 :                     surf.verts = numlitverts;
     157            0 :                     numlitverts += numverts;
     158              :                 }
     159            0 :                 continue;
     160            0 :             }
     161              : 
     162            0 :             VSlot &vslot = lookupvslot(c.texture[i], false),
     163            0 :                  *layer = vslot.layer && !(c.material&Mat_Alpha) ? &lookupvslot(vslot.layer, false) : nullptr;
     164            0 :             Shader *shader = vslot.slot->shader;
     165            0 :             int shadertype = shader->type;
     166            0 :             if(layer)
     167              :             {
     168            0 :                 shadertype |= layer->slot->shader->type;
     169              :             }
     170            0 :             surfaceinfo &surf = surfaces[i];
     171            0 :             vertinfo *curlitverts = &litverts[numlitverts];
     172            0 :             int numverts = c.ext ? c.ext->surfaces[i].numverts&Face_MaxVerts : 0;
     173            0 :             ivec mo(co);
     174            0 :             int msz = size,
     175            0 :                 convex = 0;
     176            0 :             if(numverts)
     177              :             {
     178            0 :                 const vertinfo *verts = c.ext->verts() + c.ext->surfaces[i].verts;
     179            0 :                 for(int j = 0; j < numverts; ++j)
     180              :                 {
     181            0 :                     curlitverts[j].set(verts[j].getxyz());
     182              :                 }
     183            0 :                 if(c.merged&(1<<i))
     184              :                 {
     185            0 :                     msz = 1<<calcmergedsize(mo, size, verts, numverts);
     186            0 :                     mo.mask(~(msz-1));
     187            0 :                     if(!(surf.numverts&Face_MaxVerts))
     188              :                     {
     189            0 :                         surf.verts = numlitverts;
     190            0 :                         surf.numverts |= numverts;
     191            0 :                         numlitverts += numverts;
     192              :                     }
     193              :                 }
     194            0 :                 else if(!flataxisface(c, i))
     195              :                 {
     196            0 :                     convex = faceconvexity(verts, numverts, size);
     197              :                 }
     198              :             }
     199              :             else
     200              :             {
     201            0 :                 std::array<ivec, 4> v;
     202            0 :                 genfaceverts(c, i, v);
     203            0 :                 if(!flataxisface(c, i))
     204              :                 {
     205            0 :                     convex = faceconvexity(v);
     206              :                 }
     207            0 :                 int order = usefaces&4 || convex < 0 ? 1 : 0;
     208            0 :                 ivec vo = ivec(co).mask(0xFFF).shl(3);
     209            0 :                 curlitverts[numverts++].set(v[order].mul(size).add(vo));
     210            0 :                 if(usefaces&1)
     211              :                 {
     212            0 :                     curlitverts[numverts++].set(v[order+1].mul(size).add(vo));
     213              :                 }
     214            0 :                 curlitverts[numverts++].set(v[order+2].mul(size).add(vo));
     215            0 :                 if(usefaces&2)
     216              :                 {
     217            0 :                     curlitverts[numverts++].set(v[(order+3)&3].mul(size).add(vo));
     218              :                 }
     219              :             }
     220              : 
     221            0 :             std::array<vec, Face_MaxVerts> pos,
     222            0 :                                            n;
     223            0 :             vec po(ivec(co).mask(~0xFFF));
     224            0 :             for(int j = 0; j < numverts; ++j)
     225              :             {
     226            0 :                 pos[j] = vec(curlitverts[j].getxyz()).mul(1.0f/8).add(po);
     227              :             }
     228              : 
     229            0 :             int smooth = vslot.slot->smooth;
     230            0 :             std::array<plane, 2> planes;
     231            0 :             int numplanes = 0;
     232            0 :             planes[numplanes++].toplane(pos[0], pos[1], pos[2]);
     233            0 :             if(numverts < 4 || !convex)
     234              :             {
     235            0 :                 for(int k = 0; k < numverts; ++k)
     236              :                 {
     237            0 :                     findnormal(pos[k], smooth, planes[0], n[k]);
     238              :                 }
     239            0 :             }
     240              :             else
     241              :             {
     242            0 :                 planes[numplanes++].toplane(pos[0], pos[2], pos[3]);
     243            0 :                 vec avg = vec(planes[0]).add(planes[1]).normalize();
     244            0 :                 findnormal(pos[0], smooth, avg, n[0]);
     245            0 :                 findnormal(pos[1], smooth, planes[0], n[1]);
     246            0 :                 findnormal(pos[2], smooth, avg, n[2]);
     247            0 :                 for(int k = 3; k < numverts; k++)
     248              :                 {
     249            0 :                     findnormal(pos[k], smooth, planes[1], n[k]);
     250              :                 }
     251              :             }
     252            0 :             for(int k = 0; k < numverts; ++k)
     253              :             {
     254            0 :                 curlitverts[k].norm = encodenormal(n[k]);
     255              :             }
     256            0 :             if(!(surf.numverts&Face_MaxVerts))
     257              :             {
     258            0 :                 surf.verts = numlitverts;
     259            0 :                 surf.numverts |= numverts;
     260            0 :                 numlitverts += numverts;
     261              :             }
     262            0 :             if(preview)
     263              :             {
     264            0 :                 surf.numverts |= preview;
     265            0 :                 continue;
     266              :             }
     267            0 :             int surflayer = BlendLayer_Top;
     268            0 :             if(vslot.layer)
     269              :             {
     270            0 :                 int x1 = curlitverts[numverts-1].x,
     271            0 :                     y1 = curlitverts[numverts-1].y,
     272            0 :                     x2 = x1,
     273            0 :                     y2 = y1;
     274            0 :                 for(int j = 0; j < numverts-1; ++j)
     275              :                 {
     276            0 :                     const vertinfo &v = curlitverts[j];
     277            0 :                     x1 = std::min(x1, static_cast<int>(v.x));
     278            0 :                     y1 = std::min(y1, static_cast<int>(v.y));
     279            0 :                     x2 = std::max(x2, static_cast<int>(v.x));
     280            0 :                     y2 = std::max(y2, static_cast<int>(v.y));
     281              :                 }
     282            0 :                 x2 = std::max(x2, x1+1);
     283            0 :                 y2 = std::max(y2, y1+1);
     284            0 :                 x1 = (x1>>3) + (co.x&~0xFFF);
     285            0 :                 y1 = (y1>>3) + (co.y&~0xFFF);
     286            0 :                 x2 = ((x2+7)>>3) + (co.x&~0xFFF);
     287            0 :                 y2 = ((y2+7)>>3) + (co.y&~0xFFF);
     288              :             }
     289            0 :             surf.numverts |= surflayer;
     290              :         }
     291            0 :         if(preview)
     292              :         {
     293            0 :             setsurfaces(c, surfaces, litverts.data(), numlitverts);
     294              :         }
     295              :         else
     296              :         {
     297            0 :             for(const surfaceinfo &surf : surfaces)
     298              :             {
     299            0 :                 if(surf.used())
     300              :                 {
     301            0 :                     cubeext *ext = c.ext && c.ext->maxverts >= numlitverts ? c.ext : growcubeext(c.ext, numlitverts);
     302            0 :                     std::memcpy(ext->surfaces.data(), surfaces.data(), sizeof(ext->surfaces));
     303            0 :                     std::memcpy(ext->verts(), litverts.data(), numlitverts*sizeof(vertinfo));
     304            0 :                     if(c.ext != ext)
     305              :                     {
     306            0 :                         setcubeext(c, ext);
     307              :                     }
     308            0 :                     break;
     309              :                 }
     310              :             }
     311              :         }
     312            0 :     }
     313              : 
     314            0 :     void calcsurfaces(std::array<cube, 8> &c, const ivec &co, int size)
     315              :     {
     316            0 :         for(int i = 0; i < 8; ++i)
     317              :         {
     318            0 :             ivec o(i, co, size);
     319            0 :             if(c[i].children)
     320              :             {
     321            0 :                 calcsurfaces(*(c[i].children), o, size >> 1);
     322              :             }
     323            0 :             else if(!(c[i].isempty()))
     324              :             {
     325            0 :                 if(c[i].ext)
     326              :                 {
     327            0 :                     for(surfaceinfo &s : c[i].ext->surfaces)
     328              :                     {
     329            0 :                         s.clear();
     330              :                     }
     331              :                 }
     332            0 :                 int usefacemask = 0;
     333            0 :                 for(int j = 0; j < 6; ++j)
     334              :                 {
     335            0 :                     if(c[i].texture[j] != Default_Sky && (!(c[i].merged & (1 << j)) || (c[i].ext && c[i].ext->surfaces[j].numverts & Face_MaxVerts)))
     336              :                     {
     337            0 :                         usefacemask |= visibletris(c[i], j, o, size)<<(4*j);
     338              :                     }
     339              :                 }
     340            0 :                 if(usefacemask)
     341              :                 {
     342            0 :                     calcsurfaces(c[i], o, size, usefacemask);
     343              :                 }
     344              :             }
     345              :         }
     346            0 :     }
     347              : }
     348              : 
     349              : //external functionality
     350              : 
     351            0 : CVAR1R(ambient, 0x191919);
     352              : FVARR(ambientscale, 0, 1, 16);
     353              : 
     354            0 : CVAR1R(skylight, 0);
     355              : FVARR(skylightscale, 0, 1, 16);
     356              : 
     357            0 : CVAR1FR(sunlight, 0,
     358              : {
     359              :     clearradiancehintscache();
     360              :     cleardeferredlightshaders();
     361              :     clearshadowcache();
     362              : });
     363            0 : FVARFR(sunlightscale, 0, 1, 16, clearradiancehintscache(););
     364              : 
     365              : vec sunlightdir(0, 0, 1);
     366            0 : FVARFR(sunlightyaw, 0, 0, 360, setsunlightdir());
     367            0 : FVARFR(sunlightpitch, -90, 90, 90, setsunlightdir());
     368              : 
     369            0 : void brightencube(cube &c)
     370              : {
     371            0 :     if(!c.ext)
     372              :     {
     373            0 :         newcubeext(c, 0, false);
     374              :     }
     375            0 :     c.ext->surfaces.fill(surfaceinfo());
     376            0 : }
     377              : 
     378            0 : void setsurface(cube &c, int orient, const surfaceinfo &src, const vertinfo *srcverts, int numsrcverts)
     379              : {
     380            0 :     int dstoffset = 0;
     381            0 :     if(!c.ext)
     382              :     {
     383            0 :         newcubeext(c, numsrcverts, true);
     384              :     }
     385              :     else
     386              :     {
     387            0 :         int numbefore = 0,
     388            0 :             beforeoffset = 0;
     389            0 :         for(int i = 0; i < orient; ++i)
     390              :         {
     391            0 :             const surfaceinfo &surf = c.ext->surfaces[i];
     392            0 :             int numverts = surf.totalverts();
     393            0 :             if(!numverts)
     394              :             {
     395            0 :                 continue;
     396              :             }
     397            0 :             numbefore += numverts;
     398            0 :             beforeoffset = surf.verts + numverts;
     399              :         }
     400            0 :         int numafter = 0,
     401            0 :             afteroffset = c.ext->maxverts;
     402            0 :         for(int i = 5; i > orient; i--) //note reverse iteration
     403              :         {
     404            0 :             const surfaceinfo &surf = c.ext->surfaces[i];
     405            0 :             int numverts = surf.totalverts();
     406            0 :             if(!numverts)
     407              :             {
     408            0 :                 continue;
     409              :             }
     410            0 :             numafter += numverts;
     411            0 :             afteroffset = surf.verts;
     412              :         }
     413            0 :         if(afteroffset - beforeoffset >= numsrcverts)
     414              :         {
     415            0 :             dstoffset = beforeoffset;
     416              :         }
     417              :         else
     418              :         {
     419            0 :             cubeext *ext = c.ext;
     420            0 :             if(numbefore + numsrcverts + numafter > c.ext->maxverts)
     421              :             {
     422            0 :                 ext = growcubeext(c.ext, numbefore + numsrcverts + numafter);
     423            0 :                 std::copy(ext->surfaces.begin(), ext->surfaces.end(), c.ext->surfaces.begin());
     424              :             }
     425            0 :             int offset = 0;
     426            0 :             if(numbefore == beforeoffset)
     427              :             {
     428            0 :                 if(numbefore && c.ext != ext)
     429              :                 {
     430            0 :                     std::memcpy(ext->verts(), c.ext->verts(), numbefore*sizeof(vertinfo));
     431              :                 }
     432            0 :                 offset = numbefore;
     433              :             }
     434              :             else
     435              :             {
     436            0 :                 for(int i = 0; i < orient; ++i)
     437              :                 {
     438            0 :                     surfaceinfo &surf = ext->surfaces[i];
     439            0 :                     int numverts = surf.totalverts();
     440            0 :                     if(!numverts)
     441              :                     {
     442            0 :                         continue;
     443              :                     }
     444            0 :                     std::memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
     445            0 :                     surf.verts = offset;
     446            0 :                     offset += numverts;
     447              :                 }
     448              :             }
     449            0 :             dstoffset = offset;
     450            0 :             offset += numsrcverts;
     451            0 :             if(numafter && offset > afteroffset)
     452              :             {
     453            0 :                 offset += numafter;
     454            0 :                 for(int i = 5; i > orient; i--) //note reverse iteration
     455              :                 {
     456            0 :                     surfaceinfo &surf = ext->surfaces[i];
     457            0 :                     int numverts = surf.totalverts();
     458            0 :                     if(!numverts)
     459              :                     {
     460            0 :                         continue;
     461              :                     }
     462            0 :                     offset -= numverts;
     463            0 :                     std::memmove(ext->verts() + offset, c.ext->verts() + surf.verts, numverts*sizeof(vertinfo));
     464            0 :                     surf.verts = offset;
     465              :                 }
     466              :             }
     467            0 :             if(c.ext != ext)
     468              :             {
     469            0 :                 setcubeext(c, ext);
     470              :             }
     471              :         }
     472              :     }
     473            0 :     surfaceinfo &dst = c.ext->surfaces[orient];
     474            0 :     dst = src;
     475            0 :     dst.verts = dstoffset;
     476            0 :     if(srcverts)
     477              :     {
     478            0 :         std::memcpy(c.ext->verts() + dstoffset, srcverts, numsrcverts*sizeof(vertinfo));
     479              :     }
     480            0 : }
     481              : 
     482           14 : PackNode::PackNode(ushort x, ushort y, ushort w, ushort h) :  w(w), h(h), child1(0), child2(0), x(x), y(y), available(std::min(w, h))
     483              : {
     484           14 : }
     485              : 
     486            1 : void PackNode::reset()
     487              : {
     488            1 :     discardchildren();
     489            1 :     available = std::min(w, h);
     490            1 : }
     491              : 
     492            1 : bool PackNode::resize(int nw, int nh)
     493              : {
     494            1 :     if(w == nw && h == nw)
     495              :     {
     496            0 :         return false;
     497              :     }
     498            1 :     discardchildren();
     499            1 :     w = nw;
     500            1 :     h = nh;
     501            1 :     available = std::min(w, h);
     502            1 :     return true;
     503              : }
     504              : 
     505           14 : PackNode::~PackNode()
     506              : {
     507           14 :     discardchildren();
     508           14 : }
     509              : 
     510           33 : bool PackNode::insert(ushort &tx, ushort &ty, ushort tw, ushort th)
     511              : {
     512           33 :     if((available < tw && available < th) || w < tw || h < th)
     513              :     {
     514            9 :         return false;
     515              :     }
     516           24 :     if(child1)
     517              :     {
     518           21 :         bool inserted = child1->insert(tx, ty, tw, th) ||
     519            9 :                         child2->insert(tx, ty, tw, th);
     520           12 :         available = std::max(child1->available, child2->available);
     521           12 :         if(!available)
     522              :         {
     523            3 :             discardchildren();
     524              :         }
     525           12 :         return inserted;
     526              :     }
     527           12 :     if(w == tw && h == th)
     528              :     {
     529            6 :         available = 0;
     530            6 :         tx = x;
     531            6 :         ty = y;
     532            6 :         return true;
     533              :     }
     534              : 
     535            6 :     if(w - tw > h - th)
     536              :     {
     537            4 :         child1 = new PackNode(x, y, tw, h);
     538            4 :         child2 = new PackNode(x + tw, y, w - tw, h);
     539              :     }
     540              :     else
     541              :     {
     542            2 :         child1 = new PackNode(x, y, w, th);
     543            2 :         child2 = new PackNode(x, y + th, w, h - th);
     544              :     }
     545              : 
     546            6 :     bool inserted = child1->insert(tx, ty, tw, th);
     547            6 :     available = std::max(child1->available, child2->available);
     548            6 :     return inserted;
     549              : }
     550              : 
     551            0 : void PackNode::reserve(ushort tx, ushort ty, ushort tw, ushort th)
     552              : {
     553            0 :     if(tx + tw <= x || tx >= x + w || ty + th <= y || ty >= y + h)
     554              :     {
     555            0 :         return;
     556              :     }
     557            0 :     if(child1)
     558              :     {
     559            0 :         child1->reserve(tx, ty, tw, th);
     560            0 :         child2->reserve(tx, ty, tw, th);
     561            0 :         available = std::max(child1->available, child2->available);
     562            0 :         return;
     563              :     }
     564            0 :     int dx1 = tx - x,
     565            0 :         dx2 = x + w - tx - tw,
     566            0 :         dx = std::max(dx1, dx2),
     567            0 :         dy1 = ty - y,
     568            0 :         dy2 = y + h - ty - th,
     569            0 :         dy = std::max(dy1, dy2),
     570              :         split;
     571            0 :     if(dx > dy)
     572              :     {
     573            0 :         if(dx1 > dx2)
     574              :         {
     575            0 :             split = std::min(dx1, static_cast<int>(w));
     576              :         }
     577              :         else
     578              :         {
     579            0 :             split = w - std::max(dx2, 0);
     580              :         }
     581            0 :         if(w - split <= 0)
     582              :         {
     583            0 :             w = split;
     584            0 :             available = std::min(w, h);
     585            0 :             if(dy > 0)
     586              :             {
     587            0 :                 reserve(tx, ty, tw, th);
     588              :             }
     589            0 :             else if(tx <= x && tx + tw >= x + w)
     590              :             {
     591            0 :                 available = 0;
     592              :             }
     593            0 :             return;
     594              :         }
     595            0 :         if(split <= 0)
     596              :         {
     597            0 :             x += split;
     598            0 :             w -= split;
     599            0 :             available = std::min(w, h);
     600            0 :             if(dy > 0)
     601              :             {
     602            0 :                 reserve(tx, ty, tw, th);
     603              :             }
     604            0 :             else if(tx <= x && tx + tw >= x + w)
     605              :             {
     606            0 :                 available = 0;
     607              :             }
     608            0 :             return;
     609              :         }
     610            0 :         child1 = new PackNode(x, y, split, h);
     611            0 :         child2 = new PackNode(x + split, y, w - split, h);
     612              :     }
     613              :     else
     614              :     {
     615            0 :         if(dy1 > dy2)
     616              :         {
     617            0 :             split = std::min(dy1, static_cast<int>(h));
     618              :         }
     619              :         else
     620              :         {
     621            0 :             split = h - std::max(dy2, 0);
     622              :         }
     623            0 :         if(h - split <= 0)
     624              :         {
     625            0 :             h = split;
     626            0 :             available = std::min(w, h);
     627            0 :             if(dx > 0)
     628              :             {
     629            0 :                 reserve(tx, ty, tw, th);
     630              :             }
     631            0 :             else if(ty <= y && ty + th >= y + h)
     632              :             {
     633            0 :                 available = 0;
     634              :             }
     635            0 :             return;
     636              :         }
     637            0 :         if(split <= 0)
     638              :         {
     639            0 :             y += split;
     640            0 :             h -= split;
     641            0 :             available = std::min(w, h);
     642            0 :             if(dx > 0)
     643              :             {
     644            0 :                 reserve(tx, ty, tw, th);
     645              :             }
     646            0 :             else if(ty <= y && ty + th >= y + h)
     647              :             {
     648            0 :                 available = 0;
     649              :             }
     650            0 :             return;
     651              :         }
     652            0 :         child1 = new PackNode(x, y, w, split);
     653            0 :         child2 = new PackNode(x, y + split, w, h - split);
     654              :     }
     655            0 :     child1->reserve(tx, ty, tw, th);
     656            0 :     child2->reserve(tx, ty, tw, th);
     657            0 :     available = std::max(child1->available, child2->available);
     658              : }
     659              : 
     660            3 : int PackNode::availablespace() const
     661              : {
     662            3 :     return available;
     663              : }
     664              : 
     665            2 : vec2 PackNode::dimensions() const
     666              : {
     667            2 :     return {static_cast<float>(w), static_cast<float>(h)};
     668              : }
     669              : 
     670            7 : void PackNode::printchildren(int i) const
     671              : {
     672            7 :     print(i);
     673              : 
     674            7 :     if(child1)
     675              :     {
     676            3 :         child1->printchildren(i+1);
     677              :     }
     678            7 :     if(child2)
     679              :     {
     680            3 :         child2->printchildren(i+1);
     681              :     }
     682            7 : }
     683              : 
     684            7 : void PackNode::print(int i) const
     685              : {
     686            7 :     std::printf("%d: %d %d\n", i, w, h);
     687            7 : }
     688              : 
     689           19 : void PackNode::discardchildren()
     690              : {
     691           19 :     if(child1)
     692              :     {
     693            6 :         delete child1;
     694            6 :         child1 = nullptr;
     695              :     }
     696           19 :     if(child2)
     697              :     {
     698            6 :         delete child2;
     699            6 :         child2 = nullptr;
     700              :     }
     701           19 : }
     702              : 
     703            0 : static VARF(lightcachesize, 4, 6, 12, clearlightcache());
     704              : 
     705            0 : void clearlightcache(int id)
     706              : {
     707            0 :     if(id >= 0)
     708              :     {
     709            0 :         const extentity &light = *entities::getents()[id];
     710            0 :         int radius = light.attr1;
     711            0 :         if(radius <= 0)
     712              :         {
     713            0 :             return;
     714              :         }
     715            0 :         for(int x = static_cast<int>(std::max(light.o.x-radius, 0.0f))>>lightcachesize, ex = static_cast<int>(std::min(light.o.x+radius, rootworld.mapsize()-1.0f))>>lightcachesize; x <= ex; x++)
     716              :         {
     717            0 :             for(int y = static_cast<int>(std::max(light.o.y-radius, 0.0f))>>lightcachesize, ey = static_cast<int>(std::min(light.o.y+radius, rootworld.mapsize()-1.0f))>>lightcachesize; y <= ey; y++)
     718              :             {
     719            0 :                 lightcacheentry &lce = lightcache[lightcachehash(x, y)];
     720            0 :                 if(lce.x != x || lce.y != y)
     721              :                 {
     722            0 :                     continue;
     723              :                 }
     724            0 :                 lce.x = -1;
     725              :             }
     726              :         }
     727            0 :         return;
     728              :     }
     729              : 
     730            0 :     for(lightcacheentry &lce : lightcache)
     731              :     {
     732            0 :         lce.x = -1;
     733              :     }
     734              : }
     735              : 
     736            0 : void cubeworld::calclight()
     737              : {
     738            0 :     remip();
     739            0 :     clearsurfaces(*worldroot);
     740            0 :     calcnormals(filltjoints > 0);
     741            0 :     calcsurfaces(*worldroot, ivec(0, 0, 0), rootworld.mapsize() >> 1);
     742            0 :     clearnormals();
     743            0 :     allchanged();
     744            0 : }
     745              : 
     746            0 : void clearlights()
     747              : {
     748            0 :     clearlightcache();
     749            0 :     clearshadowcache();
     750            0 :     cleardeferredlightshaders();
     751            0 :     resetsmoothgroups();
     752            0 : }
     753              : 
     754            0 : void initlights()
     755              : {
     756            0 :     clearlightcache();
     757            0 :     clearshadowcache();
     758            0 :     loaddeferredlightshaders();
     759            0 : }
        

Generated by: LCOV version 2.0-1