LCOV - code coverage report
Current view: top level - engine/model - ragdoll.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 34.8 % 348 121
Test Date: 2025-02-21 06:59:27 Functions: 52.2 % 23 12

            Line data    Source code
       1              : /* ragdoll.cpp: ragdoll physics support
       2              :  *
       3              :  * Libprimis supports limited client-side ragdolls to simulate corpses. Ragdolls
       4              :  * are created when actors are killed and support basic physical interaction with
       5              :  * terrain (but not other players).
       6              :  *
       7              :  * This file contains implementation functions for the ragdoll class. For the
       8              :  * class definition, see ragdoll.h.
       9              :  */
      10              : #include "../libprimis-headers/cube.h"
      11              : #include "../../shared/geomexts.h"
      12              : 
      13              : #include <memory>
      14              : #include <optional>
      15              : 
      16              : #include "interface/console.h"
      17              : #include "interface/control.h"
      18              : 
      19              : #include "render/rendergl.h"
      20              : 
      21              : #include "world/entities.h"
      22              : #include "world/octaworld.h"
      23              : #include "world/physics.h"
      24              : #include "world/bih.h"
      25              : 
      26              : #include "model.h"
      27              : #include "ragdoll.h"
      28              : 
      29              : /*               ragdollskel                  */
      30              : 
      31              : //ragdollskel::tri
      32              : 
      33            5 : bool ragdollskel::tri::shareverts(const tri &t) const
      34              : {
      35           15 :     for(int i = 0; i < 3; ++i)
      36              :     {
      37           43 :         for(int j = 0; j < 3; ++j)
      38              :         {
      39           33 :             if(vert[i] == t.vert[j])
      40              :             {
      41            3 :                 return true;
      42              :             }
      43              :         }
      44              :     }
      45            2 :     return false;
      46              : }
      47              : 
      48              : //ragdollskel
      49              : 
      50            1 : void ragdollskel::setupjoints()
      51              : {
      52            4 :     for(vert &i : verts)
      53              :     {
      54            3 :         i.weight = 0;
      55              :     }
      56            2 :     for(joint &j : joints)
      57              :     {
      58            1 :         j.weight = 0;
      59            1 :         vec pos(0, 0, 0);
      60            4 :         for(int k = 0; k < 3; ++k)
      61              :         {
      62            3 :             if(j.vert[k]>=0) //for each valid vertex (not -1) refered to by this joint (up to 3)
      63              :             {
      64            3 :                 pos.add(verts[j.vert[k]].pos); //j.vert[k].pos is the positon of the vertex pointed to by the joint being used
      65            3 :                 j.weight++;
      66            3 :                 verts[j.vert[k]].weight++;
      67              :             }
      68              :         }
      69            2 :         for(int k = 0; k < j.weight; ++k)
      70              :         {
      71            1 :             j.weight = 1/j.weight;
      72              :         }
      73            1 :         pos.mul(j.weight);
      74              : 
      75            1 :         const tri &t = tris[j.tri];
      76            1 :         matrix4x3 &m = j.orient;
      77            1 :         const vec &v1 = verts[t.vert[0]].pos,
      78            1 :                   &v2 = verts[t.vert[1]].pos,
      79            1 :                   &v3 = verts[t.vert[2]].pos;
      80              :         /*
      81              :          *               /|
      82              :          *              /
      83              :          *          m.c/
      84              :          *            /
      85              :          *        v1 /   m.a     v2
      86              :          *          *---------->*
      87              :          *          |
      88              :          *          |
      89              :          *          |
      90              :          *       m.b|
      91              :          *          v
      92              :          *
      93              :          *
      94              :          *          *
      95              :          *           v3
      96              :          *
      97              :          *        ----→    ----→
      98              :          *  m.c = v1 v2  x v1 v3
      99              :          *        --→   ----→
     100              :          *  m.b = m.c x v1 v2
     101              :          *
     102              :          */
     103            1 :         m.a = vec(v2).sub(v1).normalize(); //m.a has magnitude 1 at all times
     104            1 :         m.c.cross(m.a, vec(v3).sub(v1)).normalize(); //m.c will always have a magnitude <=1
     105            1 :         m.b.cross(m.c, m.a); //m.b will always have a magnitude <= m.c
     106            1 :         m.d = pos;
     107            1 :         m.transpose();
     108              :     }
     109            4 :     for(vert &i : verts)
     110              :     {
     111            3 :         if(i.weight)
     112              :         {
     113            3 :             i.weight = 1/i.weight;
     114              :         }
     115              :     }
     116            1 :     reljoints.clear();
     117            1 : }
     118              : 
     119            1 : void ragdollskel::setuprotfrictions()
     120              : {
     121            1 :     rotfrictions.clear();
     122            3 :     for(size_t i = 0; i < tris.size(); i++)
     123              :     {
     124            3 :         for(size_t j = i+1; j < tris.size(); j++)
     125              :         {
     126            1 :             if(tris[i].shareverts(tris[j]))
     127              :             {
     128              :                 rotfriction r;
     129            1 :                 r.tri[0] = i;
     130            1 :                 r.tri[1] = j;
     131            1 :                 rotfrictions.push_back(r);
     132              :             }
     133              :         }
     134              :     }
     135            1 : }
     136              : 
     137            1 : void ragdollskel::setup()
     138              : {
     139            1 :     setupjoints();
     140            1 :     setuprotfrictions();
     141              : 
     142            1 :     loaded = true;
     143            1 : }
     144              : 
     145            1 : void ragdollskel::addreljoint(int bone, int parent)
     146              : {
     147            1 :     reljoints.emplace_back(reljoint{bone, parent});
     148            1 : }
     149              : /*                  ragdolldata                   */
     150              : 
     151            3 : ragdolldata::ragdolldata(const ragdollskel *skel, float scale)
     152            3 :     : skel(skel),
     153            3 :       millis(lastmillis),
     154            3 :       collidemillis(0),
     155            3 :       lastmove(lastmillis),
     156            3 :       radius(0),
     157            6 :       tris(skel->tris.size()),
     158            3 :       animjoints(!skel->animjoints || skel->joints.empty() ? nullptr : new matrix4x3[skel->joints.size()]),
     159            3 :       reljoints(skel->reljoints.empty() ? nullptr : new dualquat[skel->reljoints.size()]),
     160            6 :       verts(skel->verts.size()),
     161            3 :       collisions(0),
     162            3 :       floating(0),
     163            3 :       unsticks(INT_MAX),
     164            3 :       timestep(0),
     165            3 :       scale(scale),
     166            9 :       rotfrictions(skel->rotfrictions.size())
     167              : {
     168            3 : }
     169              : 
     170            3 : ragdolldata::~ragdolldata()
     171              : {
     172            3 :     if(animjoints)
     173              :     {
     174            1 :         delete[] animjoints;
     175              :     }
     176            3 :     if(reljoints)
     177              :     {
     178            0 :         delete[] reljoints;
     179              :     }
     180            3 : }
     181              : 
     182              : /*
     183              :     seed particle position = avg(modelview * base2anim * spherepos)
     184              :     mapped transform = invert(curtri) * origtrig
     185              :     parented transform = parent{invert(curtri) * origtrig} * (invert(parent{base2anim}) * base2anim)
     186              : */
     187              : 
     188            1 : matrix4x3 ragdolldata::calcanimjoint(int i, const matrix4x3 &anim) const
     189              : {
     190            1 :     const ragdollskel::joint &j = skel->joints[i];
     191            1 :     vec pos(0, 0, 0);
     192            4 :     for(int k = 0; k < 3; ++k)
     193              :     {
     194            3 :         if(j.vert[k]>=0)
     195              :         {
     196            3 :             pos.add(verts[j.vert[k]].pos);
     197              :         }
     198              :     }
     199            1 :     pos.mul(j.weight);
     200              : 
     201            1 :     const ragdollskel::tri &t = skel->tris[j.tri];
     202            1 :     matrix4x3 m;
     203            1 :     const vec &v1 = verts[t.vert[0]].pos,
     204            1 :               &v2 = verts[t.vert[1]].pos,
     205            1 :               &v3 = verts[t.vert[2]].pos;
     206            1 :     m.a = vec(v2).sub(v1).normalize();
     207            1 :     m.c.cross(m.a, vec(v3).sub(v1)).normalize();
     208            1 :     m.b.cross(m.c, m.a);
     209            1 :     m.d = pos;
     210            1 :     matrix4x3 result;
     211            1 :     result.transposemul(m, anim);
     212            2 :     return result;
     213              : }
     214              : 
     215            1 : void ragdolldata::calctris()
     216              : {
     217            1 :     for(size_t i = 0; i < skel->tris.size(); i++)
     218              :     {
     219            0 :         const ragdollskel::tri &t = skel->tris[i];
     220            0 :         matrix3 &m = tris[i];
     221            0 :         const vec &v1 = verts[t.vert[0]].pos,
     222            0 :                   &v2 = verts[t.vert[1]].pos,
     223            0 :                   &v3 = verts[t.vert[2]].pos;
     224            0 :         m.a = vec(v2).sub(v1).normalize();
     225            0 :         m.c.cross(m.a, vec(v3).sub(v1)).normalize();
     226            0 :         m.b.cross(m.c, m.a);
     227              :     }
     228            1 : }
     229              : 
     230            1 : void ragdolldata::calcboundsphere()
     231              : {
     232            1 :     center = vec(0, 0, 0);
     233            3 :     for(const vert &v : verts)
     234              :     {
     235            2 :         center.add(v.pos);
     236              :     }
     237            1 :     center.div(verts.size());
     238            1 :     radius = 0;
     239            3 :     for(const vert &v : verts)
     240              :     {
     241            2 :         radius = std::max(radius, v.pos.dist(center));
     242              :     }
     243            1 : }
     244              : 
     245              : VAR(ragdolltimestepmin, 1, 5, 50);
     246              : VAR(ragdolltimestepmax, 1, 10, 50);
     247              : 
     248            1 : void ragdolldata::init(const dynent *d)
     249              : {
     250            1 :     float ts = ragdolltimestepmin/1000.0f;
     251            3 :     for(vert &v : verts)
     252              :     {
     253            2 :         (v.oldpos = v.pos).sub(vec(d->vel).add(d->falling).mul(ts));
     254              :     }
     255            1 :     timestep = ts;
     256              : 
     257            1 :     calctris();
     258            1 :     calcboundsphere();
     259            1 :     offset = d->o;
     260            1 :     offset.sub(skel->eye >= 0 ? verts[skel->eye].pos : center);
     261            1 :     offset.z += (d->eyeheight + d->aboveeye)/2;
     262            1 : }
     263              : 
     264            0 : void ragdolldata::constraindist()
     265              : {
     266            0 :     for(const ragdollskel::distlimit &d : skel->distlimits)
     267              :     {
     268            0 :         vert &v1 = verts[d.vert[0]],
     269            0 :              &v2 = verts[d.vert[1]];
     270            0 :         vec dir = vec(v2.pos).sub(v1.pos);
     271            0 :         const float dist = dir.magnitude()/scale;
     272              :         float cdist;
     273            0 :         if(dist < d.mindist)
     274              :         {
     275            0 :             cdist = d.mindist;
     276              :         }
     277            0 :         else if(dist > d.maxdist)
     278              :         {
     279            0 :             cdist = d.maxdist;
     280              :         }
     281              :         else
     282              :         {
     283            0 :             continue;
     284              :         }
     285            0 :         if(dist > 1e-4f)
     286              :         {
     287            0 :             dir.mul(cdist*0.5f/dist);
     288              :         }
     289              :         else
     290              :         {
     291            0 :             dir = vec(0, 0, cdist*0.5f*scale);
     292              :         }
     293            0 :         const vec center = vec(v1.pos).add(v2.pos).mul(0.5f);
     294            0 :         v1.newpos.add(vec(center).sub(dir));
     295            0 :         v1.weight++;
     296            0 :         v2.newpos.add(vec(center).add(dir));
     297            0 :         v2.weight++;
     298              :     }
     299            0 : }
     300              : 
     301            0 : void ragdolldata::applyrotlimit(const ragdollskel::tri &t1, const ragdollskel::tri &t2, float angle, const vec &axis)
     302              : {
     303            0 :     vert &v1a = verts[t1.vert[0]],
     304            0 :          &v1b = verts[t1.vert[1]],
     305            0 :          &v1c = verts[t1.vert[2]],
     306            0 :          &v2a = verts[t2.vert[0]],
     307            0 :          &v2b = verts[t2.vert[1]],
     308            0 :          &v2c = verts[t2.vert[2]];
     309              :     // vec() copy constructor used below to deal with the fact that vec.add/sub() are destructive operations
     310            0 :     const vec m1 = vec(v1a.pos).add(v1b.pos).add(v1c.pos).div(3),
     311            0 :               m2 = vec(v2a.pos).add(v2b.pos).add(v2c.pos).div(3);
     312            0 :     vec q1a, q1b, q1c, q2a, q2b, q2c;
     313            0 :     const float w1 = q1a.cross(axis, vec(v1a.pos).sub(m1)).magnitude() +
     314            0 :                      q1b.cross(axis, vec(v1b.pos).sub(m1)).magnitude() +
     315            0 :                      q1c.cross(axis, vec(v1c.pos).sub(m1)).magnitude(),
     316            0 :                 w2 = q2a.cross(axis, vec(v2a.pos).sub(m2)).magnitude() +
     317            0 :                      q2b.cross(axis, vec(v2b.pos).sub(m2)).magnitude() +
     318            0 :                      q2c.cross(axis, vec(v2c.pos).sub(m2)).magnitude();
     319            0 :     angle /= w1 + w2 + 1e-9f;
     320            0 :     const float a1 = angle*w2,
     321            0 :                 a2 = -angle*w1,
     322            0 :                 s1 = std::sin(a1),
     323            0 :                 s2 = std::sin(a2);
     324            0 :     const vec c1 = vec(axis).mul(1 - std::cos(a1)),
     325            0 :               c2 = vec(axis).mul(1 - std::cos(a2));
     326            0 :     v1a.newpos.add(vec().cross(c1, q1a).madd(q1a, s1).add(v1a.pos));
     327            0 :     v1a.weight++;
     328            0 :     v1b.newpos.add(vec().cross(c1, q1b).madd(q1b, s1).add(v1b.pos));
     329            0 :     v1b.weight++;
     330            0 :     v1c.newpos.add(vec().cross(c1, q1c).madd(q1c, s1).add(v1c.pos));
     331            0 :     v1c.weight++;
     332            0 :     v2a.newpos.add(vec().cross(c2, q2a).madd(q2a, s2).add(v2a.pos));
     333            0 :     v2a.weight++;
     334            0 :     v2b.newpos.add(vec().cross(c2, q2b).madd(q2b, s2).add(v2b.pos));
     335            0 :     v2b.weight++;
     336            0 :     v2c.newpos.add(vec().cross(c2, q2c).madd(q2c, s2).add(v2c.pos));
     337            0 :     v2c.weight++;
     338            0 : }
     339              : 
     340            0 : void ragdolldata::constrainrot()
     341              : {
     342            0 :     calctris(); //set up shadowing matrix3 objects for skel->tris
     343            0 :     for(const ragdollskel::rotlimit &r : skel->rotlimits)
     344              :     {
     345            0 :         matrix3 rot;
     346            0 :         rot.mul(tris[r.tri[0]], r.middle);
     347            0 :         rot.multranspose(tris[r.tri[1]]);
     348              : 
     349            0 :         vec axis;
     350              :         float angle;
     351            0 :         const float tr = rot.trace();
     352              :         //calculate angle and axis from the matrix `rot`, if possible
     353            0 :         if(tr >= r.maxtrace || !rot.calcangleaxis(tr, angle, axis))
     354              :         {
     355            0 :             continue;
     356              :         }
     357            0 :         angle = r.maxangle - angle + 1e-3f;
     358            0 :         applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis);
     359              :     }
     360            0 : }
     361              : 
     362            0 : void ragdolldata::calcrotfriction()
     363              : {
     364            0 :     for(size_t i = 0; i < skel->rotfrictions.size(); ++i)
     365              :     {
     366            0 :         rotfrictions[i].transposemul(tris[skel->rotfrictions[i].tri[0]], tris[skel->rotfrictions[i].tri[1]]);
     367              :     }
     368            0 : }
     369              : 
     370            0 : void ragdolldata::applyrotfriction(float ts)
     371              : {
     372            0 :     static FVAR(ragdollrotfric, 0, 0.85f, 1);
     373            0 :     static FVAR(ragdollrotfricstop, 0, 0.1f, 1);
     374              : 
     375            0 :     calctris();
     376            0 :     float stopangle = 2*M_PI*ts*ragdollrotfricstop,
     377            0 :           rotfric = 1.0f - std::pow(ragdollrotfric, ts*1000.0f/ragdolltimestepmin);
     378            0 :     for(size_t i = 0; i < skel->rotfrictions.size(); ++i)
     379              :     {
     380            0 :         matrix3 rot;
     381            0 :         rot.mul(tris[ skel->rotfrictions[i].tri[0]], rotfrictions[i]);
     382            0 :         rot.multranspose(tris[ skel->rotfrictions[i].tri[1]]);
     383              : 
     384            0 :         vec axis;
     385              :         float angle;
     386            0 :         if(!rot.calcangleaxis(angle, axis))
     387              :         {
     388            0 :             continue;
     389              :         }
     390            0 :         angle *= -(std::fabs(angle) >= stopangle ? rotfric : 1.0f);
     391            0 :         applyrotlimit(skel->tris[skel->rotfrictions[i].tri[0]], skel->tris[ skel->rotfrictions[i].tri[1]], angle, axis);
     392              :     }
     393            0 :     for(vert &v : verts)
     394              :     {
     395            0 :         if(!v.weight)
     396              :         {
     397            0 :             continue;
     398              :         }
     399            0 :         v.pos = v.newpos.div(v.weight);
     400            0 :         v.newpos = vec(0, 0, 0);
     401            0 :         v.weight = 0;
     402              :     }
     403            0 : }
     404              : 
     405            0 : void ragdolldata::tryunstick(float speed, vec &cwall)
     406              : {
     407              :     /* vec `unstuck` is the average position of all vertices with the `stuck` flag
     408              :      * that are not found to collide with the world, as well as all vertices without
     409              :      * the `stuck` flag.
     410              :      */
     411            0 :     vec unstuck(0, 0, 0);
     412            0 :     size_t stuck = 0;
     413            0 :     for(size_t i = 0; i < verts.size(); i++)
     414              :     {
     415            0 :         vert &v = verts[i];
     416            0 :         if(v.stuck)
     417              :         {
     418            0 :             if(collidevert(v.pos, vec(0, 0, 0), skel->verts[i].radius, cwall))
     419              :             {
     420            0 :                 stuck++;
     421            0 :                 continue;
     422              :             }
     423            0 :             v.stuck = false;
     424              :         }
     425            0 :         unstuck.add(v.pos);
     426              :     }
     427            0 :     unsticks = 0;
     428            0 :     if(!stuck || stuck >= verts.size())
     429              :     {
     430            0 :         return;
     431              :     }
     432            0 :     unstuck.div(verts.size() - stuck); //get average by dividing by # verts not stuck
     433              : 
     434            0 :     for(vert &v : verts)
     435              :     {
     436            0 :         if(v.stuck)
     437              :         {
     438            0 :             v.pos.add(vec(unstuck).sub(v.pos).rescale(speed));
     439            0 :             unsticks++;
     440              :         }
     441              :     }
     442              : }
     443              : 
     444            0 : void ragdolldata::constrain(vec &cwall)
     445              : {
     446            0 :     static VAR(ragdollconstrain, 1, 7, 100); //number of iterations to run ragdolldata::constrain() for
     447              :     //note: this for loop does not use the loop variable `i` anywhere
     448            0 :     for(int i = 0; i < ragdollconstrain; ++i)
     449              :     {
     450            0 :         constraindist();
     451            0 :         for(vert &v : verts)
     452              :         {
     453            0 :             v.undo = v.pos;
     454            0 :             if(v.weight)
     455              :             {
     456            0 :                 v.pos = v.newpos.div(v.weight);
     457            0 :                 v.newpos = vec(0, 0, 0);
     458            0 :                 v.weight = 0;
     459              :             }
     460              :         }
     461              : 
     462            0 :         constrainrot();
     463            0 :         for(size_t j = 0; j < verts.size(); j++)
     464              :         {
     465            0 :             vert &v = verts[j];
     466            0 :             if(v.weight)
     467              :             {
     468            0 :                 v.pos = v.newpos.div(v.weight);
     469            0 :                 v.newpos = vec(0, 0, 0);
     470            0 :                 v.weight = 0;
     471              :             }
     472            0 :             if(v.pos != v.undo && collidevert(v.pos, vec(v.pos).sub(v.undo), skel->verts[j].radius, cwall))
     473              :             {
     474            0 :                 vec dir = vec(v.pos).sub(v.oldpos);
     475            0 :                 const float facing = dir.dot(cwall);
     476            0 :                 if(facing < 0)
     477              :                 {
     478            0 :                     v.oldpos = vec(v.undo).sub(dir.msub(cwall, 2*facing));
     479              :                 }
     480            0 :                 v.pos = v.undo;
     481            0 :                 v.collided = true;
     482              :             }
     483              :         }
     484              :     }
     485            0 : }
     486              : 
     487            0 : void ragdolldata::move(bool water, float ts)
     488              : {
     489              : 
     490            0 :     static FVAR(ragdollbodyfric, 0, 0.95f, 1);
     491            0 :     static FVAR(ragdollbodyfricscale, 0, 2, 10);
     492            0 :     static FVAR(ragdollwaterfric, 0, 0.85f, 1);
     493            0 :     static FVAR(ragdollgroundfric, 0, 0.8f, 1);
     494            0 :     static FVAR(ragdollairfric, 0, 0.996f, 1);
     495            0 :     static FVAR(ragdollunstick, 0, 10, 1e3f);
     496            0 :     static VAR(ragdollexpireoffset, 0, 2500, 30000);
     497            0 :     static VAR(ragdollwaterexpireoffset, 0, 4000, 30000);
     498              : 
     499            0 :     if(collidemillis && lastmillis > collidemillis)
     500              :     {
     501            0 :         return;
     502              :     }
     503              : 
     504            0 :     calcrotfriction();
     505            0 :     const float tsfric = timestep ? ts/timestep : 1,
     506            0 :                 airfric = ragdollairfric + std::min((ragdollbodyfricscale*collisions)/verts.size(), 1.0f)*(ragdollbodyfric - ragdollairfric);
     507            0 :     collisions = 0;
     508            0 :     vec collidewall(0,0,0);
     509              : 
     510            0 :     for(size_t i = 0; i < verts.size(); i++)
     511              :     {
     512            0 :         vert &v = verts[i];
     513            0 :         vec dpos = vec(v.pos).sub(v.oldpos);
     514            0 :         dpos.z -= 100*ts*ts;
     515            0 :         if(water)
     516              :         {
     517              :             //reinterpret cast pointer -> "random" seed value
     518            0 :             dpos.z += 0.25f*std::sin(detrnd(reinterpret_cast<size_t>(this)+i, 360)/RAD + lastmillis/10000.0f*M_PI)*ts;
     519              :         }
     520            0 :         dpos.mul(std::pow((water ? ragdollwaterfric : 1.0f) * (v.collided ? ragdollgroundfric : airfric), ts*1000.0f/ragdolltimestepmin)*tsfric);
     521            0 :         v.oldpos = v.pos;
     522            0 :         v.pos.add(dpos);
     523              :     }
     524            0 :     applyrotfriction(ts);
     525            0 :     for(size_t i = 0; i < verts.size(); i++)
     526              :     {
     527            0 :         vert &v = verts[i];
     528            0 :         if(v.pos.z < 0)
     529              :         {
     530            0 :             v.pos.z = 0;
     531            0 :             v.oldpos = v.pos;
     532            0 :             collisions++;
     533              :         }
     534            0 :         vec dir = vec(v.pos).sub(v.oldpos);
     535            0 :         v.collided = collidevert(v.pos, dir, skel->verts[i].radius, collidewall);
     536            0 :         if(v.collided)
     537              :         {
     538            0 :             v.pos = v.oldpos;
     539            0 :             v.oldpos.sub(dir.reflect(collidewall));
     540            0 :             collisions++;
     541              :         }
     542              :     }
     543            0 :     if(unsticks && ragdollunstick)
     544              :     {
     545            0 :         tryunstick(ts*ragdollunstick, collidewall);
     546              :     }
     547            0 :     timestep = ts;
     548            0 :     if(collisions)
     549              :     {
     550            0 :         floating = 0;
     551            0 :         if(!collidemillis)
     552              :         {
     553            0 :             collidemillis = lastmillis + (water ? ragdollwaterexpireoffset : ragdollexpireoffset);
     554              :         }
     555              :     }
     556            0 :     else if(++floating > 1 && lastmillis < collidemillis)
     557              :     {
     558            0 :         collidemillis = 0;
     559              :     }
     560            0 :     constrain(collidewall);
     561            0 :     calctris();
     562            0 :     calcboundsphere();
     563              : }
     564              : 
     565            0 : bool ragdolldata::collidevert(const vec &pos, const vec &dir, float radius, vec &cwall)
     566              : {
     567              :     static struct vertent : physent
     568              :     {
     569            0 :         vertent()
     570            0 :         {
     571            0 :             type = PhysEnt_Bounce;
     572            0 :             radius = xradius = yradius = eyeheight = aboveeye = 1;
     573            0 :         }
     574            0 :     } v;
     575            0 :     v.o = pos;
     576            0 :     if(v.radius != radius) //(radius param != 1)
     577              :     {
     578            0 :         v.radius = v.xradius = v.yradius = v.eyeheight = v.aboveeye = radius;
     579              :     }
     580              :     //collide generated vertent (point with sphere bounding of r = radius)
     581              :     //with dir parameter
     582            0 :     return collide(&v, &cwall, dir, 0);
     583              : }
     584              : 
     585              : //used in iengine
     586            0 : void moveragdoll(dynent *d)
     587              : {
     588            0 :     static FVAR(ragdolleyesmooth, 0, 0.5f, 1);
     589            0 :     static VAR(ragdolleyesmoothmillis, 1, 250, 10000);
     590            0 :     if(!curtime || !d->ragdoll)
     591              :     {
     592            0 :         return;
     593              :     }
     594            0 :     if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis)
     595              :     {
     596            0 :         const int lastmove = d->ragdoll->lastmove;
     597            0 :         while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis)
     598              :         {
     599            0 :             const int timestep = std::min(ragdolltimestepmax, lastmillis - d->ragdoll->lastmove),
     600            0 :                       material = rootworld.lookupmaterial(vec(d->ragdoll->center.x, d->ragdoll->center.y, d->ragdoll->center.z + d->ragdoll->radius/2));
     601            0 :             const bool water = (material&MatFlag_Volume) == Mat_Water;
     602            0 :             d->inwater = water ? material&MatFlag_Volume : Mat_Air;
     603            0 :             d->ragdoll->move(water, timestep/1000.0f);
     604            0 :             d->ragdoll->lastmove += timestep;
     605              :         }
     606              :     }
     607              : 
     608            0 :     vec eye = d->ragdoll->skel->eye >= 0 ? d->ragdoll->verts[d->ragdoll->skel->eye].pos : d->ragdoll->center;
     609            0 :     eye.add(d->ragdoll->offset);
     610            0 :     const float k = std::pow(ragdolleyesmooth, static_cast<float>(curtime)/ragdolleyesmoothmillis);
     611            0 :     d->o.lerp(eye, 1-k);
     612              : }
     613              : 
     614            1 : void cleanragdoll(dynent *d)
     615              : {
     616            1 :     if(d->ragdoll)
     617              :     {
     618            1 :         delete d->ragdoll;
     619            1 :         d->ragdoll = nullptr;
     620              :     }
     621            1 : }
        

Generated by: LCOV version 2.0-1