diff options
Diffstat (limited to 'src/engine/ragdoll.h')
| -rw-r--r-- | src/engine/ragdoll.h | 215 |
1 files changed, 59 insertions, 156 deletions
diff --git a/src/engine/ragdoll.h b/src/engine/ragdoll.h index 4dac48c..915076e 100644 --- a/src/engine/ragdoll.h +++ b/src/engine/ragdoll.h @@ -1,53 +1,36 @@ -struct ragdollskel -{ - struct vert - { +struct ragdollskel { + struct vert { vec pos; float radius, weight; }; - - struct tri - { + struct tri { int vert[3]; - - bool shareverts(const tri &t) const - { + bool shareverts(const tri &t) const { loopi(3) loopj(3) if(vert[i] == t.vert[j]) return true; return false; } }; - - struct distlimit - { + struct distlimit { int vert[2]; float mindist, maxdist; }; - - struct rotlimit - { + struct rotlimit { int tri[2]; float maxangle; matrix3 middle; }; - - struct rotfriction - { + struct rotfriction { int tri[2]; matrix3 middle; }; - - struct joint - { + struct joint { int bone, tri, vert[3]; float weight; matrix4x3 orient; }; - - struct reljoint - { + struct reljoint { int bone, parent; }; - bool loaded, animjoints; int eye; vector<vert> verts; @@ -57,26 +40,20 @@ struct ragdollskel vector<rotfriction> rotfrictions; vector<joint> joints; vector<reljoint> reljoints; - ragdollskel() : loaded(false), animjoints(false), eye(-1) {} - - void setupjoints() - { + void setupjoints() { loopv(verts) verts[i].weight = 0; - loopv(joints) - { + loopv(joints) { joint &j = joints[i]; j.weight = 0; vec pos(0, 0, 0); - loopk(3) if(j.vert[k]>=0) - { + loopk(3) if(j.vert[k]>=0) { pos.add(verts[j.vert[k]].pos); j.weight++; verts[j.vert[k]].weight++; } if(j.weight) j.weight = 1/j.weight; pos.mul(j.weight); - tri &t = tris[j.tri]; matrix4x3 &m = j.orient; const vec &v1 = verts[t.vert[0]].pos, @@ -91,45 +68,33 @@ struct ragdollskel loopv(verts) if(verts[i].weight) verts[i].weight = 1/verts[i].weight; reljoints.shrink(0); } - - void setuprotfrictions() - { + void setuprotfrictions() { rotfrictions.shrink(0); - loopv(tris) for(int j = i+1; j < tris.length(); j++) if(tris[i].shareverts(tris[j])) - { + loopv(tris) for(int j = i+1; j < tris.length(); j++) if(tris[i].shareverts(tris[j])) { rotfriction &r = rotfrictions.add(); r.tri[0] = i; r.tri[1] = j; } } - - void setup() - { + void setup() { setupjoints(); setuprotfrictions(); - loaded = true; } - - void addreljoint(int bone, int parent) - { + void addreljoint(int bone, int parent) { reljoint &r = reljoints.add(); r.bone = bone; r.parent = parent; } }; -struct ragdolldata -{ - struct vert - { +struct ragdolldata { + struct vert { vec oldpos, pos, newpos; float weight; bool collided, stuck; - vert() : pos(0, 0, 0), newpos(0, 0, 0), weight(0), collided(false), stuck(true) {} }; - ragdollskel *skel; int millis, collidemillis, collisions, floating, lastmove, unsticks; vec offset, center; @@ -138,7 +103,6 @@ struct ragdolldata matrix3 *tris; matrix4x3 *animjoints; dualquat *reljoints; - ragdolldata(ragdollskel *skel, float scale = 1) : skel(skel), millis(lastmillis), @@ -153,26 +117,20 @@ struct ragdolldata verts(new vert[skel->verts.length()]), tris(new matrix3[skel->tris.length()]), animjoints(!skel->animjoints || skel->joints.empty() ? NULL : new matrix4x3[skel->joints.length()]), - reljoints(skel->reljoints.empty() ? NULL : new dualquat[skel->reljoints.length()]) - { + reljoints(skel->reljoints.empty() ? NULL : new dualquat[skel->reljoints.length()]) { } - - ~ragdolldata() - { + ~ragdolldata() { delete[] verts; delete[] tris; if(animjoints) delete[] animjoints; if(reljoints) delete[] reljoints; } - - void calcanimjoint(int i, const matrix4x3 &anim) - { + void calcanimjoint(int i, const matrix4x3 &anim) { if(!animjoints) return; ragdollskel::joint &j = skel->joints[i]; vec pos(0, 0, 0); loopk(3) if(j.vert[k]>=0) pos.add(verts[j.vert[k]].pos); pos.mul(j.weight); - ragdollskel::tri &t = skel->tris[j.tri]; matrix4x3 m; const vec &v1 = verts[t.vert[0]].pos, @@ -184,11 +142,8 @@ struct ragdolldata m.d = pos; animjoints[i].transposemul(m, anim); } - - void calctris() - { - loopv(skel->tris) - { + void calctris() { + loopv(skel->tris) { ragdollskel::tri &t = skel->tris[i]; matrix3 &m = tris[i]; const vec &v1 = verts[t.vert[0]].pos, @@ -199,30 +154,24 @@ struct ragdolldata m.b.cross(m.c, m.a); } } - - void calcboundsphere() - { + void calcboundsphere() { center = vec(0, 0, 0); loopv(skel->verts) center.add(verts[i].pos); center.div(skel->verts.length()); radius = 0; loopv(skel->verts) radius = max(radius, verts[i].pos.dist(center)); } - - void init(dynent *d) - { + void init(dynent *d) { extern int ragdolltimestepmin; float ts = ragdolltimestepmin/1000.0f; loopv(skel->verts) (verts[i].oldpos = verts[i].pos).sub(vec(d->vel).add(d->falling).mul(ts)); timestep = ts; - calctris(); calcboundsphere(); offset = d->o; offset.sub(skel->eye >= 0 ? verts[skel->eye].pos : center); offset.z += (d->eyeheight + d->aboveeye)/2; } - void move(dynent *pl, float ts); void updatepos(); void constrain(); @@ -232,13 +181,9 @@ struct ragdolldata void calcrotfriction(); void applyrotfriction(float ts); void tryunstick(float speed); - - static inline bool collidevert(const vec &pos, const vec &dir, float radius) - { - static struct vertent : physent - { - vertent() - { + static inline bool collidevert(const vec &pos, const vec &dir, float radius) { + static struct vertent : physent { + vertent() { type = ENT_BOUNCE; radius = xradius = yradius = eyeheight = aboveeye = 1; } @@ -255,11 +200,9 @@ struct ragdolldata parented transform = parent{invert(curtri) * origtrig} * (invert(parent{base2anim}) * base2anim) */ -void ragdolldata::constraindist() -{ +void ragdolldata::constraindist() { float invscale = 1.0f/scale; - loopv(skel->distlimits) - { + loopv(skel->distlimits) { ragdollskel::distlimit &d = skel->distlimits[i]; vert &v1 = verts[d.vert[0]], &v2 = verts[d.vert[1]]; vec dir = vec(v2.pos).sub(v1.pos); @@ -277,8 +220,7 @@ void ragdolldata::constraindist() } } -inline void ragdolldata::applyrotlimit(ragdollskel::tri &t1, ragdollskel::tri &t2, float angle, const vec &axis) -{ +inline void ragdolldata::applyrotlimit(ragdollskel::tri &t1, ragdollskel::tri &t2, float angle, const vec &axis) { vert &v1a = verts[t1.vert[0]], &v1b = verts[t1.vert[1]], &v1c = verts[t1.vert[2]], &v2a = verts[t2.vert[0]], &v2b = verts[t2.vert[1]], &v2c = verts[t2.vert[2]]; vec m1 = vec(v1a.pos).add(v1b.pos).add(v1c.pos).div(3), @@ -308,22 +250,18 @@ inline void ragdolldata::applyrotlimit(ragdollskel::tri &t1, ragdollskel::tri &t v2c.weight++; } -void ragdolldata::constrainrot() -{ - loopv(skel->rotlimits) - { +void ragdolldata::constrainrot() { + loopv(skel->rotlimits) { ragdollskel::rotlimit &r = skel->rotlimits[i]; matrix3 rot; rot.mul(tris[r.tri[0]], r.middle); rot.multranspose(tris[r.tri[1]]); - vec axis; float angle; if(!rot.calcangleaxis(angle, axis)) continue; angle = r.maxangle - fabs(angle); if(angle >= 0) continue; angle += 1e-3f; - applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis); } } @@ -333,36 +271,29 @@ VAR(ragdolltimestepmax, 1, 10, 50); FVAR(ragdollrotfric, 0, 0.85f, 1); FVAR(ragdollrotfricstop, 0, 0.1f, 1); -void ragdolldata::calcrotfriction() -{ - loopv(skel->rotfrictions) - { +void ragdolldata::calcrotfriction() { + loopv(skel->rotfrictions) { ragdollskel::rotfriction &r = skel->rotfrictions[i]; r.middle.transposemul(tris[r.tri[0]], tris[r.tri[1]]); } } -void ragdolldata::applyrotfriction(float ts) -{ +void ragdolldata::applyrotfriction(float ts) { calctris(); float stopangle = 2*M_PI*ts*ragdollrotfricstop, rotfric = 1.0f - pow(ragdollrotfric, ts*1000.0f/ragdolltimestepmin); - loopv(skel->rotfrictions) - { + loopv(skel->rotfrictions) { ragdollskel::rotfriction &r = skel->rotfrictions[i]; matrix3 rot; rot.mul(tris[r.tri[0]], r.middle); rot.multranspose(tris[r.tri[1]]); - vec axis; float angle; - if(rot.calcangleaxis(angle, axis)) - { + if(rot.calcangleaxis(angle, axis)) { angle *= -(fabs(angle) >= stopangle ? rotfric : 1.0f); applyrotlimit(skel->tris[r.tri[0]], skel->tris[r.tri[1]], angle, axis); } } - loopv(skel->verts) - { + loopv(skel->verts) { vert &v = verts[i]; if(v.weight) v.pos = v.newpos.div(v.weight); v.newpos = vec(0, 0, 0); @@ -370,15 +301,12 @@ void ragdolldata::applyrotfriction(float ts) } } -void ragdolldata::tryunstick(float speed) -{ +void ragdolldata::tryunstick(float speed) { vec unstuck(0, 0, 0); int stuck = 0; - loopv(skel->verts) - { + loopv(skel->verts) { vert &v = verts[i]; - if(v.stuck) - { + if(v.stuck) { if(collidevert(v.pos, vec(0, 0, 0), skel->verts[i].radius)) { stuck++; continue; } v.stuck = false; } @@ -387,28 +315,22 @@ void ragdolldata::tryunstick(float speed) unsticks = 0; if(!stuck || stuck >= skel->verts.length()) return; unstuck.div(skel->verts.length() - stuck); - loopv(skel->verts) - { + loopv(skel->verts) { vert &v = verts[i]; - if(v.stuck) - { + if(v.stuck) { v.pos.add(vec(unstuck).sub(v.pos).rescale(speed)); unsticks++; } } } -void ragdolldata::updatepos() -{ - loopv(skel->verts) - { +void ragdolldata::updatepos() { + loopv(skel->verts) { vert &v = verts[i]; - if(v.weight) - { + if(v.weight) { v.newpos.div(v.weight); if(!collidevert(v.newpos, vec(v.newpos).sub(v.pos), skel->verts[i].radius)) v.pos = v.newpos; - else - { + else { vec dir = vec(v.newpos).sub(v.oldpos); if(dir.dot(collidewall) < 0) v.oldpos = vec(v.pos).sub(dir.reflect(collidewall)); v.collided = true; @@ -421,13 +343,10 @@ void ragdolldata::updatepos() VAR(ragdollconstrain, 1, 5, 100); -void ragdolldata::constrain() -{ - loopi(ragdollconstrain) - { +void ragdolldata::constrain() { + loopi(ragdollconstrain) { constraindist(); updatepos(); - calctris(); constrainrot(); updatepos(); @@ -441,19 +360,15 @@ FVAR(ragdollairfric, 0, 0.996f, 1); FVAR(ragdollunstick, 0, 10, 1e3f); VAR(ragdollexpireoffset, 0, 1500, 30000); -void ragdolldata::move(dynent *pl, float ts) -{ +void ragdolldata::move(dynent *pl, float ts) { extern const float GRAVITY; if(collidemillis && lastmillis > collidemillis) return; - pl->inwater = MAT_AIR; - calcrotfriction(); float tsfric = timestep ? ts/timestep : 1, airfric = ragdollairfric + min((ragdollbodyfricscale*collisions)/skel->verts.length(), 1.0f)*(ragdollbodyfric - ragdollairfric); collisions = 0; - loopv(skel->verts) - { + loopv(skel->verts) { vert &v = verts[i]; vec dpos = vec(v.pos).sub(v.oldpos); dpos.z -= GRAVITY*ts*ts; @@ -462,30 +377,24 @@ void ragdolldata::move(dynent *pl, float ts) v.pos.add(dpos); } applyrotfriction(ts); - loopv(skel->verts) - { + loopv(skel->verts) { vert &v = verts[i]; if(v.pos.z < 0) { v.pos.z = 0; v.oldpos = v.pos; collisions++; } vec dir = vec(v.pos).sub(v.oldpos); v.collided = collidevert(v.pos, dir, skel->verts[i].radius); - if(v.collided) - { + if(v.collided) { v.pos = v.oldpos; v.oldpos.sub(dir.reflect(collidewall)); collisions++; } } - if(unsticks && ragdollunstick) tryunstick(ts*ragdollunstick); - timestep = ts; - if(collisions) - { + if(collisions) { floating = 0; if(!collidemillis) collidemillis = lastmillis + ragdollexpireoffset; } else if(++floating > 1 && lastmillis < collidemillis) collidemillis = 0; - constrain(); calctris(); calcboundsphere(); @@ -494,28 +403,22 @@ void ragdolldata::move(dynent *pl, float ts) FVAR(ragdolleyesmooth, 0, 0.5f, 1); VAR(ragdolleyesmoothmillis, 1, 250, 10000); -void moveragdoll(dynent *d) -{ +void moveragdoll(dynent *d) { if(!curtime || !d->ragdoll) return; - - if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis) - { + if(!d->ragdoll->collidemillis || lastmillis < d->ragdoll->collidemillis) { int lastmove = d->ragdoll->lastmove; - while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis) - { + while(d->ragdoll->lastmove + (lastmove == d->ragdoll->lastmove ? ragdolltimestepmin : ragdolltimestepmax) <= lastmillis) { int timestep = min(ragdolltimestepmax, lastmillis - d->ragdoll->lastmove); d->ragdoll->move(d, timestep/1000.0f); d->ragdoll->lastmove += timestep; } } - vec eye = d->ragdoll->skel->eye >= 0 ? d->ragdoll->verts[d->ragdoll->skel->eye].pos : d->ragdoll->center; eye.add(d->ragdoll->offset); float k = pow(ragdolleyesmooth, float(curtime)/ragdolleyesmoothmillis); d->o.mul(k).add(eye.mul(1-k)); } -void cleanragdoll(dynent *d) -{ +void cleanragdoll(dynent *d) { DELETEP(d->ragdoll); } |
