LCOV - code coverage report
Current view: top level - engine/model - ragdoll.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 105 347 30.3 %
Date: 2024-11-22 05:07:59 Functions: 12 23 52.2 %

          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(uint i = 0; i < tris.size(); i++)
     123             :     {
     124           3 :         for(uint 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           3 :       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           3 :       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           6 :       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 : void ragdolldata::calcanimjoint(int i, const matrix4x3 &anim)
     189             : {
     190           1 :     if(!animjoints)
     191             :     {
     192           1 :         return;
     193             :     }
     194           0 :     const ragdollskel::joint &j = skel->joints[i];
     195           0 :     vec pos(0, 0, 0);
     196           0 :     for(int k = 0; k < 3; ++k)
     197             :     {
     198           0 :         if(j.vert[k]>=0)
     199             :         {
     200           0 :             pos.add(verts[j.vert[k]].pos);
     201             :         }
     202             :     }
     203           0 :     pos.mul(j.weight);
     204             : 
     205           0 :     const ragdollskel::tri &t = skel->tris[j.tri];
     206           0 :     matrix4x3 m;
     207           0 :     const vec &v1 = verts[t.vert[0]].pos,
     208           0 :               &v2 = verts[t.vert[1]].pos,
     209           0 :               &v3 = verts[t.vert[2]].pos;
     210           0 :     m.a = vec(v2).sub(v1).normalize();
     211           0 :     m.c.cross(m.a, vec(v3).sub(v1)).normalize();
     212           0 :     m.b.cross(m.c, m.a);
     213           0 :     m.d = pos;
     214           0 :     animjoints[i].transposemul(m, anim);
     215             : }
     216             : 
     217           1 : void ragdolldata::calctris()
     218             : {
     219           1 :     for(uint i = 0; i < skel->tris.size(); i++)
     220             :     {
     221           0 :         const ragdollskel::tri &t = skel->tris[i];
     222           0 :         matrix3 &m = tris[i];
     223           0 :         const vec &v1 = verts[t.vert[0]].pos,
     224           0 :                   &v2 = verts[t.vert[1]].pos,
     225           0 :                   &v3 = verts[t.vert[2]].pos;
     226           0 :         m.a = vec(v2).sub(v1).normalize();
     227           0 :         m.c.cross(m.a, vec(v3).sub(v1)).normalize();
     228           0 :         m.b.cross(m.c, m.a);
     229             :     }
     230           1 : }
     231             : 
     232           1 : void ragdolldata::calcboundsphere()
     233             : {
     234           1 :     center = vec(0, 0, 0);
     235           3 :     for(const vert &v : verts)
     236             :     {
     237           2 :         center.add(v.pos);
     238             :     }
     239           1 :     center.div(verts.size());
     240           1 :     radius = 0;
     241           3 :     for(const vert &v : verts)
     242             :     {
     243           2 :         radius = std::max(radius, v.pos.dist(center));
     244             :     }
     245           1 : }
     246             : 
     247             : VAR(ragdolltimestepmin, 1, 5, 50);
     248             : VAR(ragdolltimestepmax, 1, 10, 50);
     249             : 
     250           1 : void ragdolldata::init(const dynent *d)
     251             : {
     252           1 :     float ts = ragdolltimestepmin/1000.0f;
     253           3 :     for(vert &v : verts)
     254             :     {
     255           2 :         (v.oldpos = v.pos).sub(vec(d->vel).add(d->falling).mul(ts));
     256             :     }
     257           1 :     timestep = ts;
     258             : 
     259           1 :     calctris();
     260           1 :     calcboundsphere();
     261           1 :     offset = d->o;
     262           1 :     offset.sub(skel->eye >= 0 ? verts[skel->eye].pos : center);
     263           1 :     offset.z += (d->eyeheight + d->aboveeye)/2;
     264           1 : }
     265             : 
     266           0 : void ragdolldata::constraindist()
     267             : {
     268           0 :     for(const ragdollskel::distlimit &d : skel->distlimits)
     269             :     {
     270           0 :         vert &v1 = verts[d.vert[0]],
     271           0 :              &v2 = verts[d.vert[1]];
     272           0 :         vec dir = vec(v2.pos).sub(v1.pos);
     273           0 :         const float dist = dir.magnitude()/scale;
     274             :         float cdist;
     275           0 :         if(dist < d.mindist)
     276             :         {
     277           0 :             cdist = d.mindist;
     278             :         }
     279           0 :         else if(dist > d.maxdist)
     280             :         {
     281           0 :             cdist = d.maxdist;
     282             :         }
     283             :         else
     284             :         {
     285           0 :             continue;
     286             :         }
     287           0 :         if(dist > 1e-4f)
     288             :         {
     289           0 :             dir.mul(cdist*0.5f/dist);
     290             :         }
     291             :         else
     292             :         {
     293           0 :             dir = vec(0, 0, cdist*0.5f*scale);
     294             :         }
     295           0 :         const vec center = vec(v1.pos).add(v2.pos).mul(0.5f);
     296           0 :         v1.newpos.add(vec(center).sub(dir));
     297           0 :         v1.weight++;
     298           0 :         v2.newpos.add(vec(center).add(dir));
     299           0 :         v2.weight++;
     300             :     }
     301           0 : }
     302             : 
     303           0 : void ragdolldata::applyrotlimit(const ragdollskel::tri &t1, const ragdollskel::tri &t2, float angle, const vec &axis)
     304             : {
     305           0 :     vert &v1a = verts[t1.vert[0]],
     306           0 :          &v1b = verts[t1.vert[1]],
     307           0 :          &v1c = verts[t1.vert[2]],
     308           0 :          &v2a = verts[t2.vert[0]],
     309           0 :          &v2b = verts[t2.vert[1]],
     310           0 :          &v2c = verts[t2.vert[2]];
     311             :     // vec() copy constructor used below to deal with the fact that vec.add/sub() are destructive operations
     312           0 :     const vec m1 = vec(v1a.pos).add(v1b.pos).add(v1c.pos).div(3),
     313           0 :               m2 = vec(v2a.pos).add(v2b.pos).add(v2c.pos).div(3);
     314           0 :     vec q1a, q1b, q1c, q2a, q2b, q2c;
     315           0 :     const float w1 = q1a.cross(axis, vec(v1a.pos).sub(m1)).magnitude() +
     316           0 :                      q1b.cross(axis, vec(v1b.pos).sub(m1)).magnitude() +
     317           0 :                      q1c.cross(axis, vec(v1c.pos).sub(m1)).magnitude(),
     318           0 :                 w2 = q2a.cross(axis, vec(v2a.pos).sub(m2)).magnitude() +
     319           0 :                      q2b.cross(axis, vec(v2b.pos).sub(m2)).magnitude() +
     320           0 :                      q2c.cross(axis, vec(v2c.pos).sub(m2)).magnitude();
     321           0 :     angle /= w1 + w2 + 1e-9f;
     322           0 :     const float a1 = angle*w2,
     323           0 :                 a2 = -angle*w1,
     324           0 :                 s1 = std::sin(a1),
     325           0 :                 s2 = std::sin(a2);
     326           0 :     const vec c1 = vec(axis).mul(1 - std::cos(a1)),
     327           0 :               c2 = vec(axis).mul(1 - std::cos(a2));
     328           0 :     v1a.newpos.add(vec().cross(c1, q1a).madd(q1a, s1).add(v1a.pos));
     329           0 :     v1a.weight++;
     330           0 :     v1b.newpos.add(vec().cross(c1, q1b).madd(q1b, s1).add(v1b.pos));
     331           0 :     v1b.weight++;
     332           0 :     v1c.newpos.add(vec().cross(c1, q1c).madd(q1c, s1).add(v1c.pos));
     333           0 :     v1c.weight++;
     334           0 :     v2a.newpos.add(vec().cross(c2, q2a).madd(q2a, s2).add(v2a.pos));
     335           0 :     v2a.weight++;
     336           0 :     v2b.newpos.add(vec().cross(c2, q2b).madd(q2b, s2).add(v2b.pos));
     337           0 :     v2b.weight++;
     338           0 :     v2c.newpos.add(vec().cross(c2, q2c).madd(q2c, s2).add(v2c.pos));
     339           0 :     v2c.weight++;
     340           0 : }
     341             : 
     342           0 : void ragdolldata::constrainrot()
     343             : {
     344           0 :     calctris();
     345           0 :     for(const ragdollskel::rotlimit &r : skel->rotlimits)
     346             :     {
     347           0 :         matrix3 rot;
     348           0 :         rot.mul(tris[r.tri[0]], r.middle);
     349           0 :         rot.multranspose(tris[r.tri[1]]);
     350             : 
     351           0 :         vec axis;
     352             :         float angle;
     353           0 :         const float tr = rot.trace();
     354           0 :         if(tr >= r.maxtrace || !rot.calcangleaxis(tr, angle, axis))
     355             :         {
     356           0 :             continue;
     357             :         }
     358           0 :         angle = r.maxangle - angle + 1e-3f;
     359           0 :         applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis);
     360             :     }
     361           0 : }
     362             : 
     363           0 : void ragdolldata::calcrotfriction()
     364             : {
     365           0 :     for(size_t i = 0; i < skel->rotfrictions.size(); ++i)
     366             :     {
     367           0 :         rotfrictions[i].transposemul(tris[skel->rotfrictions[i].tri[0]], tris[skel->rotfrictions[i].tri[1]]);
     368             :     }
     369           0 : }
     370             : 
     371           0 : void ragdolldata::applyrotfriction(float ts)
     372             : {
     373           0 :     static FVAR(ragdollrotfric, 0, 0.85f, 1);
     374           0 :     static FVAR(ragdollrotfricstop, 0, 0.1f, 1);
     375             : 
     376           0 :     calctris();
     377           0 :     float stopangle = 2*M_PI*ts*ragdollrotfricstop,
     378           0 :           rotfric = 1.0f - std::pow(ragdollrotfric, ts*1000.0f/ragdolltimestepmin);
     379           0 :     for(size_t i = 0; i < skel->rotfrictions.size(); ++i)
     380             :     {
     381           0 :         matrix3 rot;
     382           0 :         rot.mul(tris[ skel->rotfrictions[i].tri[0]], rotfrictions[i]);
     383           0 :         rot.multranspose(tris[ skel->rotfrictions[i].tri[1]]);
     384             : 
     385           0 :         vec axis;
     386             :         float angle;
     387           0 :         if(!rot.calcangleaxis(angle, axis))
     388             :         {
     389           0 :             continue;
     390             :         }
     391           0 :         angle *= -(std::fabs(angle) >= stopangle ? rotfric : 1.0f);
     392           0 :         applyrotlimit(skel->tris[skel->rotfrictions[i].tri[0]], skel->tris[ skel->rotfrictions[i].tri[1]], angle, axis);
     393             :     }
     394           0 :     for(vert &v : verts)
     395             :     {
     396           0 :         if(!v.weight)
     397             :         {
     398           0 :             continue;
     399             :         }
     400           0 :         v.pos = v.newpos.div(v.weight);
     401           0 :         v.newpos = vec(0, 0, 0);
     402           0 :         v.weight = 0;
     403             :     }
     404           0 : }
     405             : 
     406           0 : void ragdolldata::tryunstick(float speed)
     407             : {
     408             :     /* vec `unstuck` is the average position of all vertices with the `stuck` flag
     409             :      * that are not found to collide with the world, as well as all vertices without
     410             :      * the `stuck` flag.
     411             :      */
     412           0 :     vec unstuck(0, 0, 0);
     413           0 :     size_t stuck = 0;
     414           0 :     for(uint i = 0; i < verts.size(); i++)
     415             :     {
     416           0 :         vert &v = verts[i];
     417           0 :         if(v.stuck)
     418             :         {
     419           0 :             if(collidevert(v.pos, vec(0, 0, 0), skel->verts[i].radius))
     420             :             {
     421           0 :                 stuck++;
     422           0 :                 continue;
     423             :             }
     424           0 :             v.stuck = false;
     425             :         }
     426           0 :         unstuck.add(v.pos);
     427             :     }
     428           0 :     unsticks = 0;
     429           0 :     if(!stuck || stuck >= verts.size())
     430             :     {
     431           0 :         return;
     432             :     }
     433           0 :     unstuck.div(verts.size() - stuck); //get average by dividing by # verts not stuck
     434             : 
     435           0 :     for(vert &v : verts)
     436             :     {
     437           0 :         if(v.stuck)
     438             :         {
     439           0 :             v.pos.add(vec(unstuck).sub(v.pos).rescale(speed));
     440           0 :             unsticks++;
     441             :         }
     442             :     }
     443             : }
     444             : 
     445           0 : void ragdolldata::constrain()
     446             : {
     447           0 :     static VAR(ragdollconstrain, 1, 7, 100); //number of iterations to run ragdolldata::constrain() for
     448             :     //note: this for loop does not use the loop variable `i` anywhere
     449           0 :     for(int i = 0; i < ragdollconstrain; ++i)
     450             :     {
     451           0 :         constraindist();
     452           0 :         for(vert &v : verts)
     453             :         {
     454           0 :             v.undo = v.pos;
     455           0 :             if(v.weight)
     456             :             {
     457           0 :                 v.pos = v.newpos.div(v.weight);
     458           0 :                 v.newpos = vec(0, 0, 0);
     459           0 :                 v.weight = 0;
     460             :             }
     461             :         }
     462             : 
     463           0 :         constrainrot();
     464           0 :         for(uint j = 0; j < verts.size(); j++)
     465             :         {
     466           0 :             vert &v = verts[j];
     467           0 :             if(v.weight)
     468             :             {
     469           0 :                 v.pos = v.newpos.div(v.weight);
     470           0 :                 v.newpos = vec(0, 0, 0);
     471           0 :                 v.weight = 0;
     472             :             }
     473           0 :             if(v.pos != v.undo && collidevert(v.pos, vec(v.pos).sub(v.undo), skel->verts[j].radius))
     474             :             {
     475           0 :                 vec dir = vec(v.pos).sub(v.oldpos);
     476           0 :                 const float facing = dir.dot(collidewall);
     477           0 :                 if(facing < 0)
     478             :                 {
     479           0 :                     v.oldpos = vec(v.undo).sub(dir.msub(collidewall, 2*facing));
     480             :                 }
     481           0 :                 v.pos = v.undo;
     482           0 :                 v.collided = true;
     483             :             }
     484             :         }
     485             :     }
     486           0 : }
     487             : 
     488           0 : void ragdolldata::move(bool water, float ts)
     489             : {
     490             : 
     491           0 :     static FVAR(ragdollbodyfric, 0, 0.95f, 1);
     492           0 :     static FVAR(ragdollbodyfricscale, 0, 2, 10);
     493           0 :     static FVAR(ragdollwaterfric, 0, 0.85f, 1);
     494           0 :     static FVAR(ragdollgroundfric, 0, 0.8f, 1);
     495           0 :     static FVAR(ragdollairfric, 0, 0.996f, 1);
     496           0 :     static FVAR(ragdollunstick, 0, 10, 1e3f);
     497           0 :     static VAR(ragdollexpireoffset, 0, 2500, 30000);
     498           0 :     static VAR(ragdollwaterexpireoffset, 0, 4000, 30000);
     499             : 
     500           0 :     if(collidemillis && lastmillis > collidemillis)
     501             :     {
     502           0 :         return;
     503             :     }
     504             : 
     505           0 :     calcrotfriction();
     506           0 :     const float tsfric = timestep ? ts/timestep : 1,
     507           0 :                 airfric = ragdollairfric + std::min((ragdollbodyfricscale*collisions)/verts.size(), 1.0f)*(ragdollbodyfric - ragdollairfric);
     508           0 :     collisions = 0;
     509           0 :     for(uint i = 0; i < verts.size(); i++)
     510             :     {
     511           0 :         vert &v = verts[i];
     512           0 :         vec dpos = vec(v.pos).sub(v.oldpos);
     513           0 :         dpos.z -= 100*ts*ts;
     514           0 :         if(water)
     515             :         {
     516             :             //reinterpret cast pointer -> "random" seed value
     517           0 :             dpos.z += 0.25f*std::sin(detrnd(reinterpret_cast<size_t>(this)+i, 360)/RAD + lastmillis/10000.0f*M_PI)*ts;
     518             :         }
     519           0 :         dpos.mul(std::pow((water ? ragdollwaterfric : 1.0f) * (v.collided ? ragdollgroundfric : airfric), ts*1000.0f/ragdolltimestepmin)*tsfric);
     520           0 :         v.oldpos = v.pos;
     521           0 :         v.pos.add(dpos);
     522             :     }
     523           0 :     applyrotfriction(ts);
     524           0 :     for(uint i = 0; i < verts.size(); i++)
     525             :     {
     526           0 :         vert &v = verts[i];
     527           0 :         if(v.pos.z < 0)
     528             :         {
     529           0 :             v.pos.z = 0;
     530           0 :             v.oldpos = v.pos;
     531           0 :             collisions++;
     532             :         }
     533           0 :         vec dir = vec(v.pos).sub(v.oldpos);
     534           0 :         v.collided = collidevert(v.pos, dir, skel->verts[i].radius);
     535           0 :         if(v.collided)
     536             :         {
     537           0 :             v.pos = v.oldpos;
     538           0 :             v.oldpos.sub(dir.reflect(collidewall));
     539           0 :             collisions++;
     540             :         }
     541             :     }
     542           0 :     if(unsticks && ragdollunstick)
     543             :     {
     544           0 :         tryunstick(ts*ragdollunstick);
     545             :     }
     546           0 :     timestep = ts;
     547           0 :     if(collisions)
     548             :     {
     549           0 :         floating = 0;
     550           0 :         if(!collidemillis)
     551             :         {
     552           0 :             collidemillis = lastmillis + (water ? ragdollwaterexpireoffset : ragdollexpireoffset);
     553             :         }
     554             :     }
     555           0 :     else if(++floating > 1 && lastmillis < collidemillis)
     556             :     {
     557           0 :         collidemillis = 0;
     558             :     }
     559           0 :     constrain();
     560           0 :     calctris();
     561           0 :     calcboundsphere();
     562             : }
     563             : 
     564           0 : bool ragdolldata::collidevert(const vec &pos, const vec &dir, float radius)
     565             : {
     566             :     static struct vertent : physent
     567             :     {
     568           0 :         vertent()
     569           0 :         {
     570           0 :             type = PhysEnt_Bounce;
     571           0 :             radius = xradius = yradius = eyeheight = aboveeye = 1;
     572           0 :         }
     573           0 :     } v;
     574           0 :     v.o = pos;
     575           0 :     if(v.radius != radius) //(radius param != 1)
     576             :     {
     577           0 :         v.radius = v.xradius = v.yradius = v.eyeheight = v.aboveeye = radius;
     578             :     }
     579             :     //collide generated vertent (point with sphere bounding of r = radius)
     580             :     //with dir parameter
     581           0 :     return collide(&v, dir, 0, false);
     582             : }
     583             : 
     584             : //used in iengine
     585           0 : void moveragdoll(dynent *d)
     586             : {
     587           0 :     static FVAR(ragdolleyesmooth, 0, 0.5f, 1);
     588           0 :     static VAR(ragdolleyesmoothmillis, 1, 250, 10000);
     589           0 :     if(!curtime || !d->ragdoll)
     590             :     {
     591           0 :         return;
     592             :     }
     593           0 :     if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis)
     594             :     {
     595           0 :         const int lastmove = d->ragdoll->lastmove;
     596           0 :         while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis)
     597             :         {
     598           0 :             const int timestep = std::min(ragdolltimestepmax, lastmillis - d->ragdoll->lastmove),
     599           0 :                       material = rootworld.lookupmaterial(vec(d->ragdoll->center.x, d->ragdoll->center.y, d->ragdoll->center.z + d->ragdoll->radius/2));
     600           0 :             const bool water = (material&MatFlag_Volume) == Mat_Water;
     601           0 :             d->inwater = water ? material&MatFlag_Volume : Mat_Air;
     602           0 :             d->ragdoll->move(water, timestep/1000.0f);
     603           0 :             d->ragdoll->lastmove += timestep;
     604             :         }
     605             :     }
     606             : 
     607           0 :     vec eye = d->ragdoll->skel->eye >= 0 ? d->ragdoll->verts[d->ragdoll->skel->eye].pos : d->ragdoll->center;
     608           0 :     eye.add(d->ragdoll->offset);
     609           0 :     const float k = std::pow(ragdolleyesmooth, static_cast<float>(curtime)/ragdolleyesmoothmillis);
     610           0 :     d->o.lerp(eye, 1-k);
     611             : }
     612             : 
     613           1 : void cleanragdoll(dynent *d)
     614             : {
     615           1 :     if(d->ragdoll)
     616             :     {
     617           1 :         delete d->ragdoll;
     618           1 :         d->ragdoll = nullptr;
     619             :     }
     620           1 : }

Generated by: LCOV version 1.14