LCOV - code coverage report
Current view: top level - engine/world - mpr.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 36.6 % 164 60
Test Date: 2026-06-16 06:16:16 Functions: 71.4 % 35 25

            Line data    Source code
       1              : /*This code is based off the Minkowski Portal Refinement algorithm by Gary Snethen
       2              :  * in XenoCollide & Game Programming Gems 7.
       3              :  *
       4              :  * Minkowski Portal Refinement is a way of finding whether two hulls intersect
       5              :  * efficiently, useful for finding if two models are intersecting quickly
       6              :  *
       7              :  * used in physics.cpp and for model-related collision purposes
       8              :  */
       9              : #include "../libprimis-headers/cube.h"
      10              : #include "../../shared/geomexts.h"
      11              : 
      12              : #include "octaworld.h"
      13              : 
      14              : #include "mpr.h"
      15              : 
      16              : namespace mpr
      17              : {
      18              : 
      19              :     //CubePlanes
      20              : 
      21            1 :     vec CubePlanes::center() const
      22              :     {
      23            1 :         return p.o;
      24              :     }
      25              : 
      26            3 :     vec CubePlanes::supportpoint(const vec &n) const
      27              :     {
      28            3 :         int besti = 7;
      29            3 :         float bestd = n.dot(p.v[7]);
      30           24 :         for(int i = 0; i < 7; ++i)
      31              :         {
      32           21 :             float d = n.dot(p.v[i]);
      33           21 :             if(d > bestd)
      34              :             {
      35            3 :                 besti = i;
      36            3 :                 bestd = d;
      37              :             }
      38              :         }
      39            3 :         return p.v[besti];
      40              :     }
      41              : 
      42              :     //SolidCube
      43              : 
      44            2 :     vec SolidCube::center() const
      45              :     {
      46            2 :         return vec(o).add(size/2);
      47              :     }
      48              : 
      49            3 :     vec SolidCube::supportpoint (const vec &n) const
      50              :     {
      51            3 :         vec p(o);
      52            3 :         if(n.x > 0)
      53              :         {
      54            2 :             p.x += size;
      55              :         }
      56            3 :         if(n.y > 0)
      57              :         {
      58            3 :             p.y += size;
      59              :         }
      60            3 :         if(n.z > 0)
      61              :         {
      62            3 :             p.z += size;
      63              :         }
      64            3 :         return p;
      65              :     }
      66              : 
      67              :     //Ent
      68              : 
      69            3 :     vec Ent::center() const
      70              :     {
      71            3 :         return vec(ent->o.x, ent->o.y, ent->o.z + (ent->aboveeye - ent->eyeheight)/2);
      72              :     }
      73              : 
      74              :     //EntOBB
      75              : 
      76            7 :     EntOBB::EntOBB(const physent *ent) : Ent(ent)
      77              :     {
      78            7 :         orient.setyaw(ent->yaw/RAD);
      79            7 :     }
      80              : 
      81            0 :     vec EntOBB::contactface(const vec &wn, const vec &wdir) const
      82              :     {
      83            0 :         vec n = orient.transform(wn).div(vec(ent->xradius, ent->yradius, (ent->aboveeye + ent->eyeheight)/2)),
      84            0 :             dir = orient.transform(wdir),
      85            0 :             an(std::fabs(n.x), std::fabs(n.y), dir.z ? std::fabs(n.z) : 0),
      86            0 :             fn(0, 0, 0);
      87            0 :         if(an.x > an.y)
      88              :         {
      89            0 :             if(an.x > an.z)
      90              :             {
      91            0 :                 fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
      92              :             }
      93            0 :             else if(an.z > 0)
      94              :             {
      95            0 :                 fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
      96              :             }
      97              :         }
      98            0 :         else if(an.y > an.z)
      99              :         {
     100            0 :             fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
     101              :         }
     102            0 :         else if(an.z > 0)
     103              :         {
     104            0 :             fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     105              :         }
     106            0 :         return orient.transposedtransform(fn);
     107              :     }
     108              : 
     109            9 :     vec EntOBB::localsupportpoint(const vec &ln) const
     110              :     {
     111            9 :         return vec(ln.x > 0 ? ent->xradius : -ent->xradius,
     112            9 :                    ln.y > 0 ? ent->yradius : -ent->yradius,
     113           18 :                    ln.z > 0 ? ent->aboveeye : -ent->eyeheight);
     114              :     }
     115              : 
     116            1 :     vec EntOBB::supportpoint(const vec &n) const
     117              :     {
     118            1 :         return orient.transposedtransform(localsupportpoint(orient.transform(n))).add(ent->o);
     119              :     }
     120              : 
     121            4 :     float EntOBB::supportcoordneg(const vec &p) const
     122              :     {
     123            4 :         return localsupportpoint(vec(p).neg()).dot(p);
     124              :     }
     125              : 
     126            4 :     float EntOBB::supportcoord(const vec &p) const
     127              :     {
     128            4 :         return localsupportpoint(p).dot(p);
     129              :     }
     130              : 
     131            2 :     float EntOBB::left()   const { return supportcoordneg(orient.a) + ent->o.x; }
     132            2 :     float EntOBB::right()  const { return supportcoord(orient.a) + ent->o.x; }
     133            2 :     float EntOBB::back()   const { return supportcoordneg(orient.b) + ent->o.y; }
     134            2 :     float EntOBB::front()  const { return supportcoord(orient.b) + ent->o.y; }
     135            1 :     float EntOBB::bottom() const { return ent->o.z - ent->eyeheight; }
     136            1 :     float EntOBB::top()    const { return ent->o.z + ent->aboveeye; }
     137              : 
     138              :     //EntFuzzy
     139              : 
     140            1 :     float EntFuzzy::left()   const { return ent->o.x - ent->radius; }
     141            1 :     float EntFuzzy::right()  const { return ent->o.x + ent->radius; }
     142            1 :     float EntFuzzy::back()   const { return ent->o.y - ent->radius; }
     143            1 :     float EntFuzzy::front()  const { return ent->o.y + ent->radius; }
     144            2 :     float EntFuzzy::bottom() const { return ent->o.z - ent->eyeheight; }
     145            2 :     float EntFuzzy::top()    const { return ent->o.z + ent->aboveeye; }
     146              : 
     147              :     //EntCylinder
     148              : 
     149            0 :     vec EntCylinder::contactface(const vec &n, const vec &dir) const
     150              :     {
     151            0 :         float dxy = n.dot2(n)/(ent->radius*ent->radius),
     152            0 :               dz = n.z*n.z*4/(ent->aboveeye + ent->eyeheight);
     153            0 :         vec fn(0, 0, 0);
     154            0 :         if(dz > dxy && dir.z)
     155              :         {
     156            0 :             fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     157              :         }
     158            0 :         else if(n.dot2(dir) < 0)
     159              :         {
     160            0 :             fn.x = n.x;
     161            0 :             fn.y = n.y;
     162            0 :             fn.normalize();
     163              :         }
     164            0 :         return fn;
     165              :     }
     166              : 
     167            0 :     vec EntCylinder::supportpoint(const vec &n) const
     168              :     {
     169            0 :         vec p(ent->o);
     170            0 :         if(n.z > 0)
     171              :         {
     172            0 :             p.z += ent->aboveeye;
     173              :         }
     174              :         else
     175              :         {
     176            0 :             p.z -= ent->eyeheight;
     177              :         }
     178            0 :         if(n.x || n.y)
     179              :         {
     180            0 :             float r = ent->radius / n.magnitude2();
     181            0 :             p.x += n.x*r;
     182            0 :             p.y += n.y*r;
     183              :         }
     184            0 :         return p;
     185              :     }
     186              : 
     187              :     //EntCapsule
     188              : 
     189            0 :     vec EntCapsule::supportpoint(const vec &n) const
     190              :     {
     191            0 :         vec p(ent->o);
     192            0 :         if(n.z > 0)
     193              :         {
     194            0 :             p.z += ent->aboveeye - ent->radius;
     195              :         }
     196              :         else
     197              :         {
     198            0 :             p.z -= ent->eyeheight - ent->radius;
     199              :         }
     200            0 :         p.add(vec(n).mul(ent->radius / n.magnitude()));
     201            0 :         return p;
     202              :     }
     203              : 
     204              :     //EntEllipsoid
     205              : 
     206            0 :     vec EntEllipsoid::supportpoint(const vec &dir) const
     207              :     {
     208            0 :         vec p(ent->o),
     209            0 :             n = vec(dir).normalize();
     210            0 :         p.x += ent->radius*n.x;
     211            0 :         p.y += ent->radius*n.y;
     212            0 :         p.z += (ent->aboveeye + ent->eyeheight)/2*(1 + n.z) - ent->eyeheight;
     213            0 :         return p;
     214              :     }
     215              : 
     216              :     //Model
     217            3 :     Model::~Model() {}
     218              : 
     219            3 :     Model::Model(const vec &ent, const vec &center, const vec &radius, int yaw, int pitch, int roll) : o(ent), radius(radius)
     220              :     {
     221            3 :         orient.identity();
     222            3 :         if(roll)
     223              :         {
     224            0 :             orient.rotate_around_y(sincosmod360(roll));
     225              :         }
     226            3 :         if(pitch)
     227              :         {
     228            0 :             orient.rotate_around_x(sincosmod360(-pitch));
     229              :         }
     230            3 :         if(yaw)
     231              :         {
     232            1 :             orient.rotate_around_z(sincosmod360(-yaw));
     233              :         }
     234            3 :         o.add(orient.transposedtransform(center));
     235            3 :     }
     236              : 
     237            1 :     vec Model::center() const
     238              :     {
     239            1 :         return o;
     240              :     }
     241              : 
     242              :     //ModelOBB
     243              : 
     244            0 :     vec ModelOBB::contactface(const vec &wn, const vec &wdir) const
     245              :     {
     246            0 :         vec n = orient.transform(wn).div(radius),
     247            0 :             dir = orient.transform(wdir),
     248            0 :             an(std::fabs(n.x), std::fabs(n.y), dir.z ? std::fabs(n.z) : 0),
     249            0 :             fn(0, 0, 0);
     250            0 :         if(an.x > an.y)
     251              :         {
     252            0 :             if(an.x > an.z)
     253              :             {
     254            0 :                 fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
     255              :             }
     256            0 :             else if(an.z > 0)
     257              :             {
     258            0 :                 fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     259              :             }
     260              :         }
     261            0 :         else if(an.y > an.z)
     262              :         {
     263            0 :             fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
     264              :         }
     265            0 :         else if(an.z > 0)
     266              :         {
     267            0 :             fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     268              :         }
     269            0 :         return orient.transposedtransform(fn);
     270              :     }
     271              : 
     272            0 :     vec ModelOBB::supportpoint(const vec &n) const
     273              :     {
     274            0 :         vec ln = orient.transform(n),
     275            0 :             p(0, 0, 0);
     276            0 :         if(ln.x > 0)
     277              :         {
     278            0 :             p.x += radius.x;
     279              :         }
     280              :         else
     281              :         {
     282            0 :             p.x -= radius.x;
     283              :         }
     284            0 :         if(ln.y > 0)
     285              :         {
     286            0 :             p.y += radius.y;
     287              :         }
     288              :         else
     289              :         {
     290            0 :             p.y -= radius.y;
     291              :         }
     292            0 :         if(ln.z > 0)
     293              :         {
     294            0 :             p.z += radius.z;
     295              :         }
     296              :         else
     297              :         {
     298            0 :             p.z -= radius.z;
     299              :         }
     300            0 :         return orient.transposedtransform(p).add(o);
     301              :     }
     302              : 
     303              :     //ModelEllipse
     304              : 
     305            0 :     vec ModelEllipse::contactface(const vec &wn, const vec &wdir) const
     306              :     {
     307            0 :         vec n = orient.transform(wn).div(radius),
     308            0 :             dir = orient.transform(wdir);
     309            0 :         float dxy = n.dot2(n),
     310            0 :               dz = n.z*n.z;
     311            0 :         vec fn(0, 0, 0);
     312            0 :         if(dz > dxy && dir.z)
     313              :         {
     314            0 :             fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     315              :         }
     316            0 :         else if(n.dot2(dir) < 0)
     317              :         {
     318            0 :             fn.x = n.x*radius.y;
     319            0 :             fn.y = n.y*radius.x;
     320            0 :             fn.normalize();
     321              :         }
     322            0 :         return orient.transposedtransform(fn);
     323              :     }
     324              : 
     325            0 :     vec ModelEllipse::supportpoint(const vec &n) const
     326              :     {
     327            0 :         vec ln = orient.transform(n),
     328            0 :             p(0, 0, 0);
     329            0 :         if(ln.z > 0)
     330              :         {
     331            0 :             p.z += radius.z;
     332              :         }
     333              :         else
     334              :         {
     335            0 :             p.z -= radius.z;
     336              :         }
     337            0 :         if(ln.x || ln.y)
     338              :         {
     339            0 :             float r = ln.magnitude2();
     340            0 :             p.x += ln.x*radius.x/r;
     341            0 :             p.y += ln.y*radius.y/r;
     342              :         }
     343            0 :         return orient.transposedtransform(p).add(o);
     344              :     }
     345              : }
        

Generated by: LCOV version 2.0-1