LCOV - code coverage report
Current view: top level - engine/world - mpr.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 36.2 % 163 59
Test Date: 2026-01-07 07:46:09 Functions: 72.7 % 33 24

            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 :         vec 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              : 
     218            3 :     Model::Model(const vec &ent, const vec &center, const vec &radius, int yaw, int pitch, int roll) : o(ent), radius(radius)
     219              :     {
     220            3 :         orient.identity();
     221            3 :         if(roll)
     222              :         {
     223            0 :             orient.rotate_around_y(sincosmod360(roll));
     224              :         }
     225            3 :         if(pitch)
     226              :         {
     227            0 :             orient.rotate_around_x(sincosmod360(-pitch));
     228              :         }
     229            3 :         if(yaw)
     230              :         {
     231            1 :             orient.rotate_around_z(sincosmod360(-yaw));
     232              :         }
     233            3 :         o.add(orient.transposedtransform(center));
     234            3 :     }
     235              : 
     236            1 :     vec Model::center() const
     237              :     {
     238            1 :         return o;
     239              :     }
     240              : 
     241              :     //ModelOBB
     242              : 
     243            0 :     vec ModelOBB::contactface(const vec &wn, const vec &wdir) const
     244              :     {
     245            0 :         vec n = orient.transform(wn).div(radius),
     246            0 :             dir = orient.transform(wdir),
     247            0 :             an(std::fabs(n.x), std::fabs(n.y), dir.z ? std::fabs(n.z) : 0),
     248            0 :             fn(0, 0, 0);
     249            0 :         if(an.x > an.y)
     250              :         {
     251            0 :             if(an.x > an.z)
     252              :             {
     253            0 :                 fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
     254              :             }
     255            0 :             else if(an.z > 0)
     256              :             {
     257            0 :                 fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     258              :             }
     259              :         }
     260            0 :         else if(an.y > an.z)
     261              :         {
     262            0 :             fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
     263              :         }
     264            0 :         else if(an.z > 0)
     265              :         {
     266            0 :             fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     267              :         }
     268            0 :         return orient.transposedtransform(fn);
     269              :     }
     270              : 
     271            0 :     vec ModelOBB::supportpoint(const vec &n) const
     272              :     {
     273            0 :         vec ln = orient.transform(n),
     274            0 :             p(0, 0, 0);
     275            0 :         if(ln.x > 0)
     276              :         {
     277            0 :             p.x += radius.x;
     278              :         }
     279              :         else
     280              :         {
     281            0 :             p.x -= radius.x;
     282              :         }
     283            0 :         if(ln.y > 0)
     284              :         {
     285            0 :             p.y += radius.y;
     286              :         }
     287              :         else
     288              :         {
     289            0 :             p.y -= radius.y;
     290              :         }
     291            0 :         if(ln.z > 0)
     292              :         {
     293            0 :             p.z += radius.z;
     294              :         }
     295              :         else
     296              :         {
     297            0 :             p.z -= radius.z;
     298              :         }
     299            0 :         return orient.transposedtransform(p).add(o);
     300              :     }
     301              : 
     302              :     //ModelEllipse
     303              : 
     304            0 :     vec ModelEllipse::contactface(const vec &wn, const vec &wdir) const
     305              :     {
     306            0 :         vec n = orient.transform(wn).div(radius),
     307            0 :             dir = orient.transform(wdir);
     308            0 :         float dxy = n.dot2(n),
     309            0 :               dz = n.z*n.z;
     310            0 :         vec fn(0, 0, 0);
     311            0 :         if(dz > dxy && dir.z)
     312              :         {
     313            0 :             fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
     314              :         }
     315            0 :         else if(n.dot2(dir) < 0)
     316              :         {
     317            0 :             fn.x = n.x*radius.y;
     318            0 :             fn.y = n.y*radius.x;
     319            0 :             fn.normalize();
     320              :         }
     321            0 :         return orient.transposedtransform(fn);
     322              :     }
     323              : 
     324            0 :     vec ModelEllipse::supportpoint(const vec &n) const
     325              :     {
     326            0 :         vec ln = orient.transform(n),
     327            0 :             p(0, 0, 0);
     328            0 :         if(ln.z > 0)
     329              :         {
     330            0 :             p.z += radius.z;
     331              :         }
     332              :         else
     333              :         {
     334            0 :             p.z -= radius.z;
     335              :         }
     336            0 :         if(ln.x || ln.y)
     337              :         {
     338            0 :             float r = ln.magnitude2();
     339            0 :             p.x += ln.x*radius.x/r;
     340            0 :             p.y += ln.y*radius.y/r;
     341              :         }
     342            0 :         return orient.transposedtransform(p).add(o);
     343              :     }
     344              : }
        

Generated by: LCOV version 2.0-1