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-04-16 12:09:02 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              : #include <format>
      16              : 
      17              : #include "interface/console.h"
      18              : #include "interface/control.h"
      19              : 
      20              : #include "render/rendergl.h"
      21              : 
      22              : #include "world/entities.h"
      23              : #include "world/octaworld.h"
      24              : #include "world/physics.h"
      25              : #include "world/bih.h"
      26              : 
      27              : #include "model.h"
      28              : #include "ragdoll.h"
      29              : 
      30              : /*               ragdollskel                  */
      31              : 
      32              : //ragdollskel::tri
      33              : 
      34            5 : bool ragdollskel::tri::shareverts(const tri &t) const
      35              : {
      36           15 :     for(int i = 0; i < 3; ++i)
      37              :     {
      38           43 :         for(int j = 0; j < 3; ++j)
      39              :         {
      40           33 :             if(vert[i] == t.vert[j])
      41              :             {
      42            3 :                 return true;
      43              :             }
      44              :         }
      45              :     }
      46            2 :     return false;
      47              : }
      48              : 
      49              : //ragdollskel
      50              : 
      51            1 : void ragdollskel::setupjoints()
      52              : {
      53            4 :     for(vert &i : verts)
      54              :     {
      55            3 :         i.weight = 0;
      56              :     }
      57            2 :     for(joint &j : joints)
      58              :     {
      59            1 :         j.weight = 0;
      60            1 :         vec pos(0, 0, 0);
      61            4 :         for(int k = 0; k < 3; ++k)
      62              :         {
      63            3 :             if(j.vert[k]>=0) //for each valid vertex (not -1) refered to by this joint (up to 3)
      64              :             {
      65            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
      66            3 :                 j.weight++;
      67            3 :                 verts[j.vert[k]].weight++;
      68              :             }
      69              :         }
      70            2 :         for(int k = 0; k < j.weight; ++k)
      71              :         {
      72            1 :             j.weight = 1/j.weight;
      73              :         }
      74            1 :         pos.mul(j.weight);
      75              : 
      76            1 :         const tri &t = tris[j.tri];
      77            1 :         matrix4x3 &m = j.orient;
      78            1 :         const vec &v1 = verts[t.vert[0]].pos,
      79            1 :                   &v2 = verts[t.vert[1]].pos,
      80            1 :                   &v3 = verts[t.vert[2]].pos;
      81              :         /*
      82              :          *               /|
      83              :          *              /
      84              :          *          m.c/
      85              :          *            /
      86              :          *        v1 /   m.a     v2
      87              :          *          *---------->*
      88              :          *          |
      89              :          *          |
      90              :          *          |
      91              :          *       m.b|
      92              :          *          v
      93              :          *
      94              :          *
      95              :          *          *
      96              :          *           v3
      97              :          *
      98              :          *        ----→    ----→
      99              :          *  m.c = v1 v2  x v1 v3
     100              :          *        --→   ----→
     101              :          *  m.b = m.c x v1 v2
     102              :          *
     103              :          */
     104            1 :         m.a = vec(v2).sub(v1).normalize(); //m.a has magnitude 1 at all times
     105            1 :         m.c.cross(m.a, vec(v3).sub(v1)).normalize(); //m.c will always have a magnitude <=1
     106            1 :         m.b.cross(m.c, m.a); //m.b will always have a magnitude <= m.c
     107            1 :         m.d = pos;
     108            1 :         m.transpose();
     109              :     }
     110            4 :     for(vert &i : verts)
     111              :     {
     112            3 :         if(i.weight)
     113              :         {
     114            3 :             i.weight = 1/i.weight;
     115              :         }
     116              :     }
     117            1 :     reljoints.clear();
     118            1 : }
     119              : 
     120            1 : void ragdollskel::setuprotfrictions()
     121              : {
     122            1 :     rotfrictions.clear();
     123            3 :     for(size_t i = 0; i < tris.size(); i++)
     124              :     {
     125            3 :         for(size_t j = i+1; j < tris.size(); j++)
     126              :         {
     127            1 :             if(tris[i].shareverts(tris[j]))
     128              :             {
     129              :                 rotfriction r;
     130            1 :                 r.tri[0] = i;
     131            1 :                 r.tri[1] = j;
     132            1 :                 rotfrictions.push_back(r);
     133              :             }
     134              :         }
     135              :     }
     136            1 : }
     137              : 
     138            1 : void ragdollskel::setup()
     139              : {
     140            1 :     setupjoints();
     141            1 :     setuprotfrictions();
     142              : 
     143            1 :     loaded = true;
     144            1 : }
     145              : 
     146            1 : void ragdollskel::addreljoint(int bone, int parent)
     147              : {
     148            1 :     reljoints.emplace_back(reljoint{bone, parent});
     149            1 : }
     150              : /*                  ragdolldata                   */
     151              : 
     152            3 : ragdolldata::ragdolldata(const ragdollskel *skel, float scale)
     153            3 :     : skel(skel),
     154            3 :       millis(lastmillis),
     155            3 :       collidemillis(0),
     156            3 :       lastmove(lastmillis),
     157            3 :       radius(0),
     158            6 :       tris(skel->tris.size()),
     159            3 :       animjoints(!skel->animjoints || skel->joints.empty() ? nullptr : new matrix4x3[skel->joints.size()]),
     160            3 :       reljoints(skel->reljoints.empty() ? nullptr : new dualquat[skel->reljoints.size()]),
     161            6 :       verts(skel->verts.size()),
     162            3 :       collisions(0),
     163            3 :       floating(0),
     164            3 :       unsticks(INT_MAX),
     165            3 :       timestep(0),
     166            3 :       scale(scale),
     167            9 :       rotfrictions(skel->rotfrictions.size())
     168              : {
     169            3 : }
     170              : 
     171            3 : ragdolldata::~ragdolldata()
     172              : {
     173            3 :     if(animjoints)
     174              :     {
     175            1 :         delete[] animjoints;
     176              :     }
     177            3 :     if(reljoints)
     178              :     {
     179            0 :         delete[] reljoints;
     180              :     }
     181            3 : }
     182              : 
     183              : /*
     184              :     seed particle position = avg(modelview * base2anim * spherepos)
     185              :     mapped transform = invert(curtri) * origtrig
     186              :     parented transform = parent{invert(curtri) * origtrig} * (invert(parent{base2anim}) * base2anim)
     187              : */
     188              : 
     189            1 : matrix4x3 ragdolldata::calcanimjoint(int i, const matrix4x3 &anim) const
     190              : {
     191            1 :     const ragdollskel::joint &j = skel->joints[i];
     192            1 :     vec pos(0, 0, 0);
     193            4 :     for(int k = 0; k < 3; ++k)
     194              :     {
     195            3 :         if(j.vert[k]>=0)
     196              :         {
     197            3 :             pos.add(verts[j.vert[k]].pos);
     198              :         }
     199              :     }
     200            1 :     pos.mul(j.weight);
     201              : 
     202            1 :     const ragdollskel::tri &t = skel->tris[j.tri];
     203            1 :     matrix4x3 m;
     204            1 :     const vec &v1 = verts[t.vert[0]].pos,
     205            1 :               &v2 = verts[t.vert[1]].pos,
     206            1 :               &v3 = verts[t.vert[2]].pos;
     207            1 :     m.a = vec(v2).sub(v1).normalize();
     208            1 :     m.c.cross(m.a, vec(v3).sub(v1)).normalize();
     209            1 :     m.b.cross(m.c, m.a);
     210            1 :     m.d = pos;
     211            1 :     matrix4x3 result;
     212            1 :     result.transposemul(m, anim);
     213            2 :     return result;
     214              : }
     215              : 
     216            1 : void ragdolldata::calctris()
     217              : {
     218            1 :     for(size_t i = 0; i < skel->tris.size(); i++)
     219              :     {
     220            0 :         const ragdollskel::tri &t = skel->tris[i];
     221            0 :         matrix3 &m = tris[i];
     222            0 :         const vec &v1 = verts[t.vert[0]].pos,
     223            0 :                   &v2 = verts[t.vert[1]].pos,
     224            0 :                   &v3 = verts[t.vert[2]].pos;
     225            0 :         m.a = vec(v2).sub(v1).normalize();
     226            0 :         m.c.cross(m.a, vec(v3).sub(v1)).normalize();
     227            0 :         m.b.cross(m.c, m.a);
     228              :     }
     229            1 : }
     230              : 
     231            1 : void ragdolldata::calcboundsphere()
     232              : {
     233            1 :     center = vec(0, 0, 0);
     234            3 :     for(const vert &v : verts)
     235              :     {
     236            2 :         center.add(v.pos);
     237              :     }
     238            1 :     center.div(verts.size());
     239            1 :     radius = 0;
     240            3 :     for(const vert &v : verts)
     241              :     {
     242            2 :         radius = std::max(radius, v.pos.dist(center));
     243              :     }
     244            1 : }
     245              : 
     246              : VAR(ragdolltimestepmin, 1, 5, 50);
     247              : VAR(ragdolltimestepmax, 1, 10, 50);
     248              : 
     249            1 : void ragdolldata::init(const dynent *d)
     250              : {
     251            1 :     float ts = ragdolltimestepmin/1000.0f;
     252            3 :     for(vert &v : verts)
     253              :     {
     254            2 :         (v.oldpos = v.pos).sub(vec(d->vel).add(d->falling).mul(ts));
     255              :     }
     256            1 :     timestep = ts;
     257              : 
     258            1 :     calctris();
     259            1 :     calcboundsphere();
     260            1 :     offset = d->o;
     261            1 :     offset.sub(skel->eye >= 0 ? verts[skel->eye].pos : center);
     262            1 :     offset.z += (d->eyeheight + d->aboveeye)/2;
     263            1 : }
     264              : 
     265            0 : void ragdolldata::constraindist()
     266              : {
     267            0 :     for(const ragdollskel::distlimit &d : skel->distlimits)
     268              :     {
     269            0 :         vert &v1 = verts[d.vert[0]],
     270            0 :              &v2 = verts[d.vert[1]];
     271            0 :         vec dir = vec(v2.pos).sub(v1.pos);
     272            0 :         const float dist = dir.magnitude()/scale;
     273              :         float cdist;
     274            0 :         if(dist < d.mindist)
     275              :         {
     276            0 :             cdist = d.mindist;
     277              :         }
     278            0 :         else if(dist > d.maxdist)
     279              :         {
     280            0 :             cdist = d.maxdist;
     281              :         }
     282              :         else
     283              :         {
     284            0 :             continue;
     285              :         }
     286            0 :         if(dist > 1e-4f)
     287              :         {
     288            0 :             dir.mul(cdist*0.5f/dist);
     289              :         }
     290              :         else
     291              :         {
     292            0 :             dir = vec(0, 0, cdist*0.5f*scale);
     293              :         }
     294            0 :         const vec center = vec(v1.pos).add(v2.pos).mul(0.5f);
     295            0 :         v1.newpos.add(vec(center).sub(dir));
     296            0 :         v1.weight++;
     297            0 :         v2.newpos.add(vec(center).add(dir));
     298            0 :         v2.weight++;
     299              :     }
     300            0 : }
     301              : 
     302            0 : void ragdolldata::applyrotlimit(const ragdollskel::tri &t1, const ragdollskel::tri &t2, float angle, const vec &axis)
     303              : {
     304            0 :     vert &v1a = verts[t1.vert[0]],
     305            0 :          &v1b = verts[t1.vert[1]],
     306            0 :          &v1c = verts[t1.vert[2]],
     307            0 :          &v2a = verts[t2.vert[0]],
     308            0 :          &v2b = verts[t2.vert[1]],
     309            0 :          &v2c = verts[t2.vert[2]];
     310              :     // vec() copy constructor used below to deal with the fact that vec.add/sub() are destructive operations
     311            0 :     const vec m1 = vec(v1a.pos).add(v1b.pos).add(v1c.pos).div(3),
     312            0 :               m2 = vec(v2a.pos).add(v2b.pos).add(v2c.pos).div(3);
     313            0 :     vec q1a, q1b, q1c, q2a, q2b, q2c;
     314            0 :     const float w1 = q1a.cross(axis, vec(v1a.pos).sub(m1)).magnitude() +
     315            0 :                      q1b.cross(axis, vec(v1b.pos).sub(m1)).magnitude() +
     316            0 :                      q1c.cross(axis, vec(v1c.pos).sub(m1)).magnitude(),
     317            0 :                 w2 = q2a.cross(axis, vec(v2a.pos).sub(m2)).magnitude() +
     318            0 :                      q2b.cross(axis, vec(v2b.pos).sub(m2)).magnitude() +
     319            0 :                      q2c.cross(axis, vec(v2c.pos).sub(m2)).magnitude();
     320            0 :     angle /= w1 + w2 + 1e-9f;
     321            0 :     const float a1 = angle*w2,
     322            0 :                 a2 = -angle*w1,
     323            0 :                 s1 = std::sin(a1),
     324            0 :                 s2 = std::sin(a2);
     325            0 :     const vec c1 = vec(axis).mul(1 - std::cos(a1)),
     326            0 :               c2 = vec(axis).mul(1 - std::cos(a2));
     327            0 :     v1a.newpos.add(vec().cross(c1, q1a).madd(q1a, s1).add(v1a.pos));
     328            0 :     v1a.weight++;
     329            0 :     v1b.newpos.add(vec().cross(c1, q1b).madd(q1b, s1).add(v1b.pos));
     330            0 :     v1b.weight++;
     331            0 :     v1c.newpos.add(vec().cross(c1, q1c).madd(q1c, s1).add(v1c.pos));
     332            0 :     v1c.weight++;
     333            0 :     v2a.newpos.add(vec().cross(c2, q2a).madd(q2a, s2).add(v2a.pos));
     334            0 :     v2a.weight++;
     335            0 :     v2b.newpos.add(vec().cross(c2, q2b).madd(q2b, s2).add(v2b.pos));
     336            0 :     v2b.weight++;
     337            0 :     v2c.newpos.add(vec().cross(c2, q2c).madd(q2c, s2).add(v2c.pos));
     338            0 :     v2c.weight++;
     339            0 : }
     340              : 
     341            0 : void ragdolldata::constrainrot()
     342              : {
     343            0 :     calctris(); //set up shadowing matrix3 objects for skel->tris
     344            0 :     for(const ragdollskel::rotlimit &r : skel->rotlimits)
     345              :     {
     346            0 :         matrix3 rot;
     347            0 :         rot.mul(tris[r.tri[0]], r.middle);
     348            0 :         rot.multranspose(tris[r.tri[1]]);
     349              : 
     350            0 :         vec axis;
     351              :         float angle;
     352            0 :         const float tr = rot.trace();
     353              :         //calculate angle and axis from the matrix `rot`, if possible
     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, vec &cwall)
     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(size_t 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, cwall))
     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(vec &cwall)
     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(size_t 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, cwall))
     474              :             {
     475            0 :                 vec dir = vec(v.pos).sub(v.oldpos);
     476            0 :                 const float facing = dir.dot(cwall);
     477            0 :                 if(facing < 0)
     478              :                 {
     479            0 :                     v.oldpos = vec(v.undo).sub(dir.msub(cwall, 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 :     vec collidewall(0,0,0);
     510              : 
     511            0 :     for(size_t i = 0; i < verts.size(); i++)
     512              :     {
     513            0 :         vert &v = verts[i];
     514            0 :         vec dpos = vec(v.pos).sub(v.oldpos);
     515            0 :         dpos.z -= 100*ts*ts;
     516            0 :         if(water)
     517              :         {
     518              :             //reinterpret cast pointer -> "random" seed value
     519            0 :             dpos.z += 0.25f*std::sin(detrnd(reinterpret_cast<size_t>(this)+i, 360)/RAD + lastmillis/10000.0f*M_PI)*ts;
     520              :         }
     521            0 :         dpos.mul(std::pow((water ? ragdollwaterfric : 1.0f) * (v.collided ? ragdollgroundfric : airfric), ts*1000.0f/ragdolltimestepmin)*tsfric);
     522            0 :         v.oldpos = v.pos;
     523            0 :         v.pos.add(dpos);
     524              :     }
     525            0 :     applyrotfriction(ts);
     526            0 :     for(size_t i = 0; i < verts.size(); i++)
     527              :     {
     528            0 :         vert &v = verts[i];
     529            0 :         if(v.pos.z < 0)
     530              :         {
     531            0 :             v.pos.z = 0;
     532            0 :             v.oldpos = v.pos;
     533            0 :             collisions++;
     534              :         }
     535            0 :         vec dir = vec(v.pos).sub(v.oldpos);
     536            0 :         v.collided = collidevert(v.pos, dir, skel->verts[i].radius, collidewall);
     537            0 :         if(v.collided)
     538              :         {
     539            0 :             v.pos = v.oldpos;
     540            0 :             v.oldpos.sub(dir.reflect(collidewall));
     541            0 :             collisions++;
     542              :         }
     543              :     }
     544            0 :     if(unsticks && ragdollunstick)
     545              :     {
     546            0 :         tryunstick(ts*ragdollunstick, collidewall);
     547              :     }
     548            0 :     timestep = ts;
     549            0 :     if(collisions)
     550              :     {
     551            0 :         floating = 0;
     552            0 :         if(!collidemillis)
     553              :         {
     554            0 :             collidemillis = lastmillis + (water ? ragdollwaterexpireoffset : ragdollexpireoffset);
     555              :         }
     556              :     }
     557            0 :     else if(++floating > 1 && lastmillis < collidemillis)
     558              :     {
     559            0 :         collidemillis = 0;
     560              :     }
     561            0 :     constrain(collidewall);
     562            0 :     calctris();
     563            0 :     calcboundsphere();
     564              : }
     565              : 
     566            0 : bool ragdolldata::collidevert(const vec &pos, const vec &dir, float radius, vec &cwall)
     567              : {
     568              :     static struct vertent : physent
     569              :     {
     570            0 :         vertent()
     571            0 :         {
     572            0 :             type = PhysEnt_Bounce;
     573            0 :             radius = xradius = yradius = eyeheight = aboveeye = 1;
     574            0 :         }
     575            0 :     } v;
     576            0 :     v.o = pos;
     577            0 :     if(v.radius != radius) //(radius param != 1)
     578              :     {
     579            0 :         v.radius = v.xradius = v.yradius = v.eyeheight = v.aboveeye = radius;
     580              :     }
     581              :     //collide generated vertent (point with sphere bounding of r = radius)
     582              :     //with dir parameter
     583            0 :     return collide(&v, &cwall, dir, 0);
     584              : }
     585              : 
     586              : //used in iengine
     587            0 : void moveragdoll(dynent *d)
     588              : {
     589            0 :     static FVAR(ragdolleyesmooth, 0, 0.5f, 1);
     590            0 :     static VAR(ragdolleyesmoothmillis, 1, 250, 10000);
     591            0 :     if(!curtime || !d->ragdoll)
     592              :     {
     593            0 :         return;
     594              :     }
     595            0 :     if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis)
     596              :     {
     597            0 :         const int lastmove = d->ragdoll->lastmove;
     598            0 :         while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis)
     599              :         {
     600            0 :             const int timestep = std::min(ragdolltimestepmax, lastmillis - d->ragdoll->lastmove),
     601            0 :                       material = rootworld.lookupmaterial(vec(d->ragdoll->center.x, d->ragdoll->center.y, d->ragdoll->center.z + d->ragdoll->radius/2));
     602            0 :             const bool water = (material&MatFlag_Volume) == Mat_Water;
     603            0 :             d->inwater = water ? material&MatFlag_Volume : Mat_Air;
     604            0 :             d->ragdoll->move(water, timestep/1000.0f);
     605            0 :             d->ragdoll->lastmove += timestep;
     606              :         }
     607              :     }
     608              : 
     609            0 :     vec eye = d->ragdoll->skel->eye >= 0 ? d->ragdoll->verts[d->ragdoll->skel->eye].pos : d->ragdoll->center;
     610            0 :     eye.add(d->ragdoll->offset);
     611            0 :     const float k = std::pow(ragdolleyesmooth, static_cast<float>(curtime)/ragdolleyesmoothmillis);
     612            0 :     d->o.lerp(eye, 1-k);
     613              : }
     614              : 
     615            1 : void cleanragdoll(dynent *d)
     616              : {
     617            1 :     if(d->ragdoll)
     618              :     {
     619            1 :         delete d->ragdoll;
     620            1 :         d->ragdoll = nullptr;
     621              :     }
     622            1 : }
        

Generated by: LCOV version 2.0-1