LCOV - code coverage report
Current view: top level - engine/world - raycube.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 0 275 0.0 %
Date: 2024-11-22 05:07:59 Functions: 0 18 0.0 %

          Line data    Source code
       1             : 
       2             : /////////////////////////  ray - cube collision ///////////////////////////////////////////////
       3             : 
       4             : //functions for finding where vectors hit world geometry on the octree
       5             : 
       6             : /* Unlike vector geometry, finding collision with world surfaces has to interact with the
       7             :  * octree geometry. Octree geometry behaves differently for identifying collision due to
       8             :  * its recursive behavior, and as a result the algorithms for identifying collision with
       9             :  * the world looks different than other world geometry systems.
      10             :  *
      11             :  * Octree cube collision is necessary for physics (as players need to interact with the world geometry)
      12             :  * and for other world interaction by players (e.g. identifying where structure in the world is)
      13             :  */
      14             : #include "../libprimis-headers/cube.h"
      15             : #include "../../shared/geomexts.h"
      16             : 
      17             : #include "bih.h"
      18             : #include "entities.h"
      19             : #include "octaworld.h"
      20             : #include "raycube.h"
      21             : #include "world/world.h"
      22             : 
      23             : //internally relevant functionality
      24             : namespace
      25             : {
      26           0 :     clipplanes &getclipplanes(const cube &c, const ivec &o, int size)
      27             :     {
      28           0 :         clipplanes &p = rootworld.getclipbounds(c, o, size, c.visible&0x80 ? 2 : 0);
      29           0 :         if(p.visible&0x80)
      30             :         {
      31           0 :             genclipplanes(c, o, size, p, false, false);
      32             :         }
      33           0 :         return p;
      34             :     }
      35             : 
      36             :     //============================================================= INTERSECTBOX
      37             : 
      38           0 :     static bool intersectplanes(const clipplanes& p, const vec &v, const vec& ray, float &enterdist, float &exitdist, int &entry)
      39             :     {
      40           0 :         for(int i = 0; i < p.size; ++i)
      41             :         {
      42           0 :             float pdist = p.p[i].dist(v),
      43           0 :                   facing = ray.dot(p.p[i]);
      44           0 :             if(facing < 0)
      45             :             {
      46           0 :                 pdist /= -facing;
      47           0 :                 if(pdist > enterdist)
      48             :                 {
      49           0 :                     if(pdist > exitdist)
      50             :                     {
      51           0 :                         return false;
      52             :                     }
      53           0 :                     enterdist = pdist;
      54           0 :                     entry = i;
      55             :                 }
      56             :             }
      57           0 :             else if(facing > 0)
      58             :             {
      59           0 :                 pdist /= -facing;
      60           0 :                 if(pdist < exitdist)
      61             :                 {
      62           0 :                     if(pdist < enterdist)
      63             :                     {
      64           0 :                         return false;
      65             :                     }
      66           0 :                     exitdist = pdist;
      67             :                 }
      68             :             }
      69           0 :             else if(pdist > 0)
      70             :             {
      71           0 :                 return false;
      72             :             }
      73             :         }
      74           0 :         return true;
      75             :     }
      76             : 
      77           0 :     static bool intersectbox(const clipplanes& p, const vec &v, const vec& ray, const vec& invray, float &enterdist, float &exitdist, int &entry)
      78             :     {
      79           0 :         for(int i = 0; i < 3; ++i)
      80             :         {
      81           0 :             if(ray[i])
      82             :             {
      83           0 :                 float prad = std::fabs(p.r[i] * invray[i]),
      84           0 :                       pdist = (p.o[i] - v[i]) * invray[i],
      85           0 :                       pmin = pdist - prad,
      86           0 :                       pmax = pdist + prad;
      87           0 :                 if(pmin > enterdist)
      88             :                 {
      89           0 :                     if(pmin > exitdist)
      90             :                     {
      91           0 :                         return false;
      92             :                     }
      93           0 :                     enterdist = pmin;
      94           0 :                     entry = i;
      95             :                 }
      96           0 :                 if(pmax < exitdist)
      97             :                 {
      98           0 :                     if(pmax < enterdist)
      99             :                     {
     100           0 :                         return false;
     101             :                     }
     102           0 :                     exitdist = pmax;
     103             :                 }
     104             :             }
     105           0 :             else if(v[i] < p.o[i]-p.r[i] || v[i] > p.o[i]+p.r[i])
     106             :             {
     107           0 :                 return false;
     108             :             }
     109             :         }
     110           0 :         return true;
     111             :     }
     112             : 
     113           0 :     bool raycubeintersect(const clipplanes &p, const cube &c, const vec &v, const vec &ray, const vec &invray, float maxdist, float &dist)
     114             :     {
     115           0 :         int entry   = -1,
     116           0 :             bbentry = -1;
     117           0 :         float enterdist = -1e16f,
     118           0 :               exitdist  = 1e16f;
     119           0 :         if(!intersectplanes(p, v, ray, enterdist, exitdist, entry))
     120             :         {
     121           0 :             return false;
     122             :         }
     123           0 :         if(!intersectbox(p, v, ray, invray, enterdist, exitdist, bbentry))
     124             :         {
     125           0 :             return false;
     126             :         }
     127           0 :         if(exitdist < 0)
     128             :         {
     129           0 :             return false;
     130             :         }
     131           0 :         dist = std::max(enterdist+0.1f, 0.0f);
     132           0 :         if(dist < maxdist)
     133             :         {
     134           0 :             if(bbentry>=0)
     135             :             {
     136           0 :                 hitsurface = vec(0, 0, 0);
     137           0 :                 hitsurface[bbentry] = ray[bbentry]>0 ? -1 : 1;
     138             :             }
     139             :             else
     140             :             {
     141           0 :                 hitsurface = p.p[entry];
     142             :             }
     143             :         }
     144           0 :         return true;
     145             :     }
     146             : 
     147             :     float hitentdist;
     148             :     int hitent, hitorient;
     149             : 
     150           0 :     float disttoent(const octaentities *oc, const vec &o, const vec &ray, float radius, int mode, const extentity *t)
     151             :     {
     152           0 :         vec eo, es;
     153           0 :         int orient = -1;
     154           0 :         float dist = radius,
     155           0 :               f = 0.0f;
     156           0 :         const std::vector<extentity *> &ents = entities::getents();
     157             :     //=======ENT_SEL_INTERSECT ENT_INTERSECT
     158             :         #define ENT_INTERSECT(type, func) do { \
     159             :             for(uint i = 0; i < oc->type.size(); i++) \
     160             :             { \
     161             :                 extentity &e = *ents[oc->type[i]]; \
     162             :                 if(!(e.flags&EntFlag_Octa) || &e==t) \
     163             :                 { \
     164             :                     continue; \
     165             :                 } \
     166             :                 func; \
     167             :                 if(f < dist && f > 0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) \
     168             :                 { \
     169             :                     hitentdist = dist = f; \
     170             :                     hitent = oc->type[i]; \
     171             :                     hitorient = orient; \
     172             :                 } \
     173             :             } \
     174             :         } while(0)
     175             : 
     176           0 :         if((mode&Ray_Poly) == Ray_Poly)
     177             :         {
     178           0 :             ENT_INTERSECT(mapmodels,
     179             :             {
     180             :                 if(!mmintersect(e, o, ray, radius, mode, f))
     181             :                 {
     182             :                     continue;
     183             :                 }
     184             :             });
     185             :         }
     186             : 
     187             :         #define ENT_SEL_INTERSECT(type) ENT_INTERSECT(type, { \
     188             :             entselectionbox(e, eo, es); \
     189             :             if(!rayboxintersect(eo, es, o, ray, f, orient)) \
     190             :             { \
     191             :                 continue; \
     192             :             } \
     193             :         })
     194             : 
     195           0 :         if((mode&Ray_Ents) == Ray_Ents)
     196             :         {
     197           0 :             ENT_SEL_INTERSECT(other);
     198           0 :             ENT_SEL_INTERSECT(mapmodels);
     199           0 :             ENT_SEL_INTERSECT(decals);
     200             :         }
     201             : 
     202           0 :         return dist;
     203             :     }
     204             :     #undef ENT_INTERSECT
     205             :     #undef ENT_SEL_INTERSECT
     206             :     //======================================
     207           0 :     float disttooutsideent(const vec &o, const vec &ray, float radius, int mode, const extentity *t)
     208             :     {
     209           0 :         vec eo, es;
     210             :         int orient;
     211           0 :         float dist = radius,
     212           0 :               f = 0.0f;
     213           0 :         const std::vector<extentity *> &ents = entities::getents();
     214           0 :         for(const int &i : outsideents)
     215             :         {
     216           0 :             extentity &e = *ents[i];
     217           0 :             if(!(e.flags&EntFlag_Octa) || &e == t)
     218             :             {
     219           0 :                 continue;
     220             :             }
     221           0 :             entselectionbox(e, eo, es);
     222           0 :             if(!rayboxintersect(eo, es, o, ray, f, orient))
     223             :             {
     224           0 :                 continue;
     225             :             }
     226           0 :             if(f<dist && f>0)
     227             :             {
     228           0 :                 hitentdist = dist = f;
     229           0 :                 hitent = outsideents[i];
     230           0 :                 hitorient = orient;
     231             :             }
     232             :         }
     233           0 :         return dist;
     234             :     }
     235             : 
     236             :     // optimized shadow version
     237           0 :     float shadowent(const octaentities *oc, const vec &o, const vec &ray, float radius, int mode, const extentity *t)
     238             :     {
     239           0 :         float dist = radius,
     240           0 :               f = 0.0f;
     241           0 :         const std::vector<extentity *> &ents = entities::getents();
     242           0 :         for(const int &i : oc->mapmodels)
     243             :         {
     244           0 :             const extentity &e = *ents[i];
     245           0 :             if(!(e.flags&EntFlag_Octa) || &e==t)
     246             :             {
     247           0 :                 continue;
     248             :             }
     249           0 :             if(!mmintersect(e, o, ray, radius, mode, f))
     250             :             {
     251           0 :                 continue;
     252             :             }
     253           0 :             if(f>0 && f<dist)
     254             :             {
     255           0 :                 dist = f;
     256             :             }
     257             :         }
     258           0 :         return dist;
     259             :     }
     260             : }
     261             : 
     262             : //externally relevant functionality
     263           0 : bool insideworld(const vec &o)
     264             : {
     265           0 :     return o.x>=0 && o.x<rootworld.mapsize() && o.y>=0 && o.y<rootworld.mapsize() && o.z>=0 && o.z<rootworld.mapsize();
     266             : }
     267             : 
     268           0 : bool insideworld(const ivec &o)
     269             : {
     270           0 :     return static_cast<uint>(o.x) < static_cast<uint>(rootworld.mapsize()) &&
     271           0 :            static_cast<uint>(o.y) < static_cast<uint>(rootworld.mapsize()) &&
     272           0 :            static_cast<uint>(o.z) < static_cast<uint>(rootworld.mapsize());
     273             : }
     274             : 
     275             : vec hitsurface;
     276             : 
     277             : //==================INITRAYCUBE CHECKINSIDEWORLD DOWNOCTREE FINDCLOSEST UPOCTREE
     278             : 
     279             : //NOTE: levels[20] magically assumes mapscale <20
     280             : #define INITRAYCUBE \
     281             :     float dist = 0, \
     282             :           dent = radius > 0 ? radius : 1e16f; \
     283             :     vec v(o), \
     284             :         invray(ray.x ? 1/ray.x : 1e16f, ray.y ? 1/ray.y : 1e16f, ray.z ? 1/ray.z : 1e16f); \
     285             :     cube *levels[20]; \
     286             :     levels[worldscale] = &(*worldroot)[0]; \
     287             :     int lshift = worldscale, \
     288             :         elvl = mode&Ray_BB ? worldscale : 0; \
     289             :     ivec lsizemask(invray.x>0 ? 1 : 0, invray.y>0 ? 1 : 0, invray.z>0 ? 1 : 0); \
     290             : 
     291             : //will only change &outrad and &dist if not inside the world
     292             : //true if outside world, false if inside
     293           0 : bool cubeworld::checkinsideworld(const vec &invray, float radius, float &outrad, const vec &o, vec &v, const vec& ray, float &dist) const
     294             : {
     295           0 :     if(!insideworld(o))
     296             :     {
     297           0 :         float disttoworld = 0,
     298           0 :               exitworld = 1e16f;
     299           0 :         for(int i = 0; i < 3; ++i)
     300             :         {
     301           0 :             float c = v[i];
     302           0 :             if(c<0 || c>=mapsize())
     303             :             {
     304           0 :                 float d = ((invray[i]>0?0:mapsize())-c)*invray[i];
     305           0 :                 if(d<0)
     306             :                 {
     307           0 :                     outrad =  radius>0 ? radius :-1;
     308           0 :                     return true;
     309             :                 }
     310           0 :                 disttoworld = std::max(disttoworld, 0.1f + d);
     311             :             }
     312           0 :             float e = ((invray[i]>0?mapsize():0)-c)*invray[i];
     313           0 :             exitworld = std::min(exitworld, e);
     314             :         }
     315           0 :         if(disttoworld > exitworld)
     316             :         {
     317           0 :             outrad = (radius>0?radius:-1);
     318           0 :             return true;
     319             :         }
     320           0 :         v.add(vec(ray).mul(disttoworld));
     321           0 :         dist += disttoworld;
     322             :     }
     323           0 :     return false;
     324             : }
     325             : 
     326             : #define DOWNOCTREE(disttoent, earlyexit) \
     327             :         cube *lc = levels[lshift]; \
     328             :         for(;;) \
     329             :         { \
     330             :             lshift--; \
     331             :             lc += OCTA_STEP(x, y, z, lshift); \
     332             :             if(lc->ext && lc->ext->ents && lshift < elvl) \
     333             :             { \
     334             :                 float edist = disttoent(lc->ext->ents, o, ray, dent, mode, t); \
     335             :                 if(edist < dent) \
     336             :                 { \
     337             :                     earlyexit return std::min(edist, dist); \
     338             :                     elvl = lshift; \
     339             :                     dent = std::min(dent, edist); \
     340             :                 } \
     341             :             } \
     342             :             if(lc->children==nullptr) \
     343             :             { \
     344             :                 break; \
     345             :             } \
     346             :             lc = &(*lc->children)[0]; \
     347             :             levels[lshift] = lc; \
     348             :         }
     349             : 
     350           0 : static void findclosest(int &closest, int xval, int yval, int zval, const ivec &lsizemask, const vec &invray, const ivec &lo, const int &lshift, vec &v, float &dist, const vec& ray)
     351             : {
     352           0 :         float dx = (lo.x+(lsizemask.x<<lshift)-v.x)*invray.x,
     353           0 :               dy = (lo.y+(lsizemask.y<<lshift)-v.y)*invray.y,
     354           0 :               dz = (lo.z+(lsizemask.z<<lshift)-v.z)*invray.z;
     355           0 :         float disttonext = dx;
     356           0 :         closest = xval;
     357           0 :         if(dy < disttonext)
     358             :         {
     359           0 :             disttonext = dy;
     360           0 :             closest = yval;
     361             :         }
     362           0 :         if(dz < disttonext)
     363             :         {
     364           0 :             disttonext = dz;
     365           0 :             closest = zval;
     366             :         }
     367           0 :         disttonext += 0.1f;
     368           0 :         v.add(vec(ray).mul(disttonext));
     369           0 :         dist += disttonext;
     370           0 : }
     371             : 
     372           0 : bool cubeworld::upoctree(const vec& v, int& x, int& y, int& z, const ivec& lo, int& lshift) const
     373             : {
     374           0 :     x = static_cast<int>(v.x);
     375           0 :     y = static_cast<int>(v.y);
     376           0 :     z = static_cast<int>(v.z);
     377           0 :     uint diff = static_cast<uint>(lo.x^x)|static_cast<uint>(lo.y^y)|static_cast<uint>(lo.z^z);
     378           0 :     if(diff >= static_cast<uint>(mapsize()))
     379             :     {
     380           0 :         return true;
     381             :     }
     382           0 :     diff >>= lshift;
     383           0 :     if(!diff)
     384             :     {
     385           0 :         return true;
     386             :     }
     387             :     do
     388             :     {
     389           0 :         lshift++;
     390           0 :         diff >>= 1;
     391           0 :     } while(diff);
     392           0 :     return false;
     393             : }
     394             : 
     395           0 : float cubeworld::raycube(const vec &o, const vec &ray, float radius, int mode, int size, const extentity *t) const
     396             : {
     397           0 :     if(ray.iszero())
     398             :     {
     399           0 :         return 0;
     400             :     }
     401           0 :     INITRAYCUBE;
     402             :     //scope limiting brackets
     403             :     {
     404           0 :         float outrad = 0.f;
     405           0 :         if(checkinsideworld(invray, radius, outrad, o, v, ray, dist))
     406             :         {
     407           0 :             return outrad;
     408             :         }
     409             :     }
     410           0 :     int closest = -1,
     411           0 :         x = static_cast<int>(v.x),
     412           0 :         y = static_cast<int>(v.y),
     413           0 :         z = static_cast<int>(v.z);
     414             :     for(;;)
     415             :     {
     416           0 :         DOWNOCTREE(disttoent, if(mode&Ray_Shadow));
     417             : 
     418           0 :         int lsize = 1<<lshift;
     419             : 
     420           0 :         cube &c = *lc;
     421           0 :         if((dist>0 || !(mode&Ray_SkipFirst)) &&
     422           0 :            (((mode&Ray_ClipMat) && IS_CLIPPED(c.material&MatFlag_Volume)) ||
     423           0 :             ((mode&Ray_EditMat) && c.material != Mat_Air) ||
     424           0 :             (!(mode&Ray_Pass) && lsize==size && !(c.isempty())) ||
     425           0 :             c.issolid() ||
     426           0 :             dent < dist) &&
     427           0 :             (!(mode&Ray_ClipMat) || (c.material&MatFlag_Clip)!=Mat_NoClip))
     428             :         {
     429           0 :             if(dist < dent)
     430             :             {
     431           0 :                 if(closest < 0)
     432             :                 {
     433           0 :                     float dx = ((x&(~0U<<lshift))+(invray.x>0 ? 0 : 1<<lshift)-v.x)*invray.x,
     434           0 :                           dy = ((y&(~0U<<lshift))+(invray.y>0 ? 0 : 1<<lshift)-v.y)*invray.y,
     435           0 :                           dz = ((z&(~0U<<lshift))+(invray.z>0 ? 0 : 1<<lshift)-v.z)*invray.z;
     436           0 :                     closest = dx > dy ? (dx > dz ? 0 : 2) : (dy > dz ? 1 : 2);
     437             :                 }
     438           0 :                 hitsurface = vec(0, 0, 0);
     439           0 :                 hitsurface[closest] = ray[closest]>0 ? -1 : 1;
     440           0 :                 return dist;
     441             :             }
     442           0 :             return dent;
     443             :         }
     444             : 
     445           0 :         ivec lo(x&(~0U<<lshift), y&(~0U<<lshift), z&(~0U<<lshift));
     446             : 
     447           0 :         if(!(c.isempty()))
     448             :         {
     449           0 :             const clipplanes &p = getclipplanes(c, lo, lsize);
     450           0 :             float f = 0;
     451           0 :             if(raycubeintersect(p, c, v, ray, invray, dent-dist, f) && (dist+f>0 || !(mode&Ray_SkipFirst)) && (!(mode&Ray_ClipMat) || (c.material&MatFlag_Clip)!=Mat_NoClip))
     452             :             {
     453           0 :                 return std::min(dent, dist+f);
     454             :             }
     455             :         }
     456           0 :         findclosest(closest, 0, 1, 2, lsizemask, invray, lo, lshift, v, dist, ray);
     457           0 :         if(radius>0 && dist>=radius)
     458             :         {
     459           0 :             return std::min(dent, dist);
     460             :         }
     461           0 :         if(upoctree(v, x, y, z, lo, lshift))
     462             :         {
     463           0 :             return std::min(dent, radius>0 ? radius : dist);
     464             :         }
     465           0 :     }
     466             : }
     467             : 
     468             : // optimized version for light shadowing... every cycle here counts!!!
     469           0 : float cubeworld::shadowray(const vec &o, const vec &ray, float radius, int mode, const extentity *t)
     470             : {
     471           0 :     INITRAYCUBE;
     472             :     //scope limiting brackets
     473             :     {
     474           0 :         float outrad = 0.f;
     475           0 :         if(checkinsideworld(invray, radius, outrad, o, v, ray, dist))
     476             :         {
     477           0 :             return outrad;
     478             :         }
     479             :     }
     480           0 :     int side = Orient_Bottom,
     481           0 :         x = static_cast<int>(v.x),
     482           0 :         y = static_cast<int>(v.y),
     483           0 :         z = static_cast<int>(v.z);
     484             :     for(;;)
     485             :     {
     486           0 :         DOWNOCTREE(shadowent, );
     487             : 
     488           0 :         cube &c = *lc;
     489           0 :         ivec lo(x&(~0U<<lshift), y&(~0U<<lshift), z&(~0U<<lshift));
     490             : 
     491           0 :         if(!(c.isempty()) && !(c.material&Mat_Alpha))
     492             :         {
     493           0 :             if(c.issolid())
     494             :             {
     495           0 :                 return c.texture[side]==Default_Sky && mode&Ray_SkipSky ? radius : dist;
     496             :             }
     497           0 :             const clipplanes &p = getclipplanes(c, lo, 1<<lshift);
     498           0 :             float enterdist = -1e16f,
     499           0 :                   exitdist  = 1e16f;
     500           0 :             int i = 0;
     501           0 :             bool intersected = intersectplanes(p, v, ray, enterdist, exitdist, i);
     502           0 :             side = p.side[i];
     503           0 :             if(!intersected)
     504             :             {
     505           0 :                 goto nextcube;
     506             :             }
     507           0 :             intersected = intersectbox(p, v, ray, invray, enterdist, exitdist, i);
     508           0 :             side = (i<<1) + 1 - lsizemask[i];
     509           0 :             if(!intersected)
     510             :             {
     511           0 :                 goto nextcube;
     512             :             }
     513           0 :             if(exitdist >= 0)
     514             :             {
     515           0 :                 return c.texture[side]==Default_Sky && mode&Ray_SkipSky ? radius : dist+std::max(enterdist+0.1f, 0.0f);
     516             :             }
     517             :         }
     518             : 
     519           0 :     nextcube:
     520           0 :         findclosest(side, Orient_Right - lsizemask.x, Orient_Front - lsizemask.y, Orient_Top - lsizemask.z, lsizemask, invray, lo, lshift, v, dist, ray);
     521           0 :         if(dist>=radius)
     522             :         {
     523           0 :             return dist;
     524             :         }
     525           0 :         if(upoctree(v, x, y, z, lo, lshift))
     526             :         {
     527           0 :             return radius;
     528             :         }
     529           0 :     }
     530             : }
     531             : #undef INITRAYCUBE
     532             : #undef DOWNOCTREE
     533             : //==============================================================================
     534           0 : float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int &orient, int &ent)
     535             : {
     536           0 :     hitent = -1;
     537           0 :     hitentdist = radius;
     538           0 :     hitorient = -1;
     539           0 :     float dist = rootworld.raycube(o, ray, radius, mode, size);
     540           0 :     if((mode&Ray_Ents) == Ray_Ents)
     541             :     {
     542           0 :         float dent = disttooutsideent(o, ray, dist < 0 ? 1e16f : dist, mode, nullptr);
     543           0 :         if(dent < 1e15f && (dist < 0 || dent < dist))
     544             :         {
     545           0 :             dist = dent;
     546             :         }
     547             :     }
     548           0 :     orient = hitorient;
     549           0 :     ent = hitentdist == dist ? hitent : -1;
     550           0 :     return dist;
     551             : }
     552             : 
     553           0 : float raycubepos(const vec &o, const vec &ray, vec &hitpos, float radius, int mode, int size)
     554             : {
     555           0 :     hitpos = ray;
     556           0 :     float dist = rootworld.raycube(o, ray, radius, mode, size);
     557           0 :     if(radius>0 && dist>=radius)
     558             :     {
     559           0 :         dist = radius;
     560             :     }
     561           0 :     hitpos.mul(dist).add(o);
     562           0 :     return dist;
     563             : }
     564             : 
     565           0 : bool raycubelos(const vec &o, const vec &dest, vec &hitpos)
     566             : {
     567           0 :     vec ray(dest);
     568           0 :     ray.sub(o);
     569           0 :     float mag = ray.magnitude();
     570           0 :     ray.mul(1/mag);
     571           0 :     float distance = raycubepos(o, ray, hitpos, mag, Ray_ClipMat|Ray_Poly);
     572           0 :     return distance >= mag;
     573             : }
     574             : 
     575           0 : float rayfloor(const vec &o, vec &floor, int mode, float radius)
     576             : {
     577           0 :     if(o.z<=0)
     578             :     {
     579           0 :         return -1;
     580             :     }
     581           0 :     hitsurface = vec(0, 0, 1);
     582           0 :     float dist = rootworld.raycube(o, vec(0, 0, -1), radius, mode);
     583           0 :     if(dist<0 || (radius>0 && dist>=radius))
     584             :     {
     585           0 :         return dist;
     586             :     }
     587           0 :     floor = hitsurface;
     588           0 :     return dist;
     589             : }

Generated by: LCOV version 1.14