From 08d1992eaf1d427b95ceb2fd27efc0b3a51d46ec Mon Sep 17 00:00:00 2001 From: MarcelineVQ Date: Mon, 16 Mar 2026 10:45:06 -0700 Subject: [PATCH] =?UTF-8?q?bone=5Fsse:=20replace=20IsParticleBufferEmpty?= =?UTF-8?q?=20with=20pure=20Zig=20=E2=80=94=201=20game=20call=20remains=20?= =?UTF-8?q?(atexit)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/transform44/bone_sse.zig | 20 +++++++++--- .../decompiled/t44_helpers_asm.txt | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/transform44/bone_sse.zig b/src/transform44/bone_sse.zig index 037dbfe..29c9d3c 100644 --- a/src/transform44/bone_sse.zig +++ b/src/transform44/bone_sse.zig @@ -466,6 +466,20 @@ inline fn crossVec3(ax: f32, ay: f32, az: f32, bx: f32, by: f32, bz: f32) [3]f32 // Output: indices[0] = lower index, [1] = upper index, [2] = interpolation t (float bits) // ============================================================================= +/// IsParticleBufferEmpty (0x7B5F60) — recursive tree check. +/// Returns true if any node in the tree has active particles (this->0x64 != 0). +fn isParticleBufferNotEmpty(ptr: u32) bool { + if (ru32(ptr + 0x64) != 0) return true; + const count = ru32(ptr + 0x7C); + if (count == 0) return false; + const children = ptr + 0x80; + var i: u32 = 0; + while (i < count) : (i += 1) { + if (isParticleBufferNotEmpty(ru32(children + i * 4))) return true; + } + return false; +} + /// findInterpIdx: temporal-coherence keyframe search. /// Reimplementation of game function at 0x713D50 (334 bytes). /// Assembly-verified against t44_helpers_asm.txt. @@ -2252,11 +2266,7 @@ fn additionalParticleLoops(this: u32, model_hdr: u32) void { if (emitter_active != 0) { buf_active = 1; } else { - // Call IsParticleBufferEmpty (0x7B5F60) - // Assembly: MOV ECX,[EBP-0x10]; CALL 0x7B5F60 - // __thiscall(ECX=ptr), plain RET, returns 0 or 1 in EAX - const isEmptyFn: *const fn (u32) callconv(.{ .x86_fastcall = .{} }) u32 = @ptrFromInt(0x7B5F60); - if (isEmptyFn(local_14) != 0) { + if (isParticleBufferNotEmpty(local_14)) { buf_active = 1; } } diff --git a/src/transform44/decompiled/t44_helpers_asm.txt b/src/transform44/decompiled/t44_helpers_asm.txt index 65144e9..341cbe1 100644 --- a/src/transform44/decompiled/t44_helpers_asm.txt +++ b/src/transform44/decompiled/t44_helpers_asm.txt @@ -775,3 +775,34 @@ OpenJDK 64-Bit Server VM (build 21.0.10+7, mixed mode) 0x00454A0C FSTP ST0 0x00454A0E RET << RET + +=== IsParticleBufferEmpty (0x007B5F60, 59 bytes) === + 0x007B5F60 8B 41 64 MOV EAX,dword ptr [ECX + 0x64] + 0x007B5F63 85 C0 TEST EAX,EAX + 0x007B5F65 53 PUSH EBX + 0x007B5F66 56 PUSH ESI + 0x007B5F67 57 PUSH EDI + 0x007B5F68 74 09 JZ 0x007b5f73 + 0x007B5F6A 5F POP EDI + 0x007B5F6B 5E POP ESI + 0x007B5F6C B8 01 00 00 00 MOV EAX,0x1 + 0x007B5F71 5B POP EBX + 0x007B5F72 C3 RET << RET + 0x007B5F73 8B 79 7C MOV EDI,dword ptr [ECX + 0x7c] + 0x007B5F76 33 F6 XOR ESI,ESI + 0x007B5F78 85 FF TEST EDI,EDI + 0x007B5F7A 76 19 JBE 0x007b5f95 + 0x007B5F7C 8D 99 80 00 00 00 LEA EBX,[ECX + 0x80] + 0x007B5F82 8B 0B MOV ECX,dword ptr [EBX] + 0x007B5F84 E8 D7 FF FF FF CALL 0x007b5f60 << CALL + 0x007B5F89 85 C0 TEST EAX,EAX + 0x007B5F8B 75 DD JNZ 0x007b5f6a + 0x007B5F8D 46 INC ESI + 0x007B5F8E 83 C3 04 ADD EBX,0x4 + 0x007B5F91 3B F7 CMP ESI,EDI + 0x007B5F93 72 ED JC 0x007b5f82 + 0x007B5F95 5F POP EDI + 0x007B5F96 5E POP ESI + 0x007B5F97 33 C0 XOR EAX,EAX + 0x007B5F99 5B POP EBX + 0x007B5F9A C3 RET << RET