From 251b0659cbeaf146b0c382b66f59f2ec8dd8e76d Mon Sep 17 00:00:00 2001 From: water111 Date: Mon, 31 Aug 2026 15:10:16 -0700 Subject: [PATCH] up to collide-probe --- decompiler/config/jak1/demacro.jsonc | 23 + .../config/jak1/ntsc_v1/type_casts.jsonc | 7 + game/CMakeLists.txt | 2 - game/mips2c/jak1_functions/collide_probe.cpp | 1144 ------------ game/mips2c/jak1_functions/time_of_day.cpp | 272 --- goal_src/jak1/engine/collide/collide-func.gc | 40 +- .../engine/collide/collide-probe-ee-asm.gc | 955 +++++++++++ goal_src/jak1/engine/collide/collide-probe.gc | 1252 +++----------- goal_src/jak1/engine/gfx/mood/mood-tables.gc | 103 +- goal_src/jak1/engine/gfx/mood/mood.gc | 595 +++---- goal_src/jak1/engine/gfx/mood/time-of-day.gc | 3 - .../jak1/engine/gfx/sky/sky-tng-ee-asm.gc | 832 +++++++++ goal_src/jak1/engine/gfx/sky/sky-tng.gc | 1526 +++++------------ goal_src/jak1/engine/gfx/sky/sky-utils.gc | 1 + goal_src/jak1/engine/gfx/sky/sky.gc | 301 +--- goal_src/jak1/engine/level/level.gc | 31 +- .../jak1/engine/level/load-boundary-ee-asm.gc | 415 +++++ goal_src/jak1/engine/level/load-boundary-h.gc | 8 +- goal_src/jak1/engine/level/load-boundary.gc | 650 ++----- goal_src/jak1/engine/ui/text.gc | 4 +- test/common/test_demacro.cpp | 32 + 21 files changed, 3466 insertions(+), 4730 deletions(-) delete mode 100644 game/mips2c/jak1_functions/collide_probe.cpp delete mode 100644 game/mips2c/jak1_functions/time_of_day.cpp create mode 100644 goal_src/jak1/engine/collide/collide-probe-ee-asm.gc create mode 100644 goal_src/jak1/engine/gfx/sky/sky-tng-ee-asm.gc create mode 100644 goal_src/jak1/engine/level/load-boundary-ee-asm.gc diff --git a/decompiler/config/jak1/demacro.jsonc b/decompiler/config/jak1/demacro.jsonc index adeb1ff370..c09037e3c4 100644 --- a/decompiler/config/jak1/demacro.jsonc +++ b/decompiler/config/jak1/demacro.jsonc @@ -327,6 +327,29 @@ "rewrite": "(dma-buffer-add-cnt-vif2 $buf $qwc $vif0 $vif1)" }, + { + // A direct buffer cursor needs no alias binding, so let insertion leaves a single let. + "name": "dma-buffer-add-cnt-vif2-direct-object-packet", + "match": + "(let (($packet (the-as object (-> $buf base)))) (set! (-> (the-as dma-packet $packet) dma) (new 'static 'dma-tag :id (dma-tag-id cnt))) (set! (-> (the-as dma-packet $packet) vif0) $vif0) (set! (-> (the-as dma-packet $packet) vif1) $vif1) (set! (-> $buf base) (&+ (the-as pointer $packet) 16)))", + "rewrite": + "(dma-buffer-add-cnt-vif2 $buf 0 $vif0 $vif1)" + }, + { + // Constructor keyword order follows the original instruction order and is not canonicalized. + "name": "dma-buffer-add-cnt-vif2-qwc-after-id-object-packet", + "match": + "(let* (($alias $buf) ($packet (the-as object (-> $alias base)))) (set! (-> (the-as dma-packet $packet) dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc $qwc)) (set! (-> (the-as dma-packet $packet) vif0) $vif0) (set! (-> (the-as dma-packet $packet) vif1) $vif1) (set! (-> $alias base) (&+ (the-as pointer $packet) 16)))", + "rewrite": + "(dma-buffer-add-cnt-vif2 $buf $qwc $vif0 $vif1)" + }, + { + "name": "dma-buffer-add-ref-vif2-object-packet", + "match": + "(let (($packet (the-as object (-> $buf base)))) (set! (-> (the-as dma-packet $packet) dma) (new 'static 'dma-tag :qwc $qwc :id (dma-tag-id ref) :addr $addr)) (set! (-> (the-as dma-packet $packet) vif0) $vif0) (set! (-> (the-as dma-packet $packet) vif1) $vif1) (set! (-> $buf base) (&+ (the-as pointer $packet) 16)))", + "rewrite": + "(dma-buffer-add-ref-vif2 $buf $qwc $addr $vif0 $vif1)" + }, { "name": "dma-buffer-add-next-vif2-object-packet", "match": diff --git a/decompiler/config/jak1/ntsc_v1/type_casts.jsonc b/decompiler/config/jak1/ntsc_v1/type_casts.jsonc index 649f307dba..3cfbbba46a 100644 --- a/decompiler/config/jak1/ntsc_v1/type_casts.jsonc +++ b/decompiler/config/jak1/ntsc_v1/type_casts.jsonc @@ -2740,6 +2740,13 @@ [2, "v1", "(pointer process-drawable)"] ], "update-time-of-day": [[46, "v0", "(array float)"]], + "sky-add-frame-data": [ + [[3, 16], "a1", "dma-packet"], + [[18, 75], "a0", "sky-frame-data"], + [[92, 103], "v1", "dma-packet"] + ], + "sky-upload": [[[11, 22], "v1", "dma-packet"]], + "sky-draw": [[[1, 12], "a0", "dma-packet"]], "sky-make-light": [[[10, 23], "a0", "sky-sun-data"]], "make-sky-textures": [ [[90, 94], "a0", "dma-packet"], diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index a6a2de4664..05a1139730 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -161,7 +161,6 @@ set(RUNTIME_SOURCE mips2c/jak1_functions/collide_cache.cpp mips2c/jak1_functions/collide_edge_grab.cpp mips2c/jak1_functions/collide_mesh.cpp - mips2c/jak1_functions/collide_probe.cpp mips2c/jak1_functions/generic_merc.cpp mips2c/jak1_functions/merc_blend_shape.cpp mips2c/jak1_functions/ocean_vu0.cpp @@ -170,7 +169,6 @@ set(RUNTIME_SOURCE mips2c/jak1_functions/sky_tng.cpp mips2c/jak1_functions/test_func.cpp mips2c/jak1_functions/texture.cpp - mips2c/jak1_functions/time_of_day.cpp mips2c/jak2_functions/bones.cpp mips2c/jak2_functions/collide_cache.cpp diff --git a/game/mips2c/jak1_functions/collide_probe.cpp b/game/mips2c/jak1_functions/collide_probe.cpp deleted file mode 100644 index 3b5d540916..0000000000 --- a/game/mips2c/jak1_functions/collide_probe.cpp +++ /dev/null @@ -1,1144 +0,0 @@ - -//--------------------------MIPS2C--------------------- -// clang-format off -#include "game/mips2c/mips2c_private.h" -#include "game/kernel/jak1/kscheme.h" -using namespace jak1; -namespace Mips2C::jak1 { -namespace collide_probe_node { -struct Cache { - void* collide_probe_stack; // *collide-probe-stack* - void* collide_work; // *collide-work* -} cache; - -u64 execute(void* ctxt) { - auto* c = (ExecutionContext*)ctxt; - bool bc = false; - c->daddiu(sp, sp, -96); // daddiu sp, sp, -96 - c->sd(ra, 0, sp); // sd ra, 0(sp) - c->sq(s2, 16, sp); // sq s2, 16(sp) - c->sq(s3, 32, sp); // sq s3, 32(sp) - c->sq(s4, 48, sp); // sq s4, 48(sp) - c->sq(s5, 64, sp); // sq s5, 64(sp) - c->sq(gp, 80, sp); // sq gp, 80(sp) - c->load_symbol(t0, cache.collide_work); // lw t0, *collide-work*(s7) - c->load_symbol(v1, cache.collide_probe_stack); // lw v1, *collide-probe-stack*(s7) - c->sw(a0, 0, v1); // sw a0, 0(v1) - c->daddiu(a0, v1, 8); // daddiu a0, v1, 8 - c->sh(a1, 4, v1); // sh a1, 4(v1) - c->addiu(a1, r0, 1); // addiu a1, r0, 1 - c->sh(a1, 6, v1); // sh a1, 6(v1) - c->lq(a1, 16, t0); // lq a1, 16(t0) - c->lq(a3, 32, t0); // lq a3, 32(t0) - c->lqc2(vf1, 48, t0); // lqc2 vf1, 48(t0) - c->lqc2(vf2, 64, t0); // lqc2 vf2, 64(t0) - c->lqc2(vf3, 80, t0); // lqc2 vf3, 80(t0) - c->lqc2(vf4, 96, t0); // lqc2 vf4, 96(t0) - c->lw(t0, 0, a2); // lw t0, 0(a2) - c->sll(t1, t0, 4); // sll t1, t0, 4 - c->addu(t1, t1, a2); // addu t1, t1, a2 - c->addiu(t1, t1, 16); // addiu t1, t1, 16 - - block_1: - bc = c->sgpr64(a0) == c->sgpr64(v1); // beq a0, v1, L71 - // nop // sll r0, r0, 0 - if (bc) {goto block_32;} // branch non-likely - - c->daddiu(a0, a0, -8); // daddiu a0, a0, -8 - c->lw(t2, 0, a0); // lw t2, 0(a0) - c->lhu(t3, 4, a0); // lhu t3, 4(a0) - c->lhu(t4, 6, a0); // lhu t4, 6(a0) - - block_3: - c->lqc2(vf5, 12, t2); // lqc2 vf5, 12(t2) - c->lqc2(vf6, 44, t2); // lqc2 vf6, 44(t2) - c->daddiu(t5, t3, -4); // daddiu t5, t3, -4 - c->lqc2(vf7, 76, t2); // lqc2 vf7, 76(t2) - bc = ((s64)c->sgpr64(t5)) < 0; // bltz t5, L61 - c->lqc2(vf8, 108, t2); // lqc2 vf8, 108(t2) - if (bc) {goto block_5;} // branch non-likely - - // Unknown instr: pref r0, 140, t2 - - block_5: - // Unknown instr: vcallms 0 - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf05 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf5); - // nop | madday.xyzw ACC, vf02, vf05 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf5); - // nop | maddz.xyz vf05, vf03, vf05 - c->vmadd_bc(DEST::xyz, BC::z, vf5, vf3, vf5); - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf06 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf6); - // nop | madday.xyzw ACC, vf02, vf06 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf6); - // nop | maddz.xyz vf06, vf03, vf06 - c->vmadd_bc(DEST::xyz, BC::z, vf6, vf3, vf6); - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf07 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf7); - // nop | madday.xyzw ACC, vf02, vf07 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf7); - // nop | maddz.xyz vf07, vf03, vf07 - c->vmadd_bc(DEST::xyz, BC::z, vf7, vf3, vf7); - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf08 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf8); - // nop | madday.xyzw ACC, vf02, vf08 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf8); - // nop | maddz.xyz vf08, vf03, vf08 - c->vmadd_bc(DEST::xyz, BC::z, vf8, vf3, vf8); - // nop | subw.xyz vf09, vf05, vf05 - c->vsub_bc(DEST::xyz, BC::w, vf9, vf5, vf5); - // nop | subw.xyz vf11, vf06, vf06 - c->vsub_bc(DEST::xyz, BC::w, vf11, vf6, vf6); - // nop | subw.xyz vf13, vf07, vf07 - c->vsub_bc(DEST::xyz, BC::w, vf13, vf7, vf7); - // nop | subw.xyz vf15, vf08, vf08 - c->vsub_bc(DEST::xyz, BC::w, vf15, vf8, vf8); - // nop | addw.xyz vf10, vf05, vf05 - c->vadd_bc(DEST::xyz, BC::w, vf10, vf5, vf5); - // nop | addw.xyz vf12, vf06, vf06 - c->vadd_bc(DEST::xyz, BC::w, vf12, vf6, vf6); - // nop | addw.xyz vf14, vf07, vf07 - c->vadd_bc(DEST::xyz, BC::w, vf14, vf7, vf7); - // nop | addw.xyz vf16, vf08, vf08 - c->vadd_bc(DEST::xyz, BC::w, vf16, vf8, vf8); - // nop | ftoi0.xyzw vf09, vf09 - c->vftoi0(DEST::xyzw, vf9, vf9); - // nop | ftoi0.xyzw vf11, vf11 - c->vftoi0(DEST::xyzw, vf11, vf11); - // nop | ftoi0.xyzw vf13, vf13 - c->vftoi0(DEST::xyzw, vf13, vf13); - // nop | ftoi0.xyzw vf15, vf15 - c->vftoi0(DEST::xyzw, vf15, vf15); - // nop | ftoi0.xyzw vf10, vf10 - c->vftoi0(DEST::xyzw, vf10, vf10); - // nop | ftoi0.xyzw vf12, vf12 - c->vftoi0(DEST::xyzw, vf12, vf12); - // nop | ftoi0.xyzw vf14, vf14 :e - c->vftoi0(DEST::xyzw, vf14, vf14); - // nop | ftoi0.xyzw vf16, vf16 - c->vftoi0(DEST::xyzw, vf16, vf16); - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(t5, vf9); // qmfc2.i t5, vf9 - c->mov128_gpr_vf(t6, vf10); // qmfc2.i t6, vf10 - c->mov128_gpr_vf(s2, vf11); // qmfc2.i s2, vf11 - c->mov128_gpr_vf(s3, vf12); // qmfc2.i s3, vf12 - c->mov128_gpr_vf(s4, vf13); // qmfc2.i s4, vf13 - c->mov128_gpr_vf(s5, vf14); // qmfc2.i s5, vf14 - c->mov128_gpr_vf(ra, vf15); // qmfc2.i ra, vf15 - c->mov128_gpr_vf(t9, vf16); // qmfc2.i t9, vf16 - c->pcgtw(t5, t5, a3); // pcgtw t5, t5, a3 - c->lw(t8, 4, t2); // lw t8, 4(t2) - c->pcgtw(t7, a1, t6); // pcgtw t7, a1, t6 - c->lw(t6, 36, t2); // lw t6, 36(t2) - c->por(t5, t5, t7); // por t5, t5, t7 - c->lw(t7, 68, t2); // lw t7, 68(t2) - c->ppach(gp, r0, t5); // ppach gp, r0, t5 - c->lw(t5, 100, t2); // lw t5, 100(t2) - c->pcgtw(s2, s2, a3); // pcgtw s2, s2, a3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(s3, a1, s3); // pcgtw s3, a1, s3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(s3, s2, s3); // por s3, s2, s3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(s3, r0, s3); // ppach s3, r0, s3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(s4, s4, a3); // pcgtw s4, s4, a3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(s5, a1, s5); // pcgtw s5, a1, s5 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(s5, s4, s5); // por s5, s4, s5 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(s5, r0, s5); // ppach s5, r0, s5 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(ra, ra, a3); // pcgtw ra, ra, a3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t9, a1, t9); // pcgtw t9, a1, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(t9, ra, t9); // por t9, ra, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(t9, r0, t9); // ppach t9, r0, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->dsll(s4, gp, 16); // dsll s4, gp, 16 - c->dsll(gp, s3, 16); // dsll gp, s3, 16 - c->dsll(ra, s5, 16); // dsll ra, s5, 16 - c->dsll(t9, t9, 16); // dsll t9, t9, 16 - bc = c->sgpr64(t4) == 0; // beq t4, r0, L66 - // nop // sll r0, r0, 0 - if (bc) {goto block_19;} // branch non-likely - - bc = c->sgpr64(s4) != 0; // bne s4, r0, L62 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_8;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lbu(s5, 2, t2); // lbu s5, 2(t2) - // nop // sll r0, r0, 0 - c->lbu(s4, 3, t2); // lbu s4, 3(t2) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t8, -8, a0); // sw t8, -8(a0) - // nop // sll r0, r0, 0 - c->sh(s5, -4, a0); // sh s5, -4(a0) - // nop // sll r0, r0, 0 - c->sh(s4, -2, a0); // sh s4, -2(a0) - - block_8: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L65 - // nop // sll r0, r0, 0 - if (bc) {goto block_17;} // branch non-likely - - bc = c->sgpr64(gp) != 0; // bne gp, r0, L63 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_11;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lbu(t8, 34, t2); // lbu t8, 34(t2) - // nop // sll r0, r0, 0 - c->lbu(gp, 35, t2); // lbu gp, 35(t2) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t6, -8, a0); // sw t6, -8(a0) - // nop // sll r0, r0, 0 - c->sh(t8, -4, a0); // sh t8, -4(a0) - // nop // sll r0, r0, 0 - c->sh(gp, -2, a0); // sh gp, -2(a0) - - block_11: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L65 - // nop // sll r0, r0, 0 - if (bc) {goto block_17;} // branch non-likely - - bc = c->sgpr64(ra) != 0; // bne ra, r0, L64 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_14;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lbu(t6, 66, t2); // lbu t6, 66(t2) - // nop // sll r0, r0, 0 - c->lbu(t8, 67, t2); // lbu t8, 67(t2) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t7, -8, a0); // sw t7, -8(a0) - // nop // sll r0, r0, 0 - c->sh(t6, -4, a0); // sh t6, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t8, -2, a0); // sh t8, -2(a0) - - block_14: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L65 - // nop // sll r0, r0, 0 - if (bc) {goto block_17;} // branch non-likely - - bc = c->sgpr64(t9) != 0; // bne t9, r0, L65 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_17;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lbu(t6, 98, t2); // lbu t6, 98(t2) - // nop // sll r0, r0, 0 - c->lbu(t7, 99, t2); // lbu t7, 99(t2) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t5, -8, a0); // sw t5, -8(a0) - // nop // sll r0, r0, 0 - c->sh(t6, -4, a0); // sh t6, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t7, -2, a0); // sh t7, -2(a0) - - block_17: - bc = ((s64)c->sgpr64(t3)) > 0; // bgtz t3, L60 - c->daddiu(t2, t2, 128); // daddiu t2, t2, 128 - if (bc) {goto block_3;} // branch non-likely - - //beq r0, r0, L59 // beq r0, r0, L59 - // nop // sll r0, r0, 0 - goto block_1; // branch always - - - block_19: - bc = c->sgpr64(s4) != 0; // bne s4, r0, L67 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_21;} // branch non-likely - - c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 - c->sw(t8, 0, t1); // sw t8, 0(t1) - c->daddiu(t1, t1, 16); // daddiu t1, t1, 16 - c->sw(s7, -12, t1); // sw s7, -12(t1) - - block_21: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L70 - // nop // sll r0, r0, 0 - if (bc) {goto block_30;} // branch non-likely - - bc = c->sgpr64(gp) != 0; // bne gp, r0, L68 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_24;} // branch non-likely - - c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 - c->sw(t6, 0, t1); // sw t6, 0(t1) - c->daddiu(t1, t1, 16); // daddiu t1, t1, 16 - c->sw(s7, -12, t1); // sw s7, -12(t1) - - block_24: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L70 - // nop // sll r0, r0, 0 - if (bc) {goto block_30;} // branch non-likely - - bc = c->sgpr64(ra) != 0; // bne ra, r0, L69 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_27;} // branch non-likely - - c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 - c->sw(t7, 0, t1); // sw t7, 0(t1) - c->daddiu(t1, t1, 16); // daddiu t1, t1, 16 - c->sw(s7, -12, t1); // sw s7, -12(t1) - - block_27: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L70 - // nop // sll r0, r0, 0 - if (bc) {goto block_30;} // branch non-likely - - bc = c->sgpr64(t9) != 0; // bne t9, r0, L70 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_30;} // branch non-likely - - c->daddiu(t0, t0, 1); // daddiu t0, t0, 1 - c->sw(t5, 0, t1); // sw t5, 0(t1) - c->daddiu(t1, t1, 16); // daddiu t1, t1, 16 - c->sw(s7, -12, t1); // sw s7, -12(t1) - - block_30: - bc = ((s64)c->sgpr64(t3)) > 0; // bgtz t3, L60 - c->daddiu(t2, t2, 128); // daddiu t2, t2, 128 - if (bc) {goto block_3;} // branch non-likely - - //beq r0, r0, L59 // beq r0, r0, L59 - // nop // sll r0, r0, 0 - goto block_1; // branch always - - - block_32: - // nop // sll r0, r0, 0 - c->sw(t0, 0, a2); // sw t0, 0(a2) - c->gprs[v0].du64[0] = 0; // or v0, r0, r0 - c->ld(ra, 0, sp); // ld ra, 0(sp) - c->lq(gp, 80, sp); // lq gp, 80(sp) - c->lq(s5, 64, sp); // lq s5, 64(sp) - c->lq(s4, 48, sp); // lq s4, 48(sp) - c->lq(s3, 32, sp); // lq s3, 32(sp) - c->lq(s2, 16, sp); // lq s2, 16(sp) - //jr ra // jr ra - c->daddiu(sp, sp, 96); // daddiu sp, sp, 96 - goto end_of_function; // return - - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - end_of_function: - return c->gprs[v0].du64[0]; -} - -void link() { - cache.collide_probe_stack = intern_from_c("*collide-probe-stack*").c(); - cache.collide_work = intern_from_c("*collide-work*").c(); - gLinkedFunctionTable.reg("collide-probe-node", execute, 256); -} - -} // namespace collide_probe_node -} // namespace Mips2C - -//--------------------------MIPS2C--------------------- -#include "game/mips2c/mips2c_private.h" - -namespace Mips2C::jak1 { -namespace collide_probe_instance_tie { -struct Cache { - void* collide_probe_stack; // *collide-probe-stack* - void* collide_work; // *collide-work* -} cache; - -u64 execute(void* ctxt) { - auto* c = (ExecutionContext*)ctxt; - bool bc = false; - c->daddiu(sp, sp, -80); // daddiu sp, sp, -80 - c->sd(ra, 0, sp); // sd ra, 0(sp) - c->sq(s3, 16, sp); // sq s3, 16(sp) - c->sq(s4, 32, sp); // sq s4, 32(sp) - c->sq(s5, 48, sp); // sq s5, 48(sp) - c->sq(gp, 64, sp); // sq gp, 64(sp) - c->load_symbol(t2, cache.collide_work); // lw t2, *collide-work*(s7) - c->load_symbol(v1, cache.collide_probe_stack); // lw v1, *collide-probe-stack*(s7) - c->sw(a0, 0, v1); // sw a0, 0(v1) - c->daddiu(a0, v1, 8); // daddiu a0, v1, 8 - c->sh(a1, 4, v1); // sh a1, 4(v1) - c->sh(a3, 6, v1); // sh a3, 6(v1) - c->addiu(a1, r0, 0); // addiu a1, r0, 0 - c->addiu(a3, r0, 0); // addiu a3, r0, 0 - c->lq(t0, 16, t2); // lq t0, 16(t2) - c->lq(t1, 32, t2); // lq t1, 32(t2) - c->lqc2(vf1, 48, t2); // lqc2 vf1, 48(t2) - c->lqc2(vf2, 64, t2); // lqc2 vf2, 64(t2) - c->lqc2(vf3, 80, t2); // lqc2 vf3, 80(t2) - c->lqc2(vf4, 96, t2); // lqc2 vf4, 96(t2) - - block_1: - bc = c->sgpr64(a0) == c->sgpr64(v1); // beq a0, v1, L55 - // nop // sll r0, r0, 0 - if (bc) {goto block_59;} // branch non-likely - - c->daddiu(a0, a0, -8); // daddiu a0, a0, -8 - c->lw(t4, 0, a0); // lw t4, 0(a0) - c->lh(t2, 6, a0); // lh t2, 6(a0) - c->lhu(t3, 4, a0); // lhu t3, 4(a0) - bc = ((s64)c->sgpr64(t2)) < 0; // bltz t2, L45 - // nop // sll r0, r0, 0 - if (bc) {goto block_36;} // branch non-likely - - - block_3: - bc = c->sgpr64(t2) == 0; // beq t2, r0, L34 - // nop // sll r0, r0, 0 - if (bc) {goto block_7;} // branch non-likely - - c->lqc2(vf5, 12, t4); // lqc2 vf5, 12(t4) - c->daddiu(a3, a3, 1); // daddiu a3, a3, 1 - c->lqc2(vf6, 44, t4); // lqc2 vf6, 44(t4) - c->daddiu(t5, t3, -4); // daddiu t5, t3, -4 - c->lqc2(vf7, 76, t4); // lqc2 vf7, 76(t4) - bc = ((s64)c->sgpr64(t5)) < 0; // bltz t5, L33 - c->lqc2(vf8, 108, t4); // lqc2 vf8, 108(t4) - if (bc) {goto block_6;} // branch non-likely - - // Unknown instr: pref r0, 140, t4 - - block_6: - //beq r0, r0, L35 // beq r0, r0, L35 - // nop // sll r0, r0, 0 - goto block_9; // branch always - - - block_7: - c->lqc2(vf5, 12, t4); // lqc2 vf5, 12(t4) - c->daddiu(a1, a1, 1); // daddiu a1, a1, 1 - c->lqc2(vf6, 76, t4); // lqc2 vf6, 76(t4) - c->daddiu(t5, t3, -4); // daddiu t5, t3, -4 - c->lqc2(vf7, 140, t4); // lqc2 vf7, 140(t4) - bc = ((s64)c->sgpr64(t5)) < 0; // bltz t5, L35 - c->lqc2(vf8, 204, t4); // lqc2 vf8, 204(t4) - if (bc) {goto block_9;} // branch non-likely - - // Unknown instr: pref r0, 268, t4 - // Unknown instr: pref r0, 396, t4 - - block_9: - // Unknown instr: vcallms 0 - // fmt::print("vcallms 0\n"); - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf05 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf5); - // nop | madday.xyzw ACC, vf02, vf05 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf5); - // nop | maddz.xyz vf05, vf03, vf05 - c->vmadd_bc(DEST::xyz, BC::z, vf5, vf3, vf5); - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf06 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf6); - // nop | madday.xyzw ACC, vf02, vf06 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf6); - // nop | maddz.xyz vf06, vf03, vf06 - c->vmadd_bc(DEST::xyz, BC::z, vf6, vf3, vf6); - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf07 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf7); - // nop | madday.xyzw ACC, vf02, vf07 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf7); - // nop | maddz.xyz vf07, vf03, vf07 - c->vmadd_bc(DEST::xyz, BC::z, vf7, vf3, vf7); - // nop | mulaw.xyzw ACC, vf04, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf4, vf0); - // nop | maddax.xyzw ACC, vf01, vf08 - c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf8); - // nop | madday.xyzw ACC, vf02, vf08 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf8); - // nop | maddz.xyz vf08, vf03, vf08 - c->vmadd_bc(DEST::xyz, BC::z, vf8, vf3, vf8); - // nop | subw.xyz vf09, vf05, vf05 - c->vsub_bc(DEST::xyz, BC::w, vf9, vf5, vf5); - // nop | subw.xyz vf11, vf06, vf06 - c->vsub_bc(DEST::xyz, BC::w, vf11, vf6, vf6); - // nop | subw.xyz vf13, vf07, vf07 - c->vsub_bc(DEST::xyz, BC::w, vf13, vf7, vf7); - // nop | subw.xyz vf15, vf08, vf08 - c->vsub_bc(DEST::xyz, BC::w, vf15, vf8, vf8); - // nop | addw.xyz vf10, vf05, vf05 - c->vadd_bc(DEST::xyz, BC::w, vf10, vf5, vf5); - // nop | addw.xyz vf12, vf06, vf06 - c->vadd_bc(DEST::xyz, BC::w, vf12, vf6, vf6); - // nop | addw.xyz vf14, vf07, vf07 - c->vadd_bc(DEST::xyz, BC::w, vf14, vf7, vf7); - // nop | addw.xyz vf16, vf08, vf08 - c->vadd_bc(DEST::xyz, BC::w, vf16, vf8, vf8); - // nop | ftoi0.xyzw vf09, vf09 - c->vftoi0(DEST::xyzw, vf9, vf9); - // nop | ftoi0.xyzw vf11, vf11 - c->vftoi0(DEST::xyzw, vf11, vf11); - // nop | ftoi0.xyzw vf13, vf13 - c->vftoi0(DEST::xyzw, vf13, vf13); - // nop | ftoi0.xyzw vf15, vf15 - c->vftoi0(DEST::xyzw, vf15, vf15); - // nop | ftoi0.xyzw vf10, vf10 - c->vftoi0(DEST::xyzw, vf10, vf10); - // nop | ftoi0.xyzw vf12, vf12 - c->vftoi0(DEST::xyzw, vf12, vf12); - // nop | ftoi0.xyzw vf14, vf14 :e - c->vftoi0(DEST::xyzw, vf14, vf14); - // nop | ftoi0.xyzw vf16, vf16 - c->vftoi0(DEST::xyzw, vf16, vf16); - c->mov128_gpr_vf(s5, vf9); // qmfc2.i s5, vf9 - c->mov128_gpr_vf(t7, vf10); // qmfc2.i t7, vf10 - c->mov128_gpr_vf(gp, vf11); // qmfc2.i gp, vf11 - c->mov128_gpr_vf(ra, vf12); // qmfc2.i ra, vf12 - c->mov128_gpr_vf(t9, vf13); // qmfc2.i t9, vf13 - c->mov128_gpr_vf(t8, vf14); // qmfc2.i t8, vf14 - c->mov128_gpr_vf(t6, vf15); // qmfc2.i t6, vf15 - c->mov128_gpr_vf(t5, vf16); // qmfc2.i t5, vf16 - // nop // sll r0, r0, 0 - c->pcgtw(s5, s5, t1); // pcgtw s5, s5, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t7, t0, t7); // pcgtw t7, t0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(t7, s5, t7); // por t7, s5, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(t7, r0, t7); // ppach t7, r0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(gp, gp, t1); // pcgtw gp, gp, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(ra, t0, ra); // pcgtw ra, t0, ra - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(ra, gp, ra); // por ra, gp, ra - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(ra, r0, ra); // ppach ra, r0, ra - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t9, t9, t1); // pcgtw t9, t9, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t8, t0, t8); // pcgtw t8, t0, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(t8, t9, t8); // por t8, t9, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(t8, r0, t8); // ppach t8, r0, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t6, t6, t1); // pcgtw t6, t6, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t5, t0, t5); // pcgtw t5, t0, t5 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(t5, t6, t5); // por t5, t6, t5 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(t5, r0, t5); // ppach t5, r0, t5 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->dsll(t9, t7, 16); // dsll t9, t7, 16 - c->dsll(t7, ra, 16); // dsll t7, ra, 16 - c->dsll(t6, t8, 16); // dsll t6, t8, 16 - c->dsll(t5, t5, 16); // dsll t5, t5, 16 - bc = c->sgpr64(t2) == 0; // beq t2, r0, L40 - // nop // sll r0, r0, 0 - if (bc) {goto block_23;} // branch non-likely - - bc = c->sgpr64(t9) != 0; // bne t9, r0, L36 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_12;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t8, 4, t4); // lw t8, 4(t4) - // nop // sll r0, r0, 0 - c->lbu(t9, 2, t4); // lbu t9, 2(t4) - // nop // sll r0, r0, 0 - c->lbu(ra, 3, t4); // lbu ra, 3(t4) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t8, -8, a0); // sw t8, -8(a0) - // nop // sll r0, r0, 0 - c->sh(t9, -4, a0); // sh t9, -4(a0) - // nop // sll r0, r0, 0 - c->sh(ra, -2, a0); // sh ra, -2(a0) - - block_12: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L39 - // nop // sll r0, r0, 0 - if (bc) {goto block_21;} // branch non-likely - - bc = c->sgpr64(t7) != 0; // bne t7, r0, L37 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_15;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t7, 36, t4); // lw t7, 36(t4) - // nop // sll r0, r0, 0 - c->lbu(t8, 34, t4); // lbu t8, 34(t4) - // nop // sll r0, r0, 0 - c->lbu(t9, 35, t4); // lbu t9, 35(t4) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t7, -8, a0); // sw t7, -8(a0) - // nop // sll r0, r0, 0 - c->sh(t8, -4, a0); // sh t8, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t9, -2, a0); // sh t9, -2(a0) - - block_15: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L39 - // nop // sll r0, r0, 0 - if (bc) {goto block_21;} // branch non-likely - - bc = c->sgpr64(t6) != 0; // bne t6, r0, L38 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_18;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t6, 68, t4); // lw t6, 68(t4) - // nop // sll r0, r0, 0 - c->lbu(t7, 66, t4); // lbu t7, 66(t4) - // nop // sll r0, r0, 0 - c->lbu(t8, 67, t4); // lbu t8, 67(t4) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t6, -8, a0); // sw t6, -8(a0) - // nop // sll r0, r0, 0 - c->sh(t7, -4, a0); // sh t7, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t8, -2, a0); // sh t8, -2(a0) - - block_18: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L39 - // nop // sll r0, r0, 0 - if (bc) {goto block_21;} // branch non-likely - - bc = c->sgpr64(t5) != 0; // bne t5, r0, L39 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_21;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t5, 100, t4); // lw t5, 100(t4) - // nop // sll r0, r0, 0 - c->lbu(t6, 98, t4); // lbu t6, 98(t4) - // nop // sll r0, r0, 0 - c->lbu(t7, 99, t4); // lbu t7, 99(t4) - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t5, -8, a0); // sw t5, -8(a0) - // nop // sll r0, r0, 0 - c->sh(t6, -4, a0); // sh t6, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t7, -2, a0); // sh t7, -2(a0) - - block_21: - bc = ((s64)c->sgpr64(t3)) > 0; // bgtz t3, L32 - c->daddiu(t4, t4, 128); // daddiu t4, t4, 128 - if (bc) {goto block_3;} // branch non-likely - - //beq r0, r0, L31 // beq r0, r0, L31 - // nop // sll r0, r0, 0 - goto block_1; // branch always - - - block_23: - bc = c->sgpr64(t9) != 0; // bne t9, r0, L41 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_25;} // branch non-likely - - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t4, -8, a0); // sw t4, -8(a0) - c->daddiu(t8, r0, -1); // daddiu t8, r0, -1 - c->sh(r0, -4, a0); // sh r0, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t8, -2, a0); // sh t8, -2(a0) - - block_25: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L44 - c->daddiu(t4, t4, 64); // daddiu t4, t4, 64 - if (bc) {goto block_34;} // branch non-likely - - bc = c->sgpr64(t7) != 0; // bne t7, r0, L42 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_28;} // branch non-likely - - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t4, -8, a0); // sw t4, -8(a0) - c->daddiu(t7, r0, -1); // daddiu t7, r0, -1 - c->sh(r0, -4, a0); // sh r0, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t7, -2, a0); // sh t7, -2(a0) - - block_28: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L44 - c->daddiu(t4, t4, 64); // daddiu t4, t4, 64 - if (bc) {goto block_34;} // branch non-likely - - bc = c->sgpr64(t6) != 0; // bne t6, r0, L43 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_31;} // branch non-likely - - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t4, -8, a0); // sw t4, -8(a0) - c->daddiu(t6, r0, -1); // daddiu t6, r0, -1 - c->sh(r0, -4, a0); // sh r0, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t6, -2, a0); // sh t6, -2(a0) - - block_31: - bc = c->sgpr64(t3) == 0; // beq t3, r0, L44 - c->daddiu(t4, t4, 64); // daddiu t4, t4, 64 - if (bc) {goto block_34;} // branch non-likely - - bc = c->sgpr64(t5) != 0; // bne t5, r0, L44 - c->daddiu(t3, t3, -1); // daddiu t3, t3, -1 - if (bc) {goto block_34;} // branch non-likely - - c->daddiu(a0, a0, 8); // daddiu a0, a0, 8 - c->sw(t4, -8, a0); // sw t4, -8(a0) - c->daddiu(t5, r0, -1); // daddiu t5, r0, -1 - c->sh(r0, -4, a0); // sh r0, -4(a0) - // nop // sll r0, r0, 0 - c->sh(t5, -2, a0); // sh t5, -2(a0) - - block_34: - bc = ((s64)c->sgpr64(t3)) > 0; // bgtz t3, L32 - c->daddiu(t4, t4, 64); // daddiu t4, t4, 64 - if (bc) {goto block_3;} // branch non-likely - - //beq r0, r0, L31 // beq r0, r0, L31 - // nop // sll r0, r0, 0 - goto block_1; // branch always - - - block_36: - c->mov64(t2, t4); // or t2, t4, r0 - c->lhu(t4, 42, t4); // lhu t4, 42(t4) - // nop // sll r0, r0, 0 - c->lw(t3, 8, t2); // lw t3, 8(t2) - bc = c->sgpr64(t4) != 0; // bne t4, r0, L54 - c->lhu(t4, 34, t2); // lhu t4, 34(t2) - if (bc) {goto block_58;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t6, 136, t3); // lw t6, 136(t3) - // nop // sll r0, r0, 0 - c->lq(t3, 44, t2); // lq t3, 44(t2) - bc = c->sgpr64(t6) == 0; // beq t6, r0, L54 - c->lq(t5, 28, t2); // lq t5, 28(t2) - if (bc) {goto block_58;} // branch non-likely - - c->pextlw(t4, t4, t4); // pextlw t4, t4, t4 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcpyld(t4, t4, t4); // pcpyld t4, t4, t4 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcpyud(t8, t3, r0); // pcpyud t8, t3, r0 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcpyud(t7, t5, r0); // pcpyud t7, t5, r0 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pextlh(t8, t8, r0); // pextlh t8, t8, r0 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->psraw(t8, t8, 10); // psraw t8, t8, 10 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pextlh(t9, t5, r0); // pextlh t9, t5, r0 - c->lhu(t5, 2, t6); // lhu t5, 2(t6) - c->psraw(t9, t9, 16); // psraw t9, t9, 16 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pextlh(t7, t7, r0); // pextlh t7, t7, r0 - c->mov128_vf_gpr(vf20, t8); // qmtc2.i vf20, t8 - c->psraw(t7, t7, 16); // psraw t7, t7, 16 - c->mov128_vf_gpr(vf17, t9); // qmtc2.i vf17, t9 - c->pextlh(t3, t3, r0); // pextlh t3, t3, r0 - c->mov128_vf_gpr(vf18, t7); // qmtc2.i vf18, t7 - c->psraw(t3, t3, 16); // psraw t3, t3, 16 - c->lqc2(vf23, 12, t2); // lqc2 vf23, 12(t2) - c->mov128_vf_gpr(vf19, t3); // qmtc2.i vf19, t3 - c->lw(t3, 0, a2); // lw t3, 0(a2) - c->mov128_vf_gpr(vf21, t4); // qmtc2.i vf21, t4 - c->daddiu(t7, t5, -4); // daddiu t7, t5, -4 - // Unknown instr: vcallms 32 - // nop | ftoi0.xyzw vf16, vf16 - c->vftoi0(DEST::xyzw, vf16, vf16); - // nop | itof0.xyzw vf20, vf20 - c->vitof0(DEST::xyzw, vf20, vf20); - // nop | itof12.xyzw vf17, vf17 - c->vitof12(DEST::xyzw, vf17, vf17); - // nop | itof12.xyzw vf18, vf18 - c->vitof12(DEST::xyzw, vf18, vf18); - // nop | itof12.xyzw vf19, vf19 - c->vitof12(DEST::xyzw, vf19, vf19); - // nop | add.xyz vf20, vf20, vf23 - c->vadd(DEST::xyz, vf20, vf20, vf23); - // nop | itof12.xyzw vf21, vf21 - c->vitof12(DEST::xyzw, vf21, vf21); - // nop | mulax.xyzw ACC, vf01, vf20 - c->vmula_bc(DEST::xyzw, BC::x, vf1, vf20); - // nop | madday.xyzw ACC, vf02, vf20 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf20); - // nop | maddaz.xyzw ACC, vf03, vf20 - c->vmadda_bc(DEST::xyzw, BC::z, vf3, vf20); - // nop | maddw.xyz vf20, vf04, vf00 - c->vmadd_bc(DEST::xyz, BC::w, vf20, vf4, vf0); - // nop | mulax.xyzw ACC, vf01, vf17 - c->vmula_bc(DEST::xyzw, BC::x, vf1, vf17); - // nop | madday.xyzw ACC, vf02, vf17 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf17); - // nop | maddaz.xyzw ACC, vf03, vf17 - c->vmadda_bc(DEST::xyzw, BC::z, vf3, vf17); - // nop | maddx.xyz vf17, vf04, vf00 - c->vmadd_bc(DEST::xyz, BC::x, vf17, vf4, vf0); - // nop | mulax.xyzw ACC, vf01, vf18 - c->vmula_bc(DEST::xyzw, BC::x, vf1, vf18); - // nop | madday.xyzw ACC, vf02, vf18 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf18); - // nop | maddaz.xyzw ACC, vf03, vf18 - c->vmadda_bc(DEST::xyzw, BC::z, vf3, vf18); - // nop | maddx.xyz vf18, vf04, vf00 - c->vmadd_bc(DEST::xyz, BC::x, vf18, vf4, vf0); - // nop | mulax.xyzw ACC, vf01, vf19 - c->vmula_bc(DEST::xyzw, BC::x, vf1, vf19); - // nop | madday.xyzw ACC, vf02, vf19 - c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf19); - // nop | maddaz.xyzw ACC, vf03, vf19 :e - c->vmadda_bc(DEST::xyzw, BC::z, vf3, vf19); - // nop | maddx.xyz vf19, vf04, vf00 - c->vmadd_bc(DEST::xyz, BC::x, vf19, vf4, vf0); - - c->sll(t4, t3, 4); // sll t4, t3, 4 - c->addu(t4, t4, a2); // addu t4, t4, a2 - c->addu(t5, t5, r0); // addu t5, t5, r0 - c->addiu(t4, t4, 16); // addiu t4, t4, 16 - c->daddiu(t6, t6, 32); // daddiu t6, t6, 32 - bc = ((s64)c->sgpr64(t7)) < 0; // bltz t7, L52 - c->lq(t7, 12, t6); // lq t7, 12(t6) - if (bc) {goto block_54;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lq(t8, 44, t6); // lq t8, 44(t6) - // nop // sll r0, r0, 0 - c->lq(t9, 76, t6); // lq t9, 76(t6) - // nop // sll r0, r0, 0 - c->lq(ra, 108, t6); // lq ra, 108(t6) - // nop // sll r0, r0, 0 - c->mov128_vf_gpr(vf5, t7); // qmtc2.ni vf5, t7 - // nop // sll r0, r0, 0 - c->mov128_vf_gpr(vf6, t8); // qmtc2.ni vf6, t8 - // nop // sll r0, r0, 0 - c->mov128_vf_gpr(vf7, t9); // qmtc2.ni vf7, t9 - // nop // sll r0, r0, 0 - c->mov128_vf_gpr(vf8, ra); // qmtc2.ni vf8, ra - - - block_40: - // Unknown instr: vcallms 54 - // fmt::print("vcallms54\n"); - // nop | mulaw.xyzw ACC, vf20, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf20, vf0); - // nop | maddax.xyzw ACC, vf17, vf05 - c->vmadda_bc(DEST::xyzw, BC::x, vf17, vf5); - // nop | madday.xyzw ACC, vf18, vf05 - c->vmadda_bc(DEST::xyzw, BC::y, vf18, vf5); - // nop | maddz.xyzw vf09, vf19, vf05 - c->vmadd_bc(DEST::xyzw, BC::z, vf9, vf19, vf5); - // nop | mulaw.xyzw ACC, vf20, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf20, vf0); - // nop | maddax.xyzw ACC, vf17, vf06 - c->vmadda_bc(DEST::xyzw, BC::x, vf17, vf6); - // nop | madday.xyzw ACC, vf18, vf06 - c->vmadda_bc(DEST::xyzw, BC::y, vf18, vf6); - // nop | maddz.xyzw vf11, vf19, vf06 - c->vmadd_bc(DEST::xyzw, BC::z, vf11, vf19, vf6); - // nop | mulaw.xyzw ACC, vf20, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf20, vf0); - // nop | maddax.xyzw ACC, vf17, vf07 - c->vmadda_bc(DEST::xyzw, BC::x, vf17, vf7); - // nop | madday.xyzw ACC, vf18, vf07 - c->vmadda_bc(DEST::xyzw, BC::y, vf18, vf7); - // nop | maddz.xyzw vf13, vf19, vf07 - c->vmadd_bc(DEST::xyzw, BC::z, vf13, vf19, vf7); - // nop | mulaw.xyzw ACC, vf20, vf00 - c->vmula_bc(DEST::xyzw, BC::w, vf20, vf0); - // nop | maddax.xyzw ACC, vf17, vf08 - c->vmadda_bc(DEST::xyzw, BC::x, vf17, vf8); - // nop | madday.xyzw ACC, vf18, vf08 - c->vmadda_bc(DEST::xyzw, BC::y, vf18, vf8); - // nop | maddz.xyzw vf15, vf19, vf08 - c->vmadd_bc(DEST::xyzw, BC::z, vf15, vf19, vf8); - // nop | mulw.x vf22, vf21, vf05 - c->vmul_bc(DEST::x, BC::w, vf22, vf21, vf5); - // nop | mulw.y vf22, vf21, vf06 - c->vmul_bc(DEST::y, BC::w, vf22, vf21, vf6); - // nop | mulw.z vf22, vf21, vf07 - c->vmul_bc(DEST::z, BC::w, vf22, vf21, vf7); - // nop | mulw.w vf22, vf21, vf08 - c->vmul_bc(DEST::w, BC::w, vf22, vf21, vf8); - // nop | addx.xyz vf10, vf09, vf22 - c->vadd_bc(DEST::xyz, BC::x, vf10, vf9, vf22); - // nop | subx.xyz vf09, vf09, vf22 - c->vsub_bc(DEST::xyz, BC::x, vf9, vf9, vf22); - // nop | addy.xyz vf12, vf11, vf22 - c->vadd_bc(DEST::xyz, BC::y, vf12, vf11, vf22); - // nop | suby.xyz vf11, vf11, vf22 - c->vsub_bc(DEST::xyz, BC::y, vf11, vf11, vf22); - // nop | addz.xyz vf14, vf13, vf22 - c->vadd_bc(DEST::xyz, BC::z, vf14, vf13, vf22); - // nop | subz.xyz vf13, vf13, vf22 - c->vsub_bc(DEST::xyz, BC::z, vf13, vf13, vf22); - // nop | addw.xyz vf16, vf15, vf22 - c->vadd_bc(DEST::xyz, BC::w, vf16, vf15, vf22); - // nop | subw.xyz vf15, vf15, vf22 - c->vsub_bc(DEST::xyz, BC::w, vf15, vf15, vf22); - // nop | ftoi0.xyzw vf10, vf10 - c->vftoi0(DEST::xyzw, vf10, vf10); - // nop | ftoi0.xyzw vf09, vf09 - c->vftoi0(DEST::xyzw, vf9, vf9); - // nop | ftoi0.xyzw vf12, vf12 - c->vftoi0(DEST::xyzw, vf12, vf12); - // nop | ftoi0.xyzw vf11, vf11 - c->vftoi0(DEST::xyzw, vf11, vf11); - // nop | ftoi0.xyzw vf14, vf14 - c->vftoi0(DEST::xyzw, vf14, vf14); - // nop | ftoi0.xyzw vf13, vf13 - c->vftoi0(DEST::xyzw, vf13, vf13); - // nop | ftoi0.xyzw vf16, vf16 :e - c->vftoi0(DEST::xyzw, vf16, vf16); - // nop | ftoi0.xyzw vf15, vf15 - c->vftoi0(DEST::xyzw, vf15, vf15); - - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // vnop - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(s3, vf10); // qmfc2.i s3, vf10 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(t9, vf9); // qmfc2.i t9, vf9 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(s4, vf12); // qmfc2.i s4, vf12 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(s5, vf11); // qmfc2.i s5, vf11 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(gp, vf14); // qmfc2.i gp, vf14 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(ra, vf13); // qmfc2.i ra, vf13 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(t8, vf16); // qmfc2.i t8, vf16 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(t7, vf15); // qmfc2.i t7, vf15 - // nop // sll r0, r0, 0 - c->pcgtw(s3, t0, s3); // pcgtw s3, t0, s3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t9, t9, t1); // pcgtw t9, t9, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(t9, t9, s3); // por t9, t9, s3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(t9, r0, t9); // ppach t9, r0, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(s4, t0, s4); // pcgtw s4, t0, s4 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(s5, s5, t1); // pcgtw s5, s5, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(s5, s5, s4); // por s5, s5, s4 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(s5, r0, s5); // ppach s5, r0, s5 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(gp, t0, gp); // pcgtw gp, t0, gp - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(ra, ra, t1); // pcgtw ra, ra, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(ra, ra, gp); // por ra, ra, gp - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(ra, r0, ra); // ppach ra, r0, ra - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t8, t0, t8); // pcgtw t8, t0, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t7, t7, t1); // pcgtw t7, t7, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(t7, t7, t8); // por t7, t7, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(t7, r0, t7); // ppach t7, r0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->dsll(gp, t9, 16); // dsll gp, t9, 16 - c->dsll(t9, s5, 16); // dsll t9, s5, 16 - c->dsll(t8, ra, 16); // dsll t8, ra, 16 - c->dsll(t7, t7, 16); // dsll t7, t7, 16 - bc = c->sgpr64(gp) != 0; // bne gp, r0, L47 - // nop // sll r0, r0, 0 - if (bc) {goto block_42;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(ra, 4, t6); // lw ra, 4(t6) - c->daddiu(t3, t3, 1); // daddiu t3, t3, 1 - c->sw(t2, 4, t4); // sw t2, 4(t4) - c->daddiu(t4, t4, 16); // daddiu t4, t4, 16 - c->sw(ra, -16, t4); // sw ra, -16(t4) - - block_42: - c->daddiu(t5, t5, -1); // daddiu t5, t5, -1 - c->daddiu(t6, t6, 32); // daddiu t6, t6, 32 - bc = c->sgpr64(t5) == 0; // beq t5, r0, L51 - // nop // sll r0, r0, 0 - if (bc) {goto block_53;} // branch non-likely - - bc = c->sgpr64(t9) != 0; // bne t9, r0, L48 - // nop // sll r0, r0, 0 - if (bc) {goto block_45;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t9, 4, t6); // lw t9, 4(t6) - c->daddiu(t3, t3, 1); // daddiu t3, t3, 1 - c->sw(t2, 4, t4); // sw t2, 4(t4) - c->daddiu(t4, t4, 16); // daddiu t4, t4, 16 - c->sw(t9, -16, t4); // sw t9, -16(t4) - - block_45: - c->daddiu(t5, t5, -1); // daddiu t5, t5, -1 - c->daddiu(t6, t6, 32); // daddiu t6, t6, 32 - bc = c->sgpr64(t5) == 0; // beq t5, r0, L51 - // nop // sll r0, r0, 0 - if (bc) {goto block_53;} // branch non-likely - - bc = c->sgpr64(t8) != 0; // bne t8, r0, L49 - // nop // sll r0, r0, 0 - if (bc) {goto block_48;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t8, 4, t6); // lw t8, 4(t6) - c->daddiu(t3, t3, 1); // daddiu t3, t3, 1 - c->sw(t2, 4, t4); // sw t2, 4(t4) - c->daddiu(t4, t4, 16); // daddiu t4, t4, 16 - c->sw(t8, -16, t4); // sw t8, -16(t4) - - block_48: - c->daddiu(t5, t5, -1); // daddiu t5, t5, -1 - c->daddiu(t6, t6, 32); // daddiu t6, t6, 32 - bc = c->sgpr64(t5) == 0; // beq t5, r0, L51 - // nop // sll r0, r0, 0 - if (bc) {goto block_53;} // branch non-likely - - bc = c->sgpr64(t7) != 0; // bne t7, r0, L50 - // nop // sll r0, r0, 0 - if (bc) {goto block_51;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t7, 4, t6); // lw t7, 4(t6) - c->daddiu(t3, t3, 1); // daddiu t3, t3, 1 - c->sw(t2, 4, t4); // sw t2, 4(t4) - c->daddiu(t4, t4, 16); // daddiu t4, t4, 16 - c->sw(t7, -16, t4); // sw t7, -16(t4) - - block_51: - c->daddiu(t5, t5, -1); // daddiu t5, t5, -1 - c->daddiu(t6, t6, 32); // daddiu t6, t6, 32 - bc = c->sgpr64(t5) == 0; // beq t5, r0, L51 - c->lqc2(vf5, 12, t6); // lqc2 vf5, 12(t6) - if (bc) {goto block_53;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lqc2(vf6, 44, t6); // lqc2 vf6, 44(t6) - // nop // sll r0, r0, 0 - c->lqc2(vf7, 76, t6); // lqc2 vf7, 76(t6) - //beq r0, r0, L46 // beq r0, r0, L46 - c->lqc2(vf8, 108, t6); // lqc2 vf8, 108(t6) - goto block_40; // branch always - - - block_53: - // nop // sll r0, r0, 0 - c->sw(t3, 0, a2); // sw t3, 0(a2) - //beq r0, r0, L31 // beq r0, r0, L31 - // nop // sll r0, r0, 0 - goto block_1; // branch always - - - block_54: - c->mov128_vf_gpr(vf5, t7); // qmtc2.i vf5, t7 - // nop // sll r0, r0, 0 - c->vmula_bc(DEST::xyzw, BC::w, vf20, vf0); // vmulaw.xyzw acc, vf20, vf0 - // nop // sll r0, r0, 0 - c->vmadda_bc(DEST::xyzw, BC::x, vf17, vf5); // vmaddax.xyzw acc, vf17, vf5 - // nop // sll r0, r0, 0 - c->vmadda_bc(DEST::xyzw, BC::y, vf18, vf5); // vmadday.xyzw acc, vf18, vf5 - // nop // sll r0, r0, 0 - c->vmadd_bc(DEST::xyzw, BC::z, vf24, vf19, vf5); // vmaddz.xyzw vf24, vf19, vf5 - - // nop // sll r0, r0, 0 - c->vmul_bc(DEST::x, BC::w, vf22, vf21, vf5); // vmulw.x vf22, vf21, vf5 - // nop // sll r0, r0, 0 - c->vadd_bc(DEST::xyz, BC::x, vf25, vf24, vf22); // vaddx.xyz vf25, vf24, vf22 - // nop // sll r0, r0, 0 - c->vsub_bc(DEST::xyz, BC::x, vf24, vf24, vf22); // vsubx.xyz vf24, vf24, vf22 - // nop // sll r0, r0, 0 - c->vftoi0(DEST::xyzw, vf25, vf25); // vftoi0.xyzw vf25, vf25 - // nop // sll r0, r0, 0 - c->vftoi0(DEST::xyzw, vf24, vf24); // vftoi0.xyzw vf24, vf24 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(t8, vf25); // qmfc2.i t8, vf25 - // nop // sll r0, r0, 0 - c->mov128_gpr_vf(t7, vf24); // qmfc2.i t7, vf24 - // nop // sll r0, r0, 0 - c->pcgtw(t8, t0, t8); // pcgtw t8, t0, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcgtw(t7, t7, t1); // pcgtw t7, t7, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->por(t7, t7, t8); // por t7, t7, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppach(t7, r0, t7); // ppach t7, r0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->dsll(t7, t7, 16); // dsll t7, t7, 16 - // nop // sll r0, r0, 0 - bc = c->sgpr64(t7) != 0; // bne t7, r0, L53 - // nop // sll r0, r0, 0 - if (bc) {goto block_56;} // branch non-likely - - // nop // sll r0, r0, 0 - c->lw(t7, 4, t6); // lw t7, 4(t6) - c->daddiu(t3, t3, 1); // daddiu t3, t3, 1 - c->sw(t2, 4, t4); // sw t2, 4(t4) - c->daddiu(t4, t4, 16); // daddiu t4, t4, 16 - c->sw(t7, -16, t4); // sw t7, -16(t4) - - block_56: - c->daddiu(t5, t5, -1); // daddiu t5, t5, -1 - c->daddiu(t6, t6, 32); // daddiu t6, t6, 32 - bc = ((s64)c->sgpr64(t5)) > 0; // bgtz t5, L52 - c->lq(t7, 12, t6); // lq t7, 12(t6) - if (bc) {goto block_54;} // branch non-likely - - // nop // sll r0, r0, 0 - c->sw(t3, 0, a2); // sw t3, 0(a2) - - block_58: - //beq r0, r0, L31 // beq r0, r0, L31 - // nop // sll r0, r0, 0 - goto block_1; // branch always - - - block_59: - c->gprs[v0].du64[0] = 0; // or v0, r0, r0 - c->ld(ra, 0, sp); // ld ra, 0(sp) - c->lq(gp, 64, sp); // lq gp, 64(sp) - c->lq(s5, 48, sp); // lq s5, 48(sp) - c->lq(s4, 32, sp); // lq s4, 32(sp) - c->lq(s3, 16, sp); // lq s3, 16(sp) - //jr ra // jr ra - c->daddiu(sp, sp, 80); // daddiu sp, sp, 80 - goto end_of_function; // return - - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - end_of_function: - return c->gprs[v0].du64[0]; -} - -void link() { - cache.collide_probe_stack = intern_from_c("*collide-probe-stack*").c(); - cache.collide_work = intern_from_c("*collide-work*").c(); - gLinkedFunctionTable.reg("collide-probe-instance-tie", execute, 512); -} - -} // namespace collide_probe_instance_tie -} // namespace Mips2C diff --git a/game/mips2c/jak1_functions/time_of_day.cpp b/game/mips2c/jak1_functions/time_of_day.cpp deleted file mode 100644 index 23e2997de5..0000000000 --- a/game/mips2c/jak1_functions/time_of_day.cpp +++ /dev/null @@ -1,272 +0,0 @@ - -//--------------------------MIPS2C--------------------- - -#include "game/kernel/jak1/kscheme.h" -#include "game/mips2c/mips2c_private.h" -using namespace jak1; - -// clang-format off -namespace Mips2C::jak1 { -namespace time_of_day_interp_colors_scratch { - -struct Cache { - void* fake_scratchpad_data; // *fake-scratchpad-data* -} cache; - -u64 execute(void* ctxt) { - auto* c = (ExecutionContext*)ctxt; - bool bc = false; - c->daddiu(sp, sp, -16); // daddiu sp, sp, -16 - c->sd(ra, 0, sp); // sd ra, 0(sp) - c->sd(fp, 8, sp); // sd fp, 8(sp) - c->mov64(fp, t9); // or fp, t9, r0 - // nop // sll r0, r0, 0 - c->lui(v1, 28672); // lui v1, 28672 0x7000 - c->daddiu(t4, a1, 12); // daddiu t4, a1, 12 - //c->ori(v1, v1, 2064); // ori v1, v1, 2064 SPAD mods - get_fake_spad_addr(v1, cache.fake_scratchpad_data, 2064, c); - // Unknown instr: ld a3, L168(fp) - // L168: - // .word 0xff00ff - // .word 0x8000ff - c->gprs[a3].du32[0] = 0xff00ff; - c->gprs[a3].du32[1] = 0x8000ff; - - c->lui(t0, 4096); // lui t0, 4096 - c->lw(t1, 4, a1); // lw t1, 4(a1) - c->ori(a1, t0, 54272); // ori a1, t0, 54272 = (0x1000D400) SPR TO - c->lq(t0, 1852, a2); // lq t0, 1852(a2) - c->addiu(t2, t1, 31); // addiu t2, t1, 31 - c->lq(t1, 1868, a2); // lq t1, 1868(a2) - c->sra(t3, t2, 5); // sra t3, t2, 5 - c->lq(t2, 1884, a2); // lq t2, 1884(a2) - c->sll(t3, t3, 5); // sll t3, t3, 5 - c->lq(a2, 1900, a2); // lq a2, 1900(a2) - - // wait for DMA to finish, can just remove this - /* - block_1: - c->lw(t5, 0, a1); // lw t5, 0(a1) - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - c->andi(t5, t5, 256); // andi t5, t5, 256 - // nop // sll r0, r0, 0 - bc = c->sgpr64(t5) != 0; // bne t5, r0, L62 - // nop // sll r0, r0, 0 - if (bc) {goto block_1;} // branch non-likely - */ - - { - // c->sw(t4, 16, a1); // sw t4, 16(a1) - u32 madr = c->sgpr64(t4); - c->daddiu(t3, t3, -32); // daddiu t3, t3, -32 - // c->sw(v1, 128, a1); // sw v1, 128(a1) - u32 sadr = c->sgpr64(v1); - c->addiu(t5, r0, 64); // addiu t5, r0, 64 - //c->sw(t5, 32, a1); // sw t5, 32(a1) - u32 qwc = c->sgpr64(t5); - c->addiu(t5, r0, 256); // addiu t5, r0, 256 - // c->sw(t5, 0, a1); // sw t5, 0(a1) - spad_to_dma(cache.fake_scratchpad_data, madr, sadr, qwc); - c->daddiu(t4, t4, 1024); // daddiu t4, t4, 1024 - } - - block_3: - c->mov64(t6, v1); // or t6, v1, r0 - c->xori(v1, v1, 1024); // xori v1, v1, 1024 - bc = ((s64)c->sgpr64(t3)) <= 0; // blez t3, L66 - c->daddiu(t3, t3, -32); // daddiu t3, t3, -32 - if (bc) {goto block_7;} // branch non-likely - - - /* - block_4: - c->lw(t5, 0, a1); // lw t5, 0(a1) - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - c->andi(t5, t5, 256); // andi t5, t5, 256 - // nop // sll r0, r0, 0 - bc = c->sgpr64(t5) == 0; // beq t5, r0, L65 - // nop // sll r0, r0, 0 - if (bc) {goto block_6;} // branch non-likely - - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - //beq r0, r0, L64 // beq r0, r0, L64 - // nop // sll r0, r0, 0 - goto block_4; // branch always - */ - - { - // block_6: - // c->sw(t4, 16, a1); // sw t4, 16(a1) - u32 madr = c->sgpr64(t4); - // nop // sll r0, r0, 0 - // c->sw(v1, 128, a1); // sw v1, 128(a1) - u32 sadr = c->sgpr64(v1); - c->addiu(t5, r0, 64); // addiu t5, r0, 64 - // c->sw(t5, 32, a1); // sw t5, 32(a1) - u32 qwc = c->sgpr64(t5); - c->addiu(t5, r0, 256); // addiu t5, r0, 256 - // c->sw(t5, 0, a1); // sw t5, 0(a1) - spad_to_dma(cache.fake_scratchpad_data, madr, sadr, qwc); - c->daddiu(t4, t4, 1024); // daddiu t4, t4, 1024 - //beq r0, r0, L67 // beq r0, r0, L67 - // nop // sll r0, r0, 0 - } - goto block_9; // branch always - - - - block_7: - /* - c->lw(t5, 0, a1); // lw t5, 0(a1) - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - c->andi(t5, t5, 256); // andi t5, t5, 256 - // nop // sll r0, r0, 0 - bc = c->sgpr64(t5) == 0; // beq t5, r0, L67 - // nop // sll r0, r0, 0 - if (bc) {goto block_9;} // branch non-likely - - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - //beq r0, r0, L66 // beq r0, r0, L66 - // nop // sll r0, r0, 0 - goto block_7; // branch always - */ - - /* - fmt::print("{} -> {} [{}]\n", c->gprs[a0].du32[0], c->gprs[t5].du32[0], c->gprs[t3].ds64[0]); - fmt::print("[2] t0: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}\n", c->gprs[t0].du16[0], c->gprs[t0].du16[1], c->gprs[t0].du16[2], c->gprs[t0].du16[3], c->gprs[t0].du16[4], c->gprs[t0].du16[5], c->gprs[t0].du16[6], c->gprs[t0].du16[7]); - fmt::print("[2] t1: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}\n", c->gprs[t1].du16[0], c->gprs[t1].du16[1], c->gprs[t1].du16[2], c->gprs[t1].du16[3], c->gprs[t1].du16[4], c->gprs[t1].du16[5], c->gprs[t1].du16[6], c->gprs[t1].du16[7]); - fmt::print("[2] t2: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}\n", c->gprs[t2].du16[0], c->gprs[t2].du16[1], c->gprs[t2].du16[2], c->gprs[t2].du16[3], c->gprs[t2].du16[4], c->gprs[t2].du16[5], c->gprs[t2].du16[6], c->gprs[t2].du16[7]); - fmt::print("[2] a2: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}\n", c->gprs[a2].du16[0], c->gprs[a2].du16[1], c->gprs[a2].du16[2], c->gprs[a2].du16[3], c->gprs[a2].du16[4], c->gprs[a2].du16[5], c->gprs[a2].du16[6], c->gprs[a2].du16[7]); - */ - block_9: - c->lq(t9, 12, t6); // lq t9, 12(t6) - c->daddiu(t5, a0, 128); // daddiu t5, a0, 128 - c->lq(t7, 28, t6); // lq t7, 28(t6) - // nop // sll r0, r0, 0 - c->pextlb(t8, r0, t9); // pextlb t8, r0, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pextub(t9, r0, t9); // pextub t9, r0, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pmulth(r0, t8, t0); // pmulth r0, t8, t0 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pextlb(t8, r0, t7); // pextlb t8, r0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pmaddh(r0, t9, t1); // pmaddh r0, t9, t1 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pextub(t7, r0, t7); // pextub t7, r0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pmaddh(r0, t8, t2); // pmaddh r0, t8, t2 - c->lq(t8, 44, t6); // lq t8, 44(t6) - c->addiu(t6, t6, 32); // addiu t6, t6, 32 - // nop // sll r0, r0, 0 - c->pmaddh(r0, t7, a2); // pmaddh r0, t7, a2 - c->lq(t7, 28, t6); // lq t7, 28(t6) - c->pextlb(t9, r0, t8); // pextlb t9, r0, t8 - c->mfc1(r0, f31); // mfc1 r0, f31 - - block_10: - c->pextub(t8, r0, t8); // pextub t8, r0, t8 - // fmt::print("[0] t1: {:02x} {:02x} {:02x} {:02x}\n", c->gprs[t1].du32[0], c->gprs[t1].du32[1], c->gprs[t1].du32[2], c->gprs[t1].du32[3]); - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pmfhl_lh(ra); // pmfhl.lh ra - // fmt::print("[1] ra: {:02x} {:02x} {:02x} {:02x}\n", c->gprs[ra].du32[0], c->gprs[ra].du32[1], c->gprs[ra].du32[2], c->gprs[ra].du32[3]); - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pmulth(r0, t9, t0); // pmulth r0, t9, t0 - - c->mfc1(r0, f31); // mfc1 r0, f31 - c->psrlh(t9, ra, 6); // psrlh t9, ra, 6 - // fmt::print("[3] t9: {:02x} {:02x} {:02x} {:02x}\n", c->gprs[t9].du32[0], c->gprs[t9].du32[1], c->gprs[t9].du32[2], c->gprs[t9].du32[3]); - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pcpyud(ra, t9, t9); // pcpyud ra, t9, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->paddh(t9, ra, t9); // paddh t9, ra, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pminh(t9, t9, a3); // pminh t9, t9, a3 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->ppacb(ra, r0, t9); // ppacb ra, r0, t9 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pextlb(t9, r0, t7); // pextlb t9, r0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pmaddh(r0, t8, t1); // pmaddh r0, t8, t1 - c->sw(ra, 0, a0); // sw ra, 0(a0) - c->pextub(t7, r0, t7); // pextub t7, r0, t7 - c->mfc1(r0, f31); // mfc1 r0, f31 - c->pmaddh(r0, t9, t2); // pmaddh r0, t9, t2 - c->lq(t8, 44, t6); // lq t8, 44(t6) - c->addiu(t6, t6, 32); // addiu t6, t6, 32 - c->addiu(a0, a0, 4); // addiu a0, a0, 4 - c->pmaddh(r0, t7, a2); // pmaddh r0, t7, a2 - c->lq(t7, 28, t6); // lq t7, 28(t6) - /* - fmt::print(" N0"); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - fmt::print(" {:02x}", c->gprs[t8].du8[i*4 + j]); - } - fmt::print(" |"); - } - fmt::print("\n N1"); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - fmt::print(" {:02x}", c->gprs[t7].du8[i*4 + j]); - } - fmt::print(" |"); - } - fmt::print("\n"); - */ -// fmt::print("next: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}\n", c->gprs[t8].du32[0], c->gprs[t8].du32[1], c->gprs[t8].du32[2], c->gprs[t8].du32[3], -// c->gprs[t7].du32[0], c->gprs[t7].du32[1], c->gprs[t7].du32[2], c->gprs[t7].du32[3]); - bc = c->sgpr64(a0) != c->sgpr64(t5); // bne a0, t5, L68 - c->pextlb(t9, r0, t8); // pextlb t9, r0, t8 - if (bc) {goto block_10;} // branch non-likely - - bc = ((s64)c->sgpr64(t3)) >= 0; // bgez t3, L63 - // nop // sll r0, r0, 0 - if (bc) {goto block_3;} // branch non-likely - - c->gprs[v0].du64[0] = 0; // or v0, r0, r0 - c->ld(ra, 0, sp); // ld ra, 0(sp) - c->ld(fp, 8, sp); // ld fp, 8(sp) - //jr ra // jr ra - c->daddiu(sp, sp, 16); // daddiu sp, sp, 16 - goto end_of_function; // return - - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - // nop // sll r0, r0, 0 - end_of_function: - return c->gprs[v0].du64[0]; -} - -void link() { - cache.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c(); - gLinkedFunctionTable.reg("time-of-day-interp-colors-scratch", execute, 512); -} - -} // namespace time_of_day_interp_colors_scratch -} // namespace Mips2C - diff --git a/goal_src/jak1/engine/collide/collide-func.gc b/goal_src/jak1/engine/collide/collide-func.gc index bf538f83b1..54e04c9a42 100644 --- a/goal_src/jak1/engine/collide/collide-func.gc +++ b/goal_src/jak1/engine/collide/collide-func.gc @@ -25,28 +25,28 @@ ;; moving-sphere-moving-sphere-intersect ;; unused - (defconstant COLLISION_MISS -100000000.0) + (defglobalconstant COLLIDE_FUNC_COUNTERS #t) (#when COLLIDE_FUNC_COUNTERS - (define *raw-ray-sphere-intersect-count* 0) - (define *ray-sphere-intersect-count* 0) - (define *ray-circle-intersect-count* 0) - (define *ray-cylinder-intersect-count* 0) - (define *collide-do-primitives-count* 0) - (define *moving-sphere-triangle-intersect-count* 0) - (define *moving-sphere-sphere-intersect-count* 0) - (define *moving-sphere-moving-sphere-intersect-count* 0) - ) + (define *raw-ray-sphere-intersect-count* 0) + (define *ray-sphere-intersect-count* 0) + (define *ray-circle-intersect-count* 0) + (define *ray-cylinder-intersect-count* 0) + (define *collide-do-primitives-count* 0) + (define *moving-sphere-triangle-intersect-count* 0) + (define *moving-sphere-sphere-intersect-count* 0) + (define *moving-sphere-moving-sphere-intersect-count* 0) + (define *collide-probe-make-list-count* 0) + (define *collide-probe-make-list-item-count* 0) + (define *collide-probe-make-list-timer* (new 'global 'stopwatch))) (defun raw-ray-sphere-intersect ((origin vector) (direction vector) (radius float)) "Check if a ray intersects a sphere at the origin. Return the fraction along the ray where the intersection occurs, or COLLISION_MISS if there is no collision." - ;; This function is rewritten in plain GOAL - ;; Parameterize the ray with: ;; ray(t) = origin + t * direction with 0 <= t <= 1 ;; A point p is on the origin if: @@ -62,10 +62,8 @@ ;; a = dot(dir, dir) ;; b = dot(dir, origin) ;; c = dot(origin, origin) - r^2 - (#when COLLIDE_FUNC_COUNTERS (+! *raw-ray-sphere-intersect-count* 1)) - ;; this matches the order of operations in the original, just in case rounding matters. (let ((c (+ (+ (square (-> origin x)) (square (-> origin y))) @@ -464,10 +462,9 @@ (set! contact-fraction COLLISION_MISS))) contact-fraction)) - (#when COLLIDE_FUNC_COUNTERS (defun clear-collide-func-counters () - "Clear the collision function counters at the start of a frame." + "Clear the collision function counters and probe-list profile at the start of a frame." (set! *raw-ray-sphere-intersect-count* 0) (set! *ray-sphere-intersect-count* 0) (set! *ray-circle-intersect-count* 0) @@ -476,10 +473,12 @@ (set! *moving-sphere-triangle-intersect-count* 0) (set! *moving-sphere-sphere-intersect-count* 0) (set! *moving-sphere-moving-sphere-intersect-count* 0) + (set! *collide-probe-make-list-count* 0) + (set! *collide-probe-make-list-item-count* 0) + (stopwatch-init *collide-probe-make-list-timer*) (none)) - (defun display-collide-func-counters () - "Display the collision function counters, three per line." + "Display the collision function counters and probe-list frame totals." (format *stdcon* " krrs ~7D rs ~7D rc ~7D~%" *raw-ray-sphere-intersect-count* @@ -494,4 +493,9 @@ " mss ~7D msms ~7D~%" *moving-sphere-sphere-intersect-count* *moving-sphere-moving-sphere-intersect-count*) + (format *stdcon* + " probe-list ~7D calls ~7D items ~3D us~%" + *collide-probe-make-list-count* + *collide-probe-make-list-item-count* + (the int (* 1000000.0 (stopwatch-elapsed-seconds *collide-probe-make-list-timer*)))) (none))) diff --git a/goal_src/jak1/engine/collide/collide-probe-ee-asm.gc b/goal_src/jak1/engine/collide/collide-probe-ee-asm.gc new file mode 100644 index 0000000000..b254824bb5 --- /dev/null +++ b/goal_src/jak1/engine/collide/collide-probe-ee-asm.gc @@ -0,0 +1,955 @@ + +(#unless PC_PORT + ;; A BASIC value points just after its allocation's type word. Raw EE loads from such a value + ;; therefore subtract four from the displayed field offset. + (defconstant PROBE-BASIC-BIAS 4) + (defconstant PROBE-STACK-CHILD (offset-of collide-probe-stack-elem child)) ;; 0 + (defconstant PROBE-STACK-COUNT (offset-of collide-probe-stack-elem count)) ;; 4 + ;; The work kind occupies the high halfword of collide-probe-stack-elem.count. + (defconstant PROBE-STACK-KIND (+ (offset-of collide-probe-stack-elem count) 2)) ;; 6 + (defconstant PROBE-STACK-STRIDE (type-size collide-probe-stack-elem)) ;; 8 + (defconstant PROBE-DRAWABLE-CHILD-COUNT (- (offset-of draw-node child-count) PROBE-BASIC-BIAS)) ;; 2 + (defconstant PROBE-DRAWABLE-FLAGS (- (offset-of draw-node flags) PROBE-BASIC-BIAS)) ;; 3 + (defconstant PROBE-DRAWABLE-CHILD (- (offset-of draw-node child) PROBE-BASIC-BIAS)) ;; 4 + ;; The same four-byte payload is draw-node.child or collide-fragment.mesh according to work kind. + (defconstant PROBE-CANDIDATE-PAYLOAD PROBE-DRAWABLE-CHILD) + (defconstant PROBE-DRAWABLE-BSPHERE (- (offset-of draw-node bsphere) PROBE-BASIC-BIAS)) ;; 12 + (defconstant PROBE-DRAW-NODE-STRIDE (type-size draw-node)) ;; 32 + (defconstant PROBE-INSTANCE-STRIDE (type-size instance-tie)) ;; 64 + (defconstant PROBE-FRAGMENT-STRIDE (type-size collide-fragment)) ;; 32 + (defconstant PROBE-FRAGMENT-MESH (- (offset-of collide-fragment mesh) PROBE-BASIC-BIAS)) ;; 4 + (defconstant PROBE-BUCKET-COLLIDE-FRAG (- (offset-of prototype-bucket-tie collide-frag) PROBE-BASIC-BIAS)) ;; 136 + (defconstant PROBE-FRAGMENT-ARRAY-LENGTH (- (offset-of drawable-inline-array-collide-fragment length) PROBE-BASIC-BIAS)) ;; 2 + ;; data is an inline BASIC array. This displacement passes its type word and lands on the first + ;; collide-fragment's GOAL pointer. + (defconstant PROBE-FRAGMENT-ARRAY-DATA (offset-of drawable-inline-array-collide-fragment data 0)) ;; 32 + (defconstant PROBE-INSTANCE-BUCKET (- (offset-of instance-tie bucket-ptr) PROBE-BASIC-BIAS)) ;; 8 + (defconstant PROBE-INSTANCE-BSPHERE (- (offset-of instance-tie bsphere) PROBE-BASIC-BIAS)) ;; 12 + (defconstant PROBE-INSTANCE-ORIGIN-LOW (- (offset-of instance-tie origin data 0) PROBE-BASIC-BIAS)) ;; 28 + (defconstant PROBE-INSTANCE-MAX-SCALE (- (offset-of instance-tie max-scale) PROBE-BASIC-BIAS)) ;; 34 + (defconstant PROBE-INSTANCE-FLAGS (- (offset-of instance-tie flags) PROBE-BASIC-BIAS)) ;; 42 + (defconstant PROBE-INSTANCE-ORIGIN-HIGH (- (offset-of instance-tie origin data 8) PROBE-BASIC-BIAS)) ;; 44 + (defconstant PROBE-QUERY-MIN (offset-of collide-work collide-box4w min)) ;; 16 + (defconstant PROBE-QUERY-MAX (offset-of collide-work collide-box4w max)) ;; 32 + (defconstant PROBE-QUERY-ROW-X (offset-of collide-work inv-mat vector 0)) ;; 48 + (defconstant PROBE-QUERY-ROW-Y (offset-of collide-work inv-mat vector 1)) ;; 64 + (defconstant PROBE-QUERY-ROW-Z (offset-of collide-work inv-mat vector 2)) ;; 80 + (defconstant PROBE-QUERY-TRANSLATION (offset-of collide-work inv-mat vector 3)) ;; 96 + (defconstant PROBE-RESULT-COUNT (offset-of collide-list num-items)) ;; 0 + (defconstant PROBE-RESULT-ITEMS (offset-of collide-list items 0)) ;; 16 + ;; collide-list-item is eight bytes as a structure, but this fixed inline array gives each + ;; physical slot sixteen-byte alignment. + (defconstant PROBE-RESULT-ITEM-STRIDE 16) + (defconstant PROBE-RESULT-MESH (offset-of collide-list-item mesh)) ;; 0 + (defconstant PROBE-RESULT-INSTANCE (offset-of collide-list-item inst))) ;; 4 + + + +;; The inverse probe transform establishes an axis-aligned box space for the rotated line-sphere +;; query. Entry 0 transforms four bounding spheres into that space and leaves integer minimum and +;; maximum corners in vf9..vf16. Entry 32 rebuilds a compressed TIE instance transform around its +;; world bounding-sphere center and composes it with the probe transform. Entry 54 uses the composed +;; transform and the instance's maximum scale to conservatively bound four prototype fragments; +;; vf22.x/y/z/w holds one scaled radius for each sphere. The EE rejects the resulting boxes against +;; collide-work.collide-box4w. +(#unless PC_PORT + (defvu0 collide-vu0-block + (rlet ((probe-row-x :reg vf01) + (probe-row-y :reg vf02) + (probe-row-z :reg vf03) + (probe-translation :reg vf04) + (sphere-0 :reg vf05) + (sphere-1 :reg vf06) + (sphere-2 :reg vf07) + (sphere-3 :reg vf08) + (min-0 :reg vf09) + (max-0 :reg vf10) + (min-1 :reg vf11) + (max-1 :reg vf12) + (min-2 :reg vf13) + (max-2 :reg vf14) + (min-3 :reg vf15) + (max-3 :reg vf16)) + ;; Transform the four centers and expand each result by its source sphere radius. + (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-0)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-0)) + (vu-pair (nop) (maddz.xyz sphere-0 probe-row-z sphere-0)) + (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-1)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-1)) + (vu-pair (nop) (maddz.xyz sphere-1 probe-row-z sphere-1)) + (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-2)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-2)) + (vu-pair (nop) (maddz.xyz sphere-2 probe-row-z sphere-2)) + (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-3)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-3)) + (vu-pair (nop) (maddz.xyz sphere-3 probe-row-z sphere-3)) + (vu-pair (nop) (subw.xyz min-0 sphere-0 sphere-0)) + (vu-pair (nop) (subw.xyz min-1 sphere-1 sphere-1)) + (vu-pair (nop) (subw.xyz min-2 sphere-2 sphere-2)) + (vu-pair (nop) (subw.xyz min-3 sphere-3 sphere-3)) + (vu-pair (nop) (addw.xyz max-0 sphere-0 sphere-0)) + (vu-pair (nop) (addw.xyz max-1 sphere-1 sphere-1)) + (vu-pair (nop) (addw.xyz max-2 sphere-2 sphere-2)) + (vu-pair (nop) (addw.xyz max-3 sphere-3 sphere-3)) + (vu-pair (nop) (ftoi0.xyzw min-0 min-0)) + (vu-pair (nop) (ftoi0.xyzw min-1 min-1)) + (vu-pair (nop) (ftoi0.xyzw min-2 min-2)) + (vu-pair (nop) (ftoi0.xyzw min-3 min-3)) + (vu-pair (nop) (ftoi0.xyzw max-0 max-0)) + (vu-pair (nop) (ftoi0.xyzw max-1 max-1)) + (vu-pair (nop) (ftoi0.xyzw max-2 max-2 :e)) + (vu-pair (nop) (ftoi0.xyzw max-3 max-3))) + (label compose-instance-transform) + (rlet ((probe-row-x :reg vf01) + (probe-row-y :reg vf02) + (probe-row-z :reg vf03) + (probe-translation :reg vf04) + (instance-row-x :reg vf17) + (instance-row-y :reg vf18) + (instance-row-z :reg vf19) + (instance-translation :reg vf20) + (instance-max-scale :reg vf21) + (instance-origin :reg vf23)) + ;; Basis rows are signed Q12 fixed point and maximum scale is unsigned Q12. Translation + ;; is quantized in 64-unit steps relative to the instance's world bounding-sphere center. + (vu-pair (nop) (itof0.xyzw instance-translation instance-translation)) + (vu-pair (nop) (itof12.xyzw instance-row-x instance-row-x)) + (vu-pair (nop) (itof12.xyzw instance-row-y instance-row-y)) + (vu-pair (nop) (itof12.xyzw instance-row-z instance-row-z)) + (vu-pair (nop) (add.xyz instance-translation instance-translation instance-origin)) + (vu-pair (nop) (itof12.xyzw instance-max-scale instance-max-scale)) + ;; Compose the instance translation and three basis rows into the probe's box space. + (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-translation)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-translation)) + (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-translation)) + (vu-pair (nop) (maddw.xyz instance-translation probe-translation vf00)) + (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-row-x)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-row-x)) + (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-row-x)) + (vu-pair (nop) (maddx.xyz instance-row-x probe-translation vf00)) + (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-row-y)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-row-y)) + (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-row-y)) + (vu-pair (nop) (maddx.xyz instance-row-y probe-translation vf00)) + (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-row-z)) + (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-row-z)) + (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-row-z :e)) + (vu-pair (nop) (maddx.xyz instance-row-z probe-translation vf00))) + (label transform-prototype-spheres) + (rlet ((instance-row-x :reg vf17) + (instance-row-y :reg vf18) + (instance-row-z :reg vf19) + (instance-translation :reg vf20) + (instance-max-scale :reg vf21) + (scaled-radii :reg vf22) + (sphere-0 :reg vf05) + (sphere-1 :reg vf06) + (sphere-2 :reg vf07) + (sphere-3 :reg vf08) + (min-0 :reg vf09) + (max-0 :reg vf10) + (min-1 :reg vf11) + (max-1 :reg vf12) + (min-2 :reg vf13) + (max-2 :reg vf14) + (min-3 :reg vf15) + (max-3 :reg vf16)) + ;; Transform each prototype sphere and conservatively scale its radius by the instance. + (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-0)) + (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-0)) + (vu-pair (nop) (maddz.xyzw min-0 instance-row-z sphere-0)) + (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-1)) + (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-1)) + (vu-pair (nop) (maddz.xyzw min-1 instance-row-z sphere-1)) + (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-2)) + (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-2)) + (vu-pair (nop) (maddz.xyzw min-2 instance-row-z sphere-2)) + (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) + (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-3)) + (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-3)) + (vu-pair (nop) (maddz.xyzw min-3 instance-row-z sphere-3)) + (vu-pair (nop) (mulw.x scaled-radii instance-max-scale sphere-0)) + (vu-pair (nop) (mulw.y scaled-radii instance-max-scale sphere-1)) + (vu-pair (nop) (mulw.z scaled-radii instance-max-scale sphere-2)) + (vu-pair (nop) (mulw.w scaled-radii instance-max-scale sphere-3)) + (vu-pair (nop) (addx.xyz max-0 min-0 scaled-radii)) + (vu-pair (nop) (subx.xyz min-0 min-0 scaled-radii)) + (vu-pair (nop) (addy.xyz max-1 min-1 scaled-radii)) + (vu-pair (nop) (suby.xyz min-1 min-1 scaled-radii)) + (vu-pair (nop) (addz.xyz max-2 min-2 scaled-radii)) + (vu-pair (nop) (subz.xyz min-2 min-2 scaled-radii)) + (vu-pair (nop) (addw.xyz max-3 min-3 scaled-radii)) + (vu-pair (nop) (subw.xyz min-3 min-3 scaled-radii)) + (vu-pair (nop) (ftoi0.xyzw max-0 max-0)) + (vu-pair (nop) (ftoi0.xyzw min-0 min-0)) + (vu-pair (nop) (ftoi0.xyzw max-1 max-1)) + (vu-pair (nop) (ftoi0.xyzw min-1 min-1)) + (vu-pair (nop) (ftoi0.xyzw max-2 max-2)) + (vu-pair (nop) (ftoi0.xyzw min-2 min-2)) + (vu-pair (nop) (ftoi0.xyzw max-3 max-3 :e)) + (vu-pair (nop) (ftoi0.xyzw min-3 min-3))))) + + + +(#unless PC_PORT + (defun collide-probe-node ((nodes (inline-array draw-node)) (node-count int) (result collide-list)) + "Traverse node-count draw nodes against the active rotated line-sphere probe. Bounding spheres + are culled four at a time in VU0; overlapping child spans are visited through the scratchpad + stack, and surviving collision-fragment meshes are appended to result with no instance. + Callers must stay within the stack's 1024 entries and the result's 256 entries." + (rlet ((stack-top :reg a0) + (query-min :reg a1 :class i128) + (result :reg a2) + (query-max :reg a3 :class i128) + (stack-base :reg v1) + (result-count :reg t0) + (result-cursor :reg t1) + (span :reg t2) + (remaining :reg t3) + (kind :reg t4) + (probe-row-x :reg vf1) + (probe-row-y :reg vf2) + (probe-row-z :reg vf3) + (probe-translation :reg vf4) + (sphere-0 :reg vf5) + (sphere-1 :reg vf6) + (sphere-2 :reg vf7) + (sphere-3 :reg vf8) + (min-0 :reg vf9) + (max-0 :reg vf10) + (min-1 :reg vf11) + (max-1 :reg vf12) + (min-2 :reg vf13) + (max-2 :reg vf14) + (min-3 :reg vf15) + (max-3 :reg vf16)) + (asm-block save-state-and-seed-stack + (rlet ((work :reg t0) + (seed-kind :reg a1)) + (add.i sp sp -96) + (s.d ra sp) + (s.q s2 sp 16) + (s.q s3 sp 32) + (s.q s4 sp 48) + (s.q s5 sp 64) + (s.q gp sp 80) + (m! work *collide-work*) + (m! stack-base *collide-probe-stack*) + (s.w nodes stack-base PROBE-STACK-CHILD) + (add.i stack-top stack-base PROBE-STACK-STRIDE) + (s.h node-count stack-base PROBE-STACK-COUNT) + (add.i seed-kind r0 1) + (s.h seed-kind stack-base PROBE-STACK-KIND)) + (rlet ((work :reg t0)) + (l.q query-min work PROBE-QUERY-MIN) + (l.q query-max work PROBE-QUERY-MAX) + (l.vf probe-row-x work PROBE-QUERY-ROW-X) + (l.vf probe-row-y work PROBE-QUERY-ROW-Y) + (l.vf probe-row-z work PROBE-QUERY-ROW-Z) + (l.vf probe-translation work PROBE-QUERY-TRANSLATION)) + (l.w result-count result PROBE-RESULT-COUNT) + (sll result-cursor result-count 4) + (add result-cursor result-cursor result) + (add.i result-cursor result-cursor PROBE-RESULT-ITEMS)) + ;; Work entries are popped from the end. Their count word is split into a remaining halfword + ;; and a kind halfword even though the reflected structure exposes it as one uint32. + (asm-block pop-span + (label pop-span) + (b.eq stack-top stack-base done :delay (nop!)) + (add.i stack-top stack-top (- PROBE-STACK-STRIDE)) + (l.w span stack-top PROBE-STACK-CHILD) + (l.hu remaining stack-top PROBE-STACK-COUNT) + (l.hu kind stack-top PROBE-STACK-KIND)) + ;; Drawable arrays are padded, so this path can fetch all four spheres before remaining + ;; determines which results are consumed. + (asm-block cull-four-spheres + (label cull-four) + (l.vf sphere-0 span PROBE-DRAWABLE-BSPHERE) + (l.vf sphere-1 span (+ PROBE-DRAWABLE-BSPHERE PROBE-DRAW-NODE-STRIDE)) + (add.i t5 remaining -4) + (l.vf sphere-2 span (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-DRAW-NODE-STRIDE))) + (b.lt t5 r0 reduce-four :delay (l.vf sphere-3 span (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-DRAW-NODE-STRIDE)))) + (pref span (+ PROBE-DRAWABLE-BSPHERE (* 4 PROBE-DRAW-NODE-STRIDE)) :hint 0) + (label reduce-four) + (callms 0) + (nop!) + (m t5 min-0) + (m t6 max-0) + (m s2 min-1) + (m s3 max-1) + (m s4 min-2) + (m s5 max-2) + (m ra min-3) + (m t9 max-3) + ;; Each packed result is nonzero if candidate-min exceeds query-max or query-min exceeds + ;; candidate-max. Packing the high halfwords and shifting drops W, leaving the XYZ reject. + (pcgt.w t5 t5 query-max) + (l.w t8 span PROBE-CANDIDATE-PAYLOAD) + (pcgt.w t7 query-min t6) + (l.w t6 span (+ PROBE-CANDIDATE-PAYLOAD PROBE-DRAW-NODE-STRIDE)) + (or.q t5 t5 t7) + (l.w t7 span (+ PROBE-CANDIDATE-PAYLOAD (* 2 PROBE-DRAW-NODE-STRIDE))) + (ppach gp r0 t5) + (l.w t5 span (+ PROBE-CANDIDATE-PAYLOAD (* 3 PROBE-DRAW-NODE-STRIDE))) + (pcgt.w s2 s2 query-max) + (mmi-nop!) + (pcgt.w s3 query-min s3) + (mmi-nop!) + (or.q s3 s2 s3) + (mmi-nop!) + (ppach s3 r0 s3) + (mmi-nop!) + (pcgt.w s4 s4 query-max) + (mmi-nop!) + (pcgt.w s5 query-min s5) + (mmi-nop!) + (or.q s5 s4 s5) + (mmi-nop!) + (ppach s5 r0 s5) + (mmi-nop!) + (pcgt.w ra ra query-max) + (mmi-nop!) + (pcgt.w t9 query-min t9) + (mmi-nop!) + (or.q t9 ra t9) + (mmi-nop!) + (ppach t9 r0 t9) + (mmi-nop!) + (sll s4 gp 16) + (sll gp s3 16) + (sll ra s5 16) + (sll t9 t9 16)) + ;; A nonzero kind describes draw nodes. Push each overlapping child span back onto the LIFO. + (asm-block push-overlapping-children + (b.z kind append-fragment-leaves :delay (nop!)) + (b.nz s4 after-node-0 :delay (add.i remaining remaining -1)) + (nop!) + (l.bu s5 span PROBE-DRAWABLE-CHILD-COUNT) + (nop!) + (l.bu s4 span PROBE-DRAWABLE-FLAGS) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t8 stack-top -8) + (nop!) + (s.h s5 stack-top -4) + (nop!) + (s.h s4 stack-top -2) + (label after-node-0) + (b.z remaining finish-node-group :delay (nop!)) + (b.nz gp after-node-1 :delay (add.i remaining remaining -1)) + (nop!) + (l.bu t8 span (+ PROBE-DRAWABLE-CHILD-COUNT PROBE-DRAW-NODE-STRIDE)) + (nop!) + (l.bu gp span (+ PROBE-DRAWABLE-FLAGS PROBE-DRAW-NODE-STRIDE)) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t6 stack-top -8) + (nop!) + (s.h t8 stack-top -4) + (nop!) + (s.h gp stack-top -2) + (label after-node-1) + (b.z remaining finish-node-group :delay (nop!)) + (b.nz ra after-node-2 :delay (add.i remaining remaining -1)) + (nop!) + (l.bu t6 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 2 PROBE-DRAW-NODE-STRIDE))) + (nop!) + (l.bu t8 span (+ PROBE-DRAWABLE-FLAGS (* 2 PROBE-DRAW-NODE-STRIDE))) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t7 stack-top -8) + (nop!) + (s.h t6 stack-top -4) + (nop!) + (s.h t8 stack-top -2) + (label after-node-2) + (b.z remaining finish-node-group :delay (nop!)) + (b.nz t9 finish-node-group :delay (add.i remaining remaining -1)) + (nop!) + (l.bu t6 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 3 PROBE-DRAW-NODE-STRIDE))) + (nop!) + (l.bu t7 span (+ PROBE-DRAWABLE-FLAGS (* 3 PROBE-DRAW-NODE-STRIDE))) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t5 stack-top -8) + (nop!) + (s.h t6 stack-top -4) + (nop!) + (s.h t7 stack-top -2) + (label finish-node-group) + (b.gt remaining r0 cull-four :delay (add.i span span (* 4 PROBE-DRAW-NODE-STRIDE))) + (b pop-span :delay (nop!))) + ;; Kind zero means the span consists of collision-fragment leaves. The shared candidate + ;; payload is their mesh field; non-instanced results carry #f in the instance slot. + (asm-block append-fragment-leaves + (label append-fragment-leaves) + (b.nz s4 after-fragment-0 :delay (add.i remaining remaining -1)) + (add.i result-count result-count 1) + (s.w t8 result-cursor PROBE-RESULT-MESH) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) + (label after-fragment-0) + (b.z remaining finish-fragment-group :delay (nop!)) + (b.nz gp after-fragment-1 :delay (add.i remaining remaining -1)) + (add.i result-count result-count 1) + (s.w t6 result-cursor PROBE-RESULT-MESH) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) + (label after-fragment-1) + (b.z remaining finish-fragment-group :delay (nop!)) + (b.nz ra after-fragment-2 :delay (add.i remaining remaining -1)) + (add.i result-count result-count 1) + (s.w t7 result-cursor PROBE-RESULT-MESH) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) + (label after-fragment-2) + (b.z remaining finish-fragment-group :delay (nop!)) + (b.nz t9 finish-fragment-group :delay (add.i remaining remaining -1)) + (add.i result-count result-count 1) + (s.w t5 result-cursor PROBE-RESULT-MESH) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) + (label finish-fragment-group) + (b.gt remaining r0 cull-four :delay (add.i span span (* 4 PROBE-DRAW-NODE-STRIDE))) + (b pop-span :delay (nop!))) + (asm-block finish + (label done) + (nop!) + (s.w result-count result PROBE-RESULT-COUNT) + (m v0 r0) + (l.d ra sp) + (l.q gp sp 80) + (l.q s5 sp 64) + (l.q s4 sp 48) + (l.q s3 sp 32) + (l.q s2 sp 16) + (jr ra :delay (add.i sp sp 96)) + (nop! :count 3))))) + + +(#unless PC_PORT + (defun collide-probe-instance-tie ((drawables object) (drawable-count int) (result collide-list) (draw-node-span? int)) + "Traverse an instance-TIE tree against the active rotated line-sphere probe. Draw-node spans and + direct instance spans share an eight-byte scratchpad stack. Surviving instances contribute + their prototype collision fragments after the packed instance transform is composed with the + probe transform in VU0. draw-node-span? is one for draw nodes and zero for direct instances. + Callers must stay within the stack's 1024 entries and the result's 256 entries." + (rlet ((stack-top :reg a0) + (instance-batch-count :reg a1) + (result :reg a2) + (node-batch-count :reg a3) + (stack-base :reg v1) + (query-min :reg t0 :class i128) + (query-max :reg t1 :class i128) + (kind :reg t2) + (remaining :reg t3) + (span :reg t4) + (probe-row-x :reg vf1) + (probe-row-y :reg vf2) + (probe-row-z :reg vf3) + (probe-translation :reg vf4) + (sphere-0 :reg vf5) + (sphere-1 :reg vf6) + (sphere-2 :reg vf7) + (sphere-3 :reg vf8) + (min-0 :reg vf9) + (max-0 :reg vf10) + (min-1 :reg vf11) + (max-1 :reg vf12) + (min-2 :reg vf13) + (max-2 :reg vf14) + (min-3 :reg vf15) + (max-3 :reg vf16)) + ;; Seed the work stack with either the root draw-node span or the direct instance span. + (rlet ((work :reg t2)) + (asm-block save-state-and-seed-stack + (label entry) + (add.i sp sp -80) + (s.d ra sp) + (s.q s3 sp 16) + (s.q s4 sp 32) + (s.q s5 sp 48) + (s.q gp sp 64) + (m! work *collide-work*) + (m! stack-base *collide-probe-stack*) + (s.w drawables stack-base PROBE-STACK-CHILD) + (add.i stack-top stack-base PROBE-STACK-STRIDE) + (s.h drawable-count stack-base PROBE-STACK-COUNT) + (s.h draw-node-span? stack-base PROBE-STACK-KIND) + (add.i instance-batch-count r0 0) + (add.i node-batch-count r0 0) + (l.q query-min work PROBE-QUERY-MIN) + (l.q query-max work PROBE-QUERY-MAX) + (l.vf probe-row-x work PROBE-QUERY-ROW-X) + (l.vf probe-row-y work PROBE-QUERY-ROW-Y) + (l.vf probe-row-z work PROBE-QUERY-ROW-Z) + (l.vf probe-translation work PROBE-QUERY-TRANSLATION))) + ;; Negative work kinds are individual instances. Zero denotes a direct instance span, and a + ;; positive kind denotes a draw-node span. + (asm-block pop-work + (label pop-work) + (b.eq stack-top stack-base done :delay (nop!)) + (add.i stack-top stack-top (- PROBE-STACK-STRIDE)) + (l.w span stack-top PROBE-STACK-CHILD) + (l.h kind stack-top PROBE-STACK-KIND) + (l.hu remaining stack-top PROBE-STACK-COUNT) + (b.lt kind r0 process-instance :delay (nop!))) + ;; Both span kinds expose a bounding sphere at the same offset. Draw nodes are 32 bytes while + ;; instances are 64, so the paths use different strides. Their separate batch counters are + ;; retained here but are not consumed below. + (asm-block load-broadphase-four + (label load-broadphase-four) + (b.z kind load-instance-four :delay (nop!)) + (l.vf sphere-0 span PROBE-DRAWABLE-BSPHERE) + (add.i node-batch-count node-batch-count 1) + (l.vf sphere-1 span (+ PROBE-DRAWABLE-BSPHERE PROBE-DRAW-NODE-STRIDE)) + (add.i t5 remaining -4) + (l.vf sphere-2 span (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-DRAW-NODE-STRIDE))) + (b.lt t5 r0 node-prefetched :delay (l.vf sphere-3 span (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-DRAW-NODE-STRIDE)))) + (pref span (+ PROBE-DRAWABLE-BSPHERE (* 4 PROBE-DRAW-NODE-STRIDE)) :hint 0) + (label node-prefetched) + (b reduce-broadphase-four :delay (nop!)) + (label load-instance-four) + (l.vf sphere-0 span PROBE-INSTANCE-BSPHERE) + (add.i instance-batch-count instance-batch-count 1) + (l.vf sphere-1 span (+ PROBE-INSTANCE-BSPHERE PROBE-INSTANCE-STRIDE)) + (add.i t5 remaining -4) + (l.vf sphere-2 span (+ PROBE-INSTANCE-BSPHERE (* 2 PROBE-INSTANCE-STRIDE))) + (b.lt t5 r0 reduce-broadphase-four :delay (l.vf sphere-3 span (+ PROBE-INSTANCE-BSPHERE (* 3 PROBE-INSTANCE-STRIDE)))) + (pref span (+ PROBE-INSTANCE-BSPHERE (* 4 PROBE-INSTANCE-STRIDE)) :hint 0) + (pref span (+ PROBE-INSTANCE-BSPHERE (* 6 PROBE-INSTANCE-STRIDE)) :hint 0)) + ;; VU0 transforms four spheres to query-box space. The EE combines the two separating-axis + ;; comparisons, packs their XYZ results, and leaves one reject bit in each scalar. + (asm-block reduce-broadphase-four + (label reduce-broadphase-four) + (callms 0) + (m s5 min-0) + (m t7 max-0) + (m gp min-1) + (m ra max-1) + (m t9 min-2) + (m t8 max-2) + (m t6 min-3) + (m t5 max-3) + (nop!) + (pcgt.w s5 s5 query-max) + (mmi-nop!) + (pcgt.w t7 query-min t7) + (mmi-nop!) + (or.q t7 s5 t7) + (mmi-nop!) + (ppach t7 r0 t7) + (mmi-nop!) + (pcgt.w gp gp query-max) + (mmi-nop!) + (pcgt.w ra query-min ra) + (mmi-nop!) + (or.q ra gp ra) + (mmi-nop!) + (ppach ra r0 ra) + (mmi-nop!) + (pcgt.w t9 t9 query-max) + (mmi-nop!) + (pcgt.w t8 query-min t8) + (mmi-nop!) + (or.q t8 t9 t8) + (mmi-nop!) + (ppach t8 r0 t8) + (mmi-nop!) + (pcgt.w t6 t6 query-max) + (mmi-nop!) + (pcgt.w t5 query-min t5) + (mmi-nop!) + (or.q t5 t6 t5) + (mmi-nop!) + (ppach t5 r0 t5) + (mmi-nop!) + (sll t9 t7 16) + (sll t7 ra 16) + (sll t6 t8 16) + (sll t5 t5 16)) + ;; For a draw-node span, push each overlapping child span. The flags byte becomes the next + ;; work kind, so children-are-draw-nodes naturally selects the next interpretation. + (asm-block queue-node-children + (b.z kind queue-instance-hits :delay (nop!)) + (b.nz t9 after-node-0 :delay (add.i remaining remaining -1)) + (nop!) + (l.w t8 span PROBE-DRAWABLE-CHILD) + (nop!) + (l.bu t9 span PROBE-DRAWABLE-CHILD-COUNT) + (nop!) + (l.bu ra span PROBE-DRAWABLE-FLAGS) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t8 stack-top (- PROBE-STACK-STRIDE)) + (nop!) + (s.h t9 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h ra stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label after-node-0) + (b.z remaining finish-node-group :delay (nop!)) + (b.nz t7 after-node-1 :delay (add.i remaining remaining -1)) + (nop!) + (l.w t7 span (+ PROBE-DRAWABLE-CHILD PROBE-DRAW-NODE-STRIDE)) + (nop!) + (l.bu t8 span (+ PROBE-DRAWABLE-CHILD-COUNT PROBE-DRAW-NODE-STRIDE)) + (nop!) + (l.bu t9 span (+ PROBE-DRAWABLE-FLAGS PROBE-DRAW-NODE-STRIDE)) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t7 stack-top (- PROBE-STACK-STRIDE)) + (nop!) + (s.h t8 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h t9 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label after-node-1) + (b.z remaining finish-node-group :delay (nop!)) + (b.nz t6 after-node-2 :delay (add.i remaining remaining -1)) + (nop!) + (l.w t6 span (+ PROBE-DRAWABLE-CHILD (* 2 PROBE-DRAW-NODE-STRIDE))) + (nop!) + (l.bu t7 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 2 PROBE-DRAW-NODE-STRIDE))) + (nop!) + (l.bu t8 span (+ PROBE-DRAWABLE-FLAGS (* 2 PROBE-DRAW-NODE-STRIDE))) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t6 stack-top (- PROBE-STACK-STRIDE)) + (nop!) + (s.h t7 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h t8 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label after-node-2) + (b.z remaining finish-node-group :delay (nop!)) + (b.nz t5 finish-node-group :delay (add.i remaining remaining -1)) + (nop!) + (l.w t5 span (+ PROBE-DRAWABLE-CHILD (* 3 PROBE-DRAW-NODE-STRIDE))) + (nop!) + (l.bu t6 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 3 PROBE-DRAW-NODE-STRIDE))) + (nop!) + (l.bu t7 span (+ PROBE-DRAWABLE-FLAGS (* 3 PROBE-DRAW-NODE-STRIDE))) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w t5 stack-top (- PROBE-STACK-STRIDE)) + (nop!) + (s.h t6 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h t7 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label finish-node-group) + (b.gt remaining r0 load-broadphase-four :delay (add.i span span (* 4 PROBE-DRAW-NODE-STRIDE))) + (b pop-work :delay (nop!))) + ;; A direct span cannot be processed until its prototype data is known. Queue each surviving + ;; instance as a negative-kind single item, preserving the same LIFO traversal order. + (asm-block queue-instance-hits + (label queue-instance-hits) + (b.nz t9 after-instance-0 :delay (add.i remaining remaining -1)) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w span stack-top (- PROBE-STACK-STRIDE)) + (add.i t8 r0 -1) + (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h t8 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label after-instance-0) + (b.z remaining finish-instance-group :delay (add.i span span PROBE-INSTANCE-STRIDE)) + (b.nz t7 after-instance-1 :delay (add.i remaining remaining -1)) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w span stack-top (- PROBE-STACK-STRIDE)) + (add.i t7 r0 -1) + (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h t7 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label after-instance-1) + (b.z remaining finish-instance-group :delay (add.i span span PROBE-INSTANCE-STRIDE)) + (b.nz t6 after-instance-2 :delay (add.i remaining remaining -1)) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w span stack-top (- PROBE-STACK-STRIDE)) + (add.i t6 r0 -1) + (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h t6 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label after-instance-2) + (b.z remaining finish-instance-group :delay (add.i span span PROBE-INSTANCE-STRIDE)) + (b.nz t5 finish-instance-group :delay (add.i remaining remaining -1)) + (add.i stack-top stack-top PROBE-STACK-STRIDE) + (s.w span stack-top (- PROBE-STACK-STRIDE)) + (add.i t5 r0 -1) + (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) + (nop!) + (s.h t5 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) + (label finish-instance-group) + (b.gt remaining r0 load-broadphase-four :delay (add.i span span PROBE-INSTANCE-STRIDE)) + (b pop-work :delay (nop!))) + (rlet ((instance :reg t2) + (instance-row-x :reg vf17) + (instance-row-y :reg vf18) + (instance-row-z :reg vf19) + (instance-translation :reg vf20) + (instance-max-scale :reg vf21) + (scaled-radii :reg vf22) + (instance-origin :reg vf23)) + ;; TIE stores its affine transform as signed halfwords. Translation is split across the two + ;; matrix halves and encoded in 64-unit steps; basis rows use signed Q12 fixed point and + ;; max-scale is unsigned Q12. VU entry 32 converts and composes this with the probe inverse. + (asm-block decode-instance-transform + (label process-instance) + (rlet ((queued-instance :reg t4)) + (m instance queued-instance) + (rlet ((instance-flags :reg t4) + (bucket :reg t3) + (fragment-array :reg t6)) + (l.hu instance-flags queued-instance PROBE-INSTANCE-FLAGS) + (nop!) + (l.w bucket instance PROBE-INSTANCE-BUCKET) + ;; The branch tests flags before its delay load replaces the same register. + (b.nz instance-flags finish-instance :delay (l.hu t4 instance PROBE-INSTANCE-MAX-SCALE)) + (nop!) + (l.w fragment-array bucket PROBE-BUCKET-COLLIDE-FRAG) + (nop!))) + (rlet ((max-scale-bits :reg t4 :class i128) + (origin-high-bits :reg t3 :class i128) + (origin-low-bits :reg t5 :class i128) + (fragment-array :reg t6)) + (l.q origin-high-bits instance PROBE-INSTANCE-ORIGIN-HIGH) + (b.z fragment-array finish-instance :delay (l.q origin-low-bits instance PROBE-INSTANCE-ORIGIN-LOW)) + (pextlw max-scale-bits max-scale-bits max-scale-bits) + (mmi-nop!) + (pcpyld max-scale-bits max-scale-bits max-scale-bits) + (mmi-nop!) + (pcpyud t8 origin-high-bits r0) + (mmi-nop!) + (pcpyud t7 origin-low-bits r0) + (mmi-nop!) + (pextlh t8 t8 r0) + (mmi-nop!) + (sra.w t8 t8 10) + (mmi-nop!) + (pextlh t9 origin-low-bits r0)) + (rlet ((max-scale-bits :reg t4 :class i128) + (origin-high-bits :reg t3 :class i128) + (fragment-count :reg t5) + (fragment-array :reg t6)) + (l.hu fragment-count fragment-array PROBE-FRAGMENT-ARRAY-LENGTH) + (sra.w t9 t9 16) + (mmi-nop!) + (pextlh t7 t7 r0) + (m instance-translation t8) + (sra.w t7 t7 16) + (m instance-row-x t9) + (pextlh origin-high-bits origin-high-bits r0) + (m instance-row-y t7) + (sra.w origin-high-bits origin-high-bits 16) + (l.vf instance-origin instance PROBE-INSTANCE-BSPHERE) + (m instance-row-z origin-high-bits) + (rlet ((result-count :reg t3)) + (l.w result-count result PROBE-RESULT-COUNT)) + (m instance-max-scale max-scale-bits) + (add.i t7 fragment-count -4) + (callms 32))) + (rlet ((result-count :reg t3) + (result-cursor :reg t4) + (fragment-count :reg t5) + (fragment-cursor :reg t6)) + (asm-block prepare-fragment-cursor + (sll result-cursor result-count 4) + (add result-cursor result-cursor result) + (add fragment-count fragment-count r0) + (add.i result-cursor result-cursor PROBE-RESULT-ITEMS) + (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-ARRAY-DATA) + (b.lt t7 r0 cull-fragment-tail :delay (l.q t7 fragment-cursor PROBE-DRAWABLE-BSPHERE)) + (nop!) + (l.q t8 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE PROBE-FRAGMENT-STRIDE)) + (nop!) + (l.q t9 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-FRAGMENT-STRIDE))) + (nop!) + (l.q ra fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-FRAGMENT-STRIDE))) + (nop!) + (m.ni sphere-0 t7) + (nop!) + (m.ni sphere-1 t8) + (nop!) + (m.ni sphere-2 t9) + (nop!) + (m.ni sphere-3 ra)) + ;; Entry 54 transforms four prototype spheres by the composed instance transform and scales + ;; their radii conservatively. The EE then performs the same packed XYZ rejection as above. + (asm-block cull-four-fragments + (label cull-four-fragments) + ;; Entry 54 raises E before its final drain instruction; wait for completion + ;; before transferring the eight integer bounds back to the EE. + (callms 54) + (nop! :count 3) + (vnop) + (nop!) + (m s3 max-0) + (nop!) + (m t9 min-0) + (nop!) + (m s4 max-1) + (nop!) + (m s5 min-1) + (nop!) + (m gp max-2) + (nop!) + (m ra min-2) + (nop!) + (m t8 max-3) + (nop!) + (m t7 min-3) + (nop!) + (pcgt.w s3 query-min s3) + (mmi-nop!) + (pcgt.w t9 t9 query-max) + (mmi-nop!) + (or.q t9 t9 s3) + (mmi-nop!) + (ppach t9 r0 t9) + (mmi-nop!) + (pcgt.w s4 query-min s4) + (mmi-nop!) + (pcgt.w s5 s5 query-max) + (mmi-nop!) + (or.q s5 s5 s4) + (mmi-nop!) + (ppach s5 r0 s5) + (mmi-nop!) + (pcgt.w gp query-min gp) + (mmi-nop!) + (pcgt.w ra ra query-max) + (mmi-nop!) + (or.q ra ra gp) + (mmi-nop!) + (ppach ra r0 ra) + (mmi-nop!) + (pcgt.w t8 query-min t8) + (mmi-nop!) + (pcgt.w t7 t7 query-max) + (mmi-nop!) + (or.q t7 t7 t8) + (mmi-nop!) + (ppach t7 r0 t7) + (mmi-nop!) + (sll gp t9 16) + (sll t9 s5 16) + (sll t8 ra 16) + (sll t7 t7 16)) + ;; Append the mesh pointer and originating instance for each surviving fragment. The result + ;; cursor follows the list's physical sixteen-byte inline spacing. + (asm-block append-four-fragments + (b.nz gp after-fragment-0 :delay (nop!)) + (nop!) + (l.w ra fragment-cursor PROBE-FRAGMENT-MESH) + (add.i result-count result-count 1) + (s.w instance result-cursor PROBE-RESULT-INSTANCE) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w ra result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) + (label after-fragment-0) + (add.i fragment-count fragment-count -1) + (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) + (b.z fragment-count finish-fragment-group :delay (nop!)) + (b.nz t9 after-fragment-1 :delay (nop!)) + (nop!) + (l.w t9 fragment-cursor PROBE-FRAGMENT-MESH) + (add.i result-count result-count 1) + (s.w instance result-cursor PROBE-RESULT-INSTANCE) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w t9 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) + (label after-fragment-1) + (add.i fragment-count fragment-count -1) + (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) + (b.z fragment-count finish-fragment-group :delay (nop!)) + (b.nz t8 after-fragment-2 :delay (nop!)) + (nop!) + (l.w t8 fragment-cursor PROBE-FRAGMENT-MESH) + (add.i result-count result-count 1) + (s.w instance result-cursor PROBE-RESULT-INSTANCE) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w t8 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) + (label after-fragment-2) + (add.i fragment-count fragment-count -1) + (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) + (b.z fragment-count finish-fragment-group :delay (nop!)) + (b.nz t7 after-fragment-3 :delay (nop!)) + (nop!) + (l.w t7 fragment-cursor PROBE-FRAGMENT-MESH) + (add.i result-count result-count 1) + (s.w instance result-cursor PROBE-RESULT-INSTANCE) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w t7 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) + (label after-fragment-3) + (add.i fragment-count fragment-count -1) + (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) + (b.z fragment-count finish-fragment-group :delay (l.vf sphere-0 fragment-cursor PROBE-DRAWABLE-BSPHERE)) + (nop!) + (l.vf sphere-1 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE PROBE-FRAGMENT-STRIDE)) + (nop!) + (l.vf sphere-2 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-FRAGMENT-STRIDE))) + (b cull-four-fragments :delay (l.vf sphere-3 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-FRAGMENT-STRIDE))))) + (asm-block finish-fragment-group + (label finish-fragment-group) + (nop!) + (s.w result-count result PROBE-RESULT-COUNT) + (b pop-work :delay (nop!))) + ;; Fewer than four remaining fragments use the same composed transform inline. The sphere's + ;; center is transformed, its radius is multiplied by max-scale, and its integer bounds are + ;; rejected before the mesh is appended. + (asm-block cull-fragment-tail + (label cull-fragment-tail) + (rlet ((tail-center :reg vf24) + (tail-max :reg vf25)) + (m sphere-0 t7) + (nop!) + (mula.w.vf instance-translation vf0) + (nop!) + (madda.x.vf instance-row-x sphere-0) + (nop!) + (madda.y.vf instance-row-y sphere-0) + (nop!) + (madd.z.vf tail-center instance-row-z sphere-0) + (nop!) + (mul.w.vf.x scaled-radii instance-max-scale sphere-0) + (nop!) + (add.x.vf.xyz tail-max tail-center scaled-radii) + (nop!) + (rlet ((tail-min :reg vf24)) + (sub.x.vf.xyz tail-min tail-center scaled-radii) + (nop!) + (ftoi.vf tail-max tail-max) + (nop!) + (ftoi.vf tail-min tail-min) + (nop!) + (m t8 tail-max) + (nop!) + (m t7 tail-min) + (nop!) + (pcgt.w t8 query-min t8) + (mmi-nop!) + (pcgt.w t7 t7 query-max) + (mmi-nop!) + (or.q t7 t7 t8) + (mmi-nop!) + (ppach t7 r0 t7) + (mmi-nop!) + (sll t7 t7 16) + (nop!) + (b.nz t7 after-tail-fragment :delay (nop!)) + (nop!) + (l.w t7 fragment-cursor PROBE-FRAGMENT-MESH) + (add.i result-count result-count 1) + (s.w instance result-cursor PROBE-RESULT-INSTANCE) + (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) + (s.w t7 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) + (label after-tail-fragment) + (add.i fragment-count fragment-count -1) + (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) + (b.gt fragment-count r0 cull-fragment-tail :delay (l.q t7 fragment-cursor PROBE-DRAWABLE-BSPHERE)) + (nop!) + (s.w result-count result PROBE-RESULT-COUNT)))) + (asm-block finish-instance (label finish-instance) (b pop-work :delay (nop!))))) + (asm-block restore-state + (label done) + (m v0 r0) + (l.d ra sp) + (l.q gp sp 64) + (l.q s5 sp 48) + (l.q s4 sp 32) + (l.q s3 sp 16) + (jr ra :delay (add.i sp sp 80)) + (nop! :count 2))))) diff --git a/goal_src/jak1/engine/collide/collide-probe.gc b/goal_src/jak1/engine/collide/collide-probe.gc index 45e4a908af..06c35900d3 100644 --- a/goal_src/jak1/engine/collide/collide-probe.gc +++ b/goal_src/jak1/engine/collide/collide-probe.gc @@ -10,9 +10,12 @@ ;; DECOMP BEGINS -;; The collision probe builds the background-fragment list used to find the first triangle along a -;; direction. The broad phase is expensive enough to use its own tree walker and VU0 box culler. -;; It is used mainly by the y-probe methods which find the ground beneath an object. +;; Collide-probe handles broad phase collision checks for "line-sphere" (a swept sphere) collision checks. +;; It walks through the collision BVH and adds any collision fragments whose bounding spheres intersect +;; the capsule. (to be precise, it's conservative, and uses an oriented bounding box around the capsule) + +;; Note that this is not the greatest implementation for raycasts since it returns all fragments, +;; not the first one. It doesn't know how to test actual triangles within fragments. ;;;;;;;;;;;;;;;;;;;;;;;; ;; Method Debug @@ -44,7 +47,8 @@ ((overrides-parent-method? owner-type i) (format #t " overridden by ~s.~%" (symbol->string (-> owner-type symbol))) (set! owner-type (-> owner-type parent))) - (else (set! owner-type (-> owner-type parent)))))))) + (else + (set! owner-type (-> owner-type parent)))))))) #f) ;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -87,7 +91,8 @@ (dotimes (i length) (indent-to indent) (format #t "(~3d) ~a~%" i (-> inline-node data i)) - (if (= (-> inline-node data i type) draw-node) (probe-traverse-draw-node (-> inline-node data i) (+ indent 1))))) + (if (= (-> inline-node data i type) draw-node) + (probe-traverse-draw-node (-> inline-node data i) (+ indent 1))))) (none)) (defun probe-traverse-collide-fragment ((tree drawable-tree-collide-fragment) (indent int)) @@ -99,462 +104,30 @@ (dotimes (i (+ length -1)) (indent-to indent) (if (= (-> tree data i type) drawable-inline-array-node) - (probe-traverse-inline-array-node (the-as drawable-inline-array-node (-> tree data i)) (+ indent 1)) - (format #t "unknown: ~a~%" (-> tree data i))))) + (probe-traverse-inline-array-node (the-as drawable-inline-array-node (-> tree data i)) (+ indent 1)) + (format #t "unknown: ~a~%" (-> tree data i))))) (none)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Collide Probe Implementation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; This stack was used by the original EE assembly - it's a pending work list rather than +;; a "stack" of parents in the currently processing node. +;; We've rewritten collide-probe in plain GOAL using recursion, using a actual stack +;; depth that's bounded by the max depth of the collision tree structure (quite small in practice) + (deftype collide-probe-stack-elem (structure) - "The reflected view of one pending broad-phase span. The EE code packs these into eight bytes in - scratchpad: child is followed by a 16-bit remaining count and a signed 16-bit work kind in the - two halves of count. A negative kind identifies a queued TIE instance, zero identifies direct - leaves, and a positive kind identifies a draw-node span." ((child uint32) (count uint32))) (deftype collide-probe-stack (structure) - "Scratchpad LIFO storage for iterative collision-tree traversal. The EE code packs 1024 - eight-byte elements into 0x2000 bytes; the reflected inline array has a nominal 0x4000-byte - allocation because its elements receive sixteen-byte inline alignment." ((data collide-probe-stack-elem 1024 :inline))) ;;(define *collide-probe-stack* (the-as pointer (+ 4192 #x70000000))) (define *collide-probe-stack* (scratchpad-object collide-probe-stack :offset 4192)) -(#unless PC_PORT - ;; A BASIC value points just after its allocation's type word. Raw EE loads from such a value - ;; therefore subtract four from the displayed field offset. - (defconstant PROBE-BASIC-BIAS 4) - (defconstant PROBE-STACK-CHILD (offset-of collide-probe-stack-elem child)) ;; 0 - (defconstant PROBE-STACK-COUNT (offset-of collide-probe-stack-elem count)) ;; 4 - ;; The work kind occupies the high halfword of collide-probe-stack-elem.count. - (defconstant PROBE-STACK-KIND (+ (offset-of collide-probe-stack-elem count) 2)) ;; 6 - (defconstant PROBE-STACK-STRIDE (type-size collide-probe-stack-elem)) ;; 8 - (defconstant PROBE-DRAWABLE-CHILD-COUNT (- (offset-of draw-node child-count) PROBE-BASIC-BIAS)) ;; 2 - (defconstant PROBE-DRAWABLE-FLAGS (- (offset-of draw-node flags) PROBE-BASIC-BIAS)) ;; 3 - (defconstant PROBE-DRAWABLE-CHILD (- (offset-of draw-node child) PROBE-BASIC-BIAS)) ;; 4 - ;; The same four-byte payload is draw-node.child or collide-fragment.mesh according to work kind. - (defconstant PROBE-CANDIDATE-PAYLOAD PROBE-DRAWABLE-CHILD) - (defconstant PROBE-DRAWABLE-BSPHERE (- (offset-of draw-node bsphere) PROBE-BASIC-BIAS)) ;; 12 - (defconstant PROBE-DRAW-NODE-STRIDE (type-size draw-node)) ;; 32 - (defconstant PROBE-INSTANCE-STRIDE (type-size instance-tie)) ;; 64 - (defconstant PROBE-FRAGMENT-STRIDE (type-size collide-fragment)) ;; 32 - (defconstant PROBE-FRAGMENT-MESH (- (offset-of collide-fragment mesh) PROBE-BASIC-BIAS)) ;; 4 - (defconstant PROBE-BUCKET-COLLIDE-FRAG (- (offset-of prototype-bucket-tie collide-frag) PROBE-BASIC-BIAS)) ;; 136 - (defconstant PROBE-FRAGMENT-ARRAY-LENGTH (- (offset-of drawable-inline-array-collide-fragment length) PROBE-BASIC-BIAS)) ;; 2 - ;; data is an inline BASIC array. This displacement passes its type word and lands on the first - ;; collide-fragment's GOAL pointer. - (defconstant PROBE-FRAGMENT-ARRAY-DATA (offset-of drawable-inline-array-collide-fragment data 0)) ;; 32 - (defconstant PROBE-INSTANCE-BUCKET (- (offset-of instance-tie bucket-ptr) PROBE-BASIC-BIAS)) ;; 8 - (defconstant PROBE-INSTANCE-BSPHERE (- (offset-of instance-tie bsphere) PROBE-BASIC-BIAS)) ;; 12 - (defconstant PROBE-INSTANCE-ORIGIN-LOW (- (offset-of instance-tie origin data 0) PROBE-BASIC-BIAS)) ;; 28 - (defconstant PROBE-INSTANCE-MAX-SCALE (- (offset-of instance-tie max-scale) PROBE-BASIC-BIAS)) ;; 34 - (defconstant PROBE-INSTANCE-FLAGS (- (offset-of instance-tie flags) PROBE-BASIC-BIAS)) ;; 42 - (defconstant PROBE-INSTANCE-ORIGIN-HIGH (- (offset-of instance-tie origin data 8) PROBE-BASIC-BIAS)) ;; 44 - (defconstant PROBE-QUERY-MIN (offset-of collide-work collide-box4w min)) ;; 16 - (defconstant PROBE-QUERY-MAX (offset-of collide-work collide-box4w max)) ;; 32 - (defconstant PROBE-QUERY-ROW-X (offset-of collide-work inv-mat vector 0)) ;; 48 - (defconstant PROBE-QUERY-ROW-Y (offset-of collide-work inv-mat vector 1)) ;; 64 - (defconstant PROBE-QUERY-ROW-Z (offset-of collide-work inv-mat vector 2)) ;; 80 - (defconstant PROBE-QUERY-TRANSLATION (offset-of collide-work inv-mat vector 3)) ;; 96 - (defconstant PROBE-RESULT-COUNT (offset-of collide-list num-items)) ;; 0 - (defconstant PROBE-RESULT-ITEMS (offset-of collide-list items 0)) ;; 16 - ;; collide-list-item is eight bytes as a structure, but this fixed inline array gives each - ;; physical slot sixteen-byte alignment. - (defconstant PROBE-RESULT-ITEM-STRIDE 16) - (defconstant PROBE-RESULT-MESH (offset-of collide-list-item mesh)) ;; 0 - (defconstant PROBE-RESULT-INSTANCE (offset-of collide-list-item inst))) ;; 4 - -(#when PC_PORT - (define collide-vu0-block (new 'static 'vu-function :length 0 :qlength 0))) - -;; The inverse probe transform establishes an axis-aligned box space for the rotated line-sphere -;; query. Entry 0 transforms four bounding spheres into that space and leaves integer minimum and -;; maximum corners in vf9..vf16. Entry 32 rebuilds a compressed TIE instance transform around its -;; world bounding-sphere center and composes it with the probe transform. Entry 54 uses the composed -;; transform and the instance's maximum scale to conservatively bound four prototype fragments; -;; vf22.x/y/z/w holds one scaled radius for each sphere. The EE rejects the resulting boxes against -;; collide-work.collide-box4w. -(#unless PC_PORT - (defvu0 collide-vu0-block - (rlet ((probe-row-x :reg vf01) - (probe-row-y :reg vf02) - (probe-row-z :reg vf03) - (probe-translation :reg vf04) - (sphere-0 :reg vf05) - (sphere-1 :reg vf06) - (sphere-2 :reg vf07) - (sphere-3 :reg vf08) - (min-0 :reg vf09) - (max-0 :reg vf10) - (min-1 :reg vf11) - (max-1 :reg vf12) - (min-2 :reg vf13) - (max-2 :reg vf14) - (min-3 :reg vf15) - (max-3 :reg vf16)) - ;; Transform the four centers and expand each result by its source sphere radius. - (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-0)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-0)) - (vu-pair (nop) (maddz.xyz sphere-0 probe-row-z sphere-0)) - (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-1)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-1)) - (vu-pair (nop) (maddz.xyz sphere-1 probe-row-z sphere-1)) - (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-2)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-2)) - (vu-pair (nop) (maddz.xyz sphere-2 probe-row-z sphere-2)) - (vu-pair (nop) (mulaw.xyzw ACC probe-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC probe-row-x sphere-3)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y sphere-3)) - (vu-pair (nop) (maddz.xyz sphere-3 probe-row-z sphere-3)) - (vu-pair (nop) (subw.xyz min-0 sphere-0 sphere-0)) - (vu-pair (nop) (subw.xyz min-1 sphere-1 sphere-1)) - (vu-pair (nop) (subw.xyz min-2 sphere-2 sphere-2)) - (vu-pair (nop) (subw.xyz min-3 sphere-3 sphere-3)) - (vu-pair (nop) (addw.xyz max-0 sphere-0 sphere-0)) - (vu-pair (nop) (addw.xyz max-1 sphere-1 sphere-1)) - (vu-pair (nop) (addw.xyz max-2 sphere-2 sphere-2)) - (vu-pair (nop) (addw.xyz max-3 sphere-3 sphere-3)) - (vu-pair (nop) (ftoi0.xyzw min-0 min-0)) - (vu-pair (nop) (ftoi0.xyzw min-1 min-1)) - (vu-pair (nop) (ftoi0.xyzw min-2 min-2)) - (vu-pair (nop) (ftoi0.xyzw min-3 min-3)) - (vu-pair (nop) (ftoi0.xyzw max-0 max-0)) - (vu-pair (nop) (ftoi0.xyzw max-1 max-1)) - (vu-pair (nop) (ftoi0.xyzw max-2 max-2 :e)) - (vu-pair (nop) (ftoi0.xyzw max-3 max-3))) - (label compose-instance-transform) - (rlet ((probe-row-x :reg vf01) - (probe-row-y :reg vf02) - (probe-row-z :reg vf03) - (probe-translation :reg vf04) - (instance-row-x :reg vf17) - (instance-row-y :reg vf18) - (instance-row-z :reg vf19) - (instance-translation :reg vf20) - (instance-max-scale :reg vf21) - (instance-origin :reg vf23)) - ;; Basis rows are signed Q12 fixed point and maximum scale is unsigned Q12. Translation - ;; is quantized in 64-unit steps relative to the instance's world bounding-sphere center. - (vu-pair (nop) (itof0.xyzw instance-translation instance-translation)) - (vu-pair (nop) (itof12.xyzw instance-row-x instance-row-x)) - (vu-pair (nop) (itof12.xyzw instance-row-y instance-row-y)) - (vu-pair (nop) (itof12.xyzw instance-row-z instance-row-z)) - (vu-pair (nop) (add.xyz instance-translation instance-translation instance-origin)) - (vu-pair (nop) (itof12.xyzw instance-max-scale instance-max-scale)) - ;; Compose the instance translation and three basis rows into the probe's box space. - (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-translation)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-translation)) - (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-translation)) - (vu-pair (nop) (maddw.xyz instance-translation probe-translation vf00)) - (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-row-x)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-row-x)) - (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-row-x)) - (vu-pair (nop) (maddx.xyz instance-row-x probe-translation vf00)) - (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-row-y)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-row-y)) - (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-row-y)) - (vu-pair (nop) (maddx.xyz instance-row-y probe-translation vf00)) - (vu-pair (nop) (mulax.xyzw ACC probe-row-x instance-row-z)) - (vu-pair (nop) (madday.xyzw ACC probe-row-y instance-row-z)) - (vu-pair (nop) (maddaz.xyzw ACC probe-row-z instance-row-z :e)) - (vu-pair (nop) (maddx.xyz instance-row-z probe-translation vf00))) - (label transform-prototype-spheres) - (rlet ((instance-row-x :reg vf17) - (instance-row-y :reg vf18) - (instance-row-z :reg vf19) - (instance-translation :reg vf20) - (instance-max-scale :reg vf21) - (scaled-radii :reg vf22) - (sphere-0 :reg vf05) - (sphere-1 :reg vf06) - (sphere-2 :reg vf07) - (sphere-3 :reg vf08) - (min-0 :reg vf09) - (max-0 :reg vf10) - (min-1 :reg vf11) - (max-1 :reg vf12) - (min-2 :reg vf13) - (max-2 :reg vf14) - (min-3 :reg vf15) - (max-3 :reg vf16)) - ;; Transform each prototype sphere and conservatively scale its radius by the instance. - (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-0)) - (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-0)) - (vu-pair (nop) (maddz.xyzw min-0 instance-row-z sphere-0)) - (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-1)) - (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-1)) - (vu-pair (nop) (maddz.xyzw min-1 instance-row-z sphere-1)) - (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-2)) - (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-2)) - (vu-pair (nop) (maddz.xyzw min-2 instance-row-z sphere-2)) - (vu-pair (nop) (mulaw.xyzw ACC instance-translation vf00)) - (vu-pair (nop) (maddax.xyzw ACC instance-row-x sphere-3)) - (vu-pair (nop) (madday.xyzw ACC instance-row-y sphere-3)) - (vu-pair (nop) (maddz.xyzw min-3 instance-row-z sphere-3)) - (vu-pair (nop) (mulw.x scaled-radii instance-max-scale sphere-0)) - (vu-pair (nop) (mulw.y scaled-radii instance-max-scale sphere-1)) - (vu-pair (nop) (mulw.z scaled-radii instance-max-scale sphere-2)) - (vu-pair (nop) (mulw.w scaled-radii instance-max-scale sphere-3)) - (vu-pair (nop) (addx.xyz max-0 min-0 scaled-radii)) - (vu-pair (nop) (subx.xyz min-0 min-0 scaled-radii)) - (vu-pair (nop) (addy.xyz max-1 min-1 scaled-radii)) - (vu-pair (nop) (suby.xyz min-1 min-1 scaled-radii)) - (vu-pair (nop) (addz.xyz max-2 min-2 scaled-radii)) - (vu-pair (nop) (subz.xyz min-2 min-2 scaled-radii)) - (vu-pair (nop) (addw.xyz max-3 min-3 scaled-radii)) - (vu-pair (nop) (subw.xyz min-3 min-3 scaled-radii)) - (vu-pair (nop) (ftoi0.xyzw max-0 max-0)) - (vu-pair (nop) (ftoi0.xyzw min-0 min-0)) - (vu-pair (nop) (ftoi0.xyzw max-1 max-1)) - (vu-pair (nop) (ftoi0.xyzw min-1 min-1)) - (vu-pair (nop) (ftoi0.xyzw max-2 max-2)) - (vu-pair (nop) (ftoi0.xyzw min-2 min-2)) - (vu-pair (nop) (ftoi0.xyzw max-3 max-3 :e)) - (vu-pair (nop) (ftoi0.xyzw min-3 min-3))))) - -(#when PC_PORT - (def-mips2c collide-probe-node (function (inline-array draw-node) int collide-list int))) - -(#unless PC_PORT - (defun collide-probe-node ((nodes (inline-array draw-node)) (node-count int) (result collide-list)) - "Traverse node-count draw nodes against the active rotated line-sphere probe. Bounding spheres - are culled four at a time in VU0; overlapping child spans are visited through the scratchpad - stack, and surviving collision-fragment meshes are appended to result with no instance. - Callers must stay within the stack's 1024 entries and the result's 256 entries." - (rlet ((stack-top :reg a0) - (query-min :reg a1 :class i128) - (result :reg a2) - (query-max :reg a3 :class i128) - (stack-base :reg v1) - (result-count :reg t0) - (result-cursor :reg t1) - (span :reg t2) - (remaining :reg t3) - (kind :reg t4) - (probe-row-x :reg vf1) - (probe-row-y :reg vf2) - (probe-row-z :reg vf3) - (probe-translation :reg vf4) - (sphere-0 :reg vf5) - (sphere-1 :reg vf6) - (sphere-2 :reg vf7) - (sphere-3 :reg vf8) - (min-0 :reg vf9) - (max-0 :reg vf10) - (min-1 :reg vf11) - (max-1 :reg vf12) - (min-2 :reg vf13) - (max-2 :reg vf14) - (min-3 :reg vf15) - (max-3 :reg vf16)) - (asm-block save-state-and-seed-stack - (rlet ((work :reg t0) - (seed-kind :reg a1)) - (add.i sp sp -96) - (s.d ra sp) - (s.q s2 sp 16) - (s.q s3 sp 32) - (s.q s4 sp 48) - (s.q s5 sp 64) - (s.q gp sp 80) - (m! work *collide-work*) - (m! stack-base *collide-probe-stack*) - (s.w nodes stack-base PROBE-STACK-CHILD) - (add.i stack-top stack-base PROBE-STACK-STRIDE) - (s.h node-count stack-base PROBE-STACK-COUNT) - (add.i seed-kind r0 1) - (s.h seed-kind stack-base PROBE-STACK-KIND)) - (rlet ((work :reg t0)) - (l.q query-min work PROBE-QUERY-MIN) - (l.q query-max work PROBE-QUERY-MAX) - (l.vf probe-row-x work PROBE-QUERY-ROW-X) - (l.vf probe-row-y work PROBE-QUERY-ROW-Y) - (l.vf probe-row-z work PROBE-QUERY-ROW-Z) - (l.vf probe-translation work PROBE-QUERY-TRANSLATION)) - (l.w result-count result PROBE-RESULT-COUNT) - (sll result-cursor result-count 4) - (add result-cursor result-cursor result) - (add.i result-cursor result-cursor PROBE-RESULT-ITEMS)) - ;; Work entries are popped from the end. Their count word is split into a remaining halfword - ;; and a kind halfword even though the reflected structure exposes it as one uint32. - (asm-block pop-span - (label pop-span) - (b.eq stack-top stack-base done :delay (nop!)) - (add.i stack-top stack-top (- PROBE-STACK-STRIDE)) - (l.w span stack-top PROBE-STACK-CHILD) - (l.hu remaining stack-top PROBE-STACK-COUNT) - (l.hu kind stack-top PROBE-STACK-KIND)) - ;; Drawable arrays are padded, so this path can fetch all four spheres before remaining - ;; determines which results are consumed. - (asm-block cull-four-spheres - (label cull-four) - (l.vf sphere-0 span PROBE-DRAWABLE-BSPHERE) - (l.vf sphere-1 span (+ PROBE-DRAWABLE-BSPHERE PROBE-DRAW-NODE-STRIDE)) - (add.i t5 remaining -4) - (l.vf sphere-2 span (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-DRAW-NODE-STRIDE))) - (b.lt t5 r0 reduce-four :delay (l.vf sphere-3 span (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-DRAW-NODE-STRIDE)))) - (pref span (+ PROBE-DRAWABLE-BSPHERE (* 4 PROBE-DRAW-NODE-STRIDE)) :hint 0) - (label reduce-four) - (callms 0) - (nop!) - (m t5 min-0) - (m t6 max-0) - (m s2 min-1) - (m s3 max-1) - (m s4 min-2) - (m s5 max-2) - (m ra min-3) - (m t9 max-3) - ;; Each packed result is nonzero if candidate-min exceeds query-max or query-min exceeds - ;; candidate-max. Packing the high halfwords and shifting drops W, leaving the XYZ reject. - (pcgt.w t5 t5 query-max) - (l.w t8 span PROBE-CANDIDATE-PAYLOAD) - (pcgt.w t7 query-min t6) - (l.w t6 span (+ PROBE-CANDIDATE-PAYLOAD PROBE-DRAW-NODE-STRIDE)) - (or.q t5 t5 t7) - (l.w t7 span (+ PROBE-CANDIDATE-PAYLOAD (* 2 PROBE-DRAW-NODE-STRIDE))) - (ppach gp r0 t5) - (l.w t5 span (+ PROBE-CANDIDATE-PAYLOAD (* 3 PROBE-DRAW-NODE-STRIDE))) - (pcgt.w s2 s2 query-max) - (mmi-nop!) - (pcgt.w s3 query-min s3) - (mmi-nop!) - (or.q s3 s2 s3) - (mmi-nop!) - (ppach s3 r0 s3) - (mmi-nop!) - (pcgt.w s4 s4 query-max) - (mmi-nop!) - (pcgt.w s5 query-min s5) - (mmi-nop!) - (or.q s5 s4 s5) - (mmi-nop!) - (ppach s5 r0 s5) - (mmi-nop!) - (pcgt.w ra ra query-max) - (mmi-nop!) - (pcgt.w t9 query-min t9) - (mmi-nop!) - (or.q t9 ra t9) - (mmi-nop!) - (ppach t9 r0 t9) - (mmi-nop!) - (sll s4 gp 16) - (sll gp s3 16) - (sll ra s5 16) - (sll t9 t9 16)) - ;; A nonzero kind describes draw nodes. Push each overlapping child span back onto the LIFO. - (asm-block push-overlapping-children - (b.z kind append-fragment-leaves :delay (nop!)) - (b.nz s4 after-node-0 :delay (add.i remaining remaining -1)) - (nop!) - (l.bu s5 span PROBE-DRAWABLE-CHILD-COUNT) - (nop!) - (l.bu s4 span PROBE-DRAWABLE-FLAGS) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t8 stack-top -8) - (nop!) - (s.h s5 stack-top -4) - (nop!) - (s.h s4 stack-top -2) - (label after-node-0) - (b.z remaining finish-node-group :delay (nop!)) - (b.nz gp after-node-1 :delay (add.i remaining remaining -1)) - (nop!) - (l.bu t8 span (+ PROBE-DRAWABLE-CHILD-COUNT PROBE-DRAW-NODE-STRIDE)) - (nop!) - (l.bu gp span (+ PROBE-DRAWABLE-FLAGS PROBE-DRAW-NODE-STRIDE)) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t6 stack-top -8) - (nop!) - (s.h t8 stack-top -4) - (nop!) - (s.h gp stack-top -2) - (label after-node-1) - (b.z remaining finish-node-group :delay (nop!)) - (b.nz ra after-node-2 :delay (add.i remaining remaining -1)) - (nop!) - (l.bu t6 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 2 PROBE-DRAW-NODE-STRIDE))) - (nop!) - (l.bu t8 span (+ PROBE-DRAWABLE-FLAGS (* 2 PROBE-DRAW-NODE-STRIDE))) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t7 stack-top -8) - (nop!) - (s.h t6 stack-top -4) - (nop!) - (s.h t8 stack-top -2) - (label after-node-2) - (b.z remaining finish-node-group :delay (nop!)) - (b.nz t9 finish-node-group :delay (add.i remaining remaining -1)) - (nop!) - (l.bu t6 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 3 PROBE-DRAW-NODE-STRIDE))) - (nop!) - (l.bu t7 span (+ PROBE-DRAWABLE-FLAGS (* 3 PROBE-DRAW-NODE-STRIDE))) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t5 stack-top -8) - (nop!) - (s.h t6 stack-top -4) - (nop!) - (s.h t7 stack-top -2) - (label finish-node-group) - (b.gt remaining r0 cull-four :delay (add.i span span (* 4 PROBE-DRAW-NODE-STRIDE))) - (b pop-span :delay (nop!))) - ;; Kind zero means the span consists of collision-fragment leaves. The shared candidate - ;; payload is their mesh field; non-instanced results carry #f in the instance slot. - (asm-block append-fragment-leaves - (label append-fragment-leaves) - (b.nz s4 after-fragment-0 :delay (add.i remaining remaining -1)) - (add.i result-count result-count 1) - (s.w t8 result-cursor PROBE-RESULT-MESH) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) - (label after-fragment-0) - (b.z remaining finish-fragment-group :delay (nop!)) - (b.nz gp after-fragment-1 :delay (add.i remaining remaining -1)) - (add.i result-count result-count 1) - (s.w t6 result-cursor PROBE-RESULT-MESH) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) - (label after-fragment-1) - (b.z remaining finish-fragment-group :delay (nop!)) - (b.nz ra after-fragment-2 :delay (add.i remaining remaining -1)) - (add.i result-count result-count 1) - (s.w t7 result-cursor PROBE-RESULT-MESH) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) - (label after-fragment-2) - (b.z remaining finish-fragment-group :delay (nop!)) - (b.nz t9 finish-fragment-group :delay (add.i remaining remaining -1)) - (add.i result-count result-count 1) - (s.w t5 result-cursor PROBE-RESULT-MESH) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w s7 result-cursor (- PROBE-RESULT-INSTANCE PROBE-RESULT-ITEM-STRIDE)) - (label finish-fragment-group) - (b.gt remaining r0 cull-four :delay (add.i span span (* 4 PROBE-DRAW-NODE-STRIDE))) - (b pop-span :delay (nop!))) - (asm-block finish - (label done) - (nop!) - (s.w result-count result PROBE-RESULT-COUNT) - (m v0 r0) - (l.d ra sp) - (l.q gp sp 80) - (l.q s5 sp 64) - (l.q s4 sp 48) - (l.q s3 sp 32) - (l.q s2 sp 16) - (jr ra :delay (add.i sp sp 96)) - (nop! :count 3))))) +(define collide-vu0-block (new 'static 'vu-function :length 0 :qlength 0)) (defun print-out ((value int)) "Print value as a decimal integer to the debug console." @@ -565,531 +138,195 @@ 0 (none)) -(#when PC_PORT - (def-mips2c collide-probe-instance-tie (function object int collide-list int int))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Simple Probe Implementation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(#unless PC_PORT - (defun collide-probe-instance-tie ((drawables object) (drawable-count int) (result collide-list) (draw-node-span? int)) - "Traverse an instance-TIE tree against the active rotated line-sphere probe. Draw-node spans and - direct instance spans share an eight-byte scratchpad stack. Surviving instances contribute - their prototype collision fragments after the packed instance transform is composed with the - probe transform in VU0. draw-node-span? is one for draw nodes and zero for direct instances. - Callers must stay within the stack's 1024 entries and the result's 256 entries." - (rlet ((stack-top :reg a0) - (instance-batch-count :reg a1) - (result :reg a2) - (node-batch-count :reg a3) - (stack-base :reg v1) - (query-min :reg t0 :class i128) - (query-max :reg t1 :class i128) - (kind :reg t2) - (remaining :reg t3) - (span :reg t4) - (probe-row-x :reg vf1) - (probe-row-y :reg vf2) - (probe-row-z :reg vf3) - (probe-translation :reg vf4) - (sphere-0 :reg vf5) - (sphere-1 :reg vf6) - (sphere-2 :reg vf7) - (sphere-3 :reg vf8) - (min-0 :reg vf9) - (max-0 :reg vf10) - (min-1 :reg vf11) - (max-1 :reg vf12) - (min-2 :reg vf13) - (max-2 :reg vf14) - (min-3 :reg vf15) - (max-3 :reg vf16)) - ;; Seed the work stack with either the root draw-node span or the direct instance span. - (rlet ((work :reg t2)) - (asm-block save-state-and-seed-stack - (label entry) - (add.i sp sp -80) - (s.d ra sp) - (s.q s3 sp 16) - (s.q s4 sp 32) - (s.q s5 sp 48) - (s.q gp sp 64) - (m! work *collide-work*) - (m! stack-base *collide-probe-stack*) - (s.w drawables stack-base PROBE-STACK-CHILD) - (add.i stack-top stack-base PROBE-STACK-STRIDE) - (s.h drawable-count stack-base PROBE-STACK-COUNT) - (s.h draw-node-span? stack-base PROBE-STACK-KIND) - (add.i instance-batch-count r0 0) - (add.i node-batch-count r0 0) - (l.q query-min work PROBE-QUERY-MIN) - (l.q query-max work PROBE-QUERY-MAX) - (l.vf probe-row-x work PROBE-QUERY-ROW-X) - (l.vf probe-row-y work PROBE-QUERY-ROW-Y) - (l.vf probe-row-z work PROBE-QUERY-ROW-Z) - (l.vf probe-translation work PROBE-QUERY-TRANSLATION))) - ;; Negative work kinds are individual instances. Zero denotes a direct instance span, and a - ;; positive kind denotes a draw-node span. - (asm-block pop-work - (label pop-work) - (b.eq stack-top stack-base done :delay (nop!)) - (add.i stack-top stack-top (- PROBE-STACK-STRIDE)) - (l.w span stack-top PROBE-STACK-CHILD) - (l.h kind stack-top PROBE-STACK-KIND) - (l.hu remaining stack-top PROBE-STACK-COUNT) - (b.lt kind r0 process-instance :delay (nop!))) - ;; Both span kinds expose a bounding sphere at the same offset. Draw nodes are 32 bytes while - ;; instances are 64, so the paths use different strides. Their separate batch counters are - ;; retained here but are not consumed below. - (asm-block load-broadphase-four - (label load-broadphase-four) - (b.z kind load-instance-four :delay (nop!)) - (l.vf sphere-0 span PROBE-DRAWABLE-BSPHERE) - (add.i node-batch-count node-batch-count 1) - (l.vf sphere-1 span (+ PROBE-DRAWABLE-BSPHERE PROBE-DRAW-NODE-STRIDE)) - (add.i t5 remaining -4) - (l.vf sphere-2 span (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-DRAW-NODE-STRIDE))) - (b.lt t5 r0 node-prefetched :delay (l.vf sphere-3 span (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-DRAW-NODE-STRIDE)))) - (pref span (+ PROBE-DRAWABLE-BSPHERE (* 4 PROBE-DRAW-NODE-STRIDE)) :hint 0) - (label node-prefetched) - (b reduce-broadphase-four :delay (nop!)) - (label load-instance-four) - (l.vf sphere-0 span PROBE-INSTANCE-BSPHERE) - (add.i instance-batch-count instance-batch-count 1) - (l.vf sphere-1 span (+ PROBE-INSTANCE-BSPHERE PROBE-INSTANCE-STRIDE)) - (add.i t5 remaining -4) - (l.vf sphere-2 span (+ PROBE-INSTANCE-BSPHERE (* 2 PROBE-INSTANCE-STRIDE))) - (b.lt t5 r0 reduce-broadphase-four :delay (l.vf sphere-3 span (+ PROBE-INSTANCE-BSPHERE (* 3 PROBE-INSTANCE-STRIDE)))) - (pref span (+ PROBE-INSTANCE-BSPHERE (* 4 PROBE-INSTANCE-STRIDE)) :hint 0) - (pref span (+ PROBE-INSTANCE-BSPHERE (* 6 PROBE-INSTANCE-STRIDE)) :hint 0)) - ;; VU0 transforms four spheres to query-box space. The EE combines the two separating-axis - ;; comparisons, packs their XYZ results, and leaves one reject bit in each scalar. - (asm-block reduce-broadphase-four - (label reduce-broadphase-four) - (callms 0) - (m s5 min-0) - (m t7 max-0) - (m gp min-1) - (m ra max-1) - (m t9 min-2) - (m t8 max-2) - (m t6 min-3) - (m t5 max-3) - (nop!) - (pcgt.w s5 s5 query-max) - (mmi-nop!) - (pcgt.w t7 query-min t7) - (mmi-nop!) - (or.q t7 s5 t7) - (mmi-nop!) - (ppach t7 r0 t7) - (mmi-nop!) - (pcgt.w gp gp query-max) - (mmi-nop!) - (pcgt.w ra query-min ra) - (mmi-nop!) - (or.q ra gp ra) - (mmi-nop!) - (ppach ra r0 ra) - (mmi-nop!) - (pcgt.w t9 t9 query-max) - (mmi-nop!) - (pcgt.w t8 query-min t8) - (mmi-nop!) - (or.q t8 t9 t8) - (mmi-nop!) - (ppach t8 r0 t8) - (mmi-nop!) - (pcgt.w t6 t6 query-max) - (mmi-nop!) - (pcgt.w t5 query-min t5) - (mmi-nop!) - (or.q t5 t6 t5) - (mmi-nop!) - (ppach t5 r0 t5) - (mmi-nop!) - (sll t9 t7 16) - (sll t7 ra 16) - (sll t6 t8 16) - (sll t5 t5 16)) - ;; For a draw-node span, push each overlapping child span. The flags byte becomes the next - ;; work kind, so children-are-draw-nodes naturally selects the next interpretation. - (asm-block queue-node-children - (b.z kind queue-instance-hits :delay (nop!)) - (b.nz t9 after-node-0 :delay (add.i remaining remaining -1)) - (nop!) - (l.w t8 span PROBE-DRAWABLE-CHILD) - (nop!) - (l.bu t9 span PROBE-DRAWABLE-CHILD-COUNT) - (nop!) - (l.bu ra span PROBE-DRAWABLE-FLAGS) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t8 stack-top (- PROBE-STACK-STRIDE)) - (nop!) - (s.h t9 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h ra stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label after-node-0) - (b.z remaining finish-node-group :delay (nop!)) - (b.nz t7 after-node-1 :delay (add.i remaining remaining -1)) - (nop!) - (l.w t7 span (+ PROBE-DRAWABLE-CHILD PROBE-DRAW-NODE-STRIDE)) - (nop!) - (l.bu t8 span (+ PROBE-DRAWABLE-CHILD-COUNT PROBE-DRAW-NODE-STRIDE)) - (nop!) - (l.bu t9 span (+ PROBE-DRAWABLE-FLAGS PROBE-DRAW-NODE-STRIDE)) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t7 stack-top (- PROBE-STACK-STRIDE)) - (nop!) - (s.h t8 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h t9 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label after-node-1) - (b.z remaining finish-node-group :delay (nop!)) - (b.nz t6 after-node-2 :delay (add.i remaining remaining -1)) - (nop!) - (l.w t6 span (+ PROBE-DRAWABLE-CHILD (* 2 PROBE-DRAW-NODE-STRIDE))) - (nop!) - (l.bu t7 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 2 PROBE-DRAW-NODE-STRIDE))) - (nop!) - (l.bu t8 span (+ PROBE-DRAWABLE-FLAGS (* 2 PROBE-DRAW-NODE-STRIDE))) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t6 stack-top (- PROBE-STACK-STRIDE)) - (nop!) - (s.h t7 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h t8 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label after-node-2) - (b.z remaining finish-node-group :delay (nop!)) - (b.nz t5 finish-node-group :delay (add.i remaining remaining -1)) - (nop!) - (l.w t5 span (+ PROBE-DRAWABLE-CHILD (* 3 PROBE-DRAW-NODE-STRIDE))) - (nop!) - (l.bu t6 span (+ PROBE-DRAWABLE-CHILD-COUNT (* 3 PROBE-DRAW-NODE-STRIDE))) - (nop!) - (l.bu t7 span (+ PROBE-DRAWABLE-FLAGS (* 3 PROBE-DRAW-NODE-STRIDE))) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w t5 stack-top (- PROBE-STACK-STRIDE)) - (nop!) - (s.h t6 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h t7 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label finish-node-group) - (b.gt remaining r0 load-broadphase-four :delay (add.i span span (* 4 PROBE-DRAW-NODE-STRIDE))) - (b pop-work :delay (nop!))) - ;; A direct span cannot be processed until its prototype data is known. Queue each surviving - ;; instance as a negative-kind single item, preserving the same LIFO traversal order. - (asm-block queue-instance-hits - (label queue-instance-hits) - (b.nz t9 after-instance-0 :delay (add.i remaining remaining -1)) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w span stack-top (- PROBE-STACK-STRIDE)) - (add.i t8 r0 -1) - (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h t8 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label after-instance-0) - (b.z remaining finish-instance-group :delay (add.i span span PROBE-INSTANCE-STRIDE)) - (b.nz t7 after-instance-1 :delay (add.i remaining remaining -1)) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w span stack-top (- PROBE-STACK-STRIDE)) - (add.i t7 r0 -1) - (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h t7 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label after-instance-1) - (b.z remaining finish-instance-group :delay (add.i span span PROBE-INSTANCE-STRIDE)) - (b.nz t6 after-instance-2 :delay (add.i remaining remaining -1)) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w span stack-top (- PROBE-STACK-STRIDE)) - (add.i t6 r0 -1) - (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h t6 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label after-instance-2) - (b.z remaining finish-instance-group :delay (add.i span span PROBE-INSTANCE-STRIDE)) - (b.nz t5 finish-instance-group :delay (add.i remaining remaining -1)) - (add.i stack-top stack-top PROBE-STACK-STRIDE) - (s.w span stack-top (- PROBE-STACK-STRIDE)) - (add.i t5 r0 -1) - (s.h r0 stack-top (- PROBE-STACK-COUNT PROBE-STACK-STRIDE)) - (nop!) - (s.h t5 stack-top (- PROBE-STACK-KIND PROBE-STACK-STRIDE)) - (label finish-instance-group) - (b.gt remaining r0 load-broadphase-four :delay (add.i span span PROBE-INSTANCE-STRIDE)) - (b pop-work :delay (nop!))) - (rlet ((instance :reg t2) - (instance-row-x :reg vf17) - (instance-row-y :reg vf18) - (instance-row-z :reg vf19) - (instance-translation :reg vf20) - (instance-max-scale :reg vf21) - (scaled-radii :reg vf22) - (instance-origin :reg vf23)) - ;; TIE stores its affine transform as signed halfwords. Translation is split across the two - ;; matrix halves and encoded in 64-unit steps; basis rows use signed Q12 fixed point and - ;; max-scale is unsigned Q12. VU entry 32 converts and composes this with the probe inverse. - (asm-block decode-instance-transform - (label process-instance) - (rlet ((queued-instance :reg t4)) - (m instance queued-instance) - (rlet ((instance-flags :reg t4) - (bucket :reg t3) - (fragment-array :reg t6)) - (l.hu instance-flags queued-instance PROBE-INSTANCE-FLAGS) - (nop!) - (l.w bucket instance PROBE-INSTANCE-BUCKET) - ;; The branch tests flags before its delay load replaces the same register. - (b.nz instance-flags finish-instance :delay (l.hu t4 instance PROBE-INSTANCE-MAX-SCALE)) - (nop!) - (l.w fragment-array bucket PROBE-BUCKET-COLLIDE-FRAG) - (nop!))) - (rlet ((max-scale-bits :reg t4 :class i128) - (origin-high-bits :reg t3 :class i128) - (origin-low-bits :reg t5 :class i128) - (fragment-array :reg t6)) - (l.q origin-high-bits instance PROBE-INSTANCE-ORIGIN-HIGH) - (b.z fragment-array finish-instance :delay (l.q origin-low-bits instance PROBE-INSTANCE-ORIGIN-LOW)) - (pextlw max-scale-bits max-scale-bits max-scale-bits) - (mmi-nop!) - (pcpyld max-scale-bits max-scale-bits max-scale-bits) - (mmi-nop!) - (pcpyud t8 origin-high-bits r0) - (mmi-nop!) - (pcpyud t7 origin-low-bits r0) - (mmi-nop!) - (pextlh t8 t8 r0) - (mmi-nop!) - (sra.w t8 t8 10) - (mmi-nop!) - (pextlh t9 origin-low-bits r0)) - (rlet ((max-scale-bits :reg t4 :class i128) - (origin-high-bits :reg t3 :class i128) - (fragment-count :reg t5) - (fragment-array :reg t6)) - (l.hu fragment-count fragment-array PROBE-FRAGMENT-ARRAY-LENGTH) - (sra.w t9 t9 16) - (mmi-nop!) - (pextlh t7 t7 r0) - (m instance-translation t8) - (sra.w t7 t7 16) - (m instance-row-x t9) - (pextlh origin-high-bits origin-high-bits r0) - (m instance-row-y t7) - (sra.w origin-high-bits origin-high-bits 16) - (l.vf instance-origin instance PROBE-INSTANCE-BSPHERE) - (m instance-row-z origin-high-bits) - (rlet ((result-count :reg t3)) (l.w result-count result PROBE-RESULT-COUNT)) - (m instance-max-scale max-scale-bits) - (add.i t7 fragment-count -4) - (callms 32))) - (rlet ((result-count :reg t3) - (result-cursor :reg t4) - (fragment-count :reg t5) - (fragment-cursor :reg t6)) - (asm-block prepare-fragment-cursor - (sll result-cursor result-count 4) - (add result-cursor result-cursor result) - (add fragment-count fragment-count r0) - (add.i result-cursor result-cursor PROBE-RESULT-ITEMS) - (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-ARRAY-DATA) - (b.lt t7 r0 cull-fragment-tail :delay (l.q t7 fragment-cursor PROBE-DRAWABLE-BSPHERE)) - (nop!) - (l.q t8 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE PROBE-FRAGMENT-STRIDE)) - (nop!) - (l.q t9 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-FRAGMENT-STRIDE))) - (nop!) - (l.q ra fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-FRAGMENT-STRIDE))) - (nop!) - (m.ni sphere-0 t7) - (nop!) - (m.ni sphere-1 t8) - (nop!) - (m.ni sphere-2 t9) - (nop!) - (m.ni sphere-3 ra)) - ;; Entry 54 transforms four prototype spheres by the composed instance transform and scales - ;; their radii conservatively. The EE then performs the same packed XYZ rejection as above. - (asm-block cull-four-fragments - (label cull-four-fragments) - ;; Entry 54 raises E before its final drain instruction; wait for completion - ;; before transferring the eight integer bounds back to the EE. - (callms 54) - (nop! :count 3) - (vnop) - (nop!) - (m s3 max-0) - (nop!) - (m t9 min-0) - (nop!) - (m s4 max-1) - (nop!) - (m s5 min-1) - (nop!) - (m gp max-2) - (nop!) - (m ra min-2) - (nop!) - (m t8 max-3) - (nop!) - (m t7 min-3) - (nop!) - (pcgt.w s3 query-min s3) - (mmi-nop!) - (pcgt.w t9 t9 query-max) - (mmi-nop!) - (or.q t9 t9 s3) - (mmi-nop!) - (ppach t9 r0 t9) - (mmi-nop!) - (pcgt.w s4 query-min s4) - (mmi-nop!) - (pcgt.w s5 s5 query-max) - (mmi-nop!) - (or.q s5 s5 s4) - (mmi-nop!) - (ppach s5 r0 s5) - (mmi-nop!) - (pcgt.w gp query-min gp) - (mmi-nop!) - (pcgt.w ra ra query-max) - (mmi-nop!) - (or.q ra ra gp) - (mmi-nop!) - (ppach ra r0 ra) - (mmi-nop!) - (pcgt.w t8 query-min t8) - (mmi-nop!) - (pcgt.w t7 t7 query-max) - (mmi-nop!) - (or.q t7 t7 t8) - (mmi-nop!) - (ppach t7 r0 t7) - (mmi-nop!) - (sll gp t9 16) - (sll t9 s5 16) - (sll t8 ra 16) - (sll t7 t7 16)) - ;; Append the mesh pointer and originating instance for each surviving fragment. The result - ;; cursor follows the list's physical sixteen-byte inline spacing. - (asm-block append-four-fragments - (b.nz gp after-fragment-0 :delay (nop!)) - (nop!) - (l.w ra fragment-cursor PROBE-FRAGMENT-MESH) - (add.i result-count result-count 1) - (s.w instance result-cursor PROBE-RESULT-INSTANCE) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w ra result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) - (label after-fragment-0) - (add.i fragment-count fragment-count -1) - (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) - (b.z fragment-count finish-fragment-group :delay (nop!)) - (b.nz t9 after-fragment-1 :delay (nop!)) - (nop!) - (l.w t9 fragment-cursor PROBE-FRAGMENT-MESH) - (add.i result-count result-count 1) - (s.w instance result-cursor PROBE-RESULT-INSTANCE) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w t9 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) - (label after-fragment-1) - (add.i fragment-count fragment-count -1) - (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) - (b.z fragment-count finish-fragment-group :delay (nop!)) - (b.nz t8 after-fragment-2 :delay (nop!)) - (nop!) - (l.w t8 fragment-cursor PROBE-FRAGMENT-MESH) - (add.i result-count result-count 1) - (s.w instance result-cursor PROBE-RESULT-INSTANCE) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w t8 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) - (label after-fragment-2) - (add.i fragment-count fragment-count -1) - (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) - (b.z fragment-count finish-fragment-group :delay (nop!)) - (b.nz t7 after-fragment-3 :delay (nop!)) - (nop!) - (l.w t7 fragment-cursor PROBE-FRAGMENT-MESH) - (add.i result-count result-count 1) - (s.w instance result-cursor PROBE-RESULT-INSTANCE) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w t7 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) - (label after-fragment-3) - (add.i fragment-count fragment-count -1) - (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) - (b.z fragment-count finish-fragment-group :delay (l.vf sphere-0 fragment-cursor PROBE-DRAWABLE-BSPHERE)) - (nop!) - (l.vf sphere-1 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE PROBE-FRAGMENT-STRIDE)) - (nop!) - (l.vf sphere-2 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 2 PROBE-FRAGMENT-STRIDE))) - (b cull-four-fragments :delay (l.vf sphere-3 fragment-cursor (+ PROBE-DRAWABLE-BSPHERE (* 3 PROBE-FRAGMENT-STRIDE))))) - (asm-block finish-fragment-group - (label finish-fragment-group) - (nop!) - (s.w result-count result PROBE-RESULT-COUNT) - (b pop-work :delay (nop!))) - ;; Fewer than four remaining fragments use the same composed transform inline. The sphere's - ;; center is transformed, its radius is multiplied by max-scale, and its integer bounds are - ;; rejected before the mesh is appended. - (asm-block cull-fragment-tail - (label cull-fragment-tail) - (rlet ((tail-center :reg vf24) - (tail-max :reg vf25)) - (m sphere-0 t7) - (nop!) - (mula.w.vf instance-translation vf0) - (nop!) - (madda.x.vf instance-row-x sphere-0) - (nop!) - (madda.y.vf instance-row-y sphere-0) - (nop!) - (madd.z.vf tail-center instance-row-z sphere-0) - (nop!) - (mul.w.vf.x scaled-radii instance-max-scale sphere-0) - (nop!) - (add.x.vf.xyz tail-max tail-center scaled-radii) - (nop!) - (rlet ((tail-min :reg vf24)) - (sub.x.vf.xyz tail-min tail-center scaled-radii) - (nop!) - (ftoi.vf tail-max tail-max) - (nop!) - (ftoi.vf tail-min tail-min) - (nop!) - (m t8 tail-max) - (nop!) - (m t7 tail-min) - (nop!) - (pcgt.w t8 query-min t8) - (mmi-nop!) - (pcgt.w t7 t7 query-max) - (mmi-nop!) - (or.q t7 t7 t8) - (mmi-nop!) - (ppach t7 r0 t7) - (mmi-nop!) - (sll t7 t7 16) - (nop!) - (b.nz t7 after-tail-fragment :delay (nop!)) - (nop!) - (l.w t7 fragment-cursor PROBE-FRAGMENT-MESH) - (add.i result-count result-count 1) - (s.w instance result-cursor PROBE-RESULT-INSTANCE) - (add.i result-cursor result-cursor PROBE-RESULT-ITEM-STRIDE) - (s.w t7 result-cursor (- PROBE-RESULT-MESH PROBE-RESULT-ITEM-STRIDE)) - (label after-tail-fragment) - (add.i fragment-count fragment-count -1) - (add.i fragment-cursor fragment-cursor PROBE-FRAGMENT-STRIDE) - (b.gt fragment-count r0 cull-fragment-tail :delay (l.q t7 fragment-cursor PROBE-DRAWABLE-BSPHERE)) - (nop!) - (s.w result-count result PROBE-RESULT-COUNT)))) - (asm-block finish-instance (label finish-instance) (b pop-work :delay (nop!))))) - (asm-block restore-state - (label done) - (m v0 r0) - (l.d ra sp) - (l.q gp sp 64) - (l.q s5 sp 48) - (l.q s4 sp 32) - (l.q s3 sp 16) - (jr ra :delay (add.i sp sp 80)) - (nop! :count 2))))) +(defun collide-probe-append! ((result collide-list) (mesh collide-frag-mesh) (inst basic)) + "Add an fragment to the resulting collide-list." + (declare (inline)) + ;; crash rather than overwriting past the end of the list. + ;; this can happen if you submit a massive collide query + (when (>= (-> result num-items) 255) + (format 0 "collide-probe list out of room") + (crash!)) + (let ((item (-> result items (-> result num-items)))) + (set! (-> item mesh) mesh) + (set! (-> item inst) inst)) + (+! (-> result num-items) 1) + (none)) + +(defun collide-probe-sphere-intersect? ((candidate-sphere vector) (transform matrix) (radius-scale float)) + "Check if the given sphere, transformed by transform, intersects *collide-work*.collide-box4w (capsule bounding box), + with the given scale applied to the sphere's radius." + (declare (print-asm)) + (rlet ((acc :class vf) + (sphere :class vf) + (row-0 :class vf) + (row-1 :class vf) + (row-2 :class vf) + (translation :class vf) + (center :class vf) + (radius :class vf) + (radius-scale-vf :class vf) + (low-corner :class vf) + (high-corner :class vf) + (low-corner-int :class vf) + (high-corner-int :class vf) + (above-box :class i128) + (below-box :class i128) + (separated :class i128) + (separated-packed :class i128)) + (.lvf sphere (&-> candidate-sphere quad)) + (.lvf row-0 (&-> transform vector 0 quad)) + (.lvf row-1 (&-> transform vector 1 quad)) + (.lvf row-2 (&-> transform vector 2 quad)) + (.lvf translation (&-> transform vector 3 quad)) + (.mov radius-scale-vf radius-scale) ;; sets upper 64-bits to 0 + ;; radius.x stores the scaled radius + (.mul.w.vf radius radius-scale-vf sphere) + ;; transform the sphere's origin + (.mul.x.vf acc row-0 sphere) + (.add.mul.y.vf acc row-1 sphere acc) + (.add.mul.z.vf acc row-2 sphere acc) + (.add.vf center acc translation) + ;; Set center.w = 0 + (.mov.vf.w center radius-scale-vf) + ;; get the two extreme corners of the sphere's bounding box + (.sub.x.vf low-corner center radius) + (.add.x.vf high-corner center radius) + ;; convert to integers + (.ftoi.vf low-corner-int low-corner) + (.ftoi.vf high-corner-int high-corner) + ;; Compare against the capsule box, setting a lane when the candidate is separated on that axis. + (let ((work *collide-work*)) + (.pcgtw below-box (-> work collide-box4w min quad) high-corner-int) + (.pcgtw above-box low-corner-int (-> work collide-box4w max quad))) + (.por separated above-box below-box) + ;; Pack and shift away w + (.ppach separated-packed (the-as uint128 0) separated) + (let ((xyz-separated (shl (the-as int separated-packed) 16))) + (zero? xyz-separated)))) + + +(defun collide-probe-instance-transform! ((transform matrix) (inst instance-tie)) + "Expand instanced collision mesh packed transform." + (rlet ((vf0 :class vf) + (scale :class vf) + (row :class vf) + (sphere :class vf) + (lanes :class i128) + (words :class i128) + (zero :class i128)) + (init-vf0-vector) + (.mov zero 0) + (.lvf scale (&-> (new 'static 'vector :x 0.000244140625 :y 0.000244140625 :z 0.000244140625) quad)) + + + ;; Unpack and sign-extend packed s16's to s32's + (.pextlh lanes (-> inst origin vector4h 0 long) zero) + (.pw.sra words lanes 16) + ;; convert to float and apply scale + (.mov row words) + (.itof.vf row row) + (.mul.vf row row scale) + (.svf (&-> transform vector 0 quad) row) + + (.pextlh lanes (-> inst origin vector4h 1 long) zero) + (.pw.sra words lanes 16) + (.mov row words) + (.itof.vf row row) + (.mul.vf row row scale) + (.svf (&-> transform vector 1 quad) row) + + (.pextlh lanes (-> inst origin vector4h 2 long) zero) + (.pw.sra words lanes 16) + (.mov row words) + (.itof.vf row row) + (.mul.vf row row scale) + (.svf (&-> transform vector 2 quad) row) + + (.pextlh lanes (-> inst origin vector4h 3 long) zero) + ;; Its packed translation is measured in 64-unit (2^6), shift by 16 - 6 = 10 places + (.pw.sra words lanes 10) + (.mov row words) + (.itof.vf row row) + (.lvf sphere (&-> inst bsphere quad)) + (.add.vf row row sphere) + (.mov.vf.w row vf0) + (.svf (&-> transform vector 3 quad) row) + transform)) + +(defun collide-probe-instance-tie-instances ((instances (inline-array instance-tie)) (instance-count int) (result collide-list)) + "Visit a direct TIE instance span in the original traversal's reverse sibling order." + (let ((instance-index (+ instance-count -1))) + (while (>= instance-index 0) + (let ((inst (-> instances instance-index))) + ;; check this instance bsphere + (when (and (zero? (-> inst flags)) + (collide-probe-sphere-intersect? (-> inst bsphere) (-> *collide-work* inv-mat) 1.0)) + ;; check if this instance has fragments + (let ((fragments (-> inst bucket-ptr collide-frag))) + (when (nonzero? fragments) + (let ((instance-transform (new 'stack-no-clear 'matrix)) + (probe-transform (new 'stack-no-clear 'matrix))) + ;; get the instance-specific transformation + (collide-probe-instance-transform! instance-transform inst) + (matrix*! probe-transform instance-transform (-> *collide-work* inv-mat)) + ;; check each fragment + (dotimes (fragment-index (-> fragments length)) + (let ((fragment (-> fragments data fragment-index))) + (when (collide-probe-sphere-intersect? (-> fragment bsphere) + probe-transform + (* 0.000244140625 (the float (-> inst max-scale)))) + (collide-probe-append! result (-> fragment mesh) inst)))))))) + (+! instance-index -1))) + (none))) + +(defun-recursive collide-probe-instance-tie-nodes none ((nodes (inline-array draw-node)) (node-count int) (result collide-list)) + "Traverse a TIE draw-node span in reverse sibling order, then visit its direct instance leaves." + (let ((node-index (+ node-count -1))) + (while (>= node-index 0) + (let ((node (-> nodes node-index))) + (when (collide-probe-sphere-intersect? (-> node bsphere) (-> *collide-work* inv-mat) 1.0) + (cond + ((logtest? (-> node flags) (draw-node-flags children-are-draw-nodes)) + (collide-probe-instance-tie-nodes (the-as (inline-array draw-node) (-> node child)) + (the-as int (-> node child-count)) + result)) + (else + (collide-probe-instance-tie-instances (the-as (inline-array instance-tie) (-> node child)) + (the-as int (-> node child-count)) + result))))) + (+! node-index -1))) + (none)) + +(defun collide-probe-instance-tie ((drawables object) (drawable-count int) (result collide-list) (draw-node-span? int)) + "Traverse either a draw-node span or a direct TIE instance span." + (cond + ((nonzero? draw-node-span?) + (collide-probe-instance-tie-nodes (the-as (inline-array draw-node) drawables) drawable-count result)) + (else + (collide-probe-instance-tie-instances (the-as (inline-array instance-tie) drawables) drawable-count result))) + 0) + +(defun-recursive collide-probe-node none ((nodes (inline-array draw-node)) (node-count int) (result collide-list)) + "Traverse a collide-fragment BVH with the original LIFO sibling ordering." + (let ((node-index (+ node-count -1))) + (while (>= node-index 0) + (let ((node (-> nodes node-index))) + (when (collide-probe-sphere-intersect? (-> node bsphere) (-> *collide-work* inv-mat) 1.0) + (cond + ((logtest? (-> node flags) (draw-node-flags children-are-draw-nodes)) + (collide-probe-node (the-as (inline-array draw-node) (-> node child)) (the-as int (-> node child-count)) result)) + (else + (let ((fragments (the-as (inline-array collide-fragment) (-> node child)))) + (dotimes (fragment-index (-> node child-count)) + (let ((fragment (-> fragments fragment-index))) + (when (collide-probe-sphere-intersect? (-> fragment bsphere) (-> *collide-work* inv-mat) 1.0) + (collide-probe-append! result (-> fragment mesh) #f)))))))) + (+! node-index -1))) + (none))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Collide Probe Setup/Wrappers @@ -1151,49 +388,42 @@ 0 (none)) -;; main collide probe function: - (defun collide-probe-make-list ((level-to-probe level) (result collide-list)) "Upload the collision VU program, traverse every TIE and collide-fragment tree in level-to-probe, and append broad-phase matches to result without clearing its existing entries." - (let ((level-bsp (-> level-to-probe bsp))) - 0 - ;; load vu0 program + (let ((initial-item-count 0)) + (#when COLLIDE_FUNC_COUNTERS + (set! initial-item-count (-> result num-items)) + (+! *collide-probe-make-list-count* 1) + (stopwatch-begin *collide-probe-make-list-timer*)) (collide-upload-vu0) - ;; iterate over trees - (let ((drawable-trees (-> level-bsp drawable-trees))) - (dotimes (i (-> drawable-trees length)) - (let ((tree (-> drawable-trees trees i))) + (let ((drawable-trees (-> level-to-probe bsp drawable-trees))) + (dotimes (tree-index (-> drawable-trees length)) + (let ((tree (-> drawable-trees trees tree-index))) (cond ((= (-> tree type) drawable-tree-instance-tie) - ;; collide with tie instances - (let ((result result)) - (cond - ((< 1 (-> tree length)) - (let ((root-node-array (-> tree data 0))) - (collide-probe-instance-tie (-> (the-as drawable-inline-array-node root-node-array) data) - (-> (the-as drawable-inline-array-node root-node-array) length) - result - 1))) - ((= (-> tree length) 1) - (let ((instance-array (-> tree data 0))) - (collide-probe-instance-tie (-> (the-as drawable-inline-array-instance-tie instance-array) data) - (-> (the-as drawable-inline-array-instance-tie instance-array) length) - result - 0))))) - 0) + (cond + ((< 1 (-> tree length)) + (let ((root-node-array (-> tree data 0))) + (collide-probe-instance-tie (-> (the-as drawable-inline-array-node root-node-array) data) + (-> (the-as drawable-inline-array-node root-node-array) length) + result + 1))) + ((= (-> tree length) 1) + (let ((instance-array (-> tree data 0))) + (collide-probe-instance-tie (-> (the-as drawable-inline-array-instance-tie instance-array) data) + (-> (the-as drawable-inline-array-instance-tie instance-array) length) + result + 0))))) ((= (-> tree type) drawable-tree-collide-fragment) - ;; collide with tfrags - (let ((result result)) - (cond - ((< 1 (-> tree length)) - (let ((root-node-array (-> tree data 0))) - (collide-probe-node (-> (the-as drawable-inline-array-node root-node-array) data) - (-> (the-as drawable-inline-array-node root-node-array) length) - result))) - (else))) - 0) - (else)))))) + (when (< 1 (-> tree length)) + (let ((root-node-array (-> tree data 0))) + (collide-probe-node (-> (the-as drawable-inline-array-node root-node-array) data) + (-> (the-as drawable-inline-array-node root-node-array) length) + result)))))))) + (#when COLLIDE_FUNC_COUNTERS + (stopwatch-end *collide-probe-make-list-timer*) + (+! *collide-probe-make-list-item-count* (- (-> result num-items) initial-item-count)))) (none)) ;;;;;;;;;;;;;;;;;;; @@ -1223,9 +453,12 @@ (radius (distc position arena-center))) (cond ((< radius 52019.2) 111656.96) - ((>= 58982.4 radius) (interpolate radius 52019.2 111656.96 58982.4 116776.96)) - ((>= 124436.48 radius) (interpolate radius 58982.4 116776.96 124436.48 114688.0)) - ((>= 219217.92 radius) (interpolate radius 124436.48 114688.0 219217.92 113254.4)) + ((>= 58982.4 radius) + (interpolate radius 52019.2 111656.96 58982.4 116776.96)) + ((>= 124436.48 radius) + (interpolate radius 58982.4 116776.96 124436.48 114688.0)) + ((>= 219217.92 radius) + (interpolate radius 124436.48 114688.0 219217.92 113254.4)) (else 113254.4)))) (defun misty-ambush-height-probe ((position vector) (probe-length float)) @@ -1233,7 +466,8 @@ height. The fraction can exceed one; return -1 only when position is not above the ground." (let ((ground-height (misty-ambush-height position))) (cond - ((< ground-height (-> position y)) (/ (- (-> position y) ground-height) probe-length)) + ((< ground-height (-> position y)) + (/ (- (-> position y) ground-height) probe-length)) (else (format 0 "WARNING: ~%height = ~f, pos.y = ~f" (/ ground-height METER_LENGTH) (/ (-> position y) METER_LENGTH)) -1.0)))) diff --git a/goal_src/jak1/engine/gfx/mood/mood-tables.gc b/goal_src/jak1/engine/gfx/mood/mood-tables.gc index f6850f92e4..10aa28ccb8 100644 --- a/goal_src/jak1/engine/gfx/mood/mood-tables.gc +++ b/goal_src/jak1/engine/gfx/mood/mood-tables.gc @@ -12,31 +12,22 @@ (defun make-light-kit ((group light-group) (heading float) (dir0-level float) (dir1-level float) (dir2-level float)) "Build a three-directional-light kit. dir0 and dir1 are opposing warm diagonal lights rotated - around Y by heading in 65,536-units-per-turn rotation units; dir2 points straight down. The + around Y by heading in rotation units; dir2 points straight down. The three level arguments set their respective light strengths." (let ((rotation (new 'stack-no-clear 'matrix))) (matrix-rotate-y! rotation heading) (let ((dir0 (-> group dir0))) - (set! (-> dir0 direction x) -0.612) - (set! (-> dir0 direction y) 0.5) - (set! (-> dir0 direction z) 0.612) - (set! (-> dir0 direction w) 0.0)) + (set-vector! (-> dir0 direction) -0.612 0.5 0.612 0.0)) (set-vector! (-> group dir0 color) 0.8 0.775 0.7 1.0) (set! (-> group dir0 levels x) dir0-level) (let ((dir1 (-> group dir1))) - (set! (-> dir1 direction x) 0.612) - (set! (-> dir1 direction y) 0.5) - (set! (-> dir1 direction z) -0.612) - (set! (-> dir1 direction w) 0.0)) + (set-vector! (-> dir1 direction) 0.612 0.5 -0.612 0.0)) (set-vector! (-> group dir1 color) 0.8 0.775 0.7 1.0) (set! (-> group dir1 levels x) dir1-level) (vector-matrix*! (-> group dir0 direction) (-> group dir0 direction) rotation) (vector-matrix*! (-> group dir1 direction) (-> group dir1 direction) rotation)) (let ((dir2 (-> group dir2))) - (set! (-> dir2 direction x) 0.0) - (set! (-> dir2 direction y) -1.0) - (set! (-> dir2 direction z) 0.0) - (set! (-> dir2 direction w) 0.0)) + (set-vector! (-> dir2 direction) 0.0 -1.0 0.0 0.0)) (set-vector! (-> group dir2 color) 0.8 0.775 0.7 1.0) (set! (-> group dir2 levels x) dir2-level) (none)) @@ -47,10 +38,7 @@ (let ((group (-> context light-group 2))) (make-light-kit group 2730.6667 1.0 1.0 0.8) (let ((dir2 (-> group dir2))) - (set! (-> dir2 direction x) 0.0) - (set! (-> dir2 direction y) -1.0) - (set! (-> dir2 direction z) 0.0) - (set! (-> dir2 direction w) 0.0)) + (set-vector! (-> dir2 direction) 0.0 -1.0 0.0 0.0)) (set-vector! (-> group dir2 color) 0.75 0.375 0.0 1.0)) (make-light-kit (-> context light-group 3) 53703.11 0.9 0.9 0.5) (make-light-kit (-> context light-group 4) 54613.332 0.9 0.9 0.4) @@ -71,39 +59,24 @@ "Initialize Village 2 light groups 1 through 6 with the authored directional colors and levels." (let ((group (-> context light-group 1))) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) 1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 1.0 0.0 1.0)) (set-vector! (-> group dir0 color) 0.375 0.25 0.25 1.0) (set! (-> group dir0 levels x) 1.0) (let ((directional (-> group dir1))) - (set! (-> directional direction x) -0.6119) - (set! (-> directional direction y) 0.5) - (set! (-> directional direction z) -0.6119) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) -0.6119 0.5 -0.6119 1.0)) (set-vector! (-> group dir1 color) 0.25 0.75 1.0 1.0) (set! (-> group dir1 levels x) 0.666) (let ((directional (-> group dir2))) - (set! (-> directional direction x) 0.9961) - (set! (-> directional direction y) 0.0) - (set! (-> directional direction z) -0.0871) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.9961 0.0 -0.0871 1.0)) (set-vector! (-> group dir2 color) 0.0 0.25 1.0 1.0) (set! (-> group dir2 levels x) 1.0)) (let ((group (-> context light-group 2))) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.2239) - (set! (-> directional direction y) 0.5) - (set! (-> directional direction z) 0.836) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.2239 0.5 0.836 1.0)) (set-vector! (-> group dir0 color) 0.8 0.8 0.8 1.0) (set! (-> group dir0 levels x) 0.7) (let ((directional (-> group dir1))) - (set! (-> directional direction x) -0.2959) - (set! (-> directional direction y) 0.5) - (set! (-> directional direction z) -0.8133) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) -0.2959 0.5 -0.8133 1.0)) (set-vector! (-> group dir1 color) 0.8 0.8 0.8 1.0) (set! (-> group dir1 levels x) 0.7)) (let ((group (-> context light-group 3))) @@ -114,10 +87,7 @@ (set-vector! (-> group dir0 color) 0.675 0.45 0.15 1.0)) (let ((group (-> context light-group 5))) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.2425) - (set! (-> directional direction y) -0.9701) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 0.0)) + (set-vector! (-> directional direction) 0.2425 -0.9701 0.0 0.0)) (set-vector! (-> group dir0 color) 2.0 1.0 0.0 1.0) (set! (-> group dir1 levels x) 0.0) (set! (-> group dir2 levels x) 0.0)) @@ -133,82 +103,53 @@ (let ((group (-> context light-group 1))) (make-light-kit group 0.0 1.0 0.0 0.0) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) 1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 1.0 0.0 1.0)) (set-vector! (-> group dir0 color) 1.0 0.9 0.0 1.0)) (let ((group (-> context light-group 2))) (make-light-kit group 0.0 1.0 0.0 0.0) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) 1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 1.0 0.0 1.0)) (set-vector! (-> group dir0 color) 1.0 0.9 0.0 1.0)) (let ((group (-> context light-group 3))) (make-light-kit group 0.0 1.0 0.0 0.0) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) 1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 1.0 0.0 1.0)) (set-vector! (-> group dir0 color) 1.0 0.9 0.0 1.0)) (let ((group (-> context light-group 4))) (make-light-kit group 0.0 1.0 0.0 0.0) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) 1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 1.0 0.0 1.0)) (set-vector! (-> group dir0 color) 1.0 0.9 0.0 1.0)) (let ((group (-> context light-group 5))) (make-light-kit group 0.0 1.0 0.0 0.0) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) 1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 1.0 0.0 1.0)) (set-vector! (-> group dir0 color) 1.0 0.9 0.0 1.0)) (let ((group (-> context light-group 6))) (make-light-kit group 0.0 1.0 0.0 0.0) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) 1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 1.0 0.0 1.0)) (set-vector! (-> group dir0 color) 1.0 0.9 0.0 1.0)) (none)) + (defun make-village3-light-kit ((context mood-context)) "Initialize Village 3 light groups 1 and 2 with cyan upper and amber downward lighting." (let ((group (-> context light-group 1))) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.6281) - (set! (-> directional direction y) 0.7208) - (set! (-> directional direction z) 0.2929) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.6281 0.7208 0.2929 1.0)) (set-vector! (-> group dir0 color) 0.5 1.0 1.0 1.0) (set! (-> group dir0 levels x) 1.0) (let ((directional (-> group dir2))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) -1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 -1.0 0.0 1.0)) (set-vector! (-> group dir2 color) 0.625 0.375 0.1 1.0)) (let ((group (-> context light-group 2))) (let ((directional (-> group dir0))) - (set! (-> directional direction x) 0.6281) - (set! (-> directional direction y) 0.7208) - (set! (-> directional direction z) 0.2929) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.6281 0.7208 0.2929 1.0)) (set-vector! (-> group dir0 color) 0.25 0.5 0.5 1.0) (set! (-> group dir0 levels x) 1.0) (let ((directional (-> group dir2))) - (set! (-> directional direction x) 0.0) - (set! (-> directional direction y) -1.0) - (set! (-> directional direction z) 0.0) - (set! (-> directional direction w) 1.0)) + (set-vector! (-> directional direction) 0.0 -1.0 0.0 1.0)) (set-vector! (-> group dir2 color) 0.625 0.375 0.1 1.0)) (none)) diff --git a/goal_src/jak1/engine/gfx/mood/mood.gc b/goal_src/jak1/engine/gfx/mood/mood.gc index 9c3b5a8eff..a2e7632cfc 100644 --- a/goal_src/jak1/engine/gfx/mood/mood.gc +++ b/goal_src/jak1/engine/gfx/mood/mood.gc @@ -30,223 +30,115 @@ (set! (-> *target* sidekick 0 draw light-index) (the-as uint light-index)) light-index))) -(#when PC_PORT - (defun update-mood-itimes ((context mood-context)) - "Convert the eight floating palette weights into the packed values used by time-of-day palette - interpolation. Each times vector has one in xyz and its weight in w, so multiplying xyz by w - broadcasts the weight. Conversion to 20.12 fixed point followed by a six-bit arithmetic shift - produces 4.6 values; packing pairs of 32-bit lanes into high halfwords stores all eight weights - in four itimes quadwords." - (local-vars - (slot0-raw uint128) - (slot0-fixed uint128) - (packed01 uint128) - (packed45 uint128) - (slot1-raw uint128) - (slot1-fixed uint128) - (packed23 uint128) - (packed67 uint128) - (slot2-raw uint128) - (slot2-fixed uint128) - (slot3-raw uint128) - (slot3-fixed uint128) - (slot4-raw uint128) - (slot4-fixed uint128) - (slot5-raw uint128) - (slot5-fixed uint128) - (slot6-raw uint128) - (slot6-fixed uint128) - (slot7-raw uint128) - (slot7-fixed uint128)) - ;; og:preserve-this pc mood debug - (with-pc - (case *mood-override-debug* - (('copy #t) (dotimes (mti 8) (set! (-> context times mti w) (-> *mood-override-table* mti)))) - (('mult) (dotimes (mti 8) (*! (-> context times mti w) (-> *mood-override-table* mti)))))) - (rlet ((vf1 :class vf) - (vf2 :class vf) - (vf3 :class vf) - (vf4 :class vf) - (vf5 :class vf) - (vf6 :class vf) - (vf7 :class vf) - (vf8 :class vf)) - (nop!) - (nop!) - (.lvf vf1 (&-> context times 0 quad)) - (nop!) - (.lvf vf2 (&-> context times 1 quad)) - (.mul.w.vf.xyz vf1 vf1 vf1) - (.lvf vf3 (&-> context times 2 quad)) - (.mul.w.vf.xyz vf2 vf2 vf2) - (.lvf vf4 (&-> context times 3 quad)) - (.mul.w.vf.xyz vf3 vf3 vf3) - (.lvf vf5 (&-> context times 4 quad)) - (.mul.w.vf.xyz vf4 vf4 vf4) - (.lvf vf6 (&-> context times 5 quad)) - (.mul.w.vf.xyz vf5 vf5 vf5) - (.lvf vf7 (&-> context times 6 quad)) - (.mul.w.vf.xyz vf6 vf6 vf6) - (.lvf vf8 (&-> context times 7 quad)) - (.mul.w.vf.xyz vf7 vf7 vf7) - (nop!) - (.mul.w.vf.xyz vf8 vf8 vf8) - (nop!) - (vftoi12.xyzw vf1 vf1) - (nop!) - (vftoi12.xyzw vf2 vf2) - (nop!) - (vftoi12.xyzw vf3 vf3) - (nop!) - (vftoi12.xyzw vf4 vf4) - (nop!) - (vftoi12.xyzw vf5 vf5) - (nop!) - (vftoi12.xyzw vf6 vf6) - (nop!) - (vftoi12.xyzw vf7 vf7) - (nop!) - (vftoi12.xyzw vf8 vf8) - (nop!) - (.mov slot0-raw vf1) - (nop!) - (.mov slot1-raw vf2) - (nop!) - (.mov slot2-raw vf3) - (.pw.sra slot0-fixed slot0-raw 6) - (.mov slot3-raw vf4) - (.pw.sra slot1-fixed slot1-raw 6) - (.mov slot4-raw vf5) - (.pw.sra slot2-fixed slot2-raw 6) - (.mov slot5-raw vf6) - (.pw.sra slot3-fixed slot3-raw 6) - (.mov slot6-raw vf7) - (.pw.sra slot4-fixed slot4-raw 6) - (.mov slot7-raw vf8) - (.pw.sra slot5-fixed slot5-raw 6) - (.pw.sra slot6-fixed slot6-raw 6) - (nop!) - (.pw.sra slot7-fixed slot7-raw 6) - (nop!) - (.ppach packed01 slot1-fixed slot0-fixed) - (nop!) - (.ppach packed23 slot3-fixed slot2-fixed) - (set! (-> context itimes 0 quad) packed01) - (.ppach packed45 slot5-fixed slot4-fixed) - (set! (-> context itimes 1 quad) packed23) - (.ppach packed67 slot7-fixed slot6-fixed) - (set! (-> context itimes 2 quad) packed45) - (nop!) - (set! (-> context itimes 3 quad) packed67) - 0 - (none)))) - -(#unless PC_PORT - (defun update-mood-itimes ((context mood-context)) - "Convert the eight floating palette weights into the packed values used by time-of-day palette - interpolation. Each times vector has one in xyz and its weight in w, so multiplying xyz by w - broadcasts the weight. Conversion to 20.12 fixed point followed by a six-bit arithmetic shift - produces 4.6 values; packing pairs of 32-bit lanes into high halfwords stores all eight weights - in four itimes quadwords." - (rlet ((time-data (&-> context times 0 quad)) - (itime-data (&-> context itimes 0 quad)) - (time0 :reg vf1) - (time1 :reg vf2) - (time2 :reg vf3) - (time3 :reg vf4) - (time4 :reg vf5) - (time5 :reg vf6) - (time6 :reg vf7) - (time7 :reg vf8) - (slot0-raw :class i128) - (slot0-fixed :class i128) - (packed01 :class i128) - (packed45 :class i128) - (slot1-raw :class i128) - (slot1-fixed :class i128) - (packed23 :class i128) - (packed67 :class i128) - (slot2-raw :class i128) - (slot2-fixed :class i128) - (slot3-raw :class i128) - (slot3-fixed :class i128) - (slot4-raw :class i128) - (slot4-fixed :class i128) - (slot5-raw :class i128) - (slot5-fixed :class i128) - (slot6-raw :class i128) - (slot6-fixed :class i128) - (slot7-raw :class i128) - (slot7-fixed :class i128)) - (nop!) - (nop!) - (l.vf time0 time-data) - (nop!) - (l.vf time1 time-data 16) - (mul.w.vf.xyz time0 time0 time0) - (l.vf time2 time-data 32) - (mul.w.vf.xyz time1 time1 time1) - (l.vf time3 time-data 48) - (mul.w.vf.xyz time2 time2 time2) - (l.vf time4 time-data 64) - (mul.w.vf.xyz time3 time3 time3) - (l.vf time5 time-data 80) - (mul.w.vf.xyz time4 time4 time4) - (l.vf time6 time-data 96) - (mul.w.vf.xyz time5 time5 time5) - (l.vf time7 time-data 112) - (mul.w.vf.xyz time6 time6 time6) - (nop!) - (mul.w.vf.xyz time7 time7 time7) - (nop!) - (ftoi.vf time0 time0 :fixed 12) - (nop!) - (ftoi.vf time1 time1 :fixed 12) - (nop!) - (ftoi.vf time2 time2 :fixed 12) - (nop!) - (ftoi.vf time3 time3 :fixed 12) - (nop!) - (ftoi.vf time4 time4 :fixed 12) - (nop!) - (ftoi.vf time5 time5 :fixed 12) - (nop!) - (ftoi.vf time6 time6 :fixed 12) - (nop!) - (ftoi.vf time7 time7 :fixed 12) - (nop!) - (m slot0-raw time0) - (nop!) - (m slot1-raw time1) - (nop!) - (m slot2-raw time2) - (sra.w slot0-fixed slot0-raw 6) - (m slot3-raw time3) - (sra.w slot1-fixed slot1-raw 6) - (m slot4-raw time4) - (sra.w slot2-fixed slot2-raw 6) - (m slot5-raw time5) - (sra.w slot3-fixed slot3-raw 6) - (m slot6-raw time6) - (sra.w slot4-fixed slot4-raw 6) - (m slot7-raw time7) - (sra.w slot5-fixed slot5-raw 6) - (sra.w slot6-fixed slot6-raw 6) - (mmi-nop!) - (sra.w slot7-fixed slot7-raw 6) - (mmi-nop!) - (ppach packed01 slot1-fixed slot0-fixed) - (mmi-nop!) - (ppach packed23 slot3-fixed slot2-fixed) - (s.q packed01 itime-data) - (ppach packed45 slot5-fixed slot4-fixed) - (s.q packed23 itime-data 16) - (ppach packed67 slot7-fixed slot6-fixed) - (s.q packed45 itime-data 32) - (nop!) - (s.q packed67 itime-data 48) - 0 - (none)))) +(defun update-mood-itimes ((context mood-context)) + "Convert the eight floating palette weights into the packed values used by time-of-day palette + interpolation. Each times vector has one in xyz and its weight in w, so multiplying xyz by w + broadcasts the weight. Conversion to 20.12 fixed point followed by a six-bit arithmetic shift + produces 4.6 values; packing pairs of 32-bit lanes into high halfwords stores all eight weights + in four itimes quadwords." + (local-vars + (slot0-raw uint128) + (slot0-fixed uint128) + (packed01 uint128) + (packed45 uint128) + (slot1-raw uint128) + (slot1-fixed uint128) + (packed23 uint128) + (packed67 uint128) + (slot2-raw uint128) + (slot2-fixed uint128) + (slot3-raw uint128) + (slot3-fixed uint128) + (slot4-raw uint128) + (slot4-fixed uint128) + (slot5-raw uint128) + (slot5-fixed uint128) + (slot6-raw uint128) + (slot6-fixed uint128) + (slot7-raw uint128) + (slot7-fixed uint128)) + ;; og:preserve-this pc mood debug + (with-pc + (case *mood-override-debug* + (('copy #t) (dotimes (mti 8) (set! (-> context times mti w) (-> *mood-override-table* mti)))) + (('mult) (dotimes (mti 8) (*! (-> context times mti w) (-> *mood-override-table* mti)))))) + (rlet ((vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf)) + (nop!) + (nop!) + (.lvf vf1 (&-> context times 0 quad)) + (nop!) + (.lvf vf2 (&-> context times 1 quad)) + (.mul.w.vf.xyz vf1 vf1 vf1) + (.lvf vf3 (&-> context times 2 quad)) + (.mul.w.vf.xyz vf2 vf2 vf2) + (.lvf vf4 (&-> context times 3 quad)) + (.mul.w.vf.xyz vf3 vf3 vf3) + (.lvf vf5 (&-> context times 4 quad)) + (.mul.w.vf.xyz vf4 vf4 vf4) + (.lvf vf6 (&-> context times 5 quad)) + (.mul.w.vf.xyz vf5 vf5 vf5) + (.lvf vf7 (&-> context times 6 quad)) + (.mul.w.vf.xyz vf6 vf6 vf6) + (.lvf vf8 (&-> context times 7 quad)) + (.mul.w.vf.xyz vf7 vf7 vf7) + (nop!) + (.mul.w.vf.xyz vf8 vf8 vf8) + (nop!) + (vftoi12.xyzw vf1 vf1) + (nop!) + (vftoi12.xyzw vf2 vf2) + (nop!) + (vftoi12.xyzw vf3 vf3) + (nop!) + (vftoi12.xyzw vf4 vf4) + (nop!) + (vftoi12.xyzw vf5 vf5) + (nop!) + (vftoi12.xyzw vf6 vf6) + (nop!) + (vftoi12.xyzw vf7 vf7) + (nop!) + (vftoi12.xyzw vf8 vf8) + (nop!) + (.mov slot0-raw vf1) + (nop!) + (.mov slot1-raw vf2) + (nop!) + (.mov slot2-raw vf3) + (.pw.sra slot0-fixed slot0-raw 6) + (.mov slot3-raw vf4) + (.pw.sra slot1-fixed slot1-raw 6) + (.mov slot4-raw vf5) + (.pw.sra slot2-fixed slot2-raw 6) + (.mov slot5-raw vf6) + (.pw.sra slot3-fixed slot3-raw 6) + (.mov slot6-raw vf7) + (.pw.sra slot4-fixed slot4-raw 6) + (.mov slot7-raw vf8) + (.pw.sra slot5-fixed slot5-raw 6) + (.pw.sra slot6-fixed slot6-raw 6) + (nop!) + (.pw.sra slot7-fixed slot7-raw 6) + (nop!) + (.ppach packed01 slot1-fixed slot0-fixed) + (nop!) + (.ppach packed23 slot3-fixed slot2-fixed) + (set! (-> context itimes 0 quad) packed01) + (.ppach packed45 slot5-fixed slot4-fixed) + (set! (-> context itimes 1 quad) packed23) + (.ppach packed67 slot7-fixed slot6-fixed) + (set! (-> context itimes 2 quad) packed45) + (nop!) + (set! (-> context itimes 3 quad) packed67) + 0 + (none))) (defun update-mood-prt-color ((context mood-context)) "Derive a missing particle tint from seventy-five percent ambient light and twenty-five percent @@ -255,14 +147,11 @@ (ambient-color (-> groups 0 ambi color)) (directional-color (new 'stack-no-clear 'vector))) (vector4-lerp! directional-color (-> groups 0 dir0 color) (-> groups 0 dir1 color) (-> groups 0 dir1 levels x)) - (set! (-> context current-prt-color x) - (* 0.5 (+ (-> ambient-color x) (* 0.5 (+ (-> ambient-color x) (-> directional-color x)))))) - (set! (-> context current-prt-color y) - (* 0.5 (+ (-> ambient-color y) (* 0.5 (+ (-> ambient-color y) (-> directional-color y)))))) - (set! (-> context current-prt-color z) - (* 0.5 (+ (-> ambient-color z) (* 0.5 (+ (-> ambient-color z) (-> directional-color z)))))) - (set! (-> context current-prt-color w) - (* 0.5 (+ (-> ambient-color w) (* 0.5 (+ (-> ambient-color w) (-> directional-color w))))))) + (set-vector! (-> context current-prt-color) + (* 0.5 (+ (-> ambient-color x) (* 0.5 (+ (-> ambient-color x) (-> directional-color x))))) + (* 0.5 (+ (-> ambient-color y) (* 0.5 (+ (-> ambient-color y) (-> directional-color y))))) + (* 0.5 (+ (-> ambient-color z) (* 0.5 (+ (-> ambient-color z) (-> directional-color z))))) + (* 0.5 (+ (-> ambient-color w) (* 0.5 (+ (-> ambient-color w) (-> directional-color w))))))) (let ((shadow-color (-> context current-shadow-color))) (vector-copy! shadow-color (-> context current-prt-color)) shadow-color)) @@ -292,12 +181,12 @@ (let ((snapshot (-> context mood-lights-table data snapshot-a-index))) (set! (-> context times snapshot-a-index w) 1.0) (vector-copy! (-> context current-prt-color) (-> snapshot prt-color)) - (set! (-> groups 0 ambi color quad) (-> snapshot amb-color quad)) + (vector-copy! (-> groups 0 ambi color) (-> snapshot amb-color)) (set! (-> groups 0 ambi levels x) 1.0) (vector-copy! (-> context current-shadow) (-> snapshot shadow)) (let ((color-level (+ (* 2.0 (-> snapshot lgt-color x)) (* 4.0 (-> snapshot lgt-color y)) (-> snapshot lgt-color z)))) - (set! (-> groups 0 dir0 direction quad) (-> snapshot direction quad)) - (set! (-> groups 0 dir0 color quad) (-> snapshot lgt-color quad)) + (vector-copy! (-> groups 0 dir0 direction) (-> snapshot direction)) + (vector-copy! (-> groups 0 dir0 color) (-> snapshot lgt-color)) (set! (-> groups 0 dir0 levels x) 1.0) (set! (-> groups 0 dir0 levels y) color-level))) (set! (-> *time-of-day-context* light-masks-0 level-index) (the-as uint (ash 1 snapshot-a-index))) @@ -316,21 +205,21 @@ (let ((color-level-a (* (+ (* 2.0 (-> snapshot-a lgt-color x)) (* 4.0 (-> snapshot-a lgt-color y)) (-> snapshot-a lgt-color z)) (- 1.0 blend))) (color-level-b (* (+ (* 2.0 (-> snapshot-b lgt-color x)) (* 4.0 (-> snapshot-b lgt-color y)) (-> snapshot-b lgt-color z)) blend))) - (set! (-> groups 0 dir0 direction quad) (-> snapshot-a direction quad)) - (set! (-> groups 0 dir0 color quad) (-> snapshot-a lgt-color quad)) + (vector-copy! (-> groups 0 dir0 direction) (-> snapshot-a direction)) + (vector-copy! (-> groups 0 dir0 color) (-> snapshot-a lgt-color)) (set! (-> groups 0 dir0 levels x) (- 1.0 blend)) (set! (-> groups 0 dir0 levels y) color-level-a) - (set! (-> groups 0 dir1 direction quad) (-> snapshot-b direction quad)) - (set! (-> groups 0 dir1 color quad) (-> snapshot-b lgt-color quad)) + (vector-copy! (-> groups 0 dir1 direction) (-> snapshot-b direction)) + (vector-copy! (-> groups 0 dir1 color) (-> snapshot-b lgt-color)) (set! (-> groups 0 dir1 levels x) blend) (set! (-> groups 0 dir1 levels y) color-level-b))) (set! (-> *time-of-day-context* light-masks-0 level-index) (the-as uint (ash 1 snapshot-a-index))) (set! (-> *time-of-day-context* light-masks-1 level-index) (the-as uint (ash 1 snapshot-b-index))) (set! (-> *time-of-day-context* light-interp level-index) blend))) (if (and (= (-> context current-prt-color x) 0.0) - (= (-> context current-prt-color y) 0.0) - (= (-> context current-prt-color z) 0.0)) - (update-mood-prt-color context)) + (= (-> context current-prt-color y) 0.0) + (= (-> context current-prt-color z) 0.0)) + (update-mood-prt-color context)) blend)) (defun update-mood-sky-texture ((context mood-context) (hour float)) @@ -1084,9 +973,10 @@ (cond ((and (= egg-top-reminder 2) (nonzero? blue-transition-time)) (if (< (the-as uint 60) blue-transition-time) - (set! (-> context times 2 w) 2.0) - (set! (-> context times 2 w) (* 0.033333335 (the float blue-transition-time)))) - (if (not (paused?)) (set! (-> context state 2) (+ blue-transition-time -1))) + (set! (-> context times 2 w) 2.0) + (set! (-> context times 2 w) (* 0.033333335 (the float blue-transition-time)))) + (if (not (paused?)) + (set! (-> context state 2) (+ blue-transition-time -1))) (set! (-> context times 1 w) 1.0) (update-mood-jungleb-blue context hour level-index)) ((and (nonzero? egg-top-reminder) (!= blue-transition-time 180)) @@ -1098,23 +988,14 @@ (set! (-> context state 1) (the-as uint 0)) (set! (-> context state 0) (the-as uint 255)) (let ((fog-snapshot (-> context mood-fog-table data))) - (set! (-> fog-snapshot 0 fog-color x) 0.0) - (set! (-> fog-snapshot 0 fog-color y) 0.0) - (set! (-> fog-snapshot 0 fog-color z) 0.0) - (set! (-> fog-snapshot 0 fog-color w) 128.0)) + (set-vector! (-> fog-snapshot 0 fog-color) 0.0 0.0 0.0 128.0)) (set! (-> context mood-fog-table data 0 fog-dists x) 98304.0) (set-vector! (-> context mood-fog-table data 0 erase-color) 0.0 0.0 0.0 128.0) (let ((sun-snapshot (-> context mood-sun-table data))) - (set! (-> sun-snapshot 0 sun-color x) 0.0) - (set! (-> sun-snapshot 0 sun-color y) 0.0) - (set! (-> sun-snapshot 0 sun-color z) 0.0) - (set! (-> sun-snapshot 0 sun-color w) 0.0)) + (set-vector! (-> sun-snapshot 0 sun-color) 0.0 0.0 0.0 0.0)) (set-vector! (-> context mood-sun-table data 0 env-color) 48.0 60.0 96.0 255.0) (let ((light-snapshot (-> context mood-lights-table data))) - (set! (-> light-snapshot 0 direction x) 0.0) - (set! (-> light-snapshot 0 direction y) 1.0) - (set! (-> light-snapshot 0 direction z) 0.0) - (set! (-> light-snapshot 0 direction w) 0.0)) + (set-vector! (-> light-snapshot 0 direction) 0.0 1.0 0.0 0.0)) (set-vector! (-> context mood-lights-table data 0 lgt-color) 0.287 0.283 0.4 1.0) (set-vector! (-> context mood-lights-table data 0 amb-color) 0.166125 0.2125 0.4 1.0) (set-vector! (-> context mood-lights-table data 0 prt-color) 0.14235 0.1645 0.2875 1.0) @@ -1127,10 +1008,7 @@ (let ((group (-> context light-group 2))) (quad-copy! (the-as pointer group) (the-as pointer (-> context light-group)) 12) (let ((down-light (-> group dir2))) - (set! (-> down-light direction x) 0.0) - (set! (-> down-light direction y) 1.0) - (set! (-> down-light direction z) 0.0) - (set! (-> down-light direction w) 0.0)) + (set-vector! (-> down-light direction) 0.0 1.0 0.0 0.0)) (set-vector! (-> group dir2 color) 0.0 0.5 0.75 1.0) (set! (-> group dir2 levels x) 1.0)) (let ((jungle-group (-> *jungle-mood* light-group 1)) @@ -1138,10 +1016,7 @@ (let ((ambient-offset (new 'stack-no-clear 'vector))) (quad-copy! (the-as pointer group) (the-as pointer (-> context light-group)) 12) (let ((down-light (-> group dir2))) - (set! (-> down-light direction x) 0.0) - (set! (-> down-light direction y) 1.0) - (set! (-> down-light direction z) 0.0) - (set! (-> down-light direction w) 0.0)) + (set-vector! (-> down-light direction) 0.0 1.0 0.0 0.0)) (set-vector! (-> group dir2 color) 0.4 0.25 0.1 1.0) (set! (-> group dir2 levels x) 1.0) (set-vector! ambient-offset 0.25 0.25 0.25 0.0) @@ -1149,7 +1024,7 @@ (quad-copy! (the-as pointer jungle-group) (the-as pointer group) 12)) (let ((landmark-position (new 'stack-no-clear 'vector)) (target-position (target-joint-pos))) - (set-vector! landmark-position 1482752.0 (-> target-position y) -985088.0 1.0) + (set-vector! landmark-position (meters 362) (-> target-position y) -985088.0 1.0) (let ((distance (vector-vector-distance landmark-position target-position))) (when (< distance 81920.0) (let ((horizontal-fade (* 0.000034877234 (+ -53248.0 distance))) @@ -1161,31 +1036,26 @@ (let* ((height-level (- 1.0 (fmax 0.0 (fmin 1.0 height-fade)))) (fire-level (* (- 1.0 (fmax 0.0 (fmin 1.0 horizontal-fade))) height-level))) (let ((down-light (-> groups 0 dir2))) - (set! (-> down-light direction x) 0.0) - (set! (-> down-light direction y) 1.0) - (set! (-> down-light direction z) 0.0) - (set! (-> down-light direction w) 0.0)) + (set-vector! (-> down-light direction) 0.0 1.0 0.0 0.0)) (set-vector! (-> groups 0 dir2 color) 0.4 0.25 0.1 1.0) (set! (-> groups 0 dir2 levels x) fire-level) (let ((down-light (-> jungle-groups 0 dir2))) - (set! (-> down-light direction x) 0.0) - (set! (-> down-light direction y) 1.0) - (set! (-> down-light direction z) 0.0) - (set! (-> down-light direction w) 0.0)) + (set-vector! (-> down-light direction) 0.0 1.0 0.0 0.0)) (set-vector! (-> jungle-groups 0 dir2 color) 0.4 0.25 0.1 1.0) (set! (-> jungle-groups 0 dir2 levels x) fire-level) (set-vector! bright-ambient 0.25 0.25 0.25 0.0) (vector+! bright-ambient bright-ambient (the-as vector (-> groups 0 ambi color))) (vector4-lerp! (-> groups 0 ambi color) (-> groups 0 ambi color) bright-ambient fire-level))))) - (set-vector! landmark-position 1146880.0 (-> target-position y) -1232896.0 1.0) - (if (< (vector-vector-distance landmark-position target-position) 10240.0) (set! *teleport* #t)) - (set-vector! landmark-position 1781760.0 -163840.0 -1038336.0 1.0) + (set-vector! landmark-position (meters 280) (-> target-position y) (meters -301) 1.0) + (if (< (vector-vector-distance landmark-position target-position) 10240.0) + (set! *teleport* #t)) + (set-vector! landmark-position (meters 435) (meters -40) -1038336.0 1.0) (let ((distance (vector-vector-distance landmark-position target-position))) (when (< distance 147456.0) (let ((fade (* 0.000030517578 (+ -114688.0 distance)))) (set-target-light-index 2) (set! (-> *time-of-day-context* target-interp) (- 1.0 (fmax 0.0 (fmin 1.0 fade))))))) - (set-vector! landmark-position 1105920.0 -188416.0 -1204224.0 1.0) + (set-vector! landmark-position (meters 270) (meters -46) (meters -294) 1.0) (let ((distance (vector-vector-distance landmark-position target-position))) (when (< distance 106496.0) (let ((fade (* 0.000030517578 (+ -73728.0 distance)))) @@ -1449,7 +1319,7 @@ (none)) (defun update-mood-darkcave ((context mood-context) (hour float) (level-index int)) - "Update Dark Eco Plant's mood, lava glow, and proximity-based local lighting." + "Update" (when (not (paused?)) (clear-mood-times context) (set! (-> context times 0 w) 1.0) @@ -1561,8 +1431,7 @@ (time uint8))) (defun update-mood-village3 ((context mood-context) (hour float) (level-index int)) - "Update Volcanic Crater's mood, lava and caustic effects, local light kits, and target lighting - transitions." + "Update Volcanic Crater's mood, lava effects, local light kits, and target lighting transitions." (update-mood-fog context hour) (update-mood-sky-texture context hour) (clear-mood-times context) @@ -1574,31 +1443,19 @@ (dark-ambient-color (new 'stack-no-clear 'vector)) (up-direction (new 'stack-no-clear 'vector))) (let ((snapshot (-> context mood-lights-table data))) - (set! (-> snapshot 0 direction x) -0.067) - (set! (-> snapshot 0 direction y) 0.25) - (set! (-> snapshot 0 direction z) 0.966) - (set! (-> snapshot 0 direction w) 0.0)) + (set-vector! (-> snapshot 0 direction) -0.067 0.25 0.966 0.0)) (set-vector! (-> context mood-lights-table data 0 lgt-color) 0.0 0.0 0.0 1.0) (set-vector! (-> context mood-lights-table data 0 amb-color) 0.449 0.35 0.599 1.0) (let ((snapshot (-> context mood-lights-table data 1))) - (set! (-> snapshot direction x) 0.259) - (set! (-> snapshot direction y) 0.966) - (set! (-> snapshot direction z) 0.0) - (set! (-> snapshot direction w) 0.0)) + (set-vector! (-> snapshot direction) 0.259 0.966 0.0 0.0)) (set-vector! (-> context mood-lights-table data 1 lgt-color) 0.66 0.436 0.291 1.0) (set-vector! (-> context mood-lights-table data 1 amb-color) 0.358 0.575 0.716 1.0) (let ((snapshot (-> context mood-lights-table data 2))) - (set! (-> snapshot direction x) -0.067) - (set! (-> snapshot direction y) 0.25) - (set! (-> snapshot direction z) -0.966) - (set! (-> snapshot direction w) 0.0)) + (set-vector! (-> snapshot direction) -0.067 0.25 -0.966 0.0)) (set-vector! (-> context mood-lights-table data 2 lgt-color) 0.0 0.0 0.0 1.0) (set-vector! (-> context mood-lights-table data 2 amb-color) 0.383 0.366 0.599 1.0) (let ((snapshot (-> context mood-lights-table data 3))) - (set! (-> snapshot direction x) 0.866) - (set! (-> snapshot direction y) 0.5) - (set! (-> snapshot direction z) 0.0) - (set! (-> snapshot direction w) 0.0)) + (set-vector! (-> snapshot direction) 0.866 0.5 0.0 0.0)) (set-vector! (-> context mood-lights-table data 3 lgt-color) 0.0 0.0 0.0 1.0) (set-vector! (-> context mood-lights-table data 3 amb-color) 0.304 0.409 0.76 1.0) (let ((group (-> context light-group 1))) @@ -1638,11 +1495,12 @@ (let ((lava-blend (* 0.015625 (the float (logand (-> mood-state time) 63))))) (set! (-> mood-state scale) (the float (the int (rand-vu-float-range 128.0 255.0)))) (set! (-> context times 7 w) (* lava-blend (-> mood-state scale))))))) - (else (set-vector! local-light-color 0.19 0.128 0.128 1.0))))) + (else + (set-vector! local-light-color 0.19 0.128 0.128 1.0))))) (let ((landmark-position (new 'stack-no-clear 'vector)) (target-position (target-joint-pos))) 0.0 - (set-vector! landmark-position 4454400.0 196608.0 -14725120.0 1.0) + (set-vector! landmark-position 4454400.0 (meters 48) (meters -3595) 1.0) (let ((distance (vector-vector-distance landmark-position target-position))) (when (< distance 122880.0) (let ((fade (* 0.000016276043 (+ -61440.0 distance)))) @@ -1742,7 +1600,7 @@ (when *time-of-day-effects* (let ((landmark-position (new 'stack-no-clear 'vector)) (camera-position (-> *math-camera* trans))) - (set-vector! landmark-position 868352.0 151552.0 -7720960.0 1.0) + (set-vector! landmark-position (meters 212) (meters 37) (meters -1885) 1.0) (let ((distance (vector-vector-distance landmark-position camera-position))) (cond ((< distance 614400.0) @@ -1750,12 +1608,16 @@ (let* ((distance-fade (* 0.0000048828124 (+ -409600.0 distance))) (phase-blend (fmax 0.0 (fmin 1.0 distance-fade)))) (let ((mood-state (the-as ogre-states (-> context state)))) - (if (not (paused?)) (+! (-> mood-state lava-time) (rand-vu-float-range 64.0 2048.0))) - (if (not (movie?)) (update-mood-lightning context 2 2 18 4 0.5 #f)) + (if (not (paused?)) + (+! (-> mood-state lava-time) (rand-vu-float-range 64.0 2048.0))) + (if (not (movie?)) + (update-mood-lightning context 2 2 18 4 0.5 #f)) (cond ((or (nonzero? *lightning-time2*) (movie?)) - (if (not (paused?)) (+! (-> mood-state lava-fade) 0.2)) - (if (< 1.0 (-> mood-state lava-fade)) (set! (-> mood-state lava-fade) 1.0)) + (if (not (paused?)) + (+! (-> mood-state lava-fade) 0.2)) + (if (< 1.0 (-> mood-state lava-fade)) + (set! (-> mood-state lava-fade) 1.0)) (let* ((lava-fade (-> mood-state lava-fade)) (lava-light (-> context light-group 0 dir2)) (lava-level (+ 0.875 (* 0.125 (sin (-> mood-state lava-time))))) @@ -1764,26 +1626,24 @@ (set-vector! (-> lava-light color) 1.0 0.38 0.0 1.0) (set! (-> lava-light levels x) (* lava-level (- 1.0 phase-blend) lava-fade)) (set! (-> lava-light levels y) (* lava-color-level (- 1.0 phase-blend) lava-fade)))) - (else (set! (-> mood-state lava-fade) 0.0)))) + (else + (set! (-> mood-state lava-fade) 0.0)))) (let ((groups (-> context light-group)) (phase-groups (-> *ogre2-mood* light-group))) (cond ((= phase-blend 0.0) - (set! (-> groups 0 dir0 direction quad) (-> phase-groups 0 dir0 direction quad)) - (set! (-> groups 0 dir0 color quad) (-> phase-groups 0 dir0 color quad)) - (set! (-> groups 0 dir0 levels quad) (-> phase-groups 0 dir0 levels quad)) - (set! (-> groups 0 dir1 direction quad) (-> phase-groups 0 dir1 direction quad)) - (set! (-> groups 0 dir1 color quad) (-> phase-groups 0 dir1 color quad)) - (set! (-> groups 0 dir1 levels quad) (-> phase-groups 0 dir1 levels quad)) - (set! (-> groups 0 ambi direction quad) (-> phase-groups 0 ambi direction quad)) - (set! (-> groups 0 ambi color quad) (-> phase-groups 0 ambi color quad)) - (set! (-> groups 0 ambi levels quad) (-> phase-groups 0 ambi levels quad)) + (vector-copy! (-> groups 0 dir0 direction) (-> phase-groups 0 dir0 direction)) + (vector-copy! (-> groups 0 dir0 color) (-> phase-groups 0 dir0 color)) + (vector-copy! (-> groups 0 dir0 levels) (-> phase-groups 0 dir0 levels)) + (vector-copy! (-> groups 0 dir1 direction) (-> phase-groups 0 dir1 direction)) + (vector-copy! (-> groups 0 dir1 color) (-> phase-groups 0 dir1 color)) + (vector-copy! (-> groups 0 dir1 levels) (-> phase-groups 0 dir1 levels)) + (vector-copy! (-> groups 0 ambi direction) (-> phase-groups 0 ambi direction)) + (vector-copy! (-> groups 0 ambi color) (-> phase-groups 0 ambi color)) + (vector-copy! (-> groups 0 ambi levels) (-> phase-groups 0 ambi levels)) (vector-copy! (-> context current-shadow) (-> *ogre2-mood* current-shadow))) (else - (vector4-lerp! (the-as vector (-> groups 0)) - (the-as vector (-> phase-groups 0)) - (the-as vector (-> groups 0)) - phase-blend) + (vector4-lerp! (-> groups 0 dir0 direction) (-> phase-groups 0 dir0 direction) (-> groups 0 dir0 direction) phase-blend) (vector4-lerp! (-> groups 0 dir0 color) (-> phase-groups 0 dir0 color) (-> groups 0 dir0 color) phase-blend) (vector4-lerp! (-> groups 0 dir0 levels) (-> phase-groups 0 dir0 levels) (-> groups 0 dir0 levels) phase-blend) (vector4-lerp! (-> groups 0 dir1 direction) (-> phase-groups 0 dir1 direction) (-> groups 0 dir1 direction) phase-blend) @@ -1794,7 +1654,7 @@ (vector4-lerp! (-> groups 0 ambi levels) (-> phase-groups 0 ambi levels) (-> groups 0 ambi levels) phase-blend) (vector4-lerp! (-> context current-shadow) (-> *ogre2-mood* current-shadow) (-> context current-shadow) phase-blend)))))) (else - (set-vector! landmark-position 2973696.0 184320.0 -13414400.0 1.0) + (set-vector! landmark-position (meters 726) (meters 45) (meters -3275) 1.0) (let ((distance (vector-vector-distance landmark-position camera-position))) (when (< distance 1298432.0) (update-mood-quick *ogre3-mood* 0 0 0 level-index) @@ -1804,27 +1664,24 @@ (phase-groups (-> *ogre3-mood* light-group))) (cond ((= phase-blend 0.0) - (set! (-> groups 0 dir0 direction quad) (-> phase-groups 0 dir0 direction quad)) - (set! (-> groups 0 dir0 color quad) (-> phase-groups 0 dir0 color quad)) - (set! (-> groups 0 dir0 levels quad) (-> phase-groups 0 dir0 levels quad)) - (set! (-> groups 0 dir1 direction quad) (-> phase-groups 0 dir1 direction quad)) - (set! (-> groups 0 dir1 color quad) (-> phase-groups 0 dir1 color quad)) - (set! (-> groups 0 dir1 levels quad) (-> phase-groups 0 dir1 levels quad)) - (set! (-> groups 0 dir2 direction quad) (-> phase-groups 0 dir2 direction quad)) - (set! (-> groups 0 dir2 color quad) (-> phase-groups 0 dir2 color quad)) - (set! (-> groups 0 dir2 levels quad) (-> phase-groups 0 dir2 levels quad)) - (set! (-> groups 0 ambi direction quad) (-> phase-groups 0 ambi direction quad)) - (set! (-> groups 0 ambi color quad) (-> phase-groups 0 ambi color quad)) - (set! (-> groups 0 ambi levels quad) (-> phase-groups 0 ambi levels quad)) + (vector-copy! (-> groups 0 dir0 direction) (-> phase-groups 0 dir0 direction)) + (vector-copy! (-> groups 0 dir0 color) (-> phase-groups 0 dir0 color)) + (vector-copy! (-> groups 0 dir0 levels) (-> phase-groups 0 dir0 levels)) + (vector-copy! (-> groups 0 dir1 direction) (-> phase-groups 0 dir1 direction)) + (vector-copy! (-> groups 0 dir1 color) (-> phase-groups 0 dir1 color)) + (vector-copy! (-> groups 0 dir1 levels) (-> phase-groups 0 dir1 levels)) + (vector-copy! (-> groups 0 dir2 direction) (-> phase-groups 0 dir2 direction)) + (vector-copy! (-> groups 0 dir2 color) (-> phase-groups 0 dir2 color)) + (vector-copy! (-> groups 0 dir2 levels) (-> phase-groups 0 dir2 levels)) + (vector-copy! (-> groups 0 ambi direction) (-> phase-groups 0 ambi direction)) + (vector-copy! (-> groups 0 ambi color) (-> phase-groups 0 ambi color)) + (vector-copy! (-> groups 0 ambi levels) (-> phase-groups 0 ambi levels)) (vector-copy! (-> context current-shadow) (-> *ogre3-mood* current-shadow)) (vector-copy! (-> context current-fog fog-color) (-> *ogre3-mood* current-fog fog-color)) (vector-copy! (-> context current-fog fog-dists) (-> *ogre3-mood* current-fog fog-dists)) (vector-copy! (-> context current-fog erase-color) (-> *ogre3-mood* current-fog erase-color))) (else - (vector4-lerp! (the-as vector (-> groups 0)) - (the-as vector (-> phase-groups 0)) - (the-as vector (-> groups 0)) - phase-blend) + (vector4-lerp! (-> groups 0 dir0 direction) (-> phase-groups 0 dir0 direction) (-> groups 0 dir0 direction) phase-blend) (vector4-lerp! (-> groups 0 dir0 color) (-> phase-groups 0 dir0 color) (-> groups 0 dir0 color) phase-blend) (vector4-lerp! (-> groups 0 dir0 levels) (-> phase-groups 0 dir0 levels) (-> groups 0 dir0 levels) phase-blend) (vector4-lerp! (-> groups 0 dir1 direction) (-> phase-groups 0 dir1 direction) (-> groups 0 dir1 direction) phase-blend) @@ -1882,21 +1739,18 @@ (groups (-> context light-group))) (let ((snapshot (-> context mood-lights-table data 2))) (set! (-> context times 2 w) palette-fade) - (vector+float*! (the-as vector (-> groups 0)) (the-as vector (-> groups 0)) (-> snapshot direction) palette-fade) + (vector+float*! (-> groups 0 dir0 direction) (-> groups 0 dir0 direction) (-> snapshot direction) palette-fade) (vector+float*! (-> groups 0 dir0 color) (-> groups 0 dir0 color) (-> snapshot lgt-color) palette-fade)) - (vector-normalize! (the-as vector (-> groups 0)) 1.0))) + (vector-normalize! (-> groups 0 dir0 direction) 1.0))) (let ((arena-position (new 'stack-no-clear 'vector)) (camera-position (-> *math-camera* trans))) - (set-vector! arena-position 12378112.0 1990656.0 -19873792.0 1.0) + (set-vector! arena-position (meters 3022) (meters 486) (meters -4852) 1.0) (let ((distance (vector-vector-distance arena-position camera-position))) (when (< distance 819200.0) (let* ((distance-fade (* 0.0000048828124 (+ -614400.0 distance))) (arena-light-level (- 1.0 (fmax 0.0 (fmin 1.0 distance-fade))))) (let ((arena-light (-> *finalboss2-mood* light-group 0 dir2))) - (set! (-> arena-light direction x) 0.0) - (set! (-> arena-light direction y) -1.0) - (set! (-> arena-light direction z) 0.0) - (set! (-> arena-light direction w) 1.0)) + (set-vector! (-> arena-light direction) 0.0 -1.0 0.0 1.0)) (set-vector! (-> *finalboss2-mood* light-group 0 dir2 color) 1.0 0.8 2.0 1.0) (set! (-> *finalboss2-mood* light-group 0 dir2 levels x) arena-light-level))))) (cond @@ -1905,10 +1759,7 @@ (secret-light-fade (fmax 0.0 (fmin 1.0 secret-light-time))) (groups (-> context light-group))) (let ((secret-light (-> groups 0 dir2))) - (set! (-> secret-light direction x) -0.5768) - (set! (-> secret-light direction y) 0.1697) - (set! (-> secret-light direction z) -0.799) - (set! (-> secret-light direction w) 1.0)) + (set-vector! (-> secret-light direction) -0.5768 0.1697 -0.799 1.0)) (set-vector! (-> groups 0 dir2 color) 1.0 1.0 1.0 1.0) (set! (-> groups 0 dir2 levels x) secret-light-fade) (let ((shadow-direction (-> context current-shadow))) @@ -1924,7 +1775,8 @@ (set! (-> *default-shadow-settings* shadow-dir x) (-> shadow-direction x)) (set! (-> *default-shadow-settings* shadow-dir y) (-> shadow-direction y)) (set! (-> *default-shadow-settings* shadow-dir z) (-> shadow-direction z))))) - (else (set-time! (-> mood-state secret-time)))) + (else + (set-time! (-> mood-state secret-time)))) (let* ((sun-time (* 0.00019607843 (the float (- (current-time) (-> mood-state start-time))))) (sun-fade (fmax 0.0 (fmin 1.0 sun-time))) (sun-fade (fmax 0.0 (fmin 1.0 sun-fade)))) @@ -1955,22 +1807,19 @@ (groups (-> context light-group))) (let ((snapshot (-> context mood-lights-table data 2))) (set! (-> context times 2 w) palette-fade) - (vector+float*! (the-as vector (-> groups 0)) (the-as vector (-> groups 0)) (-> snapshot direction) palette-fade) + (vector+float*! (-> groups 0 dir0 direction) (-> groups 0 dir0 direction) (-> snapshot direction) palette-fade) (vector+float*! (-> groups 0 dir0 color) (-> groups 0 dir0 color) (-> snapshot lgt-color) palette-fade)) - (vector-normalize! (the-as vector (-> groups 0)) 1.0)) + (vector-normalize! (-> groups 0 dir0 direction) 1.0)) (let ((arena-position (new 'stack-no-clear 'vector)) (camera-position (-> *math-camera* trans))) - (set-vector! arena-position 12378112.0 1990656.0 -19873792.0 1.0) + (set-vector! arena-position (meters 3022) (meters 486) (meters -4852) 1.0) (let ((distance (vector-vector-distance arena-position camera-position))) (when (< distance 819200.0) (let* ((distance-fade (* 0.0000048828124 (+ -614400.0 distance))) (groups (-> context light-group)) (arena-light-level (- 1.0 (fmax 0.0 (fmin 1.0 distance-fade))))) (let ((arena-light (-> groups 0 dir2))) - (set! (-> arena-light direction x) 0.0) - (set! (-> arena-light direction y) -1.0) - (set! (-> arena-light direction z) 0.0) - (set! (-> arena-light direction w) 1.0)) + (set-vector! (-> arena-light direction) 0.0 -1.0 0.0 1.0)) (set-vector! (-> groups 0 dir2 color) 1.0 0.8 2.0 1.0) (set! (-> groups 0 dir2 levels x) arena-light-level)))))))) (update-mood-itimes context) @@ -1996,21 +1845,24 @@ (set! (-> context times 3 w) (-> *palette-fade-controls* control 3 fade)) (update-mood-flames context 4 3 0 0.45 0.001953125 1.0) (update-mood-light context 1 4 5 0.875 0.25 20.0 32) - (if (not (paused?)) (+! (-> context state 5) 1)) + (if (not (paused?)) + (+! (-> context state 5) 1)) (let ((state-data (the-as (pointer number) (-> context state)))) (let ((light-flicker (+ 0.5 (* 0.5 (cos (the float (* (logand (+ (-> (the-as (pointer uint8) state-data) 5) 32) 255) 512))))))) (cond ((movie?)) ((nonzero? (-> (the-as (pointer uint8) state-data) 7)) (set! (-> context times 2 w) 1.0) - (if (not (paused?)) (+! (-> (the-as (pointer uint8) state-data) 7) -1))) + (if (not (paused?)) + (+! (-> (the-as (pointer uint8) state-data) 7) -1))) ((nonzero? (-> (the-as (pointer uint8) state-data) 6)) - (if (not (paused?)) (+! (-> (the-as (pointer uint8) state-data) 6) -1))) + (if (not (paused?)) + (+! (-> (the-as (pointer uint8) state-data) 6) -1))) (else (set! (-> (the-as (pointer uint8) state-data) 7) (the-as uint (the int (rand-vu-float-range 2.0 20.0)))) (if (zero? (the int (rand-vu-float-range 0.0 3.0))) - (set! (-> (the-as (pointer uint8) state-data) 6) (the-as uint (the int (rand-vu-float-range 2.0 120.0)))) - (set! (-> (the-as (pointer uint8) state-data) 6) (the-as uint (the int (rand-vu-float-range 2.0 20.0))))))) + (set! (-> (the-as (pointer uint8) state-data) 6) (the-as uint (the int (rand-vu-float-range 2.0 120.0)))) + (set! (-> (the-as (pointer uint8) state-data) 6) (the-as uint (the int (rand-vu-float-range 2.0 20.0))))))) (let ((light-color (new 'stack-no-clear 'vector)) (warm-light-color (new 'stack-no-clear 'vector)) (groups (-> context light-group))) @@ -2018,15 +1870,12 @@ (set-vector! warm-light-color 0.75 0.725 0.5 1.0) (vector4-lerp! light-color light-color warm-light-color light-flicker) (let ((primary-group (-> groups 0))) - (set! (-> primary-group dir0 direction x) 0.0) - (set! (-> primary-group dir0 direction y) 1.0) - (set! (-> primary-group dir0 direction z) 0.0) - (set! (-> primary-group dir0 direction w) 1.0)) - (set! (-> groups 0 dir0 color quad) (-> light-color quad)) + (set-vector! (-> primary-group dir0 direction) 0.0 1.0 0.0 1.0)) + (vector-copy! (-> groups 0 dir0 color) light-color) (set! (-> groups 0 dir0 levels x) 1.0))) (let ((landmark-position (new 'stack-no-clear 'vector)) (target-position (target-joint-pos))) - (set-vector! landmark-position 11227136.0 (-> target-position y) -20164608.0 1.0) + (set-vector! landmark-position (meters 2741) (-> target-position y) (meters -4923) 1.0) (let ((distance (vector-vector-distance landmark-position target-position))) (when (< distance 409600.0) (let* ((distance-fade (* 0.000048828126 (+ -389120.0 distance))) @@ -2034,7 +1883,7 @@ (set! (-> context current-fog fog-dists y) (* 4096.0 (+ 250.0 (* 300.0 fog-fade)))))))) (let ((shield-position (new 'stack-no-clear 'vector)) (camera-position (-> *math-camera* trans))) - (set-vector! shield-position 11427840.0 (-> camera-position y) -19251200.0 1.0) + (set-vector! shield-position (meters 2790) (-> camera-position y) (meters -4700) 1.0) (let ((distance (vector-vector-distance shield-position camera-position)) (groups (-> context light-group))) (cond @@ -2042,45 +1891,39 @@ (let* ((distance-fade (* 0.000012207031 (+ -409600.0 distance))) (shield-proximity (- 1.0 (fmax 0.0 (fmin 1.0 distance-fade)))) (shield-flicker (+ 0.5 - (* 0.125 (cos (the float (* 4000 (/ (-> *display* time-factor) 5) (-> *display* integral-frame-counter))))) ;; og:preserve-this changed for high fps - (* 0.125 - (cos (the float (shl (the int (* (/ (-> *display* time-factor) 5) (-> *display* integral-frame-counter))) 11)))) ;; og:preserve-this changed for high fps - (* 0.25 (cos (the float (* 1500 (/ (-> *display* time-factor) 5) (-> *display* integral-frame-counter))))) ;; og:preserve-this changed for high fps - )) + (* 0.125 (cos (the float (* 4000 (-> *display* integral-frame-counter))))) + (* 0.125 (cos (the float (shl (-> *display* integral-frame-counter) 11)))) + (* 0.25 (cos (the float (* 1500 (-> *display* integral-frame-counter))))))) (shield-color (new 'stack-no-clear 'vector))) (let ((bright-shield-color (new 'stack-no-clear 'vector))) (set-vector! shield-color 0.275 0.1 1.025 1.0) (set-vector! bright-shield-color 0.35 0.1 1.1 1.0) (vector4-lerp! bright-shield-color shield-color bright-shield-color shield-flicker) (cond - ((= (-> *palette-fade-controls* control 7 fade) 1.0) (set! (-> (the-as (pointer float) state-data) 2) 1.0)) + ((= (-> *palette-fade-controls* control 7 fade) 1.0) + (set! (-> (the-as (pointer float) state-data) 2) 1.0)) (else - (if (not (paused?)) (+! (-> (the-as (pointer float) state-data) 2) -0.1)) + (if (not (paused?)) + (+! (-> (the-as (pointer float) state-data) 2) -0.1)) (set! (-> (the-as (pointer float) state-data) 2) (fmax 0.0 (fmin 1.0 (-> (the-as (pointer float) state-data) 2)))))) (set-vector! shield-color 0.1 0.1 0.1 1.0) (let ((shield-fade (* (-> (the-as (pointer float) state-data) 2) shield-proximity))) (vector4-lerp! shield-color shield-color bright-shield-color shield-fade) (set! (-> context times 7 w) (* (+ 0.8 (/ shield-flicker 10)) shield-fade)))) (let ((shield-light (-> groups 0 dir1))) - (set! (-> shield-light direction x) 0.0) - (set! (-> shield-light direction y) -1.0) - (set! (-> shield-light direction z) 0.0) - (set! (-> shield-light direction w) 1.0)) - (set! (-> groups 0 dir1 color quad) (-> shield-color quad))) + (set-vector! (-> shield-light direction) 0.0 -1.0 0.0 1.0)) + (vector-copy! (-> groups 0 dir1 color) shield-color)) (set! (-> groups 0 dir1 levels x) 1.0)) (else (let ((shield-light (-> groups 0 dir1))) - (set! (-> shield-light direction x) 0.0) - (set! (-> shield-light direction y) -1.0) - (set! (-> shield-light direction z) 0.0) - (set! (-> shield-light direction w) 1.0)) + (set-vector! (-> shield-light direction) 0.0 -1.0 0.0 1.0)) (set-vector! (-> groups 0 dir1 color) 0.1 0.1 0.1 1.0) (set! (-> groups 0 dir1 levels x) 1.0)))))) (let ((landmark-position (new 'stack-no-clear 'vector)) (target-position (target-joint-pos))) 0.0 (when (< 204800.0 (-> target-position y)) - (set-vector! landmark-position 11440128.0 (-> target-position y) -19298304.0 1.0) + (set-vector! landmark-position (meters 2793) (-> target-position y) -19298304.0 1.0) (let ((distance (vector-vector-distance landmark-position target-position)) (groups (-> context light-group))) (when (< distance 172032.0) diff --git a/goal_src/jak1/engine/gfx/mood/time-of-day.gc b/goal_src/jak1/engine/gfx/mood/time-of-day.gc index 72e6dd1957..8ba05862a4 100644 --- a/goal_src/jak1/engine/gfx/mood/time-of-day.gc +++ b/goal_src/jak1/engine/gfx/mood/time-of-day.gc @@ -553,9 +553,6 @@ (label output-complete)) (none)))) -(#when PC_PORT - (def-mips2c time-of-day-interp-colors-scratch (function (pointer rgba) time-of-day-palette mood-context none))) - (defun init-time-of-day-context ((context time-of-day-context)) "Initialize the fixed title-screen directional and ambient light colors and enable their levels." (set-vector! (-> context title-light-group dir0 color) 0.82 0.82 0.82 1.0) diff --git a/goal_src/jak1/engine/gfx/sky/sky-tng-ee-asm.gc b/goal_src/jak1/engine/gfx/sky/sky-tng-ee-asm.gc new file mode 100644 index 0000000000..3b731190e1 --- /dev/null +++ b/goal_src/jak1/engine/gfx/sky/sky-tng-ee-asm.gc @@ -0,0 +1,832 @@ +;;-*-Lisp-*- +(in-package goal) +(bundles "ENGINE.CGO" "GAME.CGO") +(require "engine/gfx/sky/sky-tng.gc") + +;; Reference-only Emotion Engine implementation of the original inline VU0 sky polygon renderer. +;; This file is intentionally not part of any project or DGO manifest. + +;; Each sky vertex is three consecutive quadwords: +;; +;; +0x00 homogeneous position +;; +0x10 perspective texture coordinates (s, t, q, unused) +;; +0x20 floating-point RGBA +;; +;; Polygon lists are closed by repeating the first complete 48-byte record after the last distinct +;; vertex. render-sky-tri and render-sky-quad transform their input into the scratch pages at +;; #x70003000 and #x70003800, preserving STQ and color. draw-large-polygon alternates those pages +;; through four Sutherland-Hodgman clipping passes before emitting ST/RGBAQ/XYZF into the DMA +;; buffer. The persistent VU0 registers are initialized once per layer: +;; +;; vf31..vf28 camera rows scaled into the homogeneous clip volume +;; vf26 inverse homogeneous scale used after clipping +;; vf25 screen/fog offset, with z forced to zero +;; vf24 normalized scrolling texture offset +;; vf23.x GS layer depth (zero normally, 256 for the base layer) +;; vf13 pfog0, fog-min, fog-max, and the 3071 fog ceiling +(#unless PC_PORT + (asm-data (label sky-fog-ceiling) + (word #x453ff000) ;; 3071.0 + (label sky-screen-offset-2049) + (word #x45001000) ;; 2049.0 + (label sky-texel-phase-scale) + (word #x37800000) ;; 1 / 65536 + (label sky-screen-offset-2047) + (word #x44ffe000)) ;; 2047.0 + (defun init-sky-regs () + "Load the camera, projection, fog, and initial layer state used by the inline VU0 sky path. + Select vertical screen offset 2049 when camera translation y is positive and 2047 otherwise." + (declare (asm-func none)) + (rlet ((camera :reg v1) + (screen-offset :reg a0) + (work :reg a1) + (address :reg a2) + (function-base :reg fp) + (result :reg v0)) + (add.i sp sp -32) + (s.d function-base sp 8) + (m function-base t9) + (m! camera *math-camera*) + (add.i screen-offset sp 16) + (s.q r0 screen-offset) + (m work screen-offset) + (lea.field address camera (hvdf-off)) + (l.q address address) + (s.q address work) + (m f0 r0) + (l.s.field f1 camera (trans y)) + (c.lt.s f0 f1) + (b.fpf sky-use-2047-offset :delay (nop!)) + (l.s f0 function-base sky-screen-offset-2049) + (s.s f0 screen-offset 4) + (m work f0) + (b sky-screen-offset-ready :delay (nop!)) + (label sky-use-2047-offset) + (l.s f0 function-base sky-screen-offset-2047) + (s.s f0 screen-offset 4) + (m work f0) + (label sky-screen-offset-ready) + ;; Keep the fog range beside the runtime texture state so the projection loop can retain it + ;; in vf13 without further scalar loads. + (m! work *sky-tng-data*) + (lea.field work work (fog)) + (l.s.field f0 camera (pfog0)) + (s.s f0 work) + (l.s.field f0 camera (fog-min)) + (s.s f0 work 4) + (l.s.field f0 camera (fog-max)) + (s.s f0 work 8) + (l.s f0 function-base sky-fog-ceiling) + (s.s f0 work 12) + (asm-block load-persistent-sky-vectors + (l.vf vf31 camera 572) + (l.vf vf30 camera 588) + (l.vf vf29 camera 604) + (l.vf vf28 camera 620) + (l.vf vf14 camera 700) + (l.vf vf26 camera 716) + (l.vf vf25 screen-offset) + (m! camera *sky-tng-data*) + (l.vf vf13 camera 60) + (mul.vf vf31 vf31 vf14) + (mul.vf vf30 vf30 vf14) + (mul.vf vf29 vf29 vf14) + (mul.vf vf28 vf28 vf14) + (vmove.z vf25 vf0) + (vmove.xyzw vf24 vf0) + (vmove.xyzw vf23 vf0)) + (m camera vf23) + (m result r0) + (l.d function-base sp 8) + (jr ra :delay (add.i sp sp 32)) + (nop! :count 3))) + (defun set-tex-offset ((s-offset int) (t-offset int)) + "Convert wrapped 16-bit texture phases to normalized offsets in vf24.xy; clear z and w." + (declare (asm-func none)) + (rlet ((offset :reg v1) + (function-base :reg fp) + (result :reg v0)) + (add.i sp sp -32) + (s.d function-base sp 8) + (m function-base t9) + (add.i offset sp 16) + (s.q r0 offset) + (l.s f0 function-base sky-texel-phase-scale) + (m f1 a0) + (cvt.s.w f1 f1) + (mul.s f0 f0 f1) + (s.s f0 offset) + (l.s f0 function-base sky-texel-phase-scale) + (m f1 a1) + (cvt.s.w f1 f1) + (mul.s f0 f0 f1) + (s.s f0 offset 4) + (m f0 r0) + (s.s f0 offset 8) + (m f0 r0) + (s.s f0 offset 12) + (l.vf vf24 offset) + (m offset vf24) + (m result r0) + (l.d function-base sp 8) + (jr ra :delay (add.i sp sp 32)) + (nop! :count 2))) + (defun draw-large-polygon () + "Clip the closed scratch polygon against the four side planes, then append its GS vertices. + The private calling convention carries the polygon count in t0, the DMA buffer in a1, and + the alternating scratch pages in t4 and t5. Return #f if clipping removes every vertex." + (declare (asm-func none)) + (nop!) + (add.i sp sp -8) + (nop!) + (s.d ra sp) + ;; Sutherland-Hodgman clipping alternates pages so that each pass may stream its output without + ;; disturbing unread input. t2 selects x or y within each position; the positive helper tests + ;; component <= w and the negative helper tests component >= -w. + (asm-block clip-sky-side-planes + (m! t9 clip-polygon-against-positive-hyperplane) + (m a2 t4) + (m a3 t5) + (jalr ra t9 :delay (add t2 a2 r0)) + (b.z t0 sky-polygon-clipped-away :delay (nop!)) + (m a2 t5) + (m a3 t4) + (jalr ra t9 :delay (add.i t2 a2 4)) + (b.z t0 sky-polygon-clipped-away :delay (m! t9 clip-polygon-against-negative-hyperplane)) + (m a2 t4) + (m a3 t5) + (jalr ra t9 :delay (add t2 a2 r0)) + (b.z t0 sky-polygon-clipped-away :delay (nop!)) + (m a2 t5) + (m a3 t4) + (jalr ra t9 :delay (add.i t2 a2 4)) + (b.z t0 sky-polygon-clipped-away :delay (l.w.field a3 a1 (base)))) + ;; vf27 is the GIF tag for this polygon. Its first word is replaced by the clipped vertex + ;; count before ST/RGBAQ/XYZF records are written behind it. + (m a2 t4) + (nop!) + (s.vf vf27 a3) + (add.i a3 a3 16) + (s.w t0 a3 -16) + (nop!) + (label emit-sky-polygon-vertices) + (asm-block project-sky-vertex + (l.vf vf1 a2) + (nop!) + (l.vf vf2 a2 16) + (nop!) + (l.vf vf3 a2 32) + ;; Recover 1/w after clipping, undo the homogeneous clip scale, and convert the packed color. + (vdiv Q vf0.w vf1.w) + (mul.vf vf1 vf1 vf26) + (nop!) + (ftoi.vf vf3 vf3) + (nop!) + ;; Add the scrolling phase before perspective division so STQ remains perspective correct. + (add.vf vf2 vf2 vf24) + (nop!) + (waitq) + (nop!) + (vmulq.xyz vf1 vf1 Q) + (s.vf vf3 a3 16) + (vmulq.xyzw vf2 vf2 Q) + (add.i a2 a2 48) + ;; Map to GS screen space. vf23.x selects the layer depth, while w becomes the clamped fog + ;; value carried in XYZF after 12.4 fixed-point conversion. + (add.vf vf1 vf1 vf25) + (add.i a3 a3 48) + (vmulz.z vf1 vf1 vf0) + (nop!) + (vminiz.w vf1 vf1 vf13) + (nop!) + (vaddx.z vf1 vf1 vf23) + (nop!) + (vmaxy.w vf1 vf1 vf13) + (nop!) + (s.vf vf2 a3 -48) + (add.i t0 t0 -1) + (vftoi4.xyzw vf1 vf1) + (nop!) + (b.nz t0 emit-sky-polygon-vertices :delay (s.vf vf1 a3 -16))) + (s.w.field a3 a1 (base)) + (nop!) + (l.d ra sp) + (add.i v0 s7 8) + (jr ra :delay (add.i sp sp 8)) + (label sky-polygon-clipped-away) + (l.d ra sp) + (m v0 s7) + (jr ra :delay (add.i sp sp 8)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2)) + (defun clip-polygon-against-positive-hyperplane () + "Clip a closed scratch polygon against component <= w. t2 points at the selected x or y + component of the first position, a2 and a3 are the input and output pages, and t0 is replaced + by the output vertex count. Every crossing interpolates position, STQ, and color together." + (declare (asm-func none)) + (asm-block classify-first-positive-vertex + (nop!) + (m t1 t0) + (add.i t0 r0 0) + (l.s f1 t2) + (add.i t2 t2 48) + (l.s f0 a2 12) + (m t3 a3) + (l.vf vf1 a2) + (add.i a2 a2 48) + (c.lt.s f0 f1) + (l.vf vf2 a2 -32) + (b.fpf positive-inside-a :delay (l.vf vf3 a2 -16))) + ;; The a/b paths alternate vf1..vf3 and vf4..vf6 as the previous and current records. This + ;; avoids moving the three qwords at every edge while retaining the closed-list traversal. + (asm-block walk-positive-outside + (label positive-outside-a) + (l.s f3 t2) + (add.i t2 t2 48) + (l.s f2 a2 12) + (add.i t1 t1 -1) + (l.vf vf4 a2) + (add.i a2 a2 48) + (c.lt.s f2 f3) + (l.vf vf5 a2 -32) + (b.fpf positive-enter-from-a :delay (l.vf vf6 a2 -16)) + (b.z t1 positive-clip-finish :delay (nop!)) + (label positive-outside-b) + (l.s f1 t2) + (add.i t2 t2 48) + (l.s f0 a2 12) + (add.i t1 t1 -1) + (l.vf vf1 a2) + (add.i a2 a2 48) + (c.lt.s f0 f1) + (l.vf vf2 a2 -32) + (b.fpf positive-enter-from-b :delay (l.vf vf3 a2 -16)) + (b.nz t1 positive-outside-a :delay (nop!)) + (b positive-clip-finish :delay (nop!)) + ;; Outside -> inside: solve the plane distance linearly and append only the crossing point. + ;; The inside endpoint remains current and is emitted by the following inside path. + (label positive-enter-from-a) + (sub.s f7 f0 f1) + (sub.vf vf7 vf4 vf1) + (sub.s f8 f2 f3) + (sub.vf vf8 vf5 vf2) + (sub.s f5 f7 f8) + (sub.vf vf9 vf6 vf3) + (div.s f6 f7 f5) + (add.i a3 a3 48) + (m v1 f6) + (m vf10 v1) + (add.i t0 t0 1) + (mula.w.vf vf1 vf0) + (add.i t6 s7 8) + (vmaddx.xyzw vf7 vf7 vf10) + (nop!) + (mula.w.vf vf2 vf0) + (nop!) + (vmaddx.xyzw vf8 vf8 vf10) + (nop!) + (mula.w.vf vf3 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.nz t1 positive-inside-b :delay (s.vf vf9 a3 -16)) + (b positive-clip-finish :delay (nop!)) + (label positive-enter-from-b) + (sub.s f7 f0 f1) + (sub.vf vf7 vf1 vf4) + (sub.s f8 f2 f3) + (sub.vf vf8 vf2 vf5) + (sub.s f5 f8 f7) + (sub.vf vf9 vf3 vf6) + (div.s f6 f8 f5) + (add.i a3 a3 48) + (m v1 f6) + (m vf10 v1) + (add.i t0 t0 1) + (mula.w.vf vf4 vf0) + (add.i t6 s7 8) + (vmaddx.xyzw vf7 vf7 vf10) + (nop!) + (mula.w.vf vf5 vf0) + (nop!) + (vmaddx.xyzw vf8 vf8 vf10) + (nop!) + (mula.w.vf vf6 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.z t1 positive-clip-finish :delay (s.vf vf9 a3 -16))) + ;; Inside -> inside copies the previous record. If the next record is outside, the leave path + ;; copies the inside endpoint and appends the crossing point as a second record. + (asm-block walk-positive-inside + (label positive-inside-a) + (l.s f3 t2) + (add.i t2 t2 48) + (l.s f2 a2 12) + (add.i t1 t1 -1) + (l.vf vf4 a2) + (add.i a2 a2 48) + (c.lt.s f2 f3) + (l.vf vf5 a2 -32) + (b.fpt positive-leave-from-a :delay (l.vf vf6 a2 -16)) + (s.vf vf1 a3) + (add.i a3 a3 48) + (s.vf vf2 a3 -32) + (add.i t0 t0 1) + (b.z t1 positive-clip-finish :delay (s.vf vf3 a3 -16)) + (label positive-inside-b) + (l.s f1 t2) + (add.i t2 t2 48) + (l.s f0 a2 12) + (add.i t1 t1 -1) + (l.vf vf1 a2) + (add.i a2 a2 48) + (c.lt.s f0 f1) + (l.vf vf2 a2 -32) + (b.fpt positive-leave-from-b :delay (l.vf vf3 a2 -16)) + (s.vf vf4 a3) + (add.i a3 a3 48) + (s.vf vf5 a3 -32) + (add.i t0 t0 1) + (b.nz t1 positive-inside-a :delay (s.vf vf6 a3 -16)) + (b positive-clip-finish :delay (nop!)) + (label positive-leave-from-a) + (sub.s f7 f0 f1) + (sub.vf vf7 vf1 vf4) + (sub.s f8 f2 f3) + (sub.vf vf8 vf2 vf5) + (sub.s f5 f8 f7) + (sub.vf vf9 vf3 vf6) + (div.s f6 f8 f5) + (add.i a3 a3 96) + (m v1 f6) + (m vf10 v1) + (s.vf vf1 a3 -96) + (mula.w.vf vf4 vf0) + (s.vf vf2 a3 -80) + (vmaddx.xyzw vf7 vf7 vf10) + (s.vf vf3 a3 -64) + (mula.w.vf vf5 vf0) + (add.i t0 t0 2) + (vmaddx.xyzw vf8 vf8 vf10) + (add.i t6 s7 8) + (mula.w.vf vf6 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.nz t1 positive-outside-b :delay (s.vf vf9 a3 -16)) + (b positive-clip-finish :delay (nop!)) + (label positive-leave-from-b) + (sub.s f7 f0 f1) + (sub.vf vf7 vf4 vf1) + (sub.s f8 f2 f3) + (sub.vf vf8 vf5 vf2) + (sub.s f5 f7 f8) + (sub.vf vf9 vf6 vf3) + (div.s f6 f7 f5) + (add.i a3 a3 96) + (m v1 f6) + (m vf10 v1) + (s.vf vf4 a3 -96) + (mula.w.vf vf1 vf0) + (s.vf vf5 a3 -80) + (vmaddx.xyzw vf7 vf7 vf10) + (s.vf vf6 a3 -64) + (mula.w.vf vf2 vf0) + (add.i t0 t0 2) + (vmaddx.xyzw vf8 vf8 vf10) + (add.i t6 s7 8) + (mula.w.vf vf3 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.nz t1 positive-outside-a :delay (s.vf vf9 a3 -16))) + ;; Restore the closed representation expected by the next clipping pass. + (asm-block close-positive-polygon + (label positive-clip-finish) + (l.vf vf1 t3) + (nop!) + (l.vf vf2 t3 16) + (nop!) + (l.vf vf3 t3 32) + (nop!) + (s.vf vf1 a3) + (nop!) + (s.vf vf2 a3 16) + (nop!) + (jr ra :delay (s.vf vf3 a3 32)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2))) + (defun clip-polygon-against-negative-hyperplane () + "Clip a closed scratch polygon against component >= -w. This is the negative-plane mirror of + clip-polygon-against-positive-hyperplane and uses the same private registers and closed output + format." + (declare (asm-func none)) + (asm-block classify-first-negative-vertex + (nop!) + (m t1 t0) + (add.i t0 r0 0) + (l.s f0 a2 12) + (m t3 a3) + (l.s f1 t2) + (add.i t2 t2 48) + (l.vf vf1 a2) + (neg.s f0 f0) + (nop!) + (l.vf vf2 a2 16) + (c.lt.s f1 f0) + (add.i a2 a2 48) + (b.fpf negative-inside-a :delay (l.vf vf3 a2 -16))) + ;; The two paths alternate register triples instead of copying the current 48-byte record. + (asm-block walk-negative-outside + (label negative-outside-a) + (l.s f2 a2 12) + (add.i t1 t1 -1) + (l.s f3 t2) + (add.i t2 t2 48) + (l.vf vf4 a2) + (neg.s f2 f2) + (nop!) + (l.vf vf5 a2 16) + (c.lt.s f3 f2) + (add.i a2 a2 48) + (b.fpf negative-enter-from-a :delay (l.vf vf6 a2 -16)) + (b.z t1 negative-clip-finish :delay (nop!)) + (label negative-outside-b) + (l.s f0 a2 12) + (add.i t1 t1 -1) + (l.s f1 t2) + (add.i t2 t2 48) + (l.vf vf1 a2) + (neg.s f0 f0) + (nop!) + (l.vf vf2 a2 16) + (c.lt.s f1 f0) + (add.i a2 a2 48) + (b.fpf negative-enter-from-b :delay (l.vf vf3 a2 -16)) + (b.nz t1 negative-outside-a :delay (nop!)) + (b negative-clip-finish :delay (nop!)) + ;; Outside -> inside writes the interpolated crossing. f6 is the edge fraction measured from + ;; the outside endpoint; the same fraction is applied to position, STQ, and color. + (label negative-enter-from-a) + (sub.s f7 f0 f1) + (sub.vf vf7 vf4 vf1) + (sub.s f8 f2 f3) + (sub.vf vf8 vf5 vf2) + (sub.s f5 f7 f8) + (sub.vf vf9 vf6 vf3) + (div.s f6 f7 f5) + (add.i a3 a3 48) + (m v1 f6) + (m vf10 v1) + (add.i t0 t0 1) + (mula.w.vf vf1 vf0) + (add.i t6 s7 8) + (vmaddx.xyzw vf7 vf7 vf10) + (nop!) + (mula.w.vf vf2 vf0) + (nop!) + (vmaddx.xyzw vf8 vf8 vf10) + (nop!) + (mula.w.vf vf3 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.nz t1 negative-inside-b :delay (s.vf vf9 a3 -16)) + (b negative-clip-finish :delay (nop!)) + (label negative-enter-from-b) + (sub.s f7 f0 f1) + (sub.vf vf7 vf1 vf4) + (sub.s f8 f2 f3) + (sub.vf vf8 vf2 vf5) + (sub.s f5 f8 f7) + (sub.vf vf9 vf3 vf6) + (div.s f6 f8 f5) + (add.i a3 a3 48) + (m v1 f6) + (m vf10 v1) + (add.i t0 t0 1) + (mula.w.vf vf4 vf0) + (add.i t6 s7 8) + (vmaddx.xyzw vf7 vf7 vf10) + (nop!) + (mula.w.vf vf5 vf0) + (nop!) + (vmaddx.xyzw vf8 vf8 vf10) + (nop!) + (mula.w.vf vf6 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.z t1 negative-clip-finish :delay (s.vf vf9 a3 -16))) + ;; Inside runs copy their previous record. A leaving edge emits the inside endpoint followed + ;; by the intersection, which is why those paths advance the output by two records. + (asm-block walk-negative-inside + (label negative-inside-a) + (l.s f2 a2 12) + (add.i t1 t1 -1) + (l.s f3 t2) + (add.i t2 t2 48) + (l.vf vf4 a2) + (neg.s f2 f2) + (nop!) + (l.vf vf5 a2 16) + (c.lt.s f3 f2) + (add.i a2 a2 48) + (b.fpt negative-leave-from-a :delay (l.vf vf6 a2 -16)) + (s.vf vf1 a3) + (add.i a3 a3 48) + (s.vf vf2 a3 -32) + (add.i t0 t0 1) + (b.z t1 negative-clip-finish :delay (s.vf vf3 a3 -16)) + (label negative-inside-b) + (l.s f0 a2 12) + (add.i t1 t1 -1) + (l.s f1 t2) + (add.i t2 t2 48) + (l.vf vf1 a2) + (neg.s f0 f0) + (nop!) + (l.vf vf2 a2 16) + (c.lt.s f1 f0) + (add.i a2 a2 48) + (b.fpt negative-leave-from-b :delay (l.vf vf3 a2 -16)) + (s.vf vf4 a3) + (add.i a3 a3 48) + (s.vf vf5 a3 -32) + (add.i t0 t0 1) + (b.nz t1 negative-inside-a :delay (s.vf vf6 a3 -16)) + (b negative-clip-finish :delay (nop!)) + (label negative-leave-from-a) + (sub.s f7 f0 f1) + (sub.vf vf7 vf1 vf4) + (sub.s f8 f2 f3) + (sub.vf vf8 vf2 vf5) + (sub.s f5 f8 f7) + (sub.vf vf9 vf3 vf6) + (div.s f6 f8 f5) + (add.i a3 a3 96) + (m v1 f6) + (m vf10 v1) + (s.vf vf1 a3 -96) + (mula.w.vf vf4 vf0) + (s.vf vf2 a3 -80) + (vmaddx.xyzw vf7 vf7 vf10) + (s.vf vf3 a3 -64) + (mula.w.vf vf5 vf0) + (add.i t0 t0 2) + (vmaddx.xyzw vf8 vf8 vf10) + (add.i t6 s7 8) + (mula.w.vf vf6 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.nz t1 negative-outside-b :delay (s.vf vf9 a3 -16)) + (b negative-clip-finish :delay (nop!)) + (label negative-leave-from-b) + (sub.s f7 f0 f1) + (sub.vf vf7 vf4 vf1) + (sub.s f8 f2 f3) + (sub.vf vf8 vf5 vf2) + (sub.s f5 f7 f8) + (sub.vf vf9 vf6 vf3) + (div.s f6 f7 f5) + (add.i a3 a3 96) + (m v1 f6) + (m vf10 v1) + (s.vf vf4 a3 -96) + (mula.w.vf vf1 vf0) + (s.vf vf5 a3 -80) + (vmaddx.xyzw vf7 vf7 vf10) + (s.vf vf6 a3 -64) + (mula.w.vf vf2 vf0) + (add.i t0 t0 2) + (vmaddx.xyzw vf8 vf8 vf10) + (add.i t6 s7 8) + (mula.w.vf vf3 vf0) + (nop!) + (vmaddx.xyzw vf9 vf9 vf10) + (nop!) + (s.vf vf7 a3 -48) + (nop!) + (s.vf vf8 a3 -32) + (nop!) + (b.nz t1 negative-outside-a :delay (s.vf vf9 a3 -16))) + (asm-block close-negative-polygon + (label negative-clip-finish) + (l.vf vf1 t3) + (nop!) + (l.vf vf2 t3 16) + (nop!) + (l.vf vf3 t3 32) + (nop!) + (s.vf vf1 a3) + (nop!) + (s.vf vf2 a3 16) + (nop!) + (jr ra :delay (s.vf vf3 a3 32)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2))) + (defun render-sky-quad ((vertices (inline-array sky-vertex)) (dma-buf dma-buffer)) + "Transform four sky vertices into a closed five-record scratch polygon and tail-call the + clipping and packet conversion path." + (declare (asm-func none)) + ;; vf31..vf28 are the persistent camera rows from init-sky-regs. Only x, y, and w are retained; + ;; z is cleared so the final layer depth is supplied explicitly by vf23.x. + (asm-block prepare-sky-quad + (m v1 a0) + (m! v1 *math-camera*) + ;; Refresh the homogeneous scale with the rest of the camera state before building the page. + (l.vf vf14 v1 700) + (lui t4 #x7000) + (ori t4 t4 #x3000) + (lui t5 #x7000) + (ori t5 t5 #x3800) + (lui v1 #x3000) + (m a3 t4) + (or a0 a0 v1) + (nop!) + (l.vf vf1 a0) + (add.i t0 r0 4) + (l.vf vf2 a0 16) + (nop!) + (l.vf vf3 a0 32) + (mula.x.vf vf31 vf1) + (l.vf vf4 a0 48) + (madda.y.vf vf30 vf1) + (l.vf vf5 a0 64) + (madda.z.vf vf29 vf1) + (l.vf vf6 a0 80) + (vmaddw.xyw vf1 vf28 vf1) + (l.vf vf7 a0 96) + (vmove.z vf1 vf0) + (l.vf vf8 a0 112) + (mula.x.vf vf31 vf4) + (l.vf vf9 a0 128) + (madda.y.vf vf30 vf4) + (l.vf vf10 a0 144) + (madda.z.vf vf29 vf4) + (l.vf vf11 a0 160) + (vmaddw.xyw vf4 vf28 vf4) + (l.vf vf12 a0 176) + (vmove.z vf4 vf0)) + (asm-block finish-sky-quad + (s.vf vf2 a3 16) + (mula.x.vf vf31 vf7) + (s.vf vf3 a3 32) + (madda.y.vf vf30 vf7) + (s.vf vf5 a3 64) + (madda.z.vf vf29 vf7) + (s.vf vf6 a3 80) + (vmaddw.xyw vf7 vf28 vf7) + (s.vf vf8 a3 112) + (vmove.z vf7 vf0) + (s.vf vf9 a3 128) + (mula.x.vf vf31 vf10) + (s.vf vf11 a3 160) + (madda.y.vf vf30 vf10) + (s.vf vf12 a3 176) + (madda.z.vf vf29 vf10) + (s.vf vf2 a3 208) + (vmaddw.xyw vf10 vf28 vf10) + (s.vf vf3 a3 224) + (vmove.z vf10 vf0) + (s.vf vf1 a3) + (nop!) + ;; Repeat record zero after record three to close the list. + (s.vf vf1 a3 192) + (nop!) + (s.vf vf4 a3 48) + (nop!) + (s.vf vf7 a3 96) + (nop!) + (s.vf vf10 a3 144) + (m! t9 draw-large-polygon) + (jr t9 :delay (nop!)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2))) + (defun render-sky-tri ((vertices (inline-array sky-vertex)) (dma-buf dma-buffer)) + "Transform three sky vertices into a closed four-record scratch polygon and tail-call the + clipping and packet conversion path." + (declare (asm-func none)) + (asm-block prepare-sky-triangle + (m v1 a0) + (lui t4 #x7000) + (ori t4 t4 #x3000) + (lui t5 #x7000) + (ori t5 t5 #x3800) + (lui v1 #x3000) + (m a3 t4) + (or a0 a0 v1) + (nop!) + (l.vf vf1 a0) + (add.i t0 r0 3) + (l.vf vf2 a0 16) + (nop!) + (l.vf vf3 a0 32) + (mula.x.vf vf31 vf1) + (l.vf vf4 a0 48) + (madda.y.vf vf30 vf1) + (l.vf vf5 a0 64) + (madda.z.vf vf29 vf1) + (l.vf vf6 a0 80) + (vmaddw.xyw vf1 vf28 vf1) + (l.vf vf7 a0 96) + (vmove.z vf1 vf0) + (l.vf vf8 a0 112) + (mula.x.vf vf31 vf4) + (l.vf vf9 a0 128) + (madda.y.vf vf30 vf4) + (s.vf vf2 a3 16) + (madda.z.vf vf29 vf4) + (s.vf vf3 a3 32) + (vmaddw.xyw vf4 vf28 vf4) + (s.vf vf5 a3 64) + (vmove.z vf4 vf0) + (s.vf vf6 a3 80) + (mula.x.vf vf31 vf7) + (s.vf vf8 a3 112) + (madda.y.vf vf30 vf7) + (s.vf vf9 a3 128) + (madda.z.vf vf29 vf7) + (s.vf vf2 a3 160) + (vmaddw.xyw vf7 vf28 vf7) + (s.vf vf3 a3 176) + (vmove.z vf7 vf0) + (s.vf vf1 a3) + (nop!) + ;; Repeat record zero after record two to close the list. + (s.vf vf1 a3 144) + (nop!) + (s.vf vf4 a3 48) + (nop!) + (s.vf vf7 a3 96) + (m! t9 draw-large-polygon) + (jr t9 :delay (nop!)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2))) + (defun sky-duplicate-polys ((dma-buf dma-buffer) (begin (pointer uint128)) (end (pointer uint128))) + "Append the half-open quadword range [begin, end) to dma-buf. An empty or reversed range writes + nothing." + (declare (asm-func none)) + (rlet ((cursor :reg v1) + (quad :reg a3 :class i128) + (result :reg v0)) + (l.w.field cursor a0 (base)) + (b sky-duplicate-test :delay (nop!)) + (label sky-duplicate-copy) + (l.q quad a1) + (s.q quad cursor) + (add.i cursor cursor 16) + (add.i a1 a1 16) + (label sky-duplicate-test) + (slt a3 a1 a2) + (b.nz a3 sky-duplicate-copy :delay (nop!)) + (m a1 s7) + (s.w.field cursor a0 (base)) + (m result r0) + (jr ra :delay (add sp sp r0)) + (nop! :count 2))) + (defun close-sky-buffer ((dma-buf dma-buffer)) + "Append the #x8000 terminator for a large-polygon stream and advance the buffer by one qword." + (declare (asm-func none)) + (rlet ((terminator :reg v1) + (cursor :reg v0)) + (nop!) + (ori terminator r0 #x8000) + (l.w.field cursor a0 (base)) + (s.q r0 cursor) + (nop!) + (s.w terminator cursor) + (add.i cursor cursor 16) + (jr ra :delay (s.w.field cursor a0 (base))) + (jr ra :delay (add sp sp r0)) + (nop! :count 2)))) diff --git a/goal_src/jak1/engine/gfx/sky/sky-tng.gc b/goal_src/jak1/engine/gfx/sky/sky-tng.gc index 0888f00796..33378c9b10 100644 --- a/goal_src/jak1/engine/gfx/sky/sky-tng.gc +++ b/goal_src/jak1/engine/gfx/sky/sky-tng.gc @@ -9,6 +9,9 @@ ;; DECOMP BEGINS +;; Initialize DMA templates in *sky-work* +;; The sky renderer creates a sky and a cloud texture from interpolating (blending) two base textures, +;; then draws very large polygons. (define *sky-work* (new 'static 'sky-work @@ -83,26 +86,27 @@ :regs2 (gif-reg-id xyzf2) :regs3 (gif-reg-id uv) :regs4 (gif-reg-id xyzf2))) + ;; GS vertex data for drawing to texture :sky-data (new 'static 'inline-array qword 5 - (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #x0 #x80)) - (new 'static 'qword) - (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #xffffff #x0)) - (new 'static 'qword :data (new 'static 'array uint32 4 #x200 #x200 #x0 #x0)) - (new 'static 'qword :data (new 'static 'array uint32 4 #x200 #x200 #xffffff #x0))) + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #x0 #x80)) ;; RGBA + (new 'static 'qword) ;; UV0 + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #xffffff #x0)) ;; XYZF0 + (new 'static 'qword :data (new 'static 'array uint32 4 #x200 #x200 #x0 #x0)) ;; UV1 + (new 'static 'qword :data (new 'static 'array uint32 4 #x200 #x200 #xffffff #x0))) ;; XYZF1 :cloud-data (new 'static 'inline-array qword 5 - (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #x0 #x80)) - (new 'static 'qword) - (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x200 #xffffff #x0)) - (new 'static 'qword :data (new 'static 'array uint32 4 #x400 #x400 #x0 #x0)) - (new 'static 'qword :data (new 'static 'array uint32 4 #x400 #x600 #xffffff #x0))))) + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x0 #x0 #x80)) ;; RGBA + (new 'static 'qword) ;; UV0 + (new 'static 'qword :data (new 'static 'array uint32 4 #x0 #x200 #xffffff #x0)) ;; XYZF0 + (new 'static 'qword :data (new 'static 'array uint32 4 #x400 #x400 #x0 #x0)) ;; UV1 + (new 'static 'qword :data (new 'static 'array uint32 4 #x400 #x600 #xffffff #x0))))) ;; XYZF1 (defun init-sky-tng-data ((data sky-tng-data)) "Initialize the untextured base, alpha-blended textured roof, and fogged ocean giftags, then @@ -172,860 +176,276 @@ 0 (none)) -;; The PC renderer keeps the persistent VU0 values in its MIPS2C context. -(#when PC_PORT - (def-mips2c init-sky-regs (function none)) - (def-mips2c set-sky-vf27 (function object none)) - (def-mips2c set-sky-vf23-value (function int none))) +;; The sky polygon renderer abused standard calling-convention and stashed intermediate values +;; in registers. We've rewritten that and use this as the context instead. -;; The rest of the PC path shares that context and the two emulated scratch pages. -(#when PC_PORT - (def-mips2c set-tex-offset (function int int none)) - (def-mips2c draw-large-polygon function) - ;;(def-mips2c clip-polygon-against-positive-hyperplane function) - ;;(def-mips2c clip-polygon-against-negative-hyperplane function) - (def-mips2c render-sky-quad (function (inline-array sky-vertex) dma-buffer none)) - (def-mips2c render-sky-tri (function (inline-array sky-vertex) dma-buffer none)) - (defun close-sky-buffer ((dma-buf dma-buffer)) - "Append the #x8000 terminator for the current large-polygon stream and advance the DMA buffer by - one qword." - (nop!) - (let ((terminator #x8000) - (cursor (-> dma-buf base))) - (set! (-> (the-as (pointer int128) cursor)) (the int128 0)) - (nop!) - (set! (-> (the-as (pointer int32) cursor)) terminator) - (let ((next-cursor (&+ cursor 16))) - ;; Advance the caller's cursor in the return delay slot. - ;;(.jr ra-0) - (set! (-> dma-buf base) next-cursor))) - (none))) +(deftype sky-polygon-renderer-state (basic) + ((transform matrix :inline) + (inv-hmge-scale vector :inline) + (screen-offset vector :inline) + (texture-offset vector :inline) + (fog-clamp vector :inline) + (giftag gs-gif-tag :inline) + (layer-depth float) + (vertex-count int32) + (dma-buf dma-buffer) + (vertices-a sky-vertex 12 :inline) + (vertices-b sky-vertex 12 :inline))) -;; Each sky vertex is three consecutive quadwords: -;; -;; +0x00 homogeneous position -;; +0x10 perspective texture coordinates (s, t, q, unused) -;; +0x20 floating-point RGBA -;; -;; Polygon lists are closed by repeating the first complete 48-byte record after the last distinct -;; vertex. render-sky-tri and render-sky-quad transform their input into the scratch pages at -;; #x70003000 and #x70003800, preserving STQ and color. draw-large-polygon alternates those pages -;; through four Sutherland-Hodgman clipping passes before emitting ST/RGBAQ/XYZF into the DMA -;; buffer. The persistent VU0 registers are initialized once per layer: -;; -;; vf31..vf28 camera rows scaled into the homogeneous clip volume -;; vf26 inverse homogeneous scale used after clipping -;; vf25 screen/fog offset, with z forced to zero -;; vf24 normalized scrolling texture offset -;; vf23.x GS layer depth (zero normally, 256 for the base layer) -;; vf13 pfog0, fog-min, fog-max, and the 3071 fog ceiling -(#unless PC_PORT - (asm-data (label sky-fog-ceiling) - (word #x453ff000) ;; 3071.0 - (label sky-screen-offset-2049) - (word #x45001000) ;; 2049.0 - (label sky-texel-phase-scale) - (word #x37800000) ;; 1 / 65536 - (label sky-screen-offset-2047) - (word #x44ffe000)) ;; 2047.0 - (defun init-sky-regs () - "Load the camera, projection, fog, and initial layer state used by the inline VU0 sky path. - Select vertical screen offset 2049 when camera translation y is positive and 2047 otherwise." - (declare (asm-func none)) - (rlet ((camera :reg v1) - (screen-offset :reg a0) - (work :reg a1) - (address :reg a2) - (function-base :reg fp) - (result :reg v0)) - (add.i sp sp -32) - (s.d function-base sp 8) - (m function-base t9) - (m! camera *math-camera*) - (add.i screen-offset sp 16) - (s.q r0 screen-offset) - (m work screen-offset) - (lea.field address camera (hvdf-off)) - (l.q address address) - (s.q address work) - (m f0 r0) - (l.s.field f1 camera (trans y)) - (c.lt.s f0 f1) - (b.fpf sky-use-2047-offset :delay (nop!)) - (l.s f0 function-base sky-screen-offset-2049) - (s.s f0 screen-offset 4) - (m work f0) - (b sky-screen-offset-ready :delay (nop!)) - (label sky-use-2047-offset) - (l.s f0 function-base sky-screen-offset-2047) - (s.s f0 screen-offset 4) - (m work f0) - (label sky-screen-offset-ready) - ;; Keep the fog range beside the runtime texture state so the projection loop can retain it - ;; in vf13 without further scalar loads. - (m! work *sky-tng-data*) - (lea.field work work (fog)) - (l.s.field f0 camera (pfog0)) - (s.s f0 work) - (l.s.field f0 camera (fog-min)) - (s.s f0 work 4) - (l.s.field f0 camera (fog-max)) - (s.s f0 work 8) - (l.s f0 function-base sky-fog-ceiling) - (s.s f0 work 12) - (asm-block load-persistent-sky-vectors - (l.vf vf31 camera 572) - (l.vf vf30 camera 588) - (l.vf vf29 camera 604) - (l.vf vf28 camera 620) - (l.vf vf14 camera 700) - (l.vf vf26 camera 716) - (l.vf vf25 screen-offset) - (m! camera *sky-tng-data*) - (l.vf vf13 camera 60) - (mul.vf vf31 vf31 vf14) - (mul.vf vf30 vf30 vf14) - (mul.vf vf29 vf29 vf14) - (mul.vf vf28 vf28 vf14) - (vmove.z vf25 vf0) - (vmove.xyzw vf24 vf0) - (vmove.xyzw vf23 vf0)) - (m camera vf23) - (m result r0) - (l.d function-base sp 8) - (jr ra :delay (add.i sp sp 32)) - (nop! :count 3))) - (defun set-tex-offset ((s-offset int) (t-offset int)) - "Convert wrapped 16-bit texture phases to normalized offsets in vf24.xy; clear z and w." - (declare (asm-func none)) - (rlet ((offset :reg v1) - (function-base :reg fp) - (result :reg v0)) - (add.i sp sp -32) - (s.d function-base sp 8) - (m function-base t9) - (add.i offset sp 16) - (s.q r0 offset) - (l.s f0 function-base sky-texel-phase-scale) - (m f1 a0) - (cvt.s.w f1 f1) - (mul.s f0 f0 f1) - (s.s f0 offset) - (l.s f0 function-base sky-texel-phase-scale) - (m f1 a1) - (cvt.s.w f1 f1) - (mul.s f0 f0 f1) - (s.s f0 offset 4) - (m f0 r0) - (s.s f0 offset 8) - (m f0 r0) - (s.s f0 offset 12) - (l.vf vf24 offset) - (m offset vf24) - (m result r0) - (l.d function-base sp 8) - (jr ra :delay (add.i sp sp 32)) - (nop! :count 2))) - (defun draw-large-polygon () - "Clip the closed scratch polygon against the four side planes, then append its GS vertices. - The private calling convention carries the polygon count in t0, the DMA buffer in a1, and - the alternating scratch pages in t4 and t5. Return #f if clipping removes every vertex." - (declare (asm-func none)) - (nop!) - (add.i sp sp -8) - (nop!) - (s.d ra sp) - ;; Sutherland-Hodgman clipping alternates pages so that each pass may stream its output without - ;; disturbing unread input. t2 selects x or y within each position; the positive helper tests - ;; component <= w and the negative helper tests component >= -w. - (asm-block clip-sky-side-planes - (m! t9 clip-polygon-against-positive-hyperplane) - (m a2 t4) - (m a3 t5) - (jalr ra t9 :delay (add t2 a2 r0)) - (b.z t0 sky-polygon-clipped-away :delay (nop!)) - (m a2 t5) - (m a3 t4) - (jalr ra t9 :delay (add.i t2 a2 4)) - (b.z t0 sky-polygon-clipped-away :delay (m! t9 clip-polygon-against-negative-hyperplane)) - (m a2 t4) - (m a3 t5) - (jalr ra t9 :delay (add t2 a2 r0)) - (b.z t0 sky-polygon-clipped-away :delay (nop!)) - (m a2 t5) - (m a3 t4) - (jalr ra t9 :delay (add.i t2 a2 4)) - (b.z t0 sky-polygon-clipped-away :delay (l.w.field a3 a1 (base)))) - ;; vf27 is the GIF tag for this polygon. Its first word is replaced by the clipped vertex - ;; count before ST/RGBAQ/XYZF records are written behind it. - (m a2 t4) - (nop!) - (s.vf vf27 a3) - (add.i a3 a3 16) - (s.w t0 a3 -16) - (nop!) - (label emit-sky-polygon-vertices) - (asm-block project-sky-vertex - (l.vf vf1 a2) - (nop!) - (l.vf vf2 a2 16) - (nop!) - (l.vf vf3 a2 32) - ;; Recover 1/w after clipping, undo the homogeneous clip scale, and convert the packed color. - (vdiv Q vf0.w vf1.w) - (mul.vf vf1 vf1 vf26) - (nop!) - (ftoi.vf vf3 vf3) - (nop!) - ;; Add the scrolling phase before perspective division so STQ remains perspective correct. - (add.vf vf2 vf2 vf24) - (nop!) - (waitq) - (nop!) - (vmulq.xyz vf1 vf1 Q) - (s.vf vf3 a3 16) - (vmulq.xyzw vf2 vf2 Q) - (add.i a2 a2 48) - ;; Map to GS screen space. vf23.x selects the layer depth, while w becomes the clamped fog - ;; value carried in XYZF after 12.4 fixed-point conversion. - (add.vf vf1 vf1 vf25) - (add.i a3 a3 48) - (vmulz.z vf1 vf1 vf0) - (nop!) - (vminiz.w vf1 vf1 vf13) - (nop!) - (vaddx.z vf1 vf1 vf23) - (nop!) - (vmaxy.w vf1 vf1 vf13) - (nop!) - (s.vf vf2 a3 -48) - (add.i t0 t0 -1) - (vftoi4.xyzw vf1 vf1) - (nop!) - (b.nz t0 emit-sky-polygon-vertices :delay (s.vf vf1 a3 -16))) - (s.w.field a3 a1 (base)) - (nop!) - (l.d ra sp) - (add.i v0 s7 8) - (jr ra :delay (add.i sp sp 8)) - (label sky-polygon-clipped-away) - (l.d ra sp) - (m v0 s7) - (jr ra :delay (add.i sp sp 8)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2)) - (defun clip-polygon-against-positive-hyperplane () - "Clip a closed scratch polygon against component <= w. t2 points at the selected x or y - component of the first position, a2 and a3 are the input and output pages, and t0 is replaced - by the output vertex count. Every crossing interpolates position, STQ, and color together." - (declare (asm-func none)) - (asm-block classify-first-positive-vertex - (nop!) - (m t1 t0) - (add.i t0 r0 0) - (l.s f1 t2) - (add.i t2 t2 48) - (l.s f0 a2 12) - (m t3 a3) - (l.vf vf1 a2) - (add.i a2 a2 48) - (c.lt.s f0 f1) - (l.vf vf2 a2 -32) - (b.fpf positive-inside-a :delay (l.vf vf3 a2 -16))) - ;; The a/b paths alternate vf1..vf3 and vf4..vf6 as the previous and current records. This - ;; avoids moving the three qwords at every edge while retaining the closed-list traversal. - (asm-block walk-positive-outside - (label positive-outside-a) - (l.s f3 t2) - (add.i t2 t2 48) - (l.s f2 a2 12) - (add.i t1 t1 -1) - (l.vf vf4 a2) - (add.i a2 a2 48) - (c.lt.s f2 f3) - (l.vf vf5 a2 -32) - (b.fpf positive-enter-from-a :delay (l.vf vf6 a2 -16)) - (b.z t1 positive-clip-finish :delay (nop!)) - (label positive-outside-b) - (l.s f1 t2) - (add.i t2 t2 48) - (l.s f0 a2 12) - (add.i t1 t1 -1) - (l.vf vf1 a2) - (add.i a2 a2 48) - (c.lt.s f0 f1) - (l.vf vf2 a2 -32) - (b.fpf positive-enter-from-b :delay (l.vf vf3 a2 -16)) - (b.nz t1 positive-outside-a :delay (nop!)) - (b positive-clip-finish :delay (nop!)) - ;; Outside -> inside: solve the plane distance linearly and append only the crossing point. - ;; The inside endpoint remains current and is emitted by the following inside path. - (label positive-enter-from-a) - (sub.s f7 f0 f1) - (sub.vf vf7 vf4 vf1) - (sub.s f8 f2 f3) - (sub.vf vf8 vf5 vf2) - (sub.s f5 f7 f8) - (sub.vf vf9 vf6 vf3) - (div.s f6 f7 f5) - (add.i a3 a3 48) - (m v1 f6) - (m vf10 v1) - (add.i t0 t0 1) - (mula.w.vf vf1 vf0) - (add.i t6 s7 8) - (vmaddx.xyzw vf7 vf7 vf10) - (nop!) - (mula.w.vf vf2 vf0) - (nop!) - (vmaddx.xyzw vf8 vf8 vf10) - (nop!) - (mula.w.vf vf3 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.nz t1 positive-inside-b :delay (s.vf vf9 a3 -16)) - (b positive-clip-finish :delay (nop!)) - (label positive-enter-from-b) - (sub.s f7 f0 f1) - (sub.vf vf7 vf1 vf4) - (sub.s f8 f2 f3) - (sub.vf vf8 vf2 vf5) - (sub.s f5 f8 f7) - (sub.vf vf9 vf3 vf6) - (div.s f6 f8 f5) - (add.i a3 a3 48) - (m v1 f6) - (m vf10 v1) - (add.i t0 t0 1) - (mula.w.vf vf4 vf0) - (add.i t6 s7 8) - (vmaddx.xyzw vf7 vf7 vf10) - (nop!) - (mula.w.vf vf5 vf0) - (nop!) - (vmaddx.xyzw vf8 vf8 vf10) - (nop!) - (mula.w.vf vf6 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.z t1 positive-clip-finish :delay (s.vf vf9 a3 -16))) - ;; Inside -> inside copies the previous record. If the next record is outside, the leave path - ;; copies the inside endpoint and appends the crossing point as a second record. - (asm-block walk-positive-inside - (label positive-inside-a) - (l.s f3 t2) - (add.i t2 t2 48) - (l.s f2 a2 12) - (add.i t1 t1 -1) - (l.vf vf4 a2) - (add.i a2 a2 48) - (c.lt.s f2 f3) - (l.vf vf5 a2 -32) - (b.fpt positive-leave-from-a :delay (l.vf vf6 a2 -16)) - (s.vf vf1 a3) - (add.i a3 a3 48) - (s.vf vf2 a3 -32) - (add.i t0 t0 1) - (b.z t1 positive-clip-finish :delay (s.vf vf3 a3 -16)) - (label positive-inside-b) - (l.s f1 t2) - (add.i t2 t2 48) - (l.s f0 a2 12) - (add.i t1 t1 -1) - (l.vf vf1 a2) - (add.i a2 a2 48) - (c.lt.s f0 f1) - (l.vf vf2 a2 -32) - (b.fpt positive-leave-from-b :delay (l.vf vf3 a2 -16)) - (s.vf vf4 a3) - (add.i a3 a3 48) - (s.vf vf5 a3 -32) - (add.i t0 t0 1) - (b.nz t1 positive-inside-a :delay (s.vf vf6 a3 -16)) - (b positive-clip-finish :delay (nop!)) - (label positive-leave-from-a) - (sub.s f7 f0 f1) - (sub.vf vf7 vf1 vf4) - (sub.s f8 f2 f3) - (sub.vf vf8 vf2 vf5) - (sub.s f5 f8 f7) - (sub.vf vf9 vf3 vf6) - (div.s f6 f8 f5) - (add.i a3 a3 96) - (m v1 f6) - (m vf10 v1) - (s.vf vf1 a3 -96) - (mula.w.vf vf4 vf0) - (s.vf vf2 a3 -80) - (vmaddx.xyzw vf7 vf7 vf10) - (s.vf vf3 a3 -64) - (mula.w.vf vf5 vf0) - (add.i t0 t0 2) - (vmaddx.xyzw vf8 vf8 vf10) - (add.i t6 s7 8) - (mula.w.vf vf6 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.nz t1 positive-outside-b :delay (s.vf vf9 a3 -16)) - (b positive-clip-finish :delay (nop!)) - (label positive-leave-from-b) - (sub.s f7 f0 f1) - (sub.vf vf7 vf4 vf1) - (sub.s f8 f2 f3) - (sub.vf vf8 vf5 vf2) - (sub.s f5 f7 f8) - (sub.vf vf9 vf6 vf3) - (div.s f6 f7 f5) - (add.i a3 a3 96) - (m v1 f6) - (m vf10 v1) - (s.vf vf4 a3 -96) - (mula.w.vf vf1 vf0) - (s.vf vf5 a3 -80) - (vmaddx.xyzw vf7 vf7 vf10) - (s.vf vf6 a3 -64) - (mula.w.vf vf2 vf0) - (add.i t0 t0 2) - (vmaddx.xyzw vf8 vf8 vf10) - (add.i t6 s7 8) - (mula.w.vf vf3 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.nz t1 positive-outside-a :delay (s.vf vf9 a3 -16))) - ;; Restore the closed representation expected by the next clipping pass. - (asm-block close-positive-polygon - (label positive-clip-finish) - (l.vf vf1 t3) - (nop!) - (l.vf vf2 t3 16) - (nop!) - (l.vf vf3 t3 32) - (nop!) - (s.vf vf1 a3) - (nop!) - (s.vf vf2 a3 16) - (nop!) - (jr ra :delay (s.vf vf3 a3 32)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2))) - (defun clip-polygon-against-negative-hyperplane () - "Clip a closed scratch polygon against component >= -w. This is the negative-plane mirror of - clip-polygon-against-positive-hyperplane and uses the same private registers and closed output - format." - (declare (asm-func none)) - (asm-block classify-first-negative-vertex - (nop!) - (m t1 t0) - (add.i t0 r0 0) - (l.s f0 a2 12) - (m t3 a3) - (l.s f1 t2) - (add.i t2 t2 48) - (l.vf vf1 a2) - (neg.s f0 f0) - (nop!) - (l.vf vf2 a2 16) - (c.lt.s f1 f0) - (add.i a2 a2 48) - (b.fpf negative-inside-a :delay (l.vf vf3 a2 -16))) - ;; The two paths alternate register triples instead of copying the current 48-byte record. - (asm-block walk-negative-outside - (label negative-outside-a) - (l.s f2 a2 12) - (add.i t1 t1 -1) - (l.s f3 t2) - (add.i t2 t2 48) - (l.vf vf4 a2) - (neg.s f2 f2) - (nop!) - (l.vf vf5 a2 16) - (c.lt.s f3 f2) - (add.i a2 a2 48) - (b.fpf negative-enter-from-a :delay (l.vf vf6 a2 -16)) - (b.z t1 negative-clip-finish :delay (nop!)) - (label negative-outside-b) - (l.s f0 a2 12) - (add.i t1 t1 -1) - (l.s f1 t2) - (add.i t2 t2 48) - (l.vf vf1 a2) - (neg.s f0 f0) - (nop!) - (l.vf vf2 a2 16) - (c.lt.s f1 f0) - (add.i a2 a2 48) - (b.fpf negative-enter-from-b :delay (l.vf vf3 a2 -16)) - (b.nz t1 negative-outside-a :delay (nop!)) - (b negative-clip-finish :delay (nop!)) - ;; Outside -> inside writes the interpolated crossing. f6 is the edge fraction measured from - ;; the outside endpoint; the same fraction is applied to position, STQ, and color. - (label negative-enter-from-a) - (sub.s f7 f0 f1) - (sub.vf vf7 vf4 vf1) - (sub.s f8 f2 f3) - (sub.vf vf8 vf5 vf2) - (sub.s f5 f7 f8) - (sub.vf vf9 vf6 vf3) - (div.s f6 f7 f5) - (add.i a3 a3 48) - (m v1 f6) - (m vf10 v1) - (add.i t0 t0 1) - (mula.w.vf vf1 vf0) - (add.i t6 s7 8) - (vmaddx.xyzw vf7 vf7 vf10) - (nop!) - (mula.w.vf vf2 vf0) - (nop!) - (vmaddx.xyzw vf8 vf8 vf10) - (nop!) - (mula.w.vf vf3 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.nz t1 negative-inside-b :delay (s.vf vf9 a3 -16)) - (b negative-clip-finish :delay (nop!)) - (label negative-enter-from-b) - (sub.s f7 f0 f1) - (sub.vf vf7 vf1 vf4) - (sub.s f8 f2 f3) - (sub.vf vf8 vf2 vf5) - (sub.s f5 f8 f7) - (sub.vf vf9 vf3 vf6) - (div.s f6 f8 f5) - (add.i a3 a3 48) - (m v1 f6) - (m vf10 v1) - (add.i t0 t0 1) - (mula.w.vf vf4 vf0) - (add.i t6 s7 8) - (vmaddx.xyzw vf7 vf7 vf10) - (nop!) - (mula.w.vf vf5 vf0) - (nop!) - (vmaddx.xyzw vf8 vf8 vf10) - (nop!) - (mula.w.vf vf6 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.z t1 negative-clip-finish :delay (s.vf vf9 a3 -16))) - ;; Inside runs copy their previous record. A leaving edge emits the inside endpoint followed - ;; by the intersection, which is why those paths advance the output by two records. - (asm-block walk-negative-inside - (label negative-inside-a) - (l.s f2 a2 12) - (add.i t1 t1 -1) - (l.s f3 t2) - (add.i t2 t2 48) - (l.vf vf4 a2) - (neg.s f2 f2) - (nop!) - (l.vf vf5 a2 16) - (c.lt.s f3 f2) - (add.i a2 a2 48) - (b.fpt negative-leave-from-a :delay (l.vf vf6 a2 -16)) - (s.vf vf1 a3) - (add.i a3 a3 48) - (s.vf vf2 a3 -32) - (add.i t0 t0 1) - (b.z t1 negative-clip-finish :delay (s.vf vf3 a3 -16)) - (label negative-inside-b) - (l.s f0 a2 12) - (add.i t1 t1 -1) - (l.s f1 t2) - (add.i t2 t2 48) - (l.vf vf1 a2) - (neg.s f0 f0) - (nop!) - (l.vf vf2 a2 16) - (c.lt.s f1 f0) - (add.i a2 a2 48) - (b.fpt negative-leave-from-b :delay (l.vf vf3 a2 -16)) - (s.vf vf4 a3) - (add.i a3 a3 48) - (s.vf vf5 a3 -32) - (add.i t0 t0 1) - (b.nz t1 negative-inside-a :delay (s.vf vf6 a3 -16)) - (b negative-clip-finish :delay (nop!)) - (label negative-leave-from-a) - (sub.s f7 f0 f1) - (sub.vf vf7 vf1 vf4) - (sub.s f8 f2 f3) - (sub.vf vf8 vf2 vf5) - (sub.s f5 f8 f7) - (sub.vf vf9 vf3 vf6) - (div.s f6 f8 f5) - (add.i a3 a3 96) - (m v1 f6) - (m vf10 v1) - (s.vf vf1 a3 -96) - (mula.w.vf vf4 vf0) - (s.vf vf2 a3 -80) - (vmaddx.xyzw vf7 vf7 vf10) - (s.vf vf3 a3 -64) - (mula.w.vf vf5 vf0) - (add.i t0 t0 2) - (vmaddx.xyzw vf8 vf8 vf10) - (add.i t6 s7 8) - (mula.w.vf vf6 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.nz t1 negative-outside-b :delay (s.vf vf9 a3 -16)) - (b negative-clip-finish :delay (nop!)) - (label negative-leave-from-b) - (sub.s f7 f0 f1) - (sub.vf vf7 vf4 vf1) - (sub.s f8 f2 f3) - (sub.vf vf8 vf5 vf2) - (sub.s f5 f7 f8) - (sub.vf vf9 vf6 vf3) - (div.s f6 f7 f5) - (add.i a3 a3 96) - (m v1 f6) - (m vf10 v1) - (s.vf vf4 a3 -96) - (mula.w.vf vf1 vf0) - (s.vf vf5 a3 -80) - (vmaddx.xyzw vf7 vf7 vf10) - (s.vf vf6 a3 -64) - (mula.w.vf vf2 vf0) - (add.i t0 t0 2) - (vmaddx.xyzw vf8 vf8 vf10) - (add.i t6 s7 8) - (mula.w.vf vf3 vf0) - (nop!) - (vmaddx.xyzw vf9 vf9 vf10) - (nop!) - (s.vf vf7 a3 -48) - (nop!) - (s.vf vf8 a3 -32) - (nop!) - (b.nz t1 negative-outside-a :delay (s.vf vf9 a3 -16))) - (asm-block close-negative-polygon - (label negative-clip-finish) - (l.vf vf1 t3) - (nop!) - (l.vf vf2 t3 16) - (nop!) - (l.vf vf3 t3 32) - (nop!) - (s.vf vf1 a3) - (nop!) - (s.vf vf2 a3 16) - (nop!) - (jr ra :delay (s.vf vf3 a3 32)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2))) - (defun render-sky-quad ((vertices (inline-array sky-vertex)) (dma-buf dma-buffer)) - "Transform four sky vertices into a closed five-record scratch polygon and tail-call the - clipping and packet conversion path." - (declare (asm-func none)) - ;; vf31..vf28 are the persistent camera rows from init-sky-regs. Only x, y, and w are retained; - ;; z is cleared so the final layer depth is supplied explicitly by vf23.x. - (asm-block prepare-sky-quad - (m v1 a0) - (m! v1 *math-camera*) - ;; Refresh the homogeneous scale with the rest of the camera state before building the page. - (l.vf vf14 v1 700) - (lui t4 #x7000) - (ori t4 t4 #x3000) - (lui t5 #x7000) - (ori t5 t5 #x3800) - (lui v1 #x3000) - (m a3 t4) - (or a0 a0 v1) - (nop!) - (l.vf vf1 a0) - (add.i t0 r0 4) - (l.vf vf2 a0 16) - (nop!) - (l.vf vf3 a0 32) - (mula.x.vf vf31 vf1) - (l.vf vf4 a0 48) - (madda.y.vf vf30 vf1) - (l.vf vf5 a0 64) - (madda.z.vf vf29 vf1) - (l.vf vf6 a0 80) - (vmaddw.xyw vf1 vf28 vf1) - (l.vf vf7 a0 96) - (vmove.z vf1 vf0) - (l.vf vf8 a0 112) - (mula.x.vf vf31 vf4) - (l.vf vf9 a0 128) - (madda.y.vf vf30 vf4) - (l.vf vf10 a0 144) - (madda.z.vf vf29 vf4) - (l.vf vf11 a0 160) - (vmaddw.xyw vf4 vf28 vf4) - (l.vf vf12 a0 176) - (vmove.z vf4 vf0)) - (asm-block finish-sky-quad - (s.vf vf2 a3 16) - (mula.x.vf vf31 vf7) - (s.vf vf3 a3 32) - (madda.y.vf vf30 vf7) - (s.vf vf5 a3 64) - (madda.z.vf vf29 vf7) - (s.vf vf6 a3 80) - (vmaddw.xyw vf7 vf28 vf7) - (s.vf vf8 a3 112) - (vmove.z vf7 vf0) - (s.vf vf9 a3 128) - (mula.x.vf vf31 vf10) - (s.vf vf11 a3 160) - (madda.y.vf vf30 vf10) - (s.vf vf12 a3 176) - (madda.z.vf vf29 vf10) - (s.vf vf2 a3 208) - (vmaddw.xyw vf10 vf28 vf10) - (s.vf vf3 a3 224) - (vmove.z vf10 vf0) - (s.vf vf1 a3) - (nop!) - ;; Repeat record zero after record three to close the list. - (s.vf vf1 a3 192) - (nop!) - (s.vf vf4 a3 48) - (nop!) - (s.vf vf7 a3 96) - (nop!) - (s.vf vf10 a3 144) - (m! t9 draw-large-polygon) - (jr t9 :delay (nop!)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2))) - (defun render-sky-tri ((vertices (inline-array sky-vertex)) (dma-buf dma-buffer)) - "Transform three sky vertices into a closed four-record scratch polygon and tail-call the - clipping and packet conversion path." - (declare (asm-func none)) - (asm-block prepare-sky-triangle - (m v1 a0) - (lui t4 #x7000) - (ori t4 t4 #x3000) - (lui t5 #x7000) - (ori t5 t5 #x3800) - (lui v1 #x3000) - (m a3 t4) - (or a0 a0 v1) - (nop!) - (l.vf vf1 a0) - (add.i t0 r0 3) - (l.vf vf2 a0 16) - (nop!) - (l.vf vf3 a0 32) - (mula.x.vf vf31 vf1) - (l.vf vf4 a0 48) - (madda.y.vf vf30 vf1) - (l.vf vf5 a0 64) - (madda.z.vf vf29 vf1) - (l.vf vf6 a0 80) - (vmaddw.xyw vf1 vf28 vf1) - (l.vf vf7 a0 96) - (vmove.z vf1 vf0) - (l.vf vf8 a0 112) - (mula.x.vf vf31 vf4) - (l.vf vf9 a0 128) - (madda.y.vf vf30 vf4) - (s.vf vf2 a3 16) - (madda.z.vf vf29 vf4) - (s.vf vf3 a3 32) - (vmaddw.xyw vf4 vf28 vf4) - (s.vf vf5 a3 64) - (vmove.z vf4 vf0) - (s.vf vf6 a3 80) - (mula.x.vf vf31 vf7) - (s.vf vf8 a3 112) - (madda.y.vf vf30 vf7) - (s.vf vf9 a3 128) - (madda.z.vf vf29 vf7) - (s.vf vf2 a3 160) - (vmaddw.xyw vf7 vf28 vf7) - (s.vf vf3 a3 176) - (vmove.z vf7 vf0) - (s.vf vf1 a3) - (nop!) - ;; Repeat record zero after record two to close the list. - (s.vf vf1 a3 144) - (nop!) - (s.vf vf4 a3 48) - (nop!) - (s.vf vf7 a3 96) - (m! t9 draw-large-polygon) - (jr t9 :delay (nop!)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2))) - (defun sky-duplicate-polys ((dma-buf dma-buffer) (begin (pointer uint128)) (end (pointer uint128))) - "Append the half-open quadword range [begin, end) to dma-buf. An empty or reversed range writes - nothing." - (declare (asm-func none)) - (rlet ((cursor :reg v1) - (quad :reg a3 :class i128) - (result :reg v0)) - (l.w.field cursor a0 (base)) - (b sky-duplicate-test :delay (nop!)) - (label sky-duplicate-copy) - (l.q quad a1) - (s.q quad cursor) - (add.i cursor cursor 16) - (add.i a1 a1 16) - (label sky-duplicate-test) - (slt a3 a1 a2) - (b.nz a3 sky-duplicate-copy :delay (nop!)) - (m a1 s7) - (s.w.field cursor a0 (base)) - (m result r0) - (jr ra :delay (add sp sp r0)) - (nop! :count 2))) - (defun close-sky-buffer ((dma-buf dma-buffer)) - "Append the #x8000 terminator for a large-polygon stream and advance the buffer by one qword." - (declare (asm-func none)) - (rlet ((terminator :reg v1) - (cursor :reg v0)) - (nop!) - (ori terminator r0 #x8000) - (l.w.field cursor a0 (base)) - (s.q r0 cursor) - (nop!) - (s.w terminator cursor) - (add.i cursor cursor 16) - (jr ra :delay (s.w.field cursor a0 (base))) - (jr ra :delay (add sp sp r0)) - (nop! :count 2)))) +(define *sky-polygon-renderer* (new 'global 'sky-polygon-renderer-state)) +(defun sky-copy-vertex! ((dst sky-vertex) (src sky-vertex)) + (declare (inline)) + (vector-copy! (-> dst pos) (-> src pos)) + (vector-copy! (-> dst stq) (-> src stq)) + (vector-copy! (-> dst col) (-> src col)) + dst) + +(defun sky-interpolate-vertex! ((dst sky-vertex) (a sky-vertex) (b sky-vertex) (amount float)) + (declare (inline)) + (vector4-lerp! (-> dst pos) (-> a pos) (-> b pos) amount) + (vector4-lerp! (-> dst stq) (-> a stq) (-> b stq) amount) + (vector4-lerp! (-> dst col) (-> a col) (-> b col) amount) + dst) + +(defun sky-vector4*! ((dst vector) (a vector) (b vector)) + "Multiply all 4 values." + (declare (inline)) + (rlet ((a-value :class vf) + (b-value :class vf) + (result :class vf)) + (.lvf a-value (&-> a quad)) + (.lvf b-value (&-> b quad)) + (.mul.vf result a-value b-value) + (.svf (&-> dst quad) result)) + dst) + +(defun sky-vector4-float*! ((dst vector) (value vector) (scale float)) + "Multiply all four values by scale." + (declare (inline)) + (rlet ((value-reg :class vf) + (scale-reg :class vf)) + (.lvf value-reg (&-> value quad)) + (.mov scale-reg scale) + (.mul.x.vf value-reg value-reg scale-reg) + (.svf (&-> dst quad) value-reg)) + dst) + +(defun sky-clip-distance ((vertex sky-vertex) (component int) (positive-plane? symbol)) + "Return the homogeneous distance from vertex to x/y <= w or x/y >= -w. Nonnegative is inside." + (declare (inline)) + (let ((axis (if (zero? component) (-> vertex pos x) (-> vertex pos y)))) + (if positive-plane? + (- (-> vertex pos w) axis) + (+ (-> vertex pos w) axis)))) + +(defun sky-clip-outside? ((vertex sky-vertex) (component int) (positive-plane? symbol)) + "Test the clip comparison directly, preserving the EE behavior that a NaN comparison is inside." + (declare (inline)) + (let ((axis (if (zero? component) (-> vertex pos x) (-> vertex pos y)))) + (if positive-plane? + (< (-> vertex pos w) axis) + (< axis (- (-> vertex pos w)))))) + +(defun sky-clip-polygon! ((input (inline-array sky-vertex)) + (output (inline-array sky-vertex)) + (vertex-count int) + (component int) + (positive-plane? symbol)) + "Sutherland-Hodgman clip one convex sky polygon against a homogeneous side plane." + ;; This iterates over edges of the polygon, emitting vertices in three cases: + ;; - original vertex on inside of plane + ;; - edge crosses from inside to outside, emit interpolated vertex on edge + ;; - edge cross from outside to inside, emit interpolated vertex on edge + (let ((output-count 0)) + (dotimes (i vertex-count) + (let* ((current (-> input i)) + (next (-> input (if (= i (- vertex-count 1)) 0 (+ i 1)))) + (current-distance (sky-clip-distance current component positive-plane?)) + (next-distance (sky-clip-distance next component positive-plane?)) + (current-outside? (sky-clip-outside? current component positive-plane?)) + (next-outside? (sky-clip-outside? next component positive-plane?))) + (cond + ((not current-outside?) + ;; Case 1, emit vertex directly + (sky-copy-vertex! (-> output output-count) current) + (+! output-count 1) + (when next-outside? + ;; Inside to outside, emit inerpolated + (let ((amount (/ next-distance (- next-distance current-distance)))) + (sky-interpolate-vertex! (-> output output-count) next current amount) + (+! output-count 1)))) + ((not next-outside?) + ;; Outside to inside, emit interpolated + (let ((amount (/ current-distance (- current-distance next-distance)))) + (sky-interpolate-vertex! (-> output output-count) current next amount) + (+! output-count 1)))))) + output-count)) + +(defun init-sky-regs () + "Snapshot the camera, projection, fog, zero texture phase, and zero layer depth used by subsequent + sky polygon calls." + (let ((state *sky-polygon-renderer*)) + ;; Sky polygon renderer does math in homogeneous coordinates, apply hmge-scale to camera matrix. + (dotimes (i 4) + (sky-vector4*! (-> state transform vector i) + (-> *math-camera* camera-temp vector i) + (-> *math-camera* hmge-scale))) + ;; Store what we need to go from homogenous to screen-space + (vector-copy! (-> state inv-hmge-scale) (-> *math-camera* inv-hmge-scale)) + (vector-copy! (-> state screen-offset) (-> *math-camera* hvdf-off)) + ;; unclear why this is done, but it applies a 1-pixel shift when the camera is below the horizon. + ;; This is possibly to avoid some seam/gap between ocean and sky. + (set! (-> state screen-offset y) (if (> (-> *math-camera* trans y) 0.0) 2049.0 2047.0)) + (set! (-> state screen-offset z) 0.0) + (set-vector! (-> state fog-clamp) + (-> *math-camera* pfog0) + (-> *math-camera* fog-max) + (-> *math-camera* fog-end) + 3071.0) + (set-vector! (-> state texture-offset) 0.0 0.0 0.0 0.0) + (set! (-> state layer-depth) 0.0)) + (none)) + +(defun set-sky-giftag ((giftag gs-gif-tag)) + "Latch the giftag used by subsequent sky polygon calls." + (declare (inline)) + (set! (-> *sky-polygon-renderer* giftag qword) (-> giftag qword)) + (none)) + +(defun set-sky-depth ((depth float)) + "Latch the layer-depth bit pattern used by subsequent sky polygon calls." + (declare (inline)) + (set! (-> *sky-polygon-renderer* layer-depth) depth) + (none)) + +(defun set-tex-offset ((s-offset int) (t-offset int)) + "Convert two wrapped 16-bit texture phases to [0, 1] UV coordinates" + (let ((offset (-> *sky-polygon-renderer* texture-offset))) + (set-vector! offset + (* (the float s-offset) 0.000015258789) + (* (the float t-offset) 0.000015258789) + 0.0 + 0.0)) + (none)) + +(defun sky-transform-vertex! ((dst sky-vertex) (src sky-vertex)) + "Transform vertex to homogeneous coordinates, set z = 0" + (vector-matrix*! (-> dst pos) (-> src pos) (-> *sky-polygon-renderer* transform)) + (set! (-> dst pos z) 0.0) + (vector-copy! (-> dst stq) (-> src stq)) + (vector-copy! (-> dst col) (-> src col)) + dst) + +(defun sky-emit-polygon! ((vertices (inline-array sky-vertex)) (vertex-count int) (dma-buf dma-buffer)) + "Append one GIF tag and the perspective-correct ST, integer RGBAQ, and 12.4 XYZF records." + (let* ((state *sky-polygon-renderer*) + (packet-start (-> dma-buf base)) + (giftag (the-as gs-gif-tag packet-start)) + (output (the-as (pointer uint128) (&+ packet-start 16)))) + (set! (-> giftag qword) (-> state giftag qword)) + ;; The original SW writes the complete low word, not just the nloop bitfield. In particular, + ;; this clears the template's EOP bit so close-sky-buffer's empty EOP tag ends the combined + ;; DIRECT transfer after every polygon has been consumed. + (set! (-> (the-as (pointer uint32) packet-start) 0) vertex-count) + (dotimes (i vertex-count) + (let* ((vertex (-> vertices i)) + (q (/ 1.0 (-> vertex pos w))) ;; perspective divide + (st (new 'stack-no-clear 'vector)) + (color-int (new 'stack-no-clear 'vector)) + (projected (new 'stack-no-clear 'vector)) + (projected-int (new 'stack-no-clear 'vector))) + ;; TEXTURE: apply offset and multiply by q for GS perspective correction + (vector-copy! st (-> vertex stq)) + (+! (-> st x) (-> state texture-offset x)) + (+! (-> st y) (-> state texture-offset y)) + (sky-vector4-float*! st st q) + ;; COLOR: convert to integers + (vector-cvt.w.s! color-int (-> vertex col)) + ;; undo homogeneous scale (done for clipping) + (sky-vector4*! projected (-> vertex pos) (-> state inv-hmge-scale)) + ;; apply perspective divide + (*! (-> projected x) q) + (*! (-> projected y) q) + (*! (-> projected z) q) + ;; apply X/Y offset for GS integer rendering area + (+! (-> projected x) (-> state screen-offset x)) + (+! (-> projected y) (-> state screen-offset y)) + ;; overwrite depth with the user-specified depth + (set! (-> projected z) (-> state layer-depth)) + ;; set fog to clamped distance from camera + (set! (-> projected w) + (max (-> state fog-clamp y) (min (-> projected w) (-> state fog-clamp z)))) + ;; Convert to GS 12.4 fixed point + (sky-vector4-float*! projected projected 16.0) + (vector-cvt.w.s! projected-int projected) + ;; Store + (set! (-> output (* i 3)) (-> st quad)) + (set! (-> output (+ (* i 3) 1)) (-> color-int quad)) + (set! (-> output (+ (* i 3) 2)) (-> projected-int quad)))) + (set! (-> dma-buf base) (&+ packet-start (* (+ 1 (* vertex-count 3)) 16)))) + (none)) + +(defun draw-large-polygon () + "Clip the current polygon against x <= w, y <= w, x >= -w, and y >= -w, then emit it." + (let* ((state *sky-polygon-renderer*) + (vertices-a (-> state vertices-a)) + (vertices-b (-> state vertices-b)) + (vertex-count (-> state vertex-count))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-a vertices-b vertex-count 0 #t))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-b vertices-a vertex-count 1 #t))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-a vertices-b vertex-count 0 #f))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-b vertices-a vertex-count 1 #f))) + (when (nonzero? vertex-count) + (sky-emit-polygon! vertices-a vertex-count (-> state dma-buf)))) + (none)) + +(defun render-sky-polygon ((vertices (inline-array sky-vertex)) (dma-buf dma-buffer) (vertex-count int)) + "Transform and render a polygon." + (let ((state *sky-polygon-renderer*)) + (set! (-> state dma-buf) dma-buf) + (set! (-> state vertex-count) vertex-count) + (dotimes (i vertex-count) + (sky-transform-vertex! (-> state vertices-a i) (-> vertices i))) + (draw-large-polygon)) + (none)) + +(defun render-sky-quad ((vertices (inline-array sky-vertex)) (dma-buf dma-buffer)) + "Transform and render four sky vertices." + (render-sky-polygon vertices dma-buf 4) + (none)) + +(defun render-sky-tri ((vertices (inline-array sky-vertex)) (dma-buf dma-buffer)) + "Transform and render three sky vertices." + (render-sky-polygon vertices dma-buf 3) + (none)) + +(defun close-sky-buffer ((dma-buf dma-buffer)) + "Append the #x8000 EOP terminator for the current large-polygon stream and advance by one qword." + (let ((cursor (the-as (pointer uint128) (-> dma-buf base)))) + (set! (-> cursor 0) (the-as uint128 #x8000)) + (set! (-> dma-buf base) (&+ (the-as pointer cursor) 16))) + (none)) + +(defun sky-duplicate-polys ((dma-buf dma-buffer) (begin (pointer uint128)) (end (pointer uint128))) + "Append the half-open aligned quadword range [begin, end) to the DMA buffer. An empty or reversed + range writes nothing." + (let ((cursor (the-as (pointer uint128) (-> dma-buf base)))) + (while (< (the-as int begin) (the-as int end)) + (set! (-> cursor 0) (-> begin 0)) + (set! cursor (&-> cursor 1)) + (set! begin (&-> begin 1))) + (set! (-> dma-buf base) (the-as pointer cursor))) + (none)) + +;; This is large, upside down, untextured pyramid (4 triangular sides, no base). +;; The camera sits inside the pyramid and this draws the stuff below the horizon. +;; The color of these polygons is updated by mood, called erase-color. +;; These have w = 0, so effectively camera translation is ignored - the pyramid is always centered at the cam. (define sky-base-polygons (new 'static 'inline-array @@ -1084,6 +504,8 @@ :col (new 'static 'vector :x 3.0 :y 18.0 :z 113.0 :w 128.0)))) +;; Large, textured pyramid over the entire game world. 4-sided, with triangular sides. +;; These have w = 0, so effectively camera translation is ignored - the pyramid is always centered at the cam. (define sky-roof-polygons (new 'static 'inline-array @@ -1264,47 +686,59 @@ (new 'static 'sky-vertex) (new 'static 'sky-vertex))) +;; Vertex indices for the cloud mesh. Clouds are drawn over the sky. +;; There are three nested squares. The inner-most square is the highest (define sky-cloud-polygon-indices (new 'static 'array uint8 48 + ;; outer to middle top #x0 #x1 #x9 #x8 + ;; outer to middle right #x1 #x2 #xa #x9 + ;; outer to middle bottom #x2 #x3 #xb #xa + ;; outer to middle left #x3 #x0 #x8 #xb + ;; middle to center top #x8 #x9 #x5 #x4 + ;; middle to center right #x9 #xa #x6 #x5 + ;; middle to center bottom #xa #xb #x7 #x6 + ;; middle to center left #xb #x8 #x4 #x7 + ;; center #x4 #x5 #x6 #x7 + ;; unused... #x0 #x0 #x0 @@ -1350,54 +784,29 @@ (inner-max-t-factor (/ (- inner-max-z outer-min-z) (- outer-max-z outer-min-z))) (inner-min-st (+ outer-min-st (* inner-min-factor (- outer-max-st outer-min-st)))) (inner-max-st (+ outer-min-st (* inner-max-factor (- outer-max-st outer-min-st))))) - ;; These two T values are computed from z but not retained. The shipped layout uses the - ;; x-derived inner-min-st and inner-max-st for both texture axes. + ;; These two T values are computed from z but not used. (+ outer-min-t (* inner-min-t-factor (- outer-max-t outer-min-t))) (+ outer-min-t (* inner-max-t-factor (- outer-max-t outer-min-t))) (let ((outer-corner (-> control-vertices 0))) - (set! (-> outer-corner pos x) outer-min-x) - (set! (-> outer-corner pos y) 0.0) - (set! (-> outer-corner pos z) outer-min-z) - (set! (-> outer-corner pos w) 0.0)) + (set-vector! (-> outer-corner pos) outer-min-x 0.0 outer-min-z 0.0)) (let ((outer-corner (-> control-vertices 1))) - (set! (-> outer-corner pos x) outer-max-x) - (set! (-> outer-corner pos y) 0.0) - (set! (-> outer-corner pos z) outer-min-z) - (set! (-> outer-corner pos w) 0.0)) + (set-vector! (-> outer-corner pos) outer-max-x 0.0 outer-min-z 0.0)) (let ((outer-corner (-> control-vertices 2))) - (set! (-> outer-corner pos x) outer-max-x) - (set! (-> outer-corner pos y) 0.0) - (set! (-> outer-corner pos z) outer-max-z) - (set! (-> outer-corner pos w) 0.0)) + (set-vector! (-> outer-corner pos) outer-max-x 0.0 outer-max-z 0.0)) (let ((outer-corner (-> control-vertices 3))) - (set! (-> outer-corner pos x) outer-min-x) - (set! (-> outer-corner pos y) 0.0) - (set! (-> outer-corner pos z) outer-max-z) - (set! (-> outer-corner pos w) 0.0)) + (set-vector! (-> outer-corner pos) outer-min-x 0.0 outer-max-z 0.0)) (set-vector! (-> control-vertices 0 stq) outer-min-st outer-min-st 1.0 1.0) (set-vector! (-> control-vertices 1 stq) outer-max-st outer-min-st 1.0 1.0) (set-vector! (-> control-vertices 2 stq) outer-max-st outer-max-st 1.0 1.0) (set-vector! (-> control-vertices 3 stq) outer-min-st outer-max-st 1.0 1.0) (let ((inner-corner (-> control-vertices 4))) - (set! (-> inner-corner pos x) inner-min-x) - (set! (-> inner-corner pos y) 1.0) - (set! (-> inner-corner pos z) inner-min-z) - (set! (-> inner-corner pos w) 0.0)) + (set-vector! (-> inner-corner pos) inner-min-x 1.0 inner-min-z 0.0)) (let ((inner-corner (-> control-vertices 5))) - (set! (-> inner-corner pos x) inner-max-x) - (set! (-> inner-corner pos y) 1.0) - (set! (-> inner-corner pos z) inner-min-z) - (set! (-> inner-corner pos w) 0.0)) + (set-vector! (-> inner-corner pos) inner-max-x 1.0 inner-min-z 0.0)) (let ((inner-corner (-> control-vertices 6))) - (set! (-> inner-corner pos x) inner-max-x) - (set! (-> inner-corner pos y) 1.0) - (set! (-> inner-corner pos z) inner-max-z) - (set! (-> inner-corner pos w) 0.0)) + (set-vector! (-> inner-corner pos) inner-max-x 1.0 inner-max-z 0.0)) (let ((inner-corner (-> control-vertices 7))) - (set! (-> inner-corner pos x) inner-min-x) - (set! (-> inner-corner pos y) 1.0) - (set! (-> inner-corner pos z) inner-max-z) - (set! (-> inner-corner pos w) 0.0)) + (set-vector! (-> inner-corner pos) inner-min-x 1.0 inner-max-z 0.0)) (set-vector! (-> control-vertices 4 stq) inner-min-st inner-min-st 1.0 1.0) (set-vector! (-> control-vertices 5 stq) inner-max-st inner-min-st 1.0 1.0) (set-vector! (-> control-vertices 6 stq) inner-max-st inner-max-st 1.0 1.0) @@ -1407,23 +816,23 @@ (z (-> control-vertices i pos z))) (set! (-> control-vertices i pos x) (+ (* x outer-rotation-cos) (* z outer-rotation-sin))) (set! (-> control-vertices i pos z) (- (* z outer-rotation-cos) (* x outer-rotation-sin)))) - (set! (-> control-vertices i col quad) (-> color quad)) + (vector-copy! (-> control-vertices i col) color) (set! (-> control-vertices i col w) 0.0)) (dotimes (i 4) (let ((x (-> control-vertices (+ i 4) pos x)) (z (-> control-vertices (+ i 4) pos z))) (set! (-> control-vertices (+ i 4) pos x) (+ (* x inner-rotation-cos) (* z inner-rotation-sin))) (set! (-> control-vertices (+ i 4) pos z) (- (* z inner-rotation-cos) (* x inner-rotation-sin)))) - (set! (-> control-vertices (+ i 4) col quad) (-> color quad))) + (vector-copy! (-> control-vertices (+ i 4) col) color)) (dotimes (i 4) (vector4-lerp! (-> control-vertices (+ i 8) pos) (-> control-vertices i pos) (-> control-vertices (+ i 4) pos) midpoint) (vector4-lerp! (-> control-vertices (+ i 8) stq) (-> control-vertices i stq) (-> control-vertices (+ i 4) stq) midpoint) - (set! (-> control-vertices (+ i 8) col quad) (-> color quad)))) + (vector-copy! (-> control-vertices (+ i 8) col) color))) (dotimes (i 36) (let ((control-index (-> sky-cloud-polygon-indices i))) - (set! (-> output i pos quad) (-> control-vertices control-index pos quad)) - (set! (-> output i stq quad) (-> control-vertices control-index stq quad)) - (set! (-> output i col quad) (-> control-vertices control-index col quad))))) + (vector-copy! (-> output i pos) (-> control-vertices control-index pos)) + (vector-copy! (-> output i stq) (-> control-vertices control-index stq)) + (vector-copy! (-> output i col) (-> control-vertices control-index col))))) 0 (none)) @@ -1433,7 +842,7 @@ (let ((layer0-color (new 'static 'vector :x 20.0 :y 20.0 :z 20.0 :w 128.0)) (layer1-color (new 'static 'vector :x 20.0 :y 20.0 :z 30.0 :w 128.0))) (sky-tng-setup-cloud-layer 0.0 0.0 layer0-color sky-cloud-polygons) - (sky-tng-setup-cloud-layer 0.05584 0.01396 layer1-color (the-as (inline-array sky-vertex) (-> sky-cloud-polygons 36)))) + (sky-tng-setup-cloud-layer 0.05584 0.01396 layer1-color (&-> sky-cloud-polygons 36))) 0 (none)) @@ -1443,141 +852,130 @@ "Composite the prepared sky texture over four roof triangles, draw two independently scrolling nine-quad cloud layers, fill the four base triangles at GS layer depth 256, and enqueue the completed packet in the sky bucket." - (local-vars (base-depth float)) - (rlet ((vf23 :class vf) - (vf27 :class vf)) - (if *debug-segment* - (add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0) - 'draw - (new 'static 'rgba :r #x40 :b #x40 :a #x80))) - (let ((usage-start (-> *display* frames (-> *display* on-screen) frame global-buf base))) - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) frame global-buf)) (bucket-id sky-draw)) :bucket-group (-> *display* frames (-> *display* on-screen) frame bucket-group) (let* ((state-buffer dma-buf) - (state-header (the-as object (-> state-buffer base)))) - (set! (-> (the-as dma-packet state-header) dma) (new 'static 'dma-tag :qwc #x4 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet state-header) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet state-header) vif1) (new 'static 'vif-tag :imm #x4 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> state-buffer base) (&+ (the-as pointer state-header) 16))) (let* ((state-buffer dma-buf) - (state-giftag (the-as object (-> state-buffer base)))) - (set! (-> (the-as gs-gif-tag state-giftag) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x3)) - (set! (-> (the-as gs-gif-tag state-giftag) regs) GIF_REGS_ALL_AD) - (set! (-> state-buffer base) (&+ (the-as pointer state-giftag) 16))) (let* ((state-buffer dma-buf) - (state-registers (-> state-buffer base))) - (set! (-> (the-as (pointer gs-zbuf) state-registers) 0) (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24))) - (set! (-> (the-as (pointer gs-reg64) state-registers) 1) (gs-reg64 zbuf-1)) - (set! (-> (the-as (pointer gs-test) state-registers) 2) - (new 'static 'gs-test :ate #x1 :atst (gs-atest always) :zte #x1 :ztst (gs-ztest always))) - (set! (-> (the-as (pointer gs-reg64) state-registers) 3) (gs-reg64 test-1)) - (set! (-> (the-as (pointer gs-alpha) state-registers) 4) (new 'static 'gs-alpha :b #x1 :d #x1)) - (set! (-> (the-as (pointer gs-reg64) state-registers) 5) (gs-reg64 alpha-1)) - (set! (-> state-buffer base) (&+ state-registers 48))) (init-sky-regs) (#unless PC_PORT - (m! vf27 (-> *sky-tng-data* giftag-roof qword))) (#when PC_PORT - (set-sky-vf27 (&-> *sky-tng-data* giftag-roof qword))) (when *sky-drawn* - (let* ((roof-buffer dma-buf) - (roof-header (the-as object (-> roof-buffer base)))) - (set! (-> (the-as dma-packet roof-header) dma) (new 'static 'dma-tag :qwc #x5 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet roof-header) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet roof-header) vif1) (new 'static 'vif-tag :imm #x5 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> roof-buffer base) (&+ (the-as pointer roof-header) 16))) - (let* ((roof-buffer dma-buf) - (roof-giftag (the-as object (-> roof-buffer base)))) - (set! (-> (the-as gs-gif-tag roof-giftag) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x4)) - (set! (-> (the-as gs-gif-tag roof-giftag) regs) GIF_REGS_ALL_AD) - (set! (-> roof-buffer base) (&+ (the-as pointer roof-giftag) 16))) - (let* ((roof-state-buffer dma-buf) - (roof-state (-> roof-state-buffer base))) - (set! (-> (the-as (pointer gs-tex0) roof-state) 0) - (new 'static 'gs-tex0 :tbw #x1 :th (log2 32) :tw (log2 32) :tbp0 *sky-base-block*)) - (set! (-> (the-as (pointer gs-reg64) roof-state) 1) (gs-reg64 tex0-1)) - (set! (-> (the-as (pointer gs-tex1) roof-state) 2) (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)) - (set! (-> (the-as (pointer gs-reg64) roof-state) 3) (gs-reg64 tex1-1)) - (set! (-> (the-as (pointer gs-clamp) roof-state) 4) - (new 'static 'gs-clamp :wms (gs-tex-wrap-mode clamp) :wmt (gs-tex-wrap-mode clamp))) - (set! (-> (the-as (pointer gs-reg64) roof-state) 5) (gs-reg64 clamp-1)) - (set! (-> (the-as (pointer uint64) roof-state) 6) (the-as uint 0)) - (set! (-> (the-as (pointer gs-reg64) roof-state) 7) (gs-reg64 texflush)) - (set! (-> roof-state-buffer base) (&+ roof-state 64))) - (let ((roof-packet-start (the-as object (-> dma-buf base)))) - (&+! (-> dma-buf base) 16) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-roof-polygons 0)) dma-buf) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-roof-polygons 3)) dma-buf) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-roof-polygons 6)) dma-buf) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-roof-polygons 9)) dma-buf) - (close-sky-buffer dma-buf) - (let ((roof-qwc (/ (the-as int (+ (- -16 (the-as int roof-packet-start)) (the-as int (-> dma-buf base)))) 16))) - (set! (-> (the-as dma-packet roof-packet-start) dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc roof-qwc)) - (set! (-> (the-as dma-packet roof-packet-start) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet roof-packet-start) vif1) (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1 :imm roof-qwc))))) (when *cloud-drawn* - (let* ((cloud-buffer dma-buf) - (cloud-header (the-as object (-> cloud-buffer base)))) - (set! (-> (the-as dma-packet cloud-header) dma) (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet cloud-header) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet cloud-header) vif1) (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> cloud-buffer base) (&+ (the-as pointer cloud-header) 16))) - (let* ((cloud-buffer dma-buf) - (cloud-giftag (the-as object (-> cloud-buffer base)))) - (set! (-> (the-as gs-gif-tag cloud-giftag) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x5)) - (set! (-> (the-as gs-gif-tag cloud-giftag) regs) GIF_REGS_ALL_AD) - (set! (-> cloud-buffer base) (&+ (the-as pointer cloud-giftag) 16))) - (let* ((cloud-state-buffer dma-buf) - (cloud-state (-> cloud-state-buffer base))) - (set! (-> (the-as (pointer gs-alpha) cloud-state) 0) (new 'static 'gs-alpha :b #x2 :d #x1)) - (set! (-> (the-as (pointer gs-reg64) cloud-state) 1) (gs-reg64 alpha-1)) - (set! (-> (the-as (pointer gs-tex0) cloud-state) 2) - (new 'static 'gs-tex0 :tbw #x1 :th (log2 64) :tw (log2 64) :tbp0 (+ *sky-base-block* 32))) - (set! (-> (the-as (pointer gs-reg64) cloud-state) 3) (gs-reg64 tex0-1)) - (set! (-> (the-as (pointer gs-tex1) cloud-state) 4) (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)) - (set! (-> (the-as (pointer gs-reg64) cloud-state) 5) (gs-reg64 tex1-1)) - (set! (-> (the-as (pointer gs-clamp) cloud-state) 6) (new 'static 'gs-clamp)) - (set! (-> (the-as (pointer gs-reg64) cloud-state) 7) (gs-reg64 clamp-1)) - (set! (-> (the-as (pointer int64) cloud-state) 8) 0) - (set! (-> (the-as (pointer gs-reg64) cloud-state) 9) (gs-reg64 texflush)) - (set! (-> cloud-state-buffer base) (&+ cloud-state 80))) - (let ((cloud-packet-start (the-as object (-> dma-buf base)))) - (&+! (-> dma-buf base) 16) - (init-sky-regs) - (let ((vertices (the-as object (-> sky-cloud-polygons 0)))) - (set-tex-offset (the-as int (-> *sky-tng-data* off-s-0)) (the-as int (-> *sky-tng-data* off-t-0))) - ;; first cloud layer - (dotimes (i 9) - (render-sky-quad (the-as (inline-array sky-vertex) vertices) dma-buf) - (set! vertices (-> (the-as (inline-array sky-vertex) vertices) 4))) - (set-tex-offset (the-as int (-> *sky-tng-data* off-s-1)) (the-as int (-> *sky-tng-data* off-t-1))) - ;; second cloud layer - (dotimes (i 9) - (render-sky-quad (the-as (inline-array sky-vertex) vertices) dma-buf) - (set! vertices (-> (the-as (inline-array sky-vertex) vertices) 4)))) - ;; The untextured base triangles fill the region below the roof at GS layer depth 256. - (#unless PC_PORT - (m! vf27 (-> *sky-tng-data* giftag-base qword)) - (let ((base-depth-bits #x43800000)) (m vf23 base-depth-bits)) - (m base-depth vf23)) - (#when PC_PORT - (set-sky-vf27 (&-> *sky-tng-data* giftag-base qword)) - (set-sky-vf23-value #x43800000)) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-base-polygons 0)) dma-buf) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-base-polygons 3)) dma-buf) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-base-polygons 6)) dma-buf) - (render-sky-tri (the-as (inline-array sky-vertex) (-> sky-base-polygons 9)) dma-buf) - (close-sky-buffer dma-buf) - (let ((cloud-qwc (/ (the-as int (+ (- -16 (the-as int cloud-packet-start)) (the-as int (-> dma-buf base)))) 16))) - (set! (-> (the-as dma-packet cloud-packet-start) dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc cloud-qwc)) - (set! (-> (the-as dma-packet cloud-packet-start) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet cloud-packet-start) vif1) - (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1 :imm cloud-qwc)))))) - (let ((usage *dma-mem-usage*)) - (when (nonzero? usage) - (set! (-> usage length) (max 86 (-> usage length))) - (set! (-> usage data 85 name) "sky") - (+! (-> usage data 85 count) 1) - (+! (-> usage data 85 used) - (&- (-> *display* frames (-> *display* on-screen) frame global-buf base) (the-as uint usage-start))) - (set! (-> usage data 85 total) (-> usage data 85 used))))) - (if *debug-segment* - (add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0) - 'draw - (new 'static 'rgba :r #xff :b #xff :a #x80))) - 0 - (none))) + (add-profile-frame! #x40 0 #x40 #x80 'draw) + (let ((usage-start (-> (current-frame) global-buf base))) + (with-dma-buffer-add-bucket ((dma-buf (-> (current-frame) global-buf)) (bucket-id sky-draw)) + ;; initialize drawing mode + (dma-buffer-add-cnt-vif2 + dma-buf + #x4 + (new 'static 'vif-tag) + (new 'static 'vif-tag :imm #x4 :cmd (vif-cmd direct) :msk #x1)) + (dma-buffer-add-gif-tag + dma-buf + (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x3) + GIF_REGS_ALL_AD) + (let ((state-registers (-> dma-buf base))) + (set! (-> (the-as (pointer gs-zbuf) state-registers) 0) + (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24))) + (set! (-> (the-as (pointer gs-reg64) state-registers) 1) (gs-reg64 zbuf-1)) + (set! (-> (the-as (pointer gs-test) state-registers) 2) + (new 'static 'gs-test :ate #x1 :atst (gs-atest always) :zte #x1 :ztst (gs-ztest always))) + (set! (-> (the-as (pointer gs-reg64) state-registers) 3) (gs-reg64 test-1)) + (set! (-> (the-as (pointer gs-alpha) state-registers) 4) + (new 'static 'gs-alpha :b #x1 :d #x1)) + (set! (-> (the-as (pointer gs-reg64) state-registers) 5) (gs-reg64 alpha-1)) + (&+! (-> dma-buf base) 48)) + + ;; initialize polygon renderer + (init-sky-regs) + (set-sky-giftag (-> *sky-tng-data* giftag-roof)) + + ;; only render sky when the texture exists. + ;; set up texturing to use the blended sky texture + (when *sky-drawn* + (dma-buffer-add-cnt-vif2 + dma-buf + #x5 + (new 'static 'vif-tag) + (new 'static 'vif-tag :imm #x5 :cmd (vif-cmd direct) :msk #x1)) + (dma-buffer-add-gif-tag + dma-buf + (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x4) + GIF_REGS_ALL_AD) + (let ((roof-state (-> dma-buf base))) + (set! (-> (the-as (pointer gs-tex0) roof-state) 0) + (new 'static 'gs-tex0 :tbw #x1 :th (log2 32) :tw (log2 32) :tbp0 *sky-base-block*)) + (set! (-> (the-as (pointer gs-reg64) roof-state) 1) (gs-reg64 tex0-1)) + (set! (-> (the-as (pointer gs-tex1) roof-state) 2) + (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)) + (set! (-> (the-as (pointer gs-reg64) roof-state) 3) (gs-reg64 tex1-1)) + (set! (-> (the-as (pointer gs-clamp) roof-state) 4) + (new 'static 'gs-clamp + :wms (gs-tex-wrap-mode clamp) + :wmt (gs-tex-wrap-mode clamp))) + (set! (-> (the-as (pointer gs-reg64) roof-state) 5) (gs-reg64 clamp-1)) + (set! (-> (the-as (pointer uint64) roof-state) 6) (the-as uint 0)) + (set! (-> (the-as (pointer gs-reg64) roof-state) 7) (gs-reg64 texflush)) + (&+! (-> dma-buf base) 64)) + ;; render 4 sides of pyramid + (with-cnt-vif-block (dma-buf) + (render-sky-tri sky-roof-polygons dma-buf) + (render-sky-tri (&-> sky-roof-polygons 3) dma-buf) + (render-sky-tri (&-> sky-roof-polygons 6) dma-buf) + (render-sky-tri (&-> sky-roof-polygons 9) dma-buf) + (close-sky-buffer dma-buf))) + + (when *cloud-drawn* + (dma-buffer-add-cnt-vif2 + dma-buf + #x6 + (new 'static 'vif-tag) + (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1)) + (dma-buffer-add-gif-tag + dma-buf + (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x5) + GIF_REGS_ALL_AD) + (let ((cloud-state (-> dma-buf base))) + (set! (-> (the-as (pointer gs-alpha) cloud-state) 0) + (new 'static 'gs-alpha :b #x2 :d #x1)) + (set! (-> (the-as (pointer gs-reg64) cloud-state) 1) (gs-reg64 alpha-1)) + (set! (-> (the-as (pointer gs-tex0) cloud-state) 2) + (new 'static + 'gs-tex0 + :tbw #x1 + :th (log2 64) + :tw (log2 64) + :tbp0 (+ *sky-base-block* 32))) + (set! (-> (the-as (pointer gs-reg64) cloud-state) 3) (gs-reg64 tex0-1)) + (set! (-> (the-as (pointer gs-tex1) cloud-state) 4) + (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)) + (set! (-> (the-as (pointer gs-reg64) cloud-state) 5) (gs-reg64 tex1-1)) + (set! (-> (the-as (pointer gs-clamp) cloud-state) 6) (new 'static 'gs-clamp)) + (set! (-> (the-as (pointer gs-reg64) cloud-state) 7) (gs-reg64 clamp-1)) + (set! (-> (the-as (pointer int64) cloud-state) 8) 0) + (set! (-> (the-as (pointer gs-reg64) cloud-state) 9) (gs-reg64 texflush)) + (&+! (-> dma-buf base) 80)) + (with-cnt-vif-block (dma-buf) + (init-sky-regs) + ;; draw first cloud + (let ((vertices sky-cloud-polygons)) + (set-tex-offset + (the-as int (-> *sky-tng-data* off-s-0)) + (the-as int (-> *sky-tng-data* off-t-0))) + (dotimes (i 9) + (render-sky-quad vertices dma-buf) + (set! vertices (&-> vertices 4))) + ;; draw second cloud + (set-tex-offset + (the-as int (-> *sky-tng-data* off-s-1)) + (the-as int (-> *sky-tng-data* off-t-1))) + (dotimes (i 9) + (render-sky-quad vertices dma-buf) + (set! vertices (&-> vertices 4)))) + + ;; draw base + (set-sky-giftag (-> *sky-tng-data* giftag-base)) + (set-sky-depth 256.0) + (render-sky-tri sky-base-polygons dma-buf) + (render-sky-tri (&-> sky-base-polygons 3) dma-buf) + (render-sky-tri (&-> sky-base-polygons 6) dma-buf) + (render-sky-tri (&-> sky-base-polygons 9) dma-buf) + (close-sky-buffer dma-buf)))) + (dma-mem-usage-add! sky 1 (&- (-> (current-frame) global-buf base) (the-as uint usage-start)))) + (add-profile-frame! #xff 0 #xff #x80 'draw) + 0 + (none)) (defun copy-sky-texture ((dma-buf dma-buffer) (shader adgif-shader) (weight float)) "Append one weighted 32-by-32 time-of-day snapshot to the runtime sky target. The first @@ -1585,10 +983,7 @@ (let ((packet (-> dma-buf base))) (let ((modulation (the int (+ 0.5 (* 128.0 weight)))) (sprite-data (-> *sky-work* sky-data))) - (set! (-> sprite-data 0 vector4w x) modulation) - (set! (-> sprite-data 0 vector4w y) modulation) - (set! (-> sprite-data 0 vector4w z) modulation) - (set! (-> sprite-data 0 vector4w w) 128)) + (set-vector! (-> sprite-data 0 vector4w) modulation modulation modulation 128)) (set! (-> (the-as (pointer uint128) packet) 0) (-> *sky-work* adgif-tmpl dma-vif quad)) (set! (-> (the-as (pointer uint128) packet) 1) (-> *sky-work* adgif-tmpl quad 1)) (let ((shader-copy (the-as object (&-> (the-as (pointer uint128) packet) 2)))) @@ -1614,10 +1009,7 @@ (let ((packet (-> dma-buf base))) (let ((modulation (the int (+ 0.5 (* 128.0 weight)))) (sprite-data (-> *sky-work* cloud-data))) - (set! (-> sprite-data 0 vector4w x) modulation) - (set! (-> sprite-data 0 vector4w y) modulation) - (set! (-> sprite-data 0 vector4w z) modulation) - (set! (-> sprite-data 0 vector4w w) 128)) + (set-vector! (-> sprite-data 0 vector4w) modulation modulation modulation 128)) (set! (-> (the-as (pointer uint128) packet) 0) (-> *sky-work* adgif-tmpl dma-vif quad)) (set! (-> (the-as (pointer uint128) packet) 1) (-> *sky-work* adgif-tmpl quad 1)) (let ((shader-copy (the-as object (&-> (the-as (pointer uint128) packet) 2)))) @@ -1641,32 +1033,32 @@ "Composite one active level's eight time-of-day sky snapshots and cloud source into the shared 64-by-96 runtime target. Weight the result for the current cross-level transition, restore the GS state, and enqueue the packet in that level's translucent bucket." - ;; This target is rebuilt because the eight sky weights change with time of day and the complete - ;; level image is weighted again while two levels crossfade. The cloud source occupies the lower - ;; 64-by-64 region beneath the 32-by-32 sky image. (when (and (= (-> *level* level level-index status) 'active) (-> *level* level level-index info sky)) (let ((level-weight (-> context current-interp))) - (if (zero? level-index) (set! level-weight (- 1.0 level-weight))) - (if (= (-> context active-count) 1) (set! level-weight 1.0)) + (if (zero? level-index) + (set! level-weight (- 1.0 level-weight))) + (if (= (-> context active-count) 1) + (set! level-weight 1.0)) (when (!= level-weight 0.0) - (let ((blend-bucket (if (zero? level-index) (the-as bucket-id (bucket-id tfrag-trans-0)) (the-as bucket-id (bucket-id tfrag-trans-1)))) + (let ((blend-bucket (if (zero? level-index) + (the-as bucket-id (bucket-id tfrag-trans-0)) + (the-as bucket-id (bucket-id tfrag-trans-1)))) (adgifs (-> *level* level level-index bsp adgifs))) (when (nonzero? adgifs) - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) frame global-buf)) (the-as bucket-id blend-bucket)) :bucket-group (-> *display* frames (-> *display* on-screen) frame bucket-group) (set-display-gs-state dma-buf *sky-base-page* 64 96 0 0) (dotimes (texture-index 8) - (let ((texture-weight (* (-> context moods level-index sky-times texture-index) level-weight))) - (if (!= texture-weight 0.0) (copy-sky-texture dma-buf (-> adgifs data texture-index) texture-weight)))) (copy-cloud-texture dma-buf (-> adgifs data 8) level-weight) (let* ((finish-buffer dma-buf) - (finish-header (the-as object (-> finish-buffer base)))) - (set! (-> (the-as dma-packet finish-header) dma) (new 'static 'dma-tag :qwc #x2 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet finish-header) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet finish-header) vif1) (new 'static 'vif-tag :imm #x2 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> finish-buffer base) (&+ (the-as pointer finish-header) 16))) (let* ((finish-buffer dma-buf) - (finish-giftag (the-as object (-> finish-buffer base)))) - (set! (-> (the-as gs-gif-tag finish-giftag) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x1)) - (set! (-> (the-as gs-gif-tag finish-giftag) regs) GIF_REGS_ALL_AD) - (set! (-> finish-buffer base) (&+ (the-as pointer finish-giftag) 16))) (let* ((finish-buffer dma-buf) - (finish-alpha (-> finish-buffer base))) - (set! (-> (the-as (pointer gs-alpha) finish-alpha) 0) (new 'static 'gs-alpha :b #x1 :d #x1)) - (set! (-> (the-as (pointer gs-reg64) finish-alpha) 1) (gs-reg64 alpha-1)) - (set! (-> finish-buffer base) (&+ finish-alpha 16))) (reset-display-gs-state *display* dma-buf *oddeven*))))))) + (with-dma-buffer-add-bucket ((dma-buf (-> (current-frame) global-buf)) (the-as bucket-id blend-bucket)) + (set-display-gs-state dma-buf *sky-base-page* 64 96 0 0) + (dotimes (texture-index 8) + (let ((texture-weight (* (-> context moods level-index sky-times texture-index) level-weight))) + (if (!= texture-weight 0.0) + (copy-sky-texture dma-buf (-> adgifs data texture-index) texture-weight)))) + (copy-cloud-texture dma-buf (-> adgifs data 8) level-weight) + (dma-buffer-add-cnt-vif2 dma-buf #x2 (new 'static 'vif-tag) (new 'static 'vif-tag :imm #x2 :cmd (vif-cmd direct) :msk #x1)) + (dma-buffer-add-gif-tag dma-buf (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x1) GIF_REGS_ALL_AD) + (let* ((finish-buffer dma-buf) + (finish-alpha (-> finish-buffer base))) + (set! (-> (the-as (pointer gs-alpha) finish-alpha) 0) (new 'static 'gs-alpha :b #x1 :d #x1)) + (set! (-> (the-as (pointer gs-reg64) finish-alpha) 1) (gs-reg64 alpha-1)) + (set! (-> finish-buffer base) (&+ finish-alpha 16))) + (reset-display-gs-state *display* dma-buf *oddeven*))))))) 0 (none)) diff --git a/goal_src/jak1/engine/gfx/sky/sky-utils.gc b/goal_src/jak1/engine/gfx/sky/sky-utils.gc index cacfa833a5..78d8b42ded 100644 --- a/goal_src/jak1/engine/gfx/sky/sky-utils.gc +++ b/goal_src/jak1/engine/gfx/sky/sky-utils.gc @@ -2,6 +2,7 @@ (in-package goal) (bundles "ENGINE.CGO" "GAME.CGO") (require "engine/gfx/sky/sky-h.gc") + (defun sky-set-sun-radii ((parms sky-parms) (index sky-sun-index) (sun-radius float) (halo-radius float) (aurora-radius float)) "Set the apparent sun, halo, and aurora radii in the sun record selected by index's low bit." (let ((sun-index (logand index (sky-sun-index green-sun)))) diff --git a/goal_src/jak1/engine/gfx/sky/sky.gc b/goal_src/jak1/engine/gfx/sky/sky.gc index 91a4348cc2..576f427567 100644 --- a/goal_src/jak1/engine/gfx/sky/sky.gc +++ b/goal_src/jak1/engine/gfx/sky/sky.gc @@ -54,17 +54,20 @@ "Point dst-light toward the selected sun or moon, assign light-color's RGB bytes as normalized floats while replacing its alpha with 1, and enable the light's first level." (let* ((orbit-data (-> parms orbit orbit-index)) - (body-data (if (= orbit-index (sky-orbit-index moon)) (-> parms upload-data moon) (-> parms upload-data sun orbit-index))) + (body-data (if (= orbit-index (sky-orbit-index moon)) + (-> parms upload-data moon) + (-> parms upload-data sun orbit-index))) (byte-to-float 0.003921569) (inverse-distance (/ 1.0 (-> orbit-data dist))) (dst dst-light)) (set! (-> dst direction x) (* (-> (the-as sky-sun-data body-data) pos x) inverse-distance)) (set! (-> dst direction y) (* (-> (the-as sky-sun-data body-data) pos y) inverse-distance)) (set! (-> dst direction z) (* (-> (the-as sky-sun-data body-data) pos z) inverse-distance)) - (set! (-> dst color x) (* (the float (-> light-color r)) byte-to-float)) - (set! (-> dst color y) (* (the float (-> light-color g)) byte-to-float)) - (set! (-> dst color z) (* (the float (-> light-color b)) byte-to-float)) - (set! (-> dst color w) 1.0) + (set-vector! (-> dst color) + (* (the float (-> light-color r)) byte-to-float) + (* (the float (-> light-color g)) byte-to-float) + (* (the float (-> light-color b)) byte-to-float) + 1.0) (set! (-> dst levels x) 1.0)) (none)) @@ -359,228 +362,64 @@ (vu-pair (nop) (nop)) ;; #x0cc )) -(#unless PC_PORT - ;; Function-relative constants used while constructing the per-frame VIF and GIF records. - (asm-data (label sky-radius) - (word #x4a7a0000) ;; 4096000.0 - (label sky-no-kick) - (word #x45400000) ;; 3072.0, which becomes the GS ADC bit after FTOI4 - (label sky-sun-strip-tag) - (word #x00008022 #x20264000) - (label sky-sun-fan-tag) - (word #x00008012 #x2026c000) - (label sky-alpha-tag) - (word #x00000001 #x10000000)) - (defun sky-add-frame-data ((dma-buf dma-buffer) (unused object)) - "Append the 18-qword frame block, update its lighting and celestial upload image, and append the - VIF reference that transfers the 27 celestial-data qwords to VU address 256." - (declare (asm-func none) (allow-saved-regs)) - ;; sky-frame-data is uploaded to VU address 291. Its first seven qwords contain the camera - ;; transform, projection scale/offset, fog scale, legacy 4096000 radius field, and ADC no-kick - ;; value. strip-giftag and save[5] are left untouched; this program loads the shared color A+D - ;; record and the later sun-specific fan, strip, and alpha records. - (rlet ((buffer :reg gp) - (frame-qwc :reg v1) - (cursor :reg a1) - (camera :reg a2) - (function-base :reg fp) - (result :reg v0)) - (add.i sp sp -32) - (s.d ra sp) - (s.d function-base sp 8) - (m function-base t9) - (s.q buffer sp 16) - (m buffer a0) - (asm-block append-frame-unpack - (add.i frame-qwc r0 18) - (m a0 buffer) - (l.w.field cursor a0 (base)) - (lui a2 #x1000) - (sll32 a3 frame-qwc 16) - (srl32 a3 a3 16) - (or a2 a2 a3) - (s.d a2 cursor) - (lui a2 256) - (ori a2 a2 1028) ;; STCYCL 4,4 - (s.w a2 cursor 8) - (lui a2 #x6c00) - (ori a2 a2 291) - (sll32 a3 frame-qwc 24) - (srl32 a3 a3 8) - (or a2 a2 a3) ;; UNPACK V4-32, 18 qwords, VU address 291 - (s.w a2 cursor 12) - (add.i cursor cursor 16) - (s.w.field cursor a0 (base))) - (asm-block fill-camera-frame-data - (l.w.field a0 buffer (base)) - (add cursor r0 a0) - (m! camera *math-camera*) - (lea.field t1 camera (camera-temp)) - (l.q camera t1) - (l.q a3 t1 16) - (l.q t0 t1 32) - (l.q t1 t1 48) - (s.q camera cursor) - (s.q a3 cursor 16) - (s.q t0 cursor 32) - (s.q t1 cursor 48) - (add.i cursor a0 64) - (m! camera *math-camera*) - (lea.field camera camera (hmge-scale)) - (l.q camera camera) - (s.q camera cursor) - (add.i cursor a0 80) - (m! camera *math-camera*) - (lea.field camera camera (hvdf-off)) - (l.q camera camera) - (s.q camera cursor) - ;; Keep the sky on its fixed GS depth plane instead of applying the camera's Z offset. - (m f0 r0) - (s.s f0 a0 88) - (m! cursor *math-camera*) - (l.s.field f0 cursor (pfog0)) - (s.s f0 a0 96) - (l.s f0 function-base sky-radius) - (s.s f0 a0 100) - (l.s f0 function-base sky-no-kick) - (s.s f0 a0 108)) - (asm-block fill-gif-state - ;; Constant RGBAQ A+D record: RGBA=(128,96,96,32), Q=1. - (lui cursor #x2060) - (ori cursor cursor #x6080) - (s.w cursor a0 128) - (lui cursor #x3f80) - (s.w cursor a0 132) - (add.i cursor r0 1) - (s.w cursor a0 136) - (s.w r0 a0 140) - ;; Gouraud, alpha-blended fan and strip tags, each alternating A+D color and XYZF2. - (l.d cursor function-base sky-sun-fan-tag) - (pcpyld cursor r0 cursor) - (s.d cursor a0 224) - (add.i cursor r0 78) - (s.d cursor a0 232) - (l.d cursor function-base sky-sun-strip-tag) - (pcpyld cursor r0 cursor) - (s.d cursor a0 240) - (add.i cursor r0 78) - (s.d cursor a0 248) - ;; ALPHA_1 value 0x44 and its one-register A+D GIF tag. - (add.i cursor r0 68) - (s.d cursor a0 256) - (add.i cursor r0 66) - (s.d cursor a0 264) - (l.d cursor function-base sky-alpha-tag) - (pcpyld cursor r0 cursor) - (s.d cursor a0 272) - (add.i cursor r0 14) - (s.d cursor a0 280)) - (l.w.field a0 buffer (base)) - (sll frame-qwc frame-qwc 4) - (add frame-qwc a0 frame-qwc) - (s.w.field frame-qwc buffer (base)) - ;; Convert the current primary light group into the VU layout retained by sky-parms. - (m! t9 vu-lights<-light-group!) - (m! frame-qwc *sky-parms*) - (lea.field a0 frame-qwc (default-vu-lights)) - (m! frame-qwc *time-of-day-context*) - (lea.field a1 frame-qwc (light-group 0)) - (jalr ra t9 :delay (sll v0 ra 0)) - ;; Refresh the standalone 27-qword image, then reference it with an UNPACK to address 256. - (m! t9 qmem-copy<-!) - (m! frame-qwc *sky-upload-data*) - (lea.field a0 frame-qwc (data)) - (m! frame-qwc *sky-parms*) - (lea.field a1 frame-qwc (upload-data data)) - (add.i a2 r0 432) - (jalr ra t9 :delay (sll v0 ra 0)) - (l.w.field frame-qwc buffer (base)) - (lui a0 #x3000) - (ori a0 a0 27) - (m! a1 *sky-upload-data*) - (lea.field a1 a1 (data)) - (sll32 a1 a1 1) - (srl a1 a1 1) - (or a0 a0 a1) - (s.d a0 frame-qwc) - (s.w r0 frame-qwc 8) - (lui a0 #x6c1b) - (ori a0 a0 256) - (s.w a0 frame-qwc 12) ;; UNPACK V4-32, 27 qwords, VU address 256 - (add.i frame-qwc frame-qwc 16) - (s.w.field frame-qwc buffer (base)) - (m result s7) - (l.d ra sp) - (l.d function-base sp 8) - (l.q buffer sp 16) - (jr ra :delay (add.i sp sp 32)) - (nop! :count 2))) - (defun sky-upload ((dma-buf dma-buffer) (unused object)) - "Upload the old sky VU1 program and frame data, then append an MSCALF packet for entry zero." - (declare (asm-func none) (allow-saved-regs)) - (rlet ((buffer :reg gp) - (legacy-arg :reg s5) - (cursor :reg v1) - (result :reg v0)) - (add.i sp sp -48) - (s.d ra sp) - (s.q legacy-arg sp 16) - (s.q buffer sp 32) - (m buffer a0) - (m legacy-arg a1) - (m! t9 dma-buffer-add-vu-function) - (m a0 buffer) - (m! a1 sky-vu1-block) - (add.i a2 r0 1) - (jalr ra t9 :delay (sll v0 ra 0)) - (m! t9 sky-add-frame-data) - (m a0 buffer) - (m a1 legacy-arg) - (jalr ra t9 :delay (sll v0 ra 0)) - (l.w.field cursor buffer (base)) - (lui a0 #x1000) - (s.d a0 cursor) - (lui a0 #x1500) - (add.i a1 r0 0) - (sll32 a1 a1 16) - (srl32 a1 a1 16) - (or a0 a0 a1) - (s.w a0 cursor 8) - (lui a0 #x1000) - (s.w a0 cursor 12) - (add.i cursor cursor 16) - (s.w.field cursor buffer (base)) - (m result r0) - (l.d ra sp) - (l.q buffer sp 32) - (l.q legacy-arg sp 16) - (jr ra :delay (add.i sp sp 48)) - (nop! :count 3))) - (defun sky-draw ((dma-buf dma-buffer)) - "Append the MSCALF packet that enters sky-vu1-block at draw-sun-0." - (declare (asm-func none)) - (rlet ((buffer :reg v1) - (cursor :reg a0) - (command :reg a1) - (entry :reg a2) - (result :reg v0)) - (m buffer a0) - (l.w.field cursor buffer (base)) - (lui command #x1000) - (s.d command cursor) - (lui command #x1500) - (add.i entry r0 191) - (sll32 entry entry 16) - (srl32 entry entry 16) - (or command command entry) - (s.w command cursor 8) - (lui command #x1000) - (s.w command cursor 12) - (add.i cursor cursor 16) - (s.w.field cursor buffer (base)) - (m result r0) - (jr ra :delay (add sp sp r0)) - (nop! :count 2)))) +(defun sky-add-frame-data ((dma-buf dma-buffer) (unused object)) + "Append the old sky renderer's 18-quadword frame constants, refresh its VU light block, copy + the current circle, sun, and moon data into contiguous upload storage, and append the VIF + transfer for that 27-quadword image." + (let ((frame-qwc 18)) + (dma-buffer-add-cnt-vif2 dma-buf + frame-qwc + (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl)) + (new 'static 'vif-tag :imm #x123 :cmd (vif-cmd unpack-v4-32) :num frame-qwc)) + (let ((frame (the-as sky-frame-data (-> dma-buf base)))) + (dotimes (i 4) + (set! (-> frame world-homo-matrix vector i quad) (-> *math-camera* camera-temp vector i quad))) + (vector-copy! (-> frame hmge-scale) (-> *math-camera* hmge-scale)) + (vector-copy! (-> frame hvdf-offset) (-> *math-camera* hvdf-off)) + ;; The sky uses a fixed GS depth plane rather than the camera's z offset. + (set! (-> frame hvdf-offset z) 0.0) + (set! (-> frame pfog0) (-> *math-camera* pfog0)) + (set! (-> frame radius) 4096000.0) + (set! (-> frame nokick) 3072.0) + (set-vector! (-> frame col-adgif vector4w) #x20606080 #x3f800000 1 0) + (set! (-> frame sun-fan-giftag dword 0) (the-as uint #x2026c00000008012)) + (set! (-> frame sun-fan-giftag dword 1) (the-as uint 78)) + (set! (-> frame sun-strip-giftag dword 0) (the-as uint #x2026400000008022)) + (set! (-> frame sun-strip-giftag dword 1) (the-as uint 78)) + (set! (-> frame sun-alpha dword 0) (the-as uint 68)) + (set! (-> frame sun-alpha dword 1) (the-as uint 66)) + (set! (-> frame sun-alpha-giftag dword 0) (the-as uint #x1000000000000001)) + (set! (-> frame sun-alpha-giftag dword 1) (the-as uint 14))) + (&+! (-> dma-buf base) (* frame-qwc 16))) + (vu-lights<-light-group! (-> *sky-parms* default-vu-lights) (-> *time-of-day-context* light-group 0)) + (qmem-copy<-! (the-as pointer (-> *sky-upload-data* circle)) + (the-as pointer (-> *sky-parms* upload-data circle)) + 432) + (dma-buffer-add-ref-vif2 dma-buf + #x1b + (the-as int (-> *sky-upload-data* circle)) + (new 'static 'vif-tag) + (new 'static 'vif-tag :imm #x100 :num #x1b :cmd (vif-cmd unpack-v4-32))) + #f) + +(defun sky-upload ((dma-buf dma-buffer) (unused object)) + "Upload the old sky VU1 program and its current frame and celestial data, then start the + program's setup entry point." + (dma-buffer-add-vu-function dma-buf sky-vu1-block 1) + (sky-add-frame-data dma-buf unused) + (dma-buffer-add-cnt-vif2 dma-buf + 0 + (new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1 :imm #x0) + (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1)) + (none)) + +(defun sky-draw ((dma-buf dma-buffer)) + "Append the VIF command that starts the old sky VU1 program's draw entry point." + (dma-buffer-add-cnt-vif2 dma-buf + 0 + (new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1 :imm #xbf) + (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1)) + (none)) ;; set the suns (sky-set-sun-radii *sky-parms* (sky-sun-index sun) 60.0 200.0 300.0) @@ -589,10 +428,10 @@ (sky-set-sun-colors *sky-parms* (sky-sun-index green-sun) - (new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x80) - (new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x80) - (new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x20) - (new 'static 'rgba :r #xc2 :g #xfe :b #x78)) + (static-rgba #xc2 #xfe #x78 #x80) + (static-rgba #xc2 #xfe #x78 #x80) + (static-rgba #xc2 #xfe #x78 #x20) + (static-rgba #xc2 #xfe #x78 0)) (sky-set-orbit *sky-parms* (sky-orbit-index sun) 12.5 -15.0 0.0 9950.0 300.0 300.0) diff --git a/goal_src/jak1/engine/level/level.gc b/goal_src/jak1/engine/level/level.gc index 00b6178bf3..f03bd2ff72 100644 --- a/goal_src/jak1/engine/level/level.gc +++ b/goal_src/jak1/engine/level/level.gc @@ -48,12 +48,15 @@ (defmethod art-group-get-by-name ((this level) (name string)) "Return this level's art group whose name matches name, or false." (countdown (i (-> this art-group art-group-array length)) - (if (name= (-> this art-group art-group-array i name) name) (return (-> this art-group art-group-array i)))) + (if (name= (-> this art-group art-group-array i name) name) + (return (-> this art-group art-group-array i)))) (the-as art-group #f)) (defmethod bsp-name ((this level)) "Return the loaded BSP name when available, otherwise return this level's requested name." - (if (and (!= (-> this status) 'inactive) (-> this bsp) (nonzero? (-> this bsp name))) (-> this bsp name) (-> this name))) + (if (and (!= (-> this status) 'inactive)(-> this bsp) (nonzero? (-> this bsp name))) + (-> this bsp name) + (-> this name))) ;;;;;;;;;;;;;;;;;;;;;;;;; ;; BSP @@ -67,9 +70,10 @@ (defun add-bsp-drawable ((bsp-data bsp-header) (level-data level) (unused symbol) (display-frame-data display-frame)) "Draw a level BSP for the current display frame and optionally append its strip-line debug view." - ;; do the draw + ;; do the draw (just adds to background queues, real drawing is deferred again.) (draw bsp-data bsp-data display-frame-data) - (if (nonzero? *display-strip-lines*) (debug-draw bsp-data bsp-data display-frame-data)) + (if (nonzero? *display-strip-lines*) + (debug-draw bsp-data bsp-data display-frame-data)) (none)) (defmethod print ((this level)) @@ -80,7 +84,7 @@ (defmethod relocate ((this bsp-header) (heap kheap) (name (pointer uint8))) "Validate a newly linked BSP for the currently loading level, preserve the corrected title and demo names, and connect the BSP and level to each other. Reject invalid types, versions, and - visibility lists longer than 2048 entries." + visibility lists longer than 2048 bytes." ;; we expect that we'll have a loading-level set when we link/login a bsp-header (let ((loading-level (-> *level* loading-level))) (if loading-level @@ -114,7 +118,8 @@ (defmethod load-required-packages ((this level)) "Load the common package requested by a non-debug BSP when its level package list is nonempty." (when (not (or (not (-> this bsp)) (= *kernel-boot-mode* 'debug-boot))) - (if (not (null? (-> this info packages))) (load-package "common" global))) + (if (not (null? (-> this info packages))) + (load-package "common" global))) this) ;;;;;;;;;;;;;; @@ -265,7 +270,9 @@ (defmethod level-status ((this level-group) (level-name symbol)) "Return the status of the loaded level matching level-name, or false." - (let ((loaded-level (level-get *level* level-name))) (if loaded-level (-> loaded-level status)))) + (let ((loaded-level (level-get *level* level-name))) + (if loaded-level + (-> loaded-level status)))) (defmethod level-status-set! ((this level) (want-status symbol)) "Move this level toward want-status through the legal load, login, birth, activation, @@ -304,7 +311,7 @@ (remove-by-param1 *background-draw-engine* (-> this bsp)) (add-connection *background-draw-engine* *dproc* - (the (function object object object object object) add-bsp-drawable) + add-bsp-drawable (-> this bsp) this #f) @@ -1037,7 +1044,7 @@ 0) (defun update-sound-banks () - "Reconcile the two resident sound-bank slots with the distinct banks required by active levels. + "Set up sound banks based on the currently loaded levels. Do nothing while the loader RPC is busy or a movie is active, report more than two requirements, and perform at most one load or unload per call." (if (nonzero? (rpc-busy? RPC-SOUND-LOADER)) (return 0)) @@ -1122,7 +1129,8 @@ (define-extern *entity* entity) (set! *entity* (the entity #f))))))))) (let ((ordinary-slots-empty #f)) - (if (and (= (-> *level* level0 status) 'inactive) (= (-> *level* level1 status) 'inactive)) (set! ordinary-slots-empty #t)) + (if (and (= (-> *level* level0 status) 'inactive) (= (-> *level* level1 status) 'inactive)) + (set! ordinary-slots-empty #t)) (if discarded-level (return 0)) (let ((need-level0 #f) (need-level1 #f)) @@ -1367,7 +1375,8 @@ (format *stdcon* " nick ~A cur ~S cont ~A~%~%" (-> *load-state* vis-nick) - (let ((lev-name (and *target* (-> *target* current-level name)))) (if lev-name (symbol->string lev-name))) + (let ((lev-name (and *target* (-> *target* current-level name)))) + (if lev-name (symbol->string lev-name))) (-> *game-info* current-continue name)) ; (let ((t9-16 format) ; (a0-53 *stdcon*) diff --git a/goal_src/jak1/engine/level/load-boundary-ee-asm.gc b/goal_src/jak1/engine/level/load-boundary-ee-asm.gc new file mode 100644 index 0000000000..6138eede87 --- /dev/null +++ b/goal_src/jak1/engine/level/load-boundary-ee-asm.gc @@ -0,0 +1,415 @@ +;;-*-Lisp-*- +(in-package goal) +(bundles "ENGINE.CGO" "GAME.CGO") +(require "engine/level/load-boundary.gc") + +;; Reference-only Emotion Engine implementation of the original inline VU0 boundary renderer. +;; This file is intentionally not part of any project or DGO manifest. + +;; Boundary faces use the sky clipper's closed 48-byte polygon records: +;; +;; +0x00 homogeneous position +;; +0x10 perspective texture coordinates +;; +0x20 floating-point RGBA +;; +;; The input uses three consecutive lbvtx values for each logical vertex. The first two logical +;; colors hold the forward- and backward-facing display colors; the remaining vertices reuse the +;; selected color. Triangles become records 0, 1, 2, 0 and quads become 0, 1, 2, 3, 0 in the +;; #x70003000 scratch page. draw-boundary-polygon alternates that page with #x70003800 while the +;; sky clippers apply x <= w, y <= w, x >= -w, and y >= -w. +(#unless PC_PORT + (asm-data (label boundary-fog-ceiling) (word #x453ff000)) ;; 3071.0 + (defun init-boundary-regs () + "Load the camera, homogeneous projection, fog range, and zero texture phase used by boundary + drawing. Unlike the sky path, vf25 keeps the camera's ordinary homogeneous screen offset." + (declare (asm-func none)) + (rlet ((camera :reg v1 :type math-camera) + (fog-data :reg a0 :type sky-tng-data) + (function-base :reg fp) + (result :reg v0) + (camera-x :reg vf31) + (camera-y :reg vf30) + (camera-z :reg vf29) + (camera-w :reg vf28) + (homogeneous-scale :reg vf14) + (inverse-homogeneous-scale :reg vf26) + (screen-offset :reg vf25) + (texture-offset :reg vf24) + (fog-range :reg vf13)) + (add.i sp sp -16) + (s.d function-base sp 8) + (m function-base t9) + (m! camera *math-camera*) + (m! fog-data *sky-tng-data*) + (lea.field fog-data fog-data (fog)) + ;; Keep fog parameters resident in vf13 so the packet loop needs no scalar camera loads. + (l.s.field f0 camera (pfog0)) + (s.s f0 fog-data) + (l.s.field f0 camera (fog-min)) + (s.s f0 fog-data 4) + (l.s.field f0 camera (fog-max)) + (s.s f0 fog-data 8) + (l.s f0 function-base boundary-fog-ceiling) + (s.s f0 fog-data 12) + (asm-block load-boundary-camera-state + (l.vf.field camera-x camera (camera-temp vector 0 quad)) + (l.vf.field camera-y camera (camera-temp vector 1 quad)) + (l.vf.field camera-z camera (camera-temp vector 2 quad)) + (l.vf.field camera-w camera (camera-temp vector 3 quad)) + (l.vf.field homogeneous-scale camera (hmge-scale quad)) + (l.vf.field inverse-homogeneous-scale camera (inv-hmge-scale quad)) + (l.vf.field screen-offset camera (hvdf-off quad)) + (rlet ((sky-data :reg v1 :type sky-tng-data)) + ;; Load the packed fog limits after the last camera field access. + (m! sky-data *sky-tng-data*) + (l.vf.field fog-range sky-data (fog))) + (mul.vf camera-x camera-x homogeneous-scale) + (mul.vf camera-y camera-y homogeneous-scale) + (mul.vf camera-z camera-z homogeneous-scale) + (mul.vf camera-w camera-w homogeneous-scale) + (vmove.xyzw texture-offset vf0)) + ;; Mirror the cleared texture phase in the EE register file. + (rlet ((texture-offset-bits :reg v1)) + (m texture-offset-bits texture-offset)) + (m result r0) + (l.d function-base sp 8) + (jr ra :delay (add.i sp sp 16)) + (nop! :count 2))) + (defun draw-boundary-polygon () + "Clip a closed boundary polygon against the four side planes and append ST/RGBAQ/XYZF records. + The private calling convention carries the vertex count in t0, DMA buffer in a1, and scratch + pages in t4 and t5. Return #f when clipping removes every vertex." + (declare (asm-func none)) + (rlet ((dma-buf :reg a1 :type dma-buffer) + (input-page :reg a2) + (output :reg a3) + (page-a :reg t4) + (page-b :reg t5) + (vertex-count :reg t0) + (component :reg t2) + (clip-function :reg t9) + (position :reg vf1) + (stq :reg vf2) + (color :reg vf3) + (gif-tag :reg vf27) + (inverse-homogeneous-scale :reg vf26) + (screen-offset :reg vf25) + (texture-offset :reg vf24) + (fog-range :reg vf13) + (result :reg v0)) + (nop!) + (add.i sp sp -8) + (nop!) + (s.d ra sp) + ;; Each pass streams into the other scratch page. component points at x for the first and + ;; third passes and y for the second and fourth. + (asm-block clip-boundary-side-planes + (m! clip-function clip-polygon-against-positive-hyperplane) + (m input-page page-a) + (m output page-b) + (jalr ra clip-function :delay (add component input-page r0)) + (b.z vertex-count boundary-polygon-clipped-away :delay (nop!)) + (m input-page page-b) + (m output page-a) + (jalr ra clip-function :delay (add.i component input-page 4)) + (b.z vertex-count boundary-polygon-clipped-away :delay (m! clip-function clip-polygon-against-negative-hyperplane)) + (m input-page page-a) + (m output page-b) + (jalr ra clip-function :delay (add component input-page r0)) + (b.z vertex-count boundary-polygon-clipped-away :delay (nop!)) + (m input-page page-b) + (m output page-a) + (jalr ra clip-function :delay (add.i component input-page 4)) + (b.z vertex-count boundary-polygon-clipped-away :delay (l.w.field output dma-buf (base)))) + ;; vf27 supplies the fixed GIF tag. The clipped count replaces its first word before emitting + ;; one three-qword GS vertex for every remaining polygon point. + (m input-page page-a) + (nop!) + (s.vf gif-tag output) + (add.i output output 16) + (s.w vertex-count output -16) + (nop!) + (label emit-boundary-vertices) + (asm-block project-boundary-vertex + (l.vf position input-page) + (nop!) + (l.vf stq input-page 16) + (nop!) + (l.vf color input-page 32) + (div.w.w Q vf0 position) + (mul.vf position position inverse-homogeneous-scale) + (nop!) + (ftoi.vf color color) + (nop!) + (add.vf stq stq texture-offset) + (nop!) + (waitq) + (nop!) + (mulq.vf.xyz position position Q) + (s.vf color output 16) + (mulq.vf stq stq Q) + (add.i input-page input-page 48) + (add.vf position position screen-offset) + (add.i output output 48) + ;; Boundary geometry keeps projected depth instead of using the sky layer value. + ;; Clamp z to the near side of the GS range, and fog between fog-min and fog-max. + (max.z.vf.z position position vf0) + (nop!) + (min.z.vf.w position position fog-range) + (nop!) + (max.y.vf.w position position fog-range) + (nop!) + (s.vf stq output -48) + (add.i vertex-count vertex-count -1) + (ftoi.vf position position :fixed 4) + (nop!) + (b.nz vertex-count emit-boundary-vertices :delay (s.vf position output -16))) + (s.w.field output dma-buf (base)) + (nop!) + (l.d ra sp) + (add.i result s7 8) + (jr ra :delay (add.i sp sp 8)) + (label boundary-polygon-clipped-away) + (l.d ra sp) + (m result s7) + (jr ra :delay (add.i sp sp 8)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2))) + (defun render-boundary-quad ((vertices lbvtx) (dma-buf dma-buffer)) + "Transform four boundary vertices into a closed scratch polygon, select the forward or backward + display color from its camera-facing sign, and tail-call draw-boundary-polygon." + (declare (asm-func none)) + (rlet ((vertex-data :reg a0) + (input-copy :reg v1) + (output :reg a3) + (page-a :reg t4) + (page-b :reg t5) + (vertex-count :reg t0) + (draw-function :reg t9) + (facing-bits :reg v0) + (point-0 :reg vf1) + (tex-0 :reg vf2) + (forward-color :reg vf3) + (point-1 :reg vf4) + (tex-1 :reg vf5) + (backward-color :reg vf6) + (point-2 :reg vf7) + (tex-2 :reg vf8) + (point-3-and-facing :reg vf10) + (tex-3 :reg vf11) + (camera-x :reg vf31) + (camera-y :reg vf30) + (camera-z :reg vf29) + (camera-w :reg vf28) + (homogeneous-scale :reg vf14)) + (m input-copy vertex-data) + (rlet ((camera :reg v1 :type math-camera)) + (m! camera *math-camera*) + ;; Refresh the homogeneous scale with the rest of the boundary camera state. + (l.vf.field homogeneous-scale camera (hmge-scale quad))) + (lui page-a #x7000) + (ori page-a page-a #x3000) + (lui page-b #x7000) + (ori page-b page-b #x3800) + (m output page-a) + ;; Each logical input record is position, STQ, and color. Only the first two colors are + ;; loaded: forward-color is installed provisionally, then replaced when the face points the + ;; other way. + (asm-block transform-boundary-quad + (nop!) + (l.vf point-0 vertex-data) + (add.i vertex-count r0 4) + (l.vf tex-0 vertex-data 16) + (nop!) + (l.vf forward-color vertex-data 32) + (mula.x.vf camera-x point-0) + (l.vf point-1 vertex-data 48) + (madda.y.vf camera-y point-0) + (l.vf tex-1 vertex-data 64) + (madda.z.vf camera-z point-0) + (l.vf backward-color vertex-data 80) + (madd.w.vf point-0 camera-w point-0) + (l.vf point-2 vertex-data 96) + (nop!) + (l.vf tex-2 vertex-data 112) + (mula.x.vf camera-x point-1) + (nop!) + (madda.y.vf camera-y point-1) + (l.vf point-3-and-facing vertex-data 144) + (madda.z.vf camera-z point-1) + (l.vf tex-3 vertex-data 160) + (madd.w.vf point-1 camera-w point-1) + (nop! :count 2) + (s.vf tex-0 output 16) + (mula.x.vf camera-x point-2) + (s.vf forward-color output 32) + (madda.y.vf camera-y point-2) + (s.vf tex-1 output 64) + (madda.z.vf camera-z point-2) + (s.vf forward-color output 80) + (madd.w.vf point-2 camera-w point-2) + (s.vf tex-2 output 112) + (nop!) + (s.vf forward-color output 128) + (mula.x.vf camera-x point-3-and-facing) + (s.vf tex-3 output 160) + (madda.y.vf camera-y point-3-and-facing) + (s.vf forward-color output 176) + (madda.z.vf camera-z point-3-and-facing) + (s.vf tex-0 output 208) + (madd.w.vf point-3-and-facing camera-w point-3-and-facing) + (s.vf forward-color output 224) + (nop!) + (s.vf point-0 output) + (nop!) + (s.vf point-0 output 192) + (nop!) + (s.vf point-1 output 48) + (nop!) + (s.vf point-2 output 96) + (nop!) + (s.vf point-3-and-facing output 144)) + ;; The scalar triple product dot(cross(p1-p0, p2-p0), p0) determines which side faces the + ;; camera origin after transformation. The sum is placed in vf10.y; moving the low 64 bits + ;; into v0 makes that lane's sign available to the integer branch. + (asm-block choose-boundary-quad-color + (m! draw-function draw-boundary-polygon) + (sub.vf point-1 point-1 point-0) + (nop!) + (sub.vf point-2 point-2 point-0) + (nop!) + (outer.product.a.vf acc point-1 point-2) + (nop!) + (outer.product.b.vf point-3-and-facing point-2 point-1 acc) + (nop!) + (mul.vf point-3-and-facing point-3-and-facing point-0) + (nop!) + (add.x.vf.y point-3-and-facing point-3-and-facing point-3-and-facing) + (nop!) + (add.z.vf.y point-3-and-facing point-3-and-facing point-3-and-facing) + (nop!) + (m facing-bits point-3-and-facing) + (nop!) + (b.ge facing-bits r0 use-backward-quad-color :delay (nop!)) + (jr draw-function :delay (nop!))) + (label use-backward-quad-color) + ;; Recolor only the four distinct records. The duplicate closure retains the provisional + ;; color, which also participates in interpolation if clipping crosses the final edge. + (s.vf backward-color output 32) + (nop!) + (s.vf backward-color output 80) + (nop!) + (s.vf backward-color output 128) + (nop!) + (s.vf backward-color output 176) + (nop!) + (jr draw-function :delay (nop!)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2))) + (defun render-boundary-tri ((vertices lbvtx) (dma-buf dma-buffer)) + "Transform three boundary vertices into a closed scratch polygon, select the forward or backward + display color from its camera-facing sign, and tail-call draw-boundary-polygon." + (declare (asm-func none)) + (rlet ((vertex-data :reg a0) + (input-copy :reg v1) + (output :reg a3) + (page-a :reg t4) + (page-b :reg t5) + (vertex-count :reg t0) + (draw-function :reg t9) + (facing-bits :reg v0) + (point-0 :reg vf1) + (tex-0 :reg vf2) + (forward-color :reg vf3) + (point-1 :reg vf4) + (tex-1 :reg vf5) + (backward-color :reg vf6) + (point-2 :reg vf7) + (tex-2 :reg vf8) + (facing :reg vf10) + (camera-x :reg vf31) + (camera-y :reg vf30) + (camera-z :reg vf29) + (camera-w :reg vf28)) + (m input-copy vertex-data) + (lui page-a #x7000) + (ori page-a page-a #x3000) + (lui page-b #x7000) + (ori page-b page-b #x3800) + (m output page-a) + (asm-block transform-boundary-triangle + (nop!) + (l.vf point-0 vertex-data) + (add.i vertex-count r0 3) + (l.vf tex-0 vertex-data 16) + (nop!) + (l.vf forward-color vertex-data 32) + (mula.x.vf camera-x point-0) + (l.vf point-1 vertex-data 48) + (madda.y.vf camera-y point-0) + (l.vf tex-1 vertex-data 64) + (madda.z.vf camera-z point-0) + (l.vf backward-color vertex-data 80) + (madd.w.vf point-0 camera-w point-0) + (l.vf point-2 vertex-data 96) + (nop!) + (l.vf tex-2 vertex-data 112) + (mula.x.vf camera-x point-1) + (nop!) + (madda.y.vf camera-y point-1) + (s.vf tex-0 output 16) + (madda.z.vf camera-z point-1) + (s.vf forward-color output 32) + (madd.w.vf point-1 camera-w point-1) + (s.vf tex-1 output 64) + (nop!) + (s.vf forward-color output 80) + (mula.x.vf camera-x point-2) + (s.vf tex-2 output 112) + (madda.y.vf camera-y point-2) + (s.vf forward-color output 128) + (madda.z.vf camera-z point-2) + (s.vf tex-0 output 160) + (madd.w.vf point-2 camera-w point-2) + (s.vf forward-color output 176) + (nop!) + (s.vf point-0 output) + (nop!) + (s.vf point-0 output 144) + (nop!) + (s.vf point-1 output 48) + (nop!) + (s.vf point-2 output 96)) + (asm-block choose-boundary-triangle-color + (m! draw-function draw-boundary-polygon) + (sub.vf point-1 point-1 point-0) + (nop!) + (sub.vf point-2 point-2 point-0) + (nop!) + (outer.product.a.vf acc point-1 point-2) + (nop!) + (outer.product.b.vf facing point-2 point-1 acc) + (nop!) + (mul.vf facing facing point-0) + (nop!) + (add.x.vf.y facing facing facing) + (nop!) + (add.z.vf.y facing facing facing) + (nop!) + (m facing-bits facing) + (nop!) + (b.ge facing-bits r0 use-backward-triangle-color :delay (nop!)) + (jr draw-function :delay (nop!))) + (label use-backward-triangle-color) + ;; The fourth record repeats point zero, so it receives the selected color as well. + (s.vf backward-color output 32) + (nop!) + (s.vf backward-color output 80) + (nop!) + (s.vf backward-color output 128) + (nop!) + (s.vf backward-color output 176) + (nop!) + (jr draw-function :delay (nop!)) + (jr ra :delay (add sp sp r0)) + (nop! :count 2)))) diff --git a/goal_src/jak1/engine/level/load-boundary-h.gc b/goal_src/jak1/engine/level/load-boundary-h.gc index 62aa50ce81..e27b83839e 100644 --- a/goal_src/jak1/engine/level/load-boundary-h.gc +++ b/goal_src/jak1/engine/level/load-boundary-h.gc @@ -16,7 +16,7 @@ ;; Boundary coordinates and the byte-sized links used while triangulating a closed polygon. ;; v0/v1/v2 are previous/next/active in *triangulation-buffer*, then triangle vertex indices in -;; load-boundary.data[0..tri-cnt). ix remembers the original vertex ordinal. +;; load-boundary.data[0..tri-cnt). ix is the original vertex index. (deftype lbvtx (structure) ((x float) (y float) @@ -33,16 +33,14 @@ :type uint8 (invalid 0) ;; No command. (load 1) ;; Replace the desired pair of loaded levels. - (cmd2 2) ;; Reserved; no executor or boundary data uses it. + (cmd2 2) ;; Unused (display 3) ;; Set a loaded level's display mode. (vis 4) ;; Select the active visibility nickname. (force-vis 5) ;; Bypass BSP visibility outside this level's inside boxes. (checkpt 6) ;; Select a continue point. ) -;; Command to execute when crossing. bparm is reserved padding; parm contains the two GOAL object -;; parameters. The named overlays describe the meanings used by each command without changing the -;; original generic lev0/lev1 vocabulary. +;; Command to execute when crossing. (deftype load-boundary-crossing-command (structure) ((cmd load-boundary-cmd) (bparm uint8 3) diff --git a/goal_src/jak1/engine/level/load-boundary.gc b/goal_src/jak1/engine/level/load-boundary.gc index bc9f6f9e1b..7e2134dbf6 100644 --- a/goal_src/jak1/engine/level/load-boundary.gc +++ b/goal_src/jak1/engine/level/load-boundary.gc @@ -36,9 +36,9 @@ ;; The editor uses the same system as sky for drawing large polygons. -;; The PC renderer keeps the persistent VU0 state in the MIPS2C context. -(#when PC_PORT - (def-mips2c init-boundary-regs (function none))) +;; Boundary rendering shares the sky polygon renderer's clipping logic. +;; Projection differs in two ways: it uses the camera's ordinary +;; screen offset and preserves projected depth instead of replacing it with a sky layer depth. (defun-debug add-boundary-shader ((shader-texture texture-id) (dma-buf dma-buffer)) "Append the fixed five-register ADGIF shader used by @@ -66,418 +66,119 @@ (&+! (-> dma-buf base) 80) (none)) -;; The polygon conversion and both entry points use that same context on PC. -(#when PC_PORT - (def-mips2c draw-boundary-polygon function) - (def-mips2c render-boundary-quad (function lbvtx dma-buffer none)) - (def-mips2c render-boundary-tri (function lbvtx dma-buffer none))) +(defun init-boundary-regs () + "Snapshot the camera, projection, fog, and roof giftag used by subsequent boundary polygon calls." + (let ((state *sky-polygon-renderer*)) + (dotimes (i 4) + (sky-vector4*! (-> state transform vector i) (-> *math-camera* camera-temp vector i) (-> *math-camera* hmge-scale))) + (vector-copy! (-> state inv-hmge-scale) (-> *math-camera* inv-hmge-scale)) + (vector-copy! (-> state screen-offset) (-> *math-camera* hvdf-off)) + (set-vector! (-> state fog-clamp) (-> *math-camera* pfog0) (-> *math-camera* fog-min) (-> *math-camera* fog-max) 3071.0) + (vector-copy! (-> *sky-tng-data* fog) (-> state fog-clamp)) + (set-vector! (-> state texture-offset) 0.0 0.0 0.0 0.0) + (set-sky-giftag (-> *sky-tng-data* giftag-roof))) + (none)) -;; Boundary faces use the sky clipper's closed 48-byte polygon records: -;; -;; +0x00 homogeneous position -;; +0x10 perspective texture coordinates -;; +0x20 floating-point RGBA -;; -;; The input uses three consecutive lbvtx values for each logical vertex. The first two logical -;; colors hold the forward- and backward-facing display colors; the remaining vertices reuse the -;; selected color. Triangles become records 0, 1, 2, 0 and quads become 0, 1, 2, 3, 0 in the -;; #x70003000 scratch page. draw-boundary-polygon alternates that page with #x70003800 while the -;; sky clippers apply x <= w, y <= w, x >= -w, and y >= -w. -(#unless PC_PORT - (asm-data (label boundary-fog-ceiling) (word #x453ff000)) ;; 3071.0 - (defun init-boundary-regs () - "Load the camera, homogeneous projection, fog range, and zero texture phase used by boundary - drawing. Unlike the sky path, vf25 keeps the camera's ordinary homogeneous screen offset." - (declare (asm-func none)) - (rlet ((camera :reg v1 :type math-camera) - (fog-data :reg a0 :type sky-tng-data) - (function-base :reg fp) - (result :reg v0) - (camera-x :reg vf31) - (camera-y :reg vf30) - (camera-z :reg vf29) - (camera-w :reg vf28) - (homogeneous-scale :reg vf14) - (inverse-homogeneous-scale :reg vf26) - (screen-offset :reg vf25) - (texture-offset :reg vf24) - (fog-range :reg vf13)) - (add.i sp sp -16) - (s.d function-base sp 8) - (m function-base t9) - (m! camera *math-camera*) - (m! fog-data *sky-tng-data*) - (lea.field fog-data fog-data (fog)) - ;; Keep fog parameters resident in vf13 so the packet loop needs no scalar camera loads. - (l.s.field f0 camera (pfog0)) - (s.s f0 fog-data) - (l.s.field f0 camera (fog-min)) - (s.s f0 fog-data 4) - (l.s.field f0 camera (fog-max)) - (s.s f0 fog-data 8) - (l.s f0 function-base boundary-fog-ceiling) - (s.s f0 fog-data 12) - (asm-block load-boundary-camera-state - (l.vf.field camera-x camera (camera-temp vector 0 quad)) - (l.vf.field camera-y camera (camera-temp vector 1 quad)) - (l.vf.field camera-z camera (camera-temp vector 2 quad)) - (l.vf.field camera-w camera (camera-temp vector 3 quad)) - (l.vf.field homogeneous-scale camera (hmge-scale quad)) - (l.vf.field inverse-homogeneous-scale camera (inv-hmge-scale quad)) - (l.vf.field screen-offset camera (hvdf-off quad)) - (rlet ((sky-data :reg v1 :type sky-tng-data)) - ;; Load the packed fog limits after the last camera field access. - (m! sky-data *sky-tng-data*) - (l.vf.field fog-range sky-data (fog))) - (mul.vf camera-x camera-x homogeneous-scale) - (mul.vf camera-y camera-y homogeneous-scale) - (mul.vf camera-z camera-z homogeneous-scale) - (mul.vf camera-w camera-w homogeneous-scale) - (vmove.xyzw texture-offset vf0)) - ;; Mirror the cleared texture phase in the EE register file. - (rlet ((texture-offset-bits :reg v1)) (m texture-offset-bits texture-offset)) - (m result r0) - (l.d function-base sp 8) - (jr ra :delay (add.i sp sp 16)) - (nop! :count 2))) - (defun draw-boundary-polygon () - "Clip a closed boundary polygon against the four side planes and append ST/RGBAQ/XYZF records. - The private calling convention carries the vertex count in t0, DMA buffer in a1, and scratch - pages in t4 and t5. Return #f when clipping removes every vertex." - (declare (asm-func none)) - (rlet ((dma-buf :reg a1 :type dma-buffer) - (input-page :reg a2) - (output :reg a3) - (page-a :reg t4) - (page-b :reg t5) - (vertex-count :reg t0) - (component :reg t2) - (clip-function :reg t9) - (position :reg vf1) - (stq :reg vf2) - (color :reg vf3) - (gif-tag :reg vf27) - (inverse-homogeneous-scale :reg vf26) - (screen-offset :reg vf25) - (texture-offset :reg vf24) - (fog-range :reg vf13) - (result :reg v0)) - (nop!) - (add.i sp sp -8) - (nop!) - (s.d ra sp) - ;; Each pass streams into the other scratch page. component points at x for the first and - ;; third passes and y for the second and fourth. - (asm-block clip-boundary-side-planes - (m! clip-function clip-polygon-against-positive-hyperplane) - (m input-page page-a) - (m output page-b) - (jalr ra clip-function :delay (add component input-page r0)) - (b.z vertex-count boundary-polygon-clipped-away :delay (nop!)) - (m input-page page-b) - (m output page-a) - (jalr ra clip-function :delay (add.i component input-page 4)) - (b.z vertex-count boundary-polygon-clipped-away :delay (m! clip-function clip-polygon-against-negative-hyperplane)) - (m input-page page-a) - (m output page-b) - (jalr ra clip-function :delay (add component input-page r0)) - (b.z vertex-count boundary-polygon-clipped-away :delay (nop!)) - (m input-page page-b) - (m output page-a) - (jalr ra clip-function :delay (add.i component input-page 4)) - (b.z vertex-count boundary-polygon-clipped-away :delay (l.w.field output dma-buf (base)))) - ;; vf27 supplies the fixed GIF tag. The clipped count replaces its first word before emitting - ;; one three-qword GS vertex for every remaining polygon point. - (m input-page page-a) - (nop!) - (s.vf gif-tag output) - (add.i output output 16) - (s.w vertex-count output -16) - (nop!) - (label emit-boundary-vertices) - (asm-block project-boundary-vertex - (l.vf position input-page) - (nop!) - (l.vf stq input-page 16) - (nop!) - (l.vf color input-page 32) - (div.w.w Q vf0 position) - (mul.vf position position inverse-homogeneous-scale) - (nop!) - (ftoi.vf color color) - (nop!) - (add.vf stq stq texture-offset) - (nop!) - (waitq) - (nop!) - (mulq.vf.xyz position position Q) - (s.vf color output 16) - (mulq.vf stq stq Q) - (add.i input-page input-page 48) - (add.vf position position screen-offset) - (add.i output output 48) - ;; Boundary geometry keeps projected depth instead of using the sky layer value. - ;; Clamp z to the near side of the GS range, and fog between fog-min and fog-max. - (max.z.vf.z position position vf0) - (nop!) - (min.z.vf.w position position fog-range) - (nop!) - (max.y.vf.w position position fog-range) - (nop!) - (s.vf stq output -48) - (add.i vertex-count vertex-count -1) - (ftoi.vf position position :fixed 4) - (nop!) - (b.nz vertex-count emit-boundary-vertices :delay (s.vf position output -16))) - (s.w.field output dma-buf (base)) - (nop!) - (l.d ra sp) - (add.i result s7 8) - (jr ra :delay (add.i sp sp 8)) - (label boundary-polygon-clipped-away) - (l.d ra sp) - (m result s7) - (jr ra :delay (add.i sp sp 8)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2))) - (defun render-boundary-quad ((vertices lbvtx) (dma-buf dma-buffer)) - "Transform four boundary vertices into a closed scratch polygon, select the forward or backward - display color from its camera-facing sign, and tail-call draw-boundary-polygon." - (declare (asm-func none)) - (rlet ((vertex-data :reg a0) - (input-copy :reg v1) - (output :reg a3) - (page-a :reg t4) - (page-b :reg t5) - (vertex-count :reg t0) - (draw-function :reg t9) - (facing-bits :reg v0) - (point-0 :reg vf1) - (tex-0 :reg vf2) - (forward-color :reg vf3) - (point-1 :reg vf4) - (tex-1 :reg vf5) - (backward-color :reg vf6) - (point-2 :reg vf7) - (tex-2 :reg vf8) - (point-3-and-facing :reg vf10) - (tex-3 :reg vf11) - (camera-x :reg vf31) - (camera-y :reg vf30) - (camera-z :reg vf29) - (camera-w :reg vf28) - (homogeneous-scale :reg vf14)) - (m input-copy vertex-data) - (rlet ((camera :reg v1 :type math-camera)) - (m! camera *math-camera*) - ;; Refresh the homogeneous scale with the rest of the boundary camera state. - (l.vf.field homogeneous-scale camera (hmge-scale quad))) - (lui page-a #x7000) - (ori page-a page-a #x3000) - (lui page-b #x7000) - (ori page-b page-b #x3800) - (m output page-a) - ;; Each logical input record is position, STQ, and color. Only the first two colors are - ;; loaded: forward-color is installed provisionally, then replaced when the face points the - ;; other way. - (asm-block transform-boundary-quad - (nop!) - (l.vf point-0 vertex-data) - (add.i vertex-count r0 4) - (l.vf tex-0 vertex-data 16) - (nop!) - (l.vf forward-color vertex-data 32) - (mula.x.vf camera-x point-0) - (l.vf point-1 vertex-data 48) - (madda.y.vf camera-y point-0) - (l.vf tex-1 vertex-data 64) - (madda.z.vf camera-z point-0) - (l.vf backward-color vertex-data 80) - (madd.w.vf point-0 camera-w point-0) - (l.vf point-2 vertex-data 96) - (nop!) - (l.vf tex-2 vertex-data 112) - (mula.x.vf camera-x point-1) - (nop!) - (madda.y.vf camera-y point-1) - (l.vf point-3-and-facing vertex-data 144) - (madda.z.vf camera-z point-1) - (l.vf tex-3 vertex-data 160) - (madd.w.vf point-1 camera-w point-1) - (nop! :count 2) - (s.vf tex-0 output 16) - (mula.x.vf camera-x point-2) - (s.vf forward-color output 32) - (madda.y.vf camera-y point-2) - (s.vf tex-1 output 64) - (madda.z.vf camera-z point-2) - (s.vf forward-color output 80) - (madd.w.vf point-2 camera-w point-2) - (s.vf tex-2 output 112) - (nop!) - (s.vf forward-color output 128) - (mula.x.vf camera-x point-3-and-facing) - (s.vf tex-3 output 160) - (madda.y.vf camera-y point-3-and-facing) - (s.vf forward-color output 176) - (madda.z.vf camera-z point-3-and-facing) - (s.vf tex-0 output 208) - (madd.w.vf point-3-and-facing camera-w point-3-and-facing) - (s.vf forward-color output 224) - (nop!) - (s.vf point-0 output) - (nop!) - (s.vf point-0 output 192) - (nop!) - (s.vf point-1 output 48) - (nop!) - (s.vf point-2 output 96) - (nop!) - (s.vf point-3-and-facing output 144)) - ;; The scalar triple product dot(cross(p1-p0, p2-p0), p0) determines which side faces the - ;; camera origin after transformation. The sum is placed in vf10.y; moving the low 64 bits - ;; into v0 makes that lane's sign available to the integer branch. - (asm-block choose-boundary-quad-color - (m! draw-function draw-boundary-polygon) - (sub.vf point-1 point-1 point-0) - (nop!) - (sub.vf point-2 point-2 point-0) - (nop!) - (outer.product.a.vf acc point-1 point-2) - (nop!) - (outer.product.b.vf point-3-and-facing point-2 point-1 acc) - (nop!) - (mul.vf point-3-and-facing point-3-and-facing point-0) - (nop!) - (add.x.vf.y point-3-and-facing point-3-and-facing point-3-and-facing) - (nop!) - (add.z.vf.y point-3-and-facing point-3-and-facing point-3-and-facing) - (nop!) - (m facing-bits point-3-and-facing) - (nop!) - (b.ge facing-bits r0 use-backward-quad-color :delay (nop!)) - (jr draw-function :delay (nop!))) - (label use-backward-quad-color) - ;; Recolor only the four distinct records. The duplicate closure retains the provisional - ;; color, which also participates in interpolation if clipping crosses the final edge. - (s.vf backward-color output 32) - (nop!) - (s.vf backward-color output 80) - (nop!) - (s.vf backward-color output 128) - (nop!) - (s.vf backward-color output 176) - (nop!) - (jr draw-function :delay (nop!)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2))) - (defun render-boundary-tri ((vertices lbvtx) (dma-buf dma-buffer)) - "Transform three boundary vertices into a closed scratch polygon, select the forward or backward - display color from its camera-facing sign, and tail-call draw-boundary-polygon." - (declare (asm-func none)) - (rlet ((vertex-data :reg a0) - (input-copy :reg v1) - (output :reg a3) - (page-a :reg t4) - (page-b :reg t5) - (vertex-count :reg t0) - (draw-function :reg t9) - (facing-bits :reg v0) - (point-0 :reg vf1) - (tex-0 :reg vf2) - (forward-color :reg vf3) - (point-1 :reg vf4) - (tex-1 :reg vf5) - (backward-color :reg vf6) - (point-2 :reg vf7) - (tex-2 :reg vf8) - (facing :reg vf10) - (camera-x :reg vf31) - (camera-y :reg vf30) - (camera-z :reg vf29) - (camera-w :reg vf28)) - (m input-copy vertex-data) - (lui page-a #x7000) - (ori page-a page-a #x3000) - (lui page-b #x7000) - (ori page-b page-b #x3800) - (m output page-a) - (asm-block transform-boundary-triangle - (nop!) - (l.vf point-0 vertex-data) - (add.i vertex-count r0 3) - (l.vf tex-0 vertex-data 16) - (nop!) - (l.vf forward-color vertex-data 32) - (mula.x.vf camera-x point-0) - (l.vf point-1 vertex-data 48) - (madda.y.vf camera-y point-0) - (l.vf tex-1 vertex-data 64) - (madda.z.vf camera-z point-0) - (l.vf backward-color vertex-data 80) - (madd.w.vf point-0 camera-w point-0) - (l.vf point-2 vertex-data 96) - (nop!) - (l.vf tex-2 vertex-data 112) - (mula.x.vf camera-x point-1) - (nop!) - (madda.y.vf camera-y point-1) - (s.vf tex-0 output 16) - (madda.z.vf camera-z point-1) - (s.vf forward-color output 32) - (madd.w.vf point-1 camera-w point-1) - (s.vf tex-1 output 64) - (nop!) - (s.vf forward-color output 80) - (mula.x.vf camera-x point-2) - (s.vf tex-2 output 112) - (madda.y.vf camera-y point-2) - (s.vf forward-color output 128) - (madda.z.vf camera-z point-2) - (s.vf tex-0 output 160) - (madd.w.vf point-2 camera-w point-2) - (s.vf forward-color output 176) - (nop!) - (s.vf point-0 output) - (nop!) - (s.vf point-0 output 144) - (nop!) - (s.vf point-1 output 48) - (nop!) - (s.vf point-2 output 96)) - (asm-block choose-boundary-triangle-color - (m! draw-function draw-boundary-polygon) - (sub.vf point-1 point-1 point-0) - (nop!) - (sub.vf point-2 point-2 point-0) - (nop!) - (outer.product.a.vf acc point-1 point-2) - (nop!) - (outer.product.b.vf facing point-2 point-1 acc) - (nop!) - (mul.vf facing facing point-0) - (nop!) - (add.x.vf.y facing facing facing) - (nop!) - (add.z.vf.y facing facing facing) - (nop!) - (m facing-bits facing) - (nop!) - (b.ge facing-bits r0 use-backward-triangle-color :delay (nop!)) - (jr draw-function :delay (nop!))) - (label use-backward-triangle-color) - ;; The fourth record repeats point zero, so it receives the selected color as well. - (s.vf backward-color output 32) - (nop!) - (s.vf backward-color output 80) - (nop!) - (s.vf backward-color output 128) - (nop!) - (s.vf backward-color output 176) - (nop!) - (jr draw-function :delay (nop!)) - (jr ra :delay (add sp sp r0)) - (nop! :count 2)))) +(defun boundary-emit-polygon! ((vertices (inline-array sky-vertex)) (vertex-count int) (dma-buf dma-buffer)) + "Append one boundary GIF tag and its perspective-correct ST, RGBAQ, and 12.4 XYZF records." + (let* ((state *sky-polygon-renderer*) + (packet-start (-> dma-buf base)) + (giftag (the-as gs-gif-tag packet-start)) + (output (the-as (pointer uint128) (&+ packet-start 16)))) + (set! (-> giftag qword) (-> state giftag qword)) + (set! (-> (the-as (pointer uint32) packet-start) 0) vertex-count) + (dotimes (i vertex-count) + (let* ((vertex (-> vertices i)) + (q (/ 1.0 (-> vertex pos w))) + (st (new 'stack-no-clear 'vector)) + (color-int (new 'stack-no-clear 'vector)) + (projected (new 'stack-no-clear 'vector)) + (projected-int (new 'stack-no-clear 'vector))) + (vector-copy! st (-> vertex stq)) + (+! (-> st x) (-> state texture-offset x)) + (+! (-> st y) (-> state texture-offset y)) + (sky-vector4-float*! st st q) + (vector-cvt.w.s! color-int (-> vertex col)) + (sky-vector4*! projected (-> vertex pos) (-> state inv-hmge-scale)) + (*! (-> projected x) q) + (*! (-> projected y) q) + (*! (-> projected z) q) + (+! (-> projected x) (-> state screen-offset x)) + (+! (-> projected y) (-> state screen-offset y)) + (+! (-> projected z) (-> state screen-offset z)) + (+! (-> projected w) (-> state screen-offset w)) + (set! (-> projected z) (max (-> projected z) 0.0)) + (set! (-> projected w) (max (-> state fog-clamp y) (min (-> projected w) (-> state fog-clamp z)))) + (sky-vector4-float*! projected projected 16.0) + (vector-cvt.w.s! projected-int projected) + (set! (-> output (* i 3)) (-> st quad)) + (set! (-> output (+ (* i 3) 1)) (-> color-int quad)) + (set! (-> output (+ (* i 3) 2)) (-> projected-int quad)))) + (set! (-> dma-buf base) (&+ packet-start (* (+ 1 (* vertex-count 3)) 16)))) + (none)) + +(defun draw-boundary-polygon () + "Clip the current boundary polygon against the four homogeneous side planes, then emit it." + (let* ((state *sky-polygon-renderer*) + (vertices-a (-> state vertices-a)) + (vertices-b (-> state vertices-b)) + (vertex-count (-> state vertex-count))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-a vertices-b vertex-count 0 #t))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-b vertices-a vertex-count 1 #t))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-a vertices-b vertex-count 0 #f))) + (when (nonzero? vertex-count) + (set! vertex-count (sky-clip-polygon! vertices-b vertices-a vertex-count 1 #f))) + (when (nonzero? vertex-count) + (boundary-emit-polygon! vertices-a vertex-count (-> state dma-buf)))) + (none)) + +(defun boundary-back-facing? ((vertices (inline-array sky-vertex))) + "Test the transformed triangle's scalar triple product, matching the original VU facing branch." + (let* ((p0 (-> vertices 0 pos)) + (p1 (-> vertices 1 pos)) + (p2 (-> vertices 2 pos)) + (edge-1-x (- (-> p1 x) (-> p0 x))) + (edge-1-y (- (-> p1 y) (-> p0 y))) + (edge-1-z (- (-> p1 z) (-> p0 z))) + (edge-2-x (- (-> p2 x) (-> p0 x))) + (edge-2-y (- (-> p2 y) (-> p0 y))) + (edge-2-z (- (-> p2 z) (-> p0 z))) + (normal-x (- (* edge-1-y edge-2-z) (* edge-1-z edge-2-y))) + (normal-y (- (* edge-1-z edge-2-x) (* edge-1-x edge-2-z))) + (normal-z (- (* edge-1-x edge-2-y) (* edge-1-y edge-2-x)))) + (>= (+ (* normal-x (-> p0 x)) (* normal-y (-> p0 y)) (* normal-z (-> p0 z))) 0.0))) + +(defun render-boundary-polygon ((vertices lbvtx) (dma-buf dma-buffer) (vertex-count int)) + "Transform a boundary polygon, select its forward or backward display color, clip it, and emit it." + (let* ((state *sky-polygon-renderer*) + (input (the-as (inline-array sky-vertex) vertices)) + (output (-> state vertices-a))) + (set! (-> state dma-buf) dma-buf) + (set! (-> state vertex-count) vertex-count) + (dotimes (i vertex-count) + (let ((dst (-> output i)) + (src (-> input i))) + ;; Unlike sky geometry, boundary polygons retain transformed z for depth and facing. + (vector-matrix*! (-> dst pos) (-> src pos) (-> state transform)) + (vector-copy! (-> dst stq) (-> src stq)))) + (let ((color (if (boundary-back-facing? output) (-> input 1 col) (-> input 0 col)))) + (dotimes (i vertex-count) + (vector-copy! (-> output i col) color))) + (draw-boundary-polygon)) + (none)) + +(defun render-boundary-quad ((vertices lbvtx) (dma-buf dma-buffer)) + "Transform and render a four-vertex boundary face." + (render-boundary-polygon vertices dma-buf 4) + (none)) + +(defun render-boundary-tri ((vertices lbvtx) (dma-buf dma-buffer)) + "Transform and render a three-vertex boundary face." + (render-boundary-polygon vertices dma-buf 3) + (none)) ;; the polygon curently rendering. (define *boundary-polygon* @@ -502,8 +203,7 @@ "Build and draw the vertical quad joining two boundary vertices between bot-plane and top-plane. uv-phase? selects the alternate UV orientation used to flash the selected boundary." - (rlet ((vf27 :class vf)) - (let ((start (-> boundary data start-index))) + (let ((start (-> boundary data start-index))) (let ((end (-> boundary data end-index))) (let ((polygon-pos (-> *boundary-polygon* 0))) (set! (-> polygon-pos x) (-> start x)) @@ -569,19 +269,14 @@ (set! (-> polygon-uv z) 1.0) (set! (-> polygon-uv v w) 1.0)))) (init-boundary-regs) - (#unless PC_PORT - (.lvf vf27 (&-> *sky-tng-data* giftag-roof qword))) - (#when PC_PORT - (set-sky-vf27 (&-> *sky-tng-data* giftag-roof qword))) (render-boundary-quad (-> *boundary-polygon* 0) dma-buf) 0 - (none))) + (none)) (defun-debug draw-boundary-cap ((boundary load-boundary) (plane-y float) (dma-buf dma-buffer) (uv-phase? symbol)) "Draw every cached triangle of a closed boundary at plane-y. uv-phase? selects the alternate UV orientation used to flash the selected boundary." - (rlet ((vf27 :class vf)) - (dotimes (i (-> boundary tri-cnt)) + (dotimes (i (-> boundary tri-cnt)) (let ((v0 (-> boundary data (-> boundary data i v0))) (v1 (-> boundary data (-> boundary data i v1))) (v2 (-> boundary data (-> boundary data i v2)))) @@ -634,13 +329,9 @@ (set! (-> polygon-uv z) 1.0) (set! (-> polygon-uv v w) 1.0)))) (init-boundary-regs) - (#unless PC_PORT - (.lvf vf27 (&-> *sky-tng-data* giftag-roof qword))) - (#when PC_PORT - (set-sky-vf27 (&-> *sky-tng-data* giftag-roof qword))) (render-boundary-tri (-> *boundary-polygon* 0) dma-buf)) 0 - (none))) + (none)) (defun-debug boundary-set-color ((color-vertex lbvtx) (command load-boundary-crossing-command)) "Set a debug polygon color from command's load-boundary command @@ -693,88 +384,30 @@ 0 (none)) -(#unless PC_PORT - (defun-debug render-boundary ((boundary load-boundary)) - "Append debug rendering for boundary to the debug DMA bucket. Closed - boundaries draw their triangulated top cap; open boundaries draw vertical side quads. The selected - boundary alternates UV phase to flash." - (let* ((uv-phase? (or (!= boundary (-> *lb-editor-parms* boundary)) (logtest? (-> *display* real-actual-frame-counter) 4))) - (dma-buf (-> *display* frames (-> *display* on-screen) frame global-buf)) - (packet-start (-> dma-buf base))) - (let* ((buffer dma-buf) - (cnt-tag (the-as object (-> buffer base)))) - (set! (-> (the-as dma-packet cnt-tag) dma) (new 'static 'dma-tag :qwc #x4 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet cnt-tag) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet cnt-tag) vif1) (new 'static 'vif-tag :imm #x4 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> buffer base) (&+ (the-as pointer cnt-tag) 16))) - (let* ((buffer dma-buf) - (giftag (the-as object (-> buffer base)))) - (set! (-> (the-as gs-gif-tag giftag) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x3)) - (set! (-> (the-as gs-gif-tag giftag) regs) GIF_REGS_ALL_AD) - (set! (-> buffer base) (&+ (the-as pointer giftag) 16))) - (let* ((buffer dma-buf) - (gs-state (-> buffer base))) - (set! (-> (the-as (pointer gs-zbuf) gs-state) 0) (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24))) - (set! (-> (the-as (pointer gs-reg64) gs-state) 1) (gs-reg64 zbuf-1)) - (set! (-> (the-as (pointer gs-test) gs-state) 2) - (new 'static 'gs-test :ate #x1 :atst (gs-atest greater-equal) :aref #x26 :zte #x1 :ztst (gs-ztest greater-equal))) - (set! (-> (the-as (pointer gs-reg64) gs-state) 3) (gs-reg64 test-1)) - (set! (-> (the-as (pointer gs-alpha) gs-state) 4) (new 'static 'gs-alpha :b #x1 :d #x1)) - (set! (-> (the-as (pointer gs-reg64) gs-state) 5) (gs-reg64 alpha-1)) - (set! (-> buffer base) (&+ gs-state 48))) + +(defun-debug render-boundary ((boundary load-boundary)) + "Append debug rendering for boundary to the debug DMA bucket. Closed boundaries draw their + triangulated top cap; open boundaries draw vertical side quads. The selected boundary + alternates UV phase to flash." + (let ((uv-phase? (or (!= boundary (-> *lb-editor-parms* boundary)) (logtest? (-> *display* real-actual-frame-counter) 4)))) + (with-dma-buffer-add-bucket ((dma-buf (-> (current-frame) global-buf)) (bucket-id debug)) + (dma-buffer-add-gs-set-flusha dma-buf + (zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24))) + (test-1 (new 'static 'gs-test :ate #x1 :atst (gs-atest greater-equal) :aref #x26 :zte #x1 :ztst (gs-ztest greater-equal))) + (alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))) (boundary-set-color (-> *boundary-polygon* 2) (-> boundary cmd-fwd)) (boundary-set-color (-> *boundary-polygon* 5) (-> boundary cmd-bwd)) - (let ((vif-block (the-as object (-> dma-buf base)))) - (&+! (-> dma-buf base) 16) - (add-boundary-shader (new 'static 'texture-id :index #x33 :page #x2) dma-buf) - (cond - ((logtest? (-> boundary flags) (load-boundary-flags closed)) - (draw-boundary-cap boundary (-> boundary top-plane) dma-buf uv-phase?)) - (else - (dotimes (i (the-as int (+ (-> boundary num-points) -1))) - (draw-boundary-side boundary i (+ i 1) dma-buf uv-phase?)))) - (close-sky-buffer dma-buf) - (let ((block-qwc (/ (the-as int (+ (- -16 (the-as int vif-block)) (the-as int (-> dma-buf base)))) 16))) - (set! (-> (the-as dma-packet vif-block) dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc block-qwc)) - (set! (-> (the-as dma-packet vif-block) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet vif-block) vif1) (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1 :imm block-qwc)))) - (let ((packet-end (-> dma-buf base))) - (let ((next-tag (the-as object (-> dma-buf base)))) - (set! (-> (the-as dma-packet next-tag) dma) (new 'static 'dma-tag :id (dma-tag-id next))) - (set! (-> (the-as dma-packet next-tag) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet next-tag) vif1) (new 'static 'vif-tag)) - (set! (-> dma-buf base) (&+ (the-as pointer next-tag) 16))) - (dma-bucket-insert-tag (-> *display* frames (-> *display* on-screen) frame bucket-group) - (bucket-id debug) - packet-start - (the-as (pointer dma-tag) packet-end)))) - 0 - (none))) - -(#when PC_PORT - (defun-debug render-boundary ((boundary load-boundary)) - "Append debug rendering for boundary to the debug DMA bucket. Closed boundaries draw their - triangulated top cap; open boundaries draw vertical side quads. The selected boundary - alternates UV phase to flash." - (let ((uv-phase? (or (!= boundary (-> *lb-editor-parms* boundary)) (logtest? (-> *display* real-actual-frame-counter) 4)))) - (with-dma-buffer-add-bucket ((dma-buf (-> (current-frame) global-buf)) (bucket-id debug)) - (dma-buffer-add-gs-set-flusha dma-buf - (zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24))) - (test-1 (new 'static 'gs-test :ate #x1 :atst (gs-atest greater-equal) :aref #x26 :zte #x1 :ztst (gs-ztest greater-equal))) - (alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))) - (boundary-set-color (-> *boundary-polygon* 2) (-> boundary cmd-fwd)) - (boundary-set-color (-> *boundary-polygon* 5) (-> boundary cmd-bwd)) - (with-cnt-vif-block-qwc (dma-buf) - (add-boundary-shader (new 'static 'texture-id :index #x33 :page #x2) dma-buf) - (cond - ((logtest? (-> boundary flags) (load-boundary-flags closed)) - (draw-boundary-cap boundary (-> boundary top-plane) dma-buf uv-phase?)) - (else - (dotimes (i (the-as int (+ (-> boundary num-points) -1))) - (draw-boundary-side boundary i (+ i 1) dma-buf uv-phase?)))) - (close-sky-buffer dma-buf)))) - 0 - (none))) + (with-cnt-vif-block-qwc (dma-buf) + (add-boundary-shader (new 'static 'texture-id :index #x33 :page #x2) dma-buf) + (cond + ((logtest? (-> boundary flags) (load-boundary-flags closed)) + (draw-boundary-cap boundary (-> boundary top-plane) dma-buf uv-phase?)) + (else + (dotimes (i (the-as int (+ (-> boundary num-points) -1))) + (draw-boundary-side boundary i (+ i 1) dma-buf uv-phase?)))) + (close-sky-buffer dma-buf)))) + 0 + (none)) ;;;;;;;;;;;;;;;;;;;;;;;;; ;; Load Boundary File @@ -1479,6 +1112,7 @@ (return (load-boundary-crossing-result none))) (let ((plane-scale (/ (- (-> current-pos y) (-> previous-pos y)) (- (-> boundary top-plane) (-> previous-pos y)))) (crossing-point (new 'stack-no-clear 'vector))) + ;; This is incorrect -- (set! (-> crossing-point x) (+ (-> previous-pos x) (* plane-scale (- (-> current-pos x) (-> previous-pos x))))) (set! (-> crossing-point y) (+ (-> previous-pos y) (* plane-scale (- (-> current-pos y) (-> previous-pos y))))) (set! (-> crossing-point z) (+ (-> previous-pos z) (* plane-scale (- (-> current-pos z) (-> previous-pos z))))) diff --git a/goal_src/jak1/engine/ui/text.gc b/goal_src/jak1/engine/ui/text.gc index 0dfef03626..d93e651b31 100644 --- a/goal_src/jak1/engine/ui/text.gc +++ b/goal_src/jak1/engine/ui/text.gc @@ -106,9 +106,7 @@ (defun load-game-text-info ((group-name string) (destination-symbol symbol) (heap kheap)) "Synchronously ensure group-name is loaded in the selected language into heap and publish the linked game-text-info through destination-symbol. Reuse matching data; otherwise reset the heap, - load and link the language/group TXT file, and clear destination-symbol on link failure. EE maps - English to UK English in SCEE territory; PC reads its selected text language. Errors are reported - while the function always returns zero." + load and link the language/group TXT file, and clear destination-symbol on link failure." (local-vars (result int) (loaded-text game-text-info) (language-id language-enum) (load-size int) (heap-free int)) (set! loaded-text (the-as game-text-info (-> destination-symbol value))) ;; split languages in PC port diff --git a/test/common/test_demacro.cpp b/test/common/test_demacro.cpp index c469d4b738..0006f33b72 100644 --- a/test/common/test_demacro.cpp +++ b/test/common/test_demacro.cpp @@ -313,6 +313,38 @@ TEST(Demacro, Jak1RecognizesDmaCntPacketsWithExplicitQwc) { )"); } +TEST(Demacro, Jak1RecognizesDirectDmaCntAndRefPackets) { + const auto rules = + demacro::load_rules(file_util::get_file_path({"decompiler/config/jak1/demacro.jsonc"})); + const std::string source = R"((begin + (let ((packet (the-as object (-> dma-buf base)))) + (set! (-> (the-as dma-packet packet) dma) (new 'static 'dma-tag :id (dma-tag-id cnt))) + (set! (-> (the-as dma-packet packet) vif0) vif0) + (set! (-> (the-as dma-packet packet) vif1) vif1) + (set! (-> dma-buf base) (&+ (the-as pointer packet) 16))) + (let* ((dma-state dma-buf) + (packet (the-as object (-> dma-state base)))) + (set! (-> (the-as dma-packet packet) dma) + (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc qwc)) + (set! (-> (the-as dma-packet packet) vif0) vif0) + (set! (-> (the-as dma-packet packet) vif1) vif1) + (set! (-> dma-state base) (&+ (the-as pointer packet) 16))) + (let ((packet (the-as object (-> dma-buf base)))) + (set! (-> (the-as dma-packet packet) dma) + (new 'static 'dma-tag :qwc qwc :id (dma-tag-id ref) :addr addr)) + (set! (-> (the-as dma-packet packet) vif0) vif0) + (set! (-> (the-as dma-packet packet) vif1) vif1) + (set! (-> dma-buf base) (&+ (the-as pointer packet) 16)))) +)"; + const auto result = demacro::rewrite(source, rules); + EXPECT_EQ(result.rewrite_count(), 3); + EXPECT_EQ(result.source, R"((begin + (dma-buffer-add-cnt-vif2 dma-buf 0 vif0 vif1) + (dma-buffer-add-cnt-vif2 dma-buf qwc vif0 vif1) + (dma-buffer-add-ref-vif2 dma-buf qwc addr vif0 vif1)) +)"); +} + TEST(Demacro, Jak1RecognizesDmaNextPackets) { const auto rules = demacro::load_rules(file_util::get_file_path({"decompiler/config/jak1/demacro.jsonc"}));