diff options
Diffstat (limited to 'src/bones.cpp')
| -rw-r--r-- | src/bones.cpp | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/src/bones.cpp b/src/bones.cpp index 1940449..787af1b 100644 --- a/src/bones.cpp +++ b/src/bones.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | // Everything here is client-side; no server access is involved. | 6 | // Everything here is client-side; no server access is involved. |
| 7 | 7 | ||
| 8 | #include "hl2h.h" | 8 | #include "hl2h.h" |
| 9 | #include <cmath> | ||
| 9 | #include <cstdint> | 10 | #include <cstdint> |
| 10 | #include <cstring> | 11 | #include <cstring> |
| 11 | #include <ctime> | 12 | #include <ctime> |
| @@ -95,6 +96,7 @@ struct BoneEntry { | |||
| 95 | const StudioHdr *hdr; | 96 | const StudioHdr *hdr; |
| 96 | int count; | 97 | int count; |
| 97 | bool core[MAX_BONES]; | 98 | bool core[MAX_BONES]; |
| 99 | bool bone_valid[MAX_BONES]; | ||
| 98 | Matrix3x4 mats[MAX_BONES]; | 100 | Matrix3x4 mats[MAX_BONES]; |
| 99 | }; | 101 | }; |
| 100 | 102 | ||
| @@ -138,6 +140,17 @@ static const char *bone_name_raw(const StudioHdr *h, int i) { | |||
| 138 | return n[0] ? n : nullptr; | 140 | return n[0] ? n : nullptr; |
| 139 | } | 141 | } |
| 140 | 142 | ||
| 143 | // SetupBones can leave extra/modded bones uninitialized; they show up as a | ||
| 144 | // zero matrix and would draw a line to world (0,0,0). | ||
| 145 | static bool matrix_ok(const Matrix3x4 &m) { | ||
| 146 | for (int r = 0; r < 3; r++) | ||
| 147 | for (int c = 0; c < 4; c++) | ||
| 148 | if (!std::isfinite(m.m[r][c])) | ||
| 149 | return false; | ||
| 150 | float x = m.m[0][3], y = m.m[1][3], z = m.m[2][3]; | ||
| 151 | return (fabsf(x) + fabsf(y) + fabsf(z)) > 0.01f; | ||
| 152 | } | ||
| 153 | |||
| 141 | static const HitboxSet *hitbox_set0(const StudioHdr *h) { | 154 | static const HitboxSet *hitbox_set0(const StudioHdr *h) { |
| 142 | if (!h || h->numhitboxsets <= 0 || h->hitboxsetindex <= 0) | 155 | if (!h || h->numhitboxsets <= 0 || h->hitboxsetindex <= 0) |
| 143 | return nullptr; | 156 | return nullptr; |
| @@ -181,7 +194,7 @@ static bool head_like_name(const char *n) { | |||
| 181 | } | 194 | } |
| 182 | 195 | ||
| 183 | static bool hitbox_world(const BoneEntry *e, const Hitbox &b, Vector &out) { | 196 | static bool hitbox_world(const BoneEntry *e, const Hitbox &b, Vector &out) { |
| 184 | if (b.bone < 0 || b.bone >= e->count) | 197 | if (b.bone < 0 || b.bone >= e->count || !e->bone_valid[b.bone]) |
| 185 | return false; | 198 | return false; |
| 186 | Vector local{(b.bbmin.x + b.bbmax.x) * 0.5f, | 199 | Vector local{(b.bbmin.x + b.bbmax.x) * 0.5f, |
| 187 | (b.bbmin.y + b.bbmax.y) * 0.5f, | 200 | (b.bbmin.y + b.bbmax.y) * 0.5f, |
| @@ -347,11 +360,18 @@ bool bones_update(int idx, void *ent) { | |||
| 347 | e->hdr = hdr; | 360 | e->hdr = hdr; |
| 348 | e->count = hdr->numbones; | 361 | e->count = hdr->numbones; |
| 349 | build_core_mask(e); | 362 | build_core_mask(e); |
| 363 | int invalid_bones = 0; | ||
| 364 | for (int i = 0; i < e->count; i++) { | ||
| 365 | e->bone_valid[i] = matrix_ok(e->mats[i]); | ||
| 366 | if (!e->bone_valid[i]) | ||
| 367 | invalid_bones++; | ||
| 368 | } | ||
| 350 | e->valid = true; | 369 | e->valid = true; |
| 351 | e->stamp = now; | 370 | e->stamp = now; |
| 352 | if (g_logged < 4) { | 371 | if (g_logged < 4) { |
| 353 | g_logged++; | 372 | g_logged++; |
| 354 | logf("bones: idx=%d count=%d bone0=%s", idx, e->count, | 373 | logf("bones: idx=%d count=%d invalid=%d bone0=%s", idx, e->count, |
| 374 | invalid_bones, | ||
| 355 | bone_name_raw(hdr, 0) ? bone_name_raw(hdr, 0) : "?"); | 375 | bone_name_raw(hdr, 0) ? bone_name_raw(hdr, 0) : "?"); |
| 356 | } | 376 | } |
| 357 | return true; | 377 | return true; |
| @@ -385,6 +405,8 @@ bool bone_is_skeleton_core(int idx, int bone) { | |||
| 385 | BoneEntry *e = find_entry(idx); | 405 | BoneEntry *e = find_entry(idx); |
| 386 | if (!e || !e->valid || bone < 0 || bone >= e->count) | 406 | if (!e || !e->valid || bone < 0 || bone >= e->count) |
| 387 | return false; | 407 | return false; |
| 408 | if (!e->bone_valid[bone]) | ||
| 409 | return false; | ||
| 388 | if (!e->humanoid) | 410 | if (!e->humanoid) |
| 389 | return true; // non-humanoid: draw its full bone tree | 411 | return true; // non-humanoid: draw its full bone tree |
| 390 | return e->core[bone]; | 412 | return e->core[bone]; |
| @@ -395,10 +417,13 @@ int bone_nearest_core_parent(int idx, int bone) { | |||
| 395 | if (!e || !e->valid || bone < 0 || bone >= e->count) | 417 | if (!e || !e->valid || bone < 0 || bone >= e->count) |
| 396 | return -1; | 418 | return -1; |
| 397 | int p = bone_at(e->hdr, bone)->parent; | 419 | int p = bone_at(e->hdr, bone)->parent; |
| 398 | if (!e->humanoid) | 420 | if (!e->humanoid) { |
| 421 | while (p >= 0 && p < e->count && !e->bone_valid[p]) | ||
| 422 | p = bone_at(e->hdr, p)->parent; | ||
| 399 | return (p >= 0 && p < e->count) ? p : -1; | 423 | return (p >= 0 && p < e->count) ? p : -1; |
| 424 | } | ||
| 400 | for (int guard = 0; p >= 0 && p < e->count && guard < 64; guard++) { | 425 | for (int guard = 0; p >= 0 && p < e->count && guard < 64; guard++) { |
| 401 | if (e->core[p]) | 426 | if (e->core[p] && e->bone_valid[p]) |
| 402 | return p; | 427 | return p; |
| 403 | p = bone_at(e->hdr, p)->parent; | 428 | p = bone_at(e->hdr, p)->parent; |
| 404 | } | 429 | } |
| @@ -412,7 +437,8 @@ bool bones_is_humanoid(int idx) { | |||
| 412 | 437 | ||
| 413 | bool bone_pos(int idx, int bone, Vector &out) { | 438 | bool bone_pos(int idx, int bone, Vector &out) { |
| 414 | BoneEntry *e = find_entry(idx); | 439 | BoneEntry *e = find_entry(idx); |
| 415 | if (!e || !e->valid || bone < 0 || bone >= e->count) | 440 | if (!e || !e->valid || bone < 0 || bone >= e->count || |
| 441 | !e->bone_valid[bone]) | ||
| 416 | return false; | 442 | return false; |
| 417 | const Matrix3x4 &m = e->mats[bone]; | 443 | const Matrix3x4 &m = e->mats[bone]; |
| 418 | out = {m.m[0][3], m.m[1][3], m.m[2][3]}; | 444 | out = {m.m[0][3], m.m[1][3], m.m[2][3]}; |
