LCOV - code coverage report
Current view: top level - engine/world - dynlight.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 0.0 % 101 0
Test Date: 2026-08-20 06:51:03 Functions: 0.0 % 10 0

            Line data    Source code
       1              : /**
       2              :  * @brief Handling of changing lights
       3              :  *
       4              :  * while the lighting system is dynamic, the changing state of the light entities
       5              :  * for the renderer to handle must be updated with new values that reflect the type
       6              :  * of light to be drawn
       7              :  *
       8              :  * this includes pulsating lights (which change in radius dynamically)
       9              :  * and multicolored lights (which change hue dynamically)
      10              :  */
      11              : #include "../libprimis-headers/cube.h"
      12              : #include "../../shared/geomexts.h"
      13              : 
      14              : #include "dynlight.h"
      15              : #include "physics.h"
      16              : 
      17              : #include "interface/control.h"
      18              : 
      19              : #include "render/rendergl.h"
      20              : #include "render/renderva.h"
      21              : 
      22              : //internally relevant functionality
      23              : namespace
      24              : {
      25              :     VARNP(dynlights, usedynlights, 0, 1, 1); //toggle using dynamic lights
      26              :     VARP(dynlightdist, 0, 1024, 10000); //distance after which dynamic lights are not rendered (1024 = 128m)
      27              : 
      28              :     class dynlight final
      29              :     {
      30              :         public:
      31              :             vec o;
      32              :             float curradius, dist;
      33              :             int expire;
      34              :             const physent *owner;
      35              : 
      36            0 :             dynlight(vec o, int expire, physent *owner, float radius, float initradius, vec color, vec initcolor, int fade, int peak, int flags, vec dir, int spot) :
      37            0 :                 o(o), expire(expire), owner(owner), radius(radius), initradius(initradius), color(color), initcolor(initcolor), fade(fade), peak(peak), flags(flags), dir(dir), spot(spot)
      38              :             {
      39            0 :             }
      40              : 
      41            0 :             void calcradius()
      42              :             {
      43            0 :                 if(fade + peak > 0)
      44              :                 {
      45            0 :                     int remaining = expire - lastmillis;
      46            0 :                     if(flags&DynLight_Expand)
      47              :                     {
      48            0 :                         curradius = initradius + (radius - initradius) * (1.0f - remaining/static_cast<float>(fade + peak));
      49              :                     }
      50            0 :                     else if(!(flags&DynLight_Flash) && remaining > fade)
      51              :                     {
      52            0 :                         curradius = initradius + (radius - initradius) * (1.0f - static_cast<float>(remaining - fade)/peak);
      53              :                     }
      54            0 :                     else if(flags&DynLight_Shrink)
      55              :                     {
      56            0 :                         curradius = (radius*remaining)/fade;
      57              :                     }
      58              :                     else
      59              :                     {
      60            0 :                         curradius = radius;
      61              :                     }
      62              :                 }
      63              :                 else
      64              :                 {
      65            0 :                     curradius = radius;
      66              :                 }
      67            0 :             }
      68              : 
      69              :             /**
      70              :              * @brief Updates the color of this dynamic light.
      71              :              *
      72              :              * Sets the curcolor and intensity fields depending on the current timestamp
      73              :              * and the object's flags.
      74              :              */
      75            0 :             void calccolor()
      76              :             {
      77            0 :                 if(flags&DynLight_Flash || peak <= 0)
      78              :                 {
      79            0 :                     curcolor = color;
      80              :                 }
      81              :                 else
      82              :                 {
      83            0 :                     int peaking = expire - lastmillis - fade;
      84            0 :                     if(peaking <= 0)
      85              :                     {
      86            0 :                         curcolor = color;
      87              :                     }
      88              :                     else
      89              :                     {
      90            0 :                         curcolor.lerp(initcolor, color, 1.0f - static_cast<float>(peaking)/peak);
      91              :                     }
      92              :                 }
      93            0 :                 float intensity = 1.0f;
      94            0 :                 if(fade > 0)
      95              :                 {
      96            0 :                     int fading = expire - lastmillis;
      97            0 :                     if(fading < fade)
      98              :                     {
      99            0 :                         intensity = static_cast<float>(fading)/fade;
     100              :                     }
     101              :                 }
     102            0 :                 curcolor.mul(intensity);
     103            0 :             }
     104              : 
     105              :             /**
     106              :              * @brief gets information about this dynlight
     107              :              *
     108              :              *  @param n the nth closest dynamic light
     109              :              *  @param o a reference to set as the location of the specified dynlight
     110              :              *  @param radius a reference to set as the radius of the specified dynlight
     111              :              *  @param color a reference to set as the color of the specifeid dynlight
     112              :              *  @param spot a reference to the spotlight information of the dynlight
     113              :              *  @param dir a reference to set as the direction the dynlight is pointing
     114              :              *  @param flags a reference to the flag bitmap for the dynlight
     115              :              */
     116            0 :             void dynlightinfo(vec &origin, float &radius, vec &color, vec &direction, int &spotlight, int &flagmask) const
     117              :             {
     118            0 :                 origin = o;
     119            0 :                 radius = curradius;
     120            0 :                 color = curcolor;
     121            0 :                 spotlight = spot;
     122            0 :                 direction = dir;
     123            0 :                 flagmask = flags & 0xFF;
     124            0 :             }
     125              : 
     126              :         private:
     127              :             float radius, initradius;
     128              :             vec color, initcolor, curcolor;
     129              :             int fade, peak, flags;
     130              :             vec dir;
     131              :             int spot;
     132              :     };
     133              : 
     134              :     std::vector<dynlight> dynlights;
     135              :     std::vector<const dynlight *> closedynlights;
     136              : 
     137              :     //cleans up dynlights, deletes dynlights contents once none have expire field
     138            0 :     void cleardynlights()
     139              :     {
     140            0 :         int faded = -1;
     141            0 :         for(size_t i = 0; i < dynlights.size(); i++)
     142              :         {
     143            0 :             if(lastmillis<dynlights[i].expire)
     144              :             {
     145            0 :                 faded = i;
     146            0 :                 break;
     147              :             }
     148              :         }
     149            0 :         if(faded<0) //if any light has lastmillis > expire field
     150              :         {
     151            0 :             dynlights.clear();
     152              :         }
     153            0 :         else if(faded>0)
     154              :         {
     155            0 :             dynlights.erase(dynlights.begin(), dynlights.begin() + faded);
     156              :         }
     157            0 :     }
     158              : }
     159              : //externally relevant functionality
     160              : 
     161              : //adds a dynamic light object to the dynlights vector with the attributes indicated (radius, color, fade, peak, flags, etc..)
     162            0 : void adddynlight(const vec &o, float radius, const vec &color, int fade, int peak, int flags, float initradius, const vec &initcolor, physent *owner, const vec &dir, int spot)
     163              : {
     164            0 :     if(!usedynlights)
     165              :     {
     166            0 :         return;
     167              :     }
     168            0 :     if(o.dist(camera1->o) > dynlightdist || radius <= 0)
     169              :     {
     170            0 :         return;
     171              :     }
     172            0 :     int insert = 0,
     173            0 :         expire = fade + peak + lastmillis;
     174            0 :     for(int i = dynlights.size(); --i >=0;) //note reverse iteration
     175              :     {
     176            0 :         if(expire>=dynlights[i].expire)
     177              :         {
     178            0 :             insert = i+1;
     179            0 :             break;
     180              :         }
     181              :     }
     182            0 :     dynlight d(o, expire, owner, radius, initradius, color, initcolor, fade, peak, flags, dir, spot);
     183            0 :     dynlights.insert(dynlights.begin() + insert, d);
     184              : }
     185              : 
     186            0 : void removetrackeddynlights(const physent *owner)
     187              : {
     188            0 :     for(int i = dynlights.size(); --i >=0;) //note reverse iteration
     189              :     {
     190            0 :         if(owner ? dynlights[i].owner == owner : dynlights[i].owner != nullptr)
     191              :         {
     192            0 :             dynlights.erase(dynlights.begin() + i);
     193              :         }
     194              :     }
     195            0 : }
     196              : 
     197              : //finds which dynamic lights are near enough and are visible to the player
     198              : //returns the number of lights (and sets `closedynlights` vector contents to the appropriate nearby light ents)
     199            0 : size_t finddynlights()
     200              : {
     201            0 :     closedynlights.clear();
     202            0 :     if(!usedynlights)
     203              :     {
     204            0 :         return 0;
     205              :     }
     206            0 :     physent e;
     207            0 :     e.type = physent::PhysEnt_Camera;
     208            0 :     for(dynlight &d : dynlights)
     209              :     {
     210            0 :         if(d.curradius <= 0)
     211              :         {
     212            0 :             continue;
     213              :         }
     214            0 :         d.dist = camera1->o.dist(d.o) - d.curradius;
     215            0 :         if(d.dist > dynlightdist || view.isfoggedsphere(d.curradius, d.o))
     216              :         {
     217            0 :             continue;
     218              :         }
     219            0 :         e.o = d.o;
     220            0 :         e.radius = e.xradius = e.yradius = e.eyeheight = e.aboveeye = d.curradius;
     221            0 :         if(!collide(&e, nullptr, vec(0, 0, 0), 0))
     222              :         {
     223            0 :             continue;
     224              :         }
     225            0 :         int insert = 0;
     226            0 :         for(int i = closedynlights.size(); --i >=0;) //note reverse iteration
     227              :         {
     228            0 :             if(d.dist >= closedynlights[i]->dist)
     229              :             {
     230            0 :                 insert = i+1;
     231            0 :                 break;
     232              :             }
     233              :         }
     234            0 :         closedynlights.insert(closedynlights.begin() + insert, &d);
     235              :     }
     236            0 :     return closedynlights.size();
     237              : }
     238              : 
     239            0 : bool getdynlight(size_t n, vec &o, float &radius, vec &color, vec &dir, int &spot, int &flags)
     240              : {
     241            0 :     if(!(closedynlights.size() > n))
     242              :     {
     243            0 :         return false;
     244              :     }
     245            0 :     const dynlight &d = *closedynlights[n];
     246            0 :     d.dynlightinfo(o, radius, color, dir, spot, flags);
     247            0 :     return true;
     248              : }
     249              : 
     250            0 : void updatedynlights()
     251              : {
     252            0 :     cleardynlights();
     253            0 :     for(dynlight &d : dynlights)
     254              :     {
     255            0 :         d.calcradius();
     256            0 :         d.calccolor();
     257              :     }
     258            0 : }
        

Generated by: LCOV version 2.0-1