LCOV - code coverage report
Current view: top level - engine/world - raycube.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 0.0 % 288 0
Test Date: 2026-06-16 06:16:16 Functions: 0.0 % 19 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 :     const 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            0 :     bool intersectplanes(const clipplanes& p, const vec &v, const vec& ray, float &enterdist, float &exitdist, int &entry)
      37              :     {
      38            0 :         for(int i = 0; i < p.size; ++i)
      39              :         {
      40            0 :             float pdist = p.p[i].dist(v),
      41            0 :                   facing = ray.dot(p.p[i]);
      42            0 :             if(facing < 0)
      43              :             {
      44            0 :                 pdist /= -facing;
      45            0 :                 if(pdist > enterdist)
      46              :                 {
      47            0 :                     if(pdist > exitdist)
      48              :                     {
      49            0 :                         return false;
      50              :                     }
      51            0 :                     enterdist = pdist;
      52            0 :                     entry = i;
      53              :                 }
      54              :             }
      55            0 :             else if(facing > 0)
      56              :             {
      57            0 :                 pdist /= -facing;
      58            0 :                 if(pdist < exitdist)
      59              :                 {
      60            0 :                     if(pdist < enterdist)
      61              :                     {
      62            0 :                         return false;
      63              :                     }
      64            0 :                     exitdist = pdist;
      65              :                 }
      66              :             }
      67            0 :             else if(pdist > 0)
      68              :             {
      69            0 :                 return false;
      70              :             }
      71              :         }
      72            0 :         return true;
      73              :     }
      74              : 
      75            0 :     bool intersectbox(const clipplanes& p, const vec &v, const vec& ray, const vec& invray, float &enterdist, float &exitdist, int &entry)
      76              :     {
      77            0 :         for(int i = 0; i < 3; ++i)
      78              :         {
      79            0 :             if(ray[i])
      80              :             {
      81            0 :                 float prad = std::fabs(p.r[i] * invray[i]),
      82            0 :                       pdist = (p.o[i] - v[i]) * invray[i],
      83            0 :                       pmin = pdist - prad,
      84            0 :                       pmax = pdist + prad;
      85            0 :                 if(pmin > enterdist)
      86              :                 {
      87            0 :                     if(pmin > exitdist)
      88              :                     {
      89            0 :                         return false;
      90              :                     }
      91            0 :                     enterdist = pmin;
      92            0 :                     entry = i;
      93              :                 }
      94            0 :                 if(pmax < exitdist)
      95              :                 {
      96            0 :                     if(pmax < enterdist)
      97              :                     {
      98            0 :                         return false;
      99              :                     }
     100            0 :                     exitdist = pmax;
     101              :                 }
     102              :             }
     103            0 :             else if(v[i] < p.o[i]-p.r[i] || v[i] > p.o[i]+p.r[i])
     104              :             {
     105            0 :                 return false;
     106              :             }
     107              :         }
     108            0 :         return true;
     109              :     }
     110              : 
     111            0 :     bool raycubeintersect(const clipplanes &p, const vec &v, const vec &ray, const vec &invray, float maxdist, float &dist)
     112              :     {
     113            0 :         int entry   = -1,
     114            0 :             bbentry = -1;
     115            0 :         float enterdist = -1e16f,
     116            0 :               exitdist  = 1e16f;
     117            0 :         if(!intersectplanes(p, v, ray, enterdist, exitdist, entry))
     118              :         {
     119            0 :             return false;
     120              :         }
     121            0 :         if(!intersectbox(p, v, ray, invray, enterdist, exitdist, bbentry))
     122              :         {
     123            0 :             return false;
     124              :         }
     125            0 :         if(exitdist < 0)
     126              :         {
     127            0 :             return false;
     128              :         }
     129            0 :         dist = std::max(enterdist+0.1f, 0.0f);
     130            0 :         if(dist < maxdist)
     131              :         {
     132            0 :             if(bbentry>=0)
     133              :             {
     134            0 :                 hitsurface = vec(0, 0, 0);
     135            0 :                 hitsurface[bbentry] = ray[bbentry]>0 ? -1 : 1;
     136              :             }
     137              :             else
     138              :             {
     139            0 :                 hitsurface = p.p[entry];
     140              :             }
     141              :         }
     142            0 :         return true;
     143              :     }
     144              : 
     145              :     float hitentdist;
     146              :     int hitent, hitorient;
     147              : 
     148            0 :     float disttoent(const octaentities *oc, const vec &o, const vec &ray, float radius, int mode, const extentity *t)
     149              :     {
     150            0 :         vec eo, es;
     151            0 :         int orient = -1;
     152            0 :         float dist = radius,
     153            0 :               f = 0.0f;
     154            0 :         const std::vector<extentity *> &ents = entities::getents();
     155              :     //=======ENT_SEL_INTERSECT ENT_INTERSECT
     156              :         #define ENT_INTERSECT(type, func) do { \
     157              :             for(size_t i = 0; i < oc->type.size(); i++) \
     158              :             { \
     159              :                 extentity &e = *ents[oc->type[i]]; \
     160              :                 if(!(e.flags&EntFlag_Octa) || &e==t) \
     161              :                 { \
     162              :                     continue; \
     163              :                 } \
     164              :                 func; \
     165              :                 if(f < dist && f > 0 && vec(ray).mul(f).add(o).insidebb(oc->o, oc->size)) \
     166              :                 { \
     167              :                     hitentdist = dist = f; \
     168              :                     hitent = oc->type[i]; \
     169              :                     hitorient = orient; \
     170              :                 } \
     171              :             } \
     172              :         } while(0)
     173              : 
     174            0 :         if((mode&Ray_Poly) == Ray_Poly)
     175              :         {
     176            0 :             ENT_INTERSECT(mapmodels,
     177              :             {
     178              :                 if(!mmintersect(e, o, ray, radius, mode, f))
     179              :                 {
     180              :                     continue;
     181              :                 }
     182              :             });
     183              :         }
     184              : 
     185              :         #define ENT_SEL_INTERSECT(type) ENT_INTERSECT(type, { \
     186              :             entselectionbox(e, eo, es); \
     187              :             if(!rayboxintersect(eo, es, o, ray, f, orient)) \
     188              :             { \
     189              :                 continue; \
     190              :             } \
     191              :         })
     192              : 
     193            0 :         if((mode&Ray_Ents) == Ray_Ents)
     194              :         {
     195            0 :             ENT_SEL_INTERSECT(other);
     196            0 :             ENT_SEL_INTERSECT(mapmodels);
     197            0 :             ENT_SEL_INTERSECT(decals);
     198              :         }
     199              : 
     200            0 :         return dist;
     201              :     }
     202              :     #undef ENT_INTERSECT
     203              :     #undef ENT_SEL_INTERSECT
     204              :     //======================================
     205            0 :     float disttooutsideent(const vec &o, const vec &ray, float radius, const extentity *t)
     206              :     {
     207            0 :         vec eo, es;
     208              :         int orient;
     209            0 :         float dist = radius,
     210            0 :               f = 0.0f;
     211            0 :         const std::vector<extentity *> &ents = entities::getents();
     212            0 :         for(const int &i : outsideents)
     213              :         {
     214            0 :             const extentity &e = *ents[i];
     215            0 :             if(!(e.flags&EntFlag_Octa) || &e == t)
     216              :             {
     217            0 :                 continue;
     218              :             }
     219            0 :             entselectionbox(e, eo, es);
     220            0 :             if(!rayboxintersect(eo, es, o, ray, f, orient))
     221              :             {
     222            0 :                 continue;
     223              :             }
     224            0 :             if(f < dist && f > 0)
     225              :             {
     226            0 :                 hitentdist = dist = f;
     227            0 :                 hitent = outsideents[i];
     228            0 :                 hitorient = orient;
     229              :             }
     230              :         }
     231            0 :         return dist;
     232              :     }
     233              : 
     234              :     // optimized shadow version
     235              :     /**
     236              :      * @brief Shadow optimized entity distance check
     237              :      *
     238              :      * @param oc octaentities object containing list of ent indices to use
     239              :      * @param o intersect start location
     240              :      * @param ray intersect ray direction
     241              :      * @param radius maximum radius
     242              :      * @param mode type of intersection to use (not necessarily Ray_Shadow)
     243              :      * @param t entity to exclude checking (e.g. self)
     244              :      *
     245              :      * @return distance to entity, or radius if distance out of bounds or no intersection
     246              :      */
     247            0 :     float shadowent(const octaentities *oc, const vec &o, const vec &ray, float radius, int mode, const extentity *t)
     248              :     {
     249            0 :         float dist = radius,
     250            0 :               f = 0.0f;
     251            0 :         const std::vector<extentity *> &ents = entities::getents();
     252            0 :         for(const int &i : oc->mapmodels)
     253              :         {
     254            0 :             const extentity &e = *ents[i];
     255            0 :             if(!(e.flags&EntFlag_Octa) || &e==t)
     256              :             {
     257            0 :                 continue;
     258              :             }
     259            0 :             if(!mmintersect(e, o, ray, radius, mode, f))
     260              :             {
     261            0 :                 continue;
     262              :             }
     263            0 :             if(f > 0 && f < dist)
     264              :             {
     265            0 :                 dist = f;
     266              :             }
     267              :         }
     268            0 :         return dist;
     269              :     }
     270              : 
     271              :     /**
     272              :      * @brief Finds the closest value and returns it to ref parameters
     273              :      *
     274              :      * @param xval value to return if dx is smallest
     275              :      * @param yval value to return if dy is smallest
     276              :      * @param zval value to return if dz is smallest
     277              :      * @param lsizemask scale mask to shift
     278              :      * @param invray inverse of the ray to track (elementwise inverse)
     279              :      * @param lo origin of the coordinates
     280              :      * @param lshift shift factor for the sizemask
     281              :      * @param v returns sum of itself and ray scaled to dist value
     282              :      * @param dist returns sum of itself and whichever of dx/dy/dz returned
     283              :      * @param ray direction of value to add to v
     284              :      *
     285              :      * @return closest returns closest of xval, yval, zval
     286              :      */
     287            0 :     int findclosest(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)
     288              :     {
     289            0 :         float dx = (lo.x+(lsizemask.x<<lshift)-v.x)*invray.x,
     290            0 :               dy = (lo.y+(lsizemask.y<<lshift)-v.y)*invray.y,
     291            0 :               dz = (lo.z+(lsizemask.z<<lshift)-v.z)*invray.z;
     292            0 :         float disttonext = dx;
     293            0 :         int closest = xval;
     294            0 :         if(dy < disttonext)
     295              :         {
     296            0 :             disttonext = dy;
     297            0 :             closest = yval;
     298              :         }
     299            0 :         if(dz < disttonext)
     300              :         {
     301            0 :             disttonext = dz;
     302            0 :             closest = zval;
     303              :         }
     304            0 :         disttonext += 0.1f;
     305            0 :         v.add(vec(ray).mul(disttonext));
     306            0 :         dist += disttonext;
     307            0 :         return closest;
     308              :     }
     309              : }
     310              : 
     311              : //externally relevant functionality
     312            0 : bool insideworld(const vec &o)
     313              : {
     314            0 :     return o.x>=0 && o.x<rootworld.mapsize() && o.y>=0 && o.y<rootworld.mapsize() && o.z>=0 && o.z<rootworld.mapsize();
     315              : }
     316              : 
     317            0 : bool insideworld(const ivec &o)
     318              : {
     319            0 :     return static_cast<uint>(o.x) < static_cast<uint>(rootworld.mapsize()) &&
     320            0 :            static_cast<uint>(o.y) < static_cast<uint>(rootworld.mapsize()) &&
     321            0 :            static_cast<uint>(o.z) < static_cast<uint>(rootworld.mapsize());
     322              : }
     323              : 
     324              : vec hitsurface;
     325              : 
     326              : //will only change &outrad and &dist if not inside the world
     327              : //true if outside world, false if inside
     328            0 : bool cubeworld::checkinsideworld(const vec &invray, float radius, float &outrad, const vec &o, vec &v, const vec& ray, float &dist) const
     329              : {
     330            0 :     if(!insideworld(o))
     331              :     {
     332            0 :         float disttoworld = 0,
     333            0 :               exitworld = 1e16f;
     334            0 :         for(int i = 0; i < 3; ++i)
     335              :         {
     336            0 :             float c = v[i];
     337            0 :             if(c<0 || c>=mapsize())
     338              :             {
     339            0 :                 float d = ((invray[i]>0?0:mapsize())-c)*invray[i];
     340            0 :                 if(d<0)
     341              :                 {
     342            0 :                     outrad =  radius>0 ? radius :-1;
     343            0 :                     return true;
     344              :                 }
     345            0 :                 disttoworld = std::max(disttoworld, 0.1f + d);
     346              :             }
     347            0 :             float e = ((invray[i]>0?mapsize():0)-c)*invray[i];
     348            0 :             exitworld = std::min(exitworld, e);
     349              :         }
     350            0 :         if(disttoworld > exitworld)
     351              :         {
     352            0 :             outrad = (radius>0?radius:-1);
     353            0 :             return true;
     354              :         }
     355            0 :         v.add(vec(ray).mul(disttoworld));
     356            0 :         dist += disttoworld;
     357              :     }
     358            0 :     return false;
     359              : }
     360              : 
     361            0 : bool cubeworld::upoctree(const vec &v, int &x, int &y, int &z, const ivec &lo, int &lshift) const
     362              : {
     363            0 :     x = static_cast<int>(v.x);
     364            0 :     y = static_cast<int>(v.y);
     365            0 :     z = static_cast<int>(v.z);
     366            0 :     uint diff = static_cast<uint>(lo.x^x)|static_cast<uint>(lo.y^y)|static_cast<uint>(lo.z^z);
     367            0 :     if(diff >= static_cast<uint>(mapsize()))
     368              :     {
     369            0 :         return true;
     370              :     }
     371            0 :     diff >>= lshift;
     372            0 :     if(!diff)
     373              :     {
     374            0 :         return true;
     375              :     }
     376              :     do
     377              :     {
     378            0 :         lshift++;
     379            0 :         diff >>= 1;
     380            0 :     } while(diff);
     381            0 :     return false;
     382              : }
     383              : 
     384              : //=================================================================== DOWNOCTREE
     385              : 
     386              : #define DOWNOCTREE(disttoent, earlyexit) \
     387              :         cube *lc = r.levels[r.lshift]; \
     388              :         for(;;) \
     389              :         { \
     390              :             r.lshift--; \
     391              :             lc += OCTA_STEP(x, y, z, r.lshift); \
     392              :             if(lc->ext && lc->ext->ents && r.lshift < r.elvl) \
     393              :             { \
     394              :                 float edist = disttoent(lc->ext->ents, o, ray, r.dent, mode, t); \
     395              :                 if(edist < r.dent) \
     396              :                 { \
     397              :                     earlyexit return std::min(edist, r.dist); \
     398              :                     r.elvl = r.lshift; \
     399              :                     r.dent = std::min(r.dent, edist); \
     400              :                 } \
     401              :             } \
     402              :             if(lc->children==nullptr) \
     403              :             { \
     404              :                 break; \
     405              :             } \
     406              :             lc = &(*lc->children)[0]; \
     407              :             r.levels[r.lshift] = lc; \
     408              :         }
     409              : 
     410              : struct raycubeinfo final
     411              : {
     412              :     float dist,
     413              :           dent;
     414              :     vec v,
     415              :         invray;
     416              :     std::array<cube *, 20> levels; //NOTE: levels[20] magically assumes mapscale <20
     417              :     int lshift,
     418              :         elvl;
     419              :     ivec lsizemask;
     420              : 
     421            0 :     raycubeinfo(float radius, const vec &o, const vec &ray, int worldscale, int mode, cube *r)
     422            0 :     {
     423            0 :         dist = 0;
     424            0 :         dent = radius > 0 ? radius : 1e16f;
     425            0 :         v = o;
     426            0 :         invray = vec(ray.x ? 1/ray.x : 1e16f, ray.y ? 1/ray.y : 1e16f, ray.z ? 1/ray.z : 1e16f);
     427            0 :         levels[worldscale] = r;
     428            0 :         lshift = worldscale;
     429            0 :         elvl = mode&Ray_BB ? worldscale : 0;
     430            0 :         lsizemask = ivec(invray.x>0 ? 1 : 0, invray.y>0 ? 1 : 0, invray.z>0 ? 1 : 0);
     431            0 :     }
     432              : };
     433              : 
     434            0 : float cubeworld::raycube(const vec &o, const vec &ray, float radius, int mode, int size, const extentity *t) const
     435              : {
     436            0 :     if(ray.iszero())
     437              :     {
     438            0 :         return 0;
     439              :     }
     440            0 :     raycubeinfo r(radius, o, ray, worldscale, mode, &(*worldroot)[0]);
     441              :     //scope limiting brackets
     442              :     {
     443            0 :         float outrad = 0.f;
     444            0 :         if(checkinsideworld(r.invray, radius, outrad, o, r.v, ray, r.dist))
     445              :         {
     446            0 :             return outrad;
     447              :         }
     448              :     }
     449            0 :     int closest = -1,
     450            0 :         x = static_cast<int>(r.v.x),
     451            0 :         y = static_cast<int>(r.v.y),
     452            0 :         z = static_cast<int>(r.v.z);
     453              :     for(;;)
     454              :     {
     455            0 :         DOWNOCTREE(disttoent, if(mode&Ray_Shadow));
     456              : 
     457            0 :         int lsize = 1<<r.lshift;
     458              : 
     459            0 :         const cube &c = *lc;
     460            0 :         if((r.dist>0 || !(mode&Ray_SkipFirst)) &&
     461            0 :            (((mode&Ray_ClipMat) && IS_CLIPPED(c.material&MatFlag_Volume)) ||
     462            0 :             ((mode&Ray_EditMat) && c.material != Mat_Air) ||
     463            0 :             (!(mode&Ray_Pass) && lsize==size && !(c.isempty())) ||
     464            0 :             c.issolid() ||
     465            0 :             r.dent < r.dist) &&
     466            0 :             (!(mode&Ray_ClipMat) || (c.material&MatFlag_Clip)!=Mat_NoClip))
     467              :         {
     468            0 :             if(r.dist < r.dent)
     469              :             {
     470            0 :                 if(closest < 0)
     471              :                 {
     472            0 :                     float dx = ((x&(~0U<<r.lshift))+(r.invray.x>0 ? 0 : 1<<r.lshift)-r.v.x)*r.invray.x,
     473            0 :                           dy = ((y&(~0U<<r.lshift))+(r.invray.y>0 ? 0 : 1<<r.lshift)-r.v.y)*r.invray.y,
     474            0 :                           dz = ((z&(~0U<<r.lshift))+(r.invray.z>0 ? 0 : 1<<r.lshift)-r.v.z)*r.invray.z;
     475            0 :                     closest = dx > dy ? (dx > dz ? 0 : 2) : (dy > dz ? 1 : 2);
     476              :                 }
     477            0 :                 hitsurface = vec(0, 0, 0);
     478            0 :                 hitsurface[closest] = ray[closest]>0 ? -1 : 1;
     479            0 :                 return r.dist;
     480              :             }
     481            0 :             return r.dent;
     482              :         }
     483              : 
     484            0 :         const ivec lo(x&(~0U<<r.lshift), y&(~0U<<r.lshift), z&(~0U<<r.lshift));
     485              : 
     486            0 :         if(!(c.isempty()))
     487              :         {
     488            0 :             const clipplanes &p = getclipplanes(c, lo, lsize);
     489            0 :             float f = 0;
     490            0 :             if(raycubeintersect(p, r.v, ray, r.invray, r.dent-r.dist, f) && (r.dist+f>0 || !(mode&Ray_SkipFirst)) && (!(mode&Ray_ClipMat) || (c.material&MatFlag_Clip)!=Mat_NoClip))
     491              :             {
     492            0 :                 return std::min(r.dent, r.dist+f);
     493              :             }
     494              :         }
     495            0 :         closest = findclosest(0, 1, 2, r.lsizemask, r.invray, lo, r.lshift, r.v, r.dist, ray);
     496            0 :         if(radius>0 && r.dist>=radius)
     497              :         {
     498            0 :             return std::min(r.dent, r.dist);
     499              :         }
     500            0 :         if(upoctree(r.v, x, y, z, lo, r.lshift))
     501              :         {
     502            0 :             return std::min(r.dent, radius>0 ? radius : r.dist);
     503              :         }
     504            0 :     }
     505              : }
     506              : 
     507              : // optimized version for light shadowing... every cycle here counts!!!
     508            0 : float cubeworld::shadowray(const vec &o, const vec &ray, float radius, int mode, const extentity *t)
     509              : {
     510            0 :     raycubeinfo r(radius, o, ray, worldscale, mode, &(*worldroot)[0]);
     511              :     //scope limiting brackets
     512              :     {
     513            0 :         float outrad = 0.f;
     514            0 :         if(checkinsideworld(r.invray, radius, outrad, o, r.v, ray, r.dist))
     515              :         {
     516            0 :             return outrad;
     517              :         }
     518              :     }
     519            0 :     int side = Orient_Bottom,
     520            0 :         x = static_cast<int>(r.v.x),
     521            0 :         y = static_cast<int>(r.v.y),
     522            0 :         z = static_cast<int>(r.v.z);
     523              :     for(;;)
     524              :     {
     525            0 :         DOWNOCTREE(shadowent, );
     526              : 
     527            0 :         const cube &c = *lc;
     528            0 :         ivec lo(x&(~0U<<r.lshift),
     529            0 :              y&(~0U<<r.lshift),
     530            0 :              z&(~0U<<r.lshift));
     531              : 
     532            0 :         if(!(c.isempty()) && !(c.material&Mat_Alpha))
     533              :         {
     534            0 :             if(c.issolid())
     535              :             {
     536            0 :                 return c.texture[side]==Default_Sky && mode&Ray_SkipSky ? radius : r.dist;
     537              :             }
     538            0 :             const clipplanes &p = getclipplanes(c, lo, 1<<r.lshift);
     539            0 :             float enterdist = -1e16f,
     540            0 :                   exitdist  = 1e16f;
     541            0 :             int i = 0;
     542            0 :             bool intersected = intersectplanes(p, r.v, ray, enterdist, exitdist, i);
     543            0 :             side = p.side[i];
     544            0 :             if(!intersected)
     545              :             {
     546            0 :                 goto nextcube;
     547              :             }
     548            0 :             intersected = intersectbox(p, r.v, ray, r.invray, enterdist, exitdist, i);
     549            0 :             side = (i<<1) + 1 - r.lsizemask[i];
     550            0 :             if(!intersected)
     551              :             {
     552            0 :                 goto nextcube;
     553              :             }
     554            0 :             if(exitdist >= 0)
     555              :             {
     556            0 :                 return c.texture[side]==Default_Sky && mode&Ray_SkipSky ? radius : r.dist+std::max(enterdist+0.1f, 0.0f);
     557              :             }
     558              :         }
     559              : 
     560            0 :     nextcube:
     561            0 :         side = findclosest(Orient_Right - r.lsizemask.x, Orient_Front - r.lsizemask.y, Orient_Top - r.lsizemask.z, r.lsizemask, r.invray, lo, r.lshift, r.v, r.dist, ray);
     562            0 :         if(r.dist>=radius)
     563              :         {
     564            0 :             return r.dist;
     565              :         }
     566            0 :         if(upoctree(r.v, x, y, z, lo, r.lshift))
     567              :         {
     568            0 :             return radius;
     569              :         }
     570            0 :     }
     571              : }
     572              : #undef DOWNOCTREE
     573              : //==============================================================================
     574            0 : float rayent(const vec &o, const vec &ray, float radius, int mode, int size, int &orient, int &ent)
     575              : {
     576            0 :     hitent = -1;
     577            0 :     hitentdist = radius;
     578            0 :     hitorient = -1;
     579            0 :     float dist = rootworld.raycube(o, ray, radius, mode, size);
     580            0 :     if((mode&Ray_Ents) == Ray_Ents)
     581              :     {
     582            0 :         float dent = disttooutsideent(o, ray, dist < 0 ? 1e16f : dist, nullptr);
     583            0 :         if(dent < 1e15f && (dist < 0 || dent < dist))
     584              :         {
     585            0 :             dist = dent;
     586              :         }
     587              :     }
     588            0 :     orient = hitorient;
     589            0 :     ent = hitentdist == dist ? hitent : -1;
     590            0 :     return dist;
     591              : }
     592              : 
     593            0 : float raycubepos(const vec &o, const vec &ray, vec &hitpos, float radius, int mode, int size)
     594              : {
     595            0 :     hitpos = ray;
     596            0 :     float dist = rootworld.raycube(o, ray, radius, mode, size);
     597            0 :     if(radius>0 && dist>=radius)
     598              :     {
     599            0 :         dist = radius;
     600              :     }
     601            0 :     hitpos.mul(dist).add(o);
     602            0 :     return dist;
     603              : }
     604              : 
     605            0 : bool raycubelos(const vec &o, const vec &dest, vec &hitpos)
     606              : {
     607            0 :     vec ray(dest);
     608            0 :     ray.sub(o);
     609            0 :     float mag = ray.magnitude();
     610            0 :     ray.mul(1/mag);
     611            0 :     float distance = raycubepos(o, ray, hitpos, mag, Ray_ClipMat|Ray_Poly);
     612            0 :     return distance >= mag;
     613              : }
     614              : 
     615            0 : float rayfloor(const vec &o, vec &floor, int mode, float radius)
     616              : {
     617            0 :     if(o.z<=0)
     618              :     {
     619            0 :         return -1;
     620              :     }
     621            0 :     hitsurface = vec(0, 0, 1);
     622            0 :     float dist = rootworld.raycube(o, vec(0, 0, -1), radius, mode);
     623            0 :     if(dist<0 || (radius>0 && dist>=radius))
     624              :     {
     625            0 :         return dist;
     626              :     }
     627            0 :     floor = hitsurface;
     628            0 :     return dist;
     629              : }
        

Generated by: LCOV version 2.0-1