summaryrefslogtreecommitdiff
path: root/src/engine/ragdoll.h
diff options
context:
space:
mode:
authorxolatile2025-08-06 22:54:55 +0200
committerxolatile2025-08-06 22:54:55 +0200
commit0a1172b75f571685c264a8b9d8ee224bbf11381f (patch)
treed041fdc68a60f0ebb48a3852bbcce6d9432f83d5 /src/engine/ragdoll.h
parentaffde05dc07a94643f1fd2751b2b441f57f73d7d (diff)
downloadxolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.xz
xolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.zst
Please do not hate me, it makes sense...
Diffstat (limited to 'src/engine/ragdoll.h')
-rw-r--r--src/engine/ragdoll.h215
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);
}