From 08741f0a427a568296411e6b6a51fc425ec048fa Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 4 Jun 2023 15:19:08 -0400 Subject: [PATCH] [jak2] float patch for bogus collide frags (#2686) Should fix https://github.com/open-goal/jak-project/issues/2679 Here's a test program that will trigger the bug when near these guards: ```lisp (define *cquery* (new 'global 'collide-query)) (defun test-bad-collide () (let ((lower (new 'static 'vector :x 1681893.8750 :y 61314.2031 :z 345208.6562 :w 1.)) (upper (new 'static 'vector :x 1701603.8750 :y 67624.0625 :z 357881.0312 :w 1.)) ;(cquery (new 'stack-no-clear 'collide-query)) ) (set! (-> *cquery* collide-with) (the-as collide-spec 1)) (set! (-> *cquery* ignore-process0) #f) (set! (-> *cquery* ignore-process1) #f) (set! (-> *cquery* ignore-pat) (new 'static 'pat-surface :noentity #x1 :nojak #x1 :probe #x1 :noendlessfall #x1)) (set! (-> *cquery* action-mask) (collide-action solid)) (set! (-> *cquery* bbox min quad) (-> lower quad)) (set! (-> *cquery* bbox max quad) (-> upper quad)) (format 0 "doing collide...~%") (fill-using-bounding-box *collide-cache* *cquery*) (format 0 "have ~d and ~d~%" (-> *collide-cache* num-tris) (-> *collide-cache* num-prims)) ) (none) ) ``` As far as I can tell, there's a totally invalid collide-hash with an inside `axis-scale.z`. On the PS2, it gets ignore because of how float->int works for floats that are too big. On PC, it ends up using a negative value and loop forever. --- docs/progress-notes/jak2/shadow-vu1.txt | 2 + game/mips2c/jak2_functions/collide_hash.cpp | 56 +++++++++++---------- game/mips2c/mips2c_private.h | 9 ++++ 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/docs/progress-notes/jak2/shadow-vu1.txt b/docs/progress-notes/jak2/shadow-vu1.txt index e086d11208..c921a1ba1f 100644 --- a/docs/progress-notes/jak2/shadow-vu1.txt +++ b/docs/progress-notes/jak2/shadow-vu1.txt @@ -405,6 +405,8 @@ L20: mtir vi07, vf29.z | nop b L19 | nop mtir vi02, vf29.x | nop + + ;;;;;;;;;; WEIRD TRIANGLES L21: iaddiu vi03, vi00, 0x158 | nop ilwr.x vi08, vi03 | nop diff --git a/game/mips2c/jak2_functions/collide_hash.cpp b/game/mips2c/jak2_functions/collide_hash.cpp index 6d5cf63485..1f262d7707 100644 --- a/game/mips2c/jak2_functions/collide_hash.cpp +++ b/game/mips2c/jak2_functions/collide_hash.cpp @@ -639,40 +639,42 @@ u64 execute(void* ctxt) { c->sq(s5, 96, sp); // sq s5, 96(sp) c->sq(gp, 112, sp); // sq gp, 112(sp) // nop // sll r0, r0, 0 - c->lw(v1, 40, a1); // lw v1, 40(a1) + c->lw(v1, 40, a1); // lw v1, 40(a1) v1 = frag.dimension_array; // nop // sll r0, r0, 0 - c->lqc2(vf1, 44, a1); // lqc2 vf1, 44(a1) - c->lui(a3, 1); // lui a3, 1 - c->lqc2(vf2, 128, a2); // lqc2 vf2, 128(a2) - c->ori(a3, a3, 257); // ori a3, a3, 257 - c->lqc2(vf3, 144, a2); // lqc2 vf3, 144(a2) - c->dsubu(v1, v1, a3); // dsubu v1, v1, a3 - c->lqc2(vf6, 60, a1); // lqc2 vf6, 60(a1) - c->vsub(DEST::xyzw, vf2, vf2, vf1); // vsub.xyzw vf2, vf2, vf1 - c->lq(a3, 160, a2); // lq a3, 160(a2) - c->vsub(DEST::xyzw, vf3, vf3, vf1); // vsub.xyzw vf3, vf3, vf1 - c->lq(t0, 176, a2); // lq t0, 176(a2) + c->lqc2(vf1, 44, a1); // lqc2 vf1, 44(a1) vf1 = frag.bbox.min + c->lui(a3, 1); // lui a3, 1 a3 = 0x10000 + c->lqc2(vf2, 128, a2); // lqc2 vf2, 128(a2) vf2 = query.bbox.min + c->ori(a3, a3, 257); // ori a3, a3, 257 a3=0x10101 + c->lqc2(vf3, 144, a2); // lqc2 vf3, 144(a2) vf3 = query.bbox.max + c->dsubu(v1, v1, a3); // dsubu v1, v1, a3 some math on the dim array + c->lqc2(vf6, 60, a1); // lqc2 vf6, 60(a1) vf6 = frag.axis_scale; + c->vsub(DEST::xyzw, vf2, vf2, vf1); // vsub.xyzw vf2, vf2, vf1 vf2 = query.min - frag.min + c->lq(a3, 160, a2); // lq a3, 160(a2) a3 = query.bbox.min.i + c->vsub(DEST::xyzw, vf3, vf3, vf1); // vsub.xyzw vf3, vf3, vf1 vf3 = query.max - frag.min + c->lq(t0, 176, a2); // lq t0, 176(a2) t0 = query.bbox.max.i c->pextlb(v1, r0, v1); // pextlb v1, r0, v1 - c->lq(t1, 76, a1); // lq t1, 76(a1) - c->pextlh(v1, r0, v1); // pextlh v1, r0, v1 - c->lq(t2, 92, a1); // lq t2, 92(a1) - c->pcgtw(t0, t1, t0); // pcgtw t0, t1, t0 - c->vftoi0(DEST::xyzw, vf4, vf2); // vftoi0.xyzw vf4, vf2 - c->pcgtw(a3, a3, t2); // pcgtw a3, a3, t2 - c->vftoi0(DEST::xyzw, vf5, vf3); // vftoi0.xyzw vf5, vf3 - c->por(a3, t0, a3); // por a3, t0, a3 - c->vmul(DEST::xyzw, vf2, vf2, vf6); // vmul.xyzw vf2, vf2, vf6 - c->ppach(a3, r0, a3); // ppach a3, r0, a3 - c->vmul(DEST::xyzw, vf3, vf3, vf6); // vmul.xyzw vf3, vf3, vf6 + c->lq(t1, 76, a1); // lq t1, 76(a1) t1 = frag.bbox.min.i + c->pextlh(v1, r0, v1); // pextlh v1, r0, v1 v1 = dimensions, int. + c->lq(t2, 92, a1); // lq t2, 92(a1) t2 = frag.bbox.max.i + c->pcgtw(t0, t1, t0); // pcgtw t0, t1, t0 check for bbox miss. + c->vftoi0(DEST::xyzw, vf4, vf2); // vftoi0.xyzw vf4, vf2 vf4 = int(q.min - f.min) + c->pcgtw(a3, a3, t2); // pcgtw a3, a3, t2 check for bbox miss. + c->vftoi0(DEST::xyzw, vf5, vf3); // vftoi0.xyzw vf5, vf3 vf5 = int(q.max - f.min) + c->por(a3, t0, a3); // por a3, t0, a3 or miss + c->vmul(DEST::xyzw, vf2, vf2, vf6); // vmul.xyzw vf2, vf2, vf6 axis scale + c->ppach(a3, r0, a3); // ppach a3, r0, a3 or stuff + c->vmul(DEST::xyzw, vf3, vf3, vf6); // vmul.xyzw vf3, vf3, vf6 axis scale c->dsll(t0, a3, 16); // dsll t0, a3, 16 - c->mov128_gpr_vf(a3, vf4); // qmfc2.i a3, vf4 + c->mov128_gpr_vf(a3, vf4); // qmfc2.i a3, vf4 a3 = int(q.min - f.min) bc = c->sgpr64(t0) != 0; // bne t0, r0, L75 - c->mov128_gpr_vf(t0, vf5); // qmfc2.i t0, vf5 + c->mov128_gpr_vf(t0, vf5); // qmfc2.i t0, vf5 t0 = int(q.max - f.min) if (bc) {goto block_17;} // branch non-likely - c->vftoi0(DEST::xyzw, vf2, vf2); // vftoi0.xyzw vf2, vf2 + // patch because there's a totally bogus collide fragment with an axis scale of + // 0.00012207031, 0.00012207031, 1807931 + c->vftoi0_sat(DEST::xyzw, vf2, vf2); // vftoi0.xyzw vf2, vf2 c->psraw(a3, a3, 4); // psraw a3, a3, 4 - c->vftoi0(DEST::xyzw, vf3, vf3); // vftoi0.xyzw vf3, vf3 + c->vftoi0_sat(DEST::xyzw, vf3, vf3); // vftoi0.xyzw vf3, vf3 c->psraw(t0, t0, 4); // psraw t0, t0, 4 // nop // sll r0, r0, 0 c->sq(a3, 368, a2); // sq a3, 368(a2) diff --git a/game/mips2c/mips2c_private.h b/game/mips2c/mips2c_private.h index 72619d5cf2..419f65826a 100644 --- a/game/mips2c/mips2c_private.h +++ b/game/mips2c/mips2c_private.h @@ -1344,6 +1344,15 @@ struct ExecutionContext { } } + void vftoi0_sat(DEST mask, int dst, int src) { + auto s = vf_src(src); + for (int i = 0; i < 4; i++) { + if ((u64)mask & (1 << i)) { + vfs[dst].ds32[i] = float_to_int_sat(s.f[i]); + } + } + } + void mfc1(int dst, int src) { s32 val; memcpy(&val, &fprs[src], 4);