forked from Ports/goldeneye-pc-port
D112: fix d43_emit put_f32 byte-swap off-by-one (skeletal models collapsed)
put_f32 reversed bytes doff+1..doff+4 instead of doff..doff+3, dropping each float's MSB and pulling in a byte of the adjacent field. Corrupted every f32 in converted model rodata (joint Origins, LOD distances, BSP planes, bounding radii) for all sidecar-loaded models. Compiled-in front-end models were unaffected, hence 'logo fine, every guard a line'. render_pos[] joint matrices now coherent; BUNKER guards render as humanoids and monitor screens draw content. Regen: python tools_pc/d43_emit.py ntsc-final.
This commit is contained in:
1 parent
cb73ea0985
commit
3a02ded079
3 files changed
+66
-19
No files matched your search
+25
-18
@@ -40,27 +40,34 @@ the base image and magnified it. `gfx_lod_tile_offset` now returns 0
|
||||
(base tile) when detail textures are off. BUNKER1 rooms render crisp.
|
||||
See §F "D107".
|
||||
|
||||
**Storage-room sky void — root-caused (session M-4), it is the
|
||||
prop/model track:** the void is *closed doors* — portals 25/26 are
|
||||
correctly `PORTALFLAG_DISABLED`, and `chrpropsRenderPass` runs (`n=3..10`
|
||||
props/room) but emits almost no geometry, so the door models that should
|
||||
fill those openings never draw. Portal visibility itself is healthy
|
||||
post-D106 (room 18 → 8 rooms deep). Fixing prop/door rendering unblocks
|
||||
this AND the missing weapon.
|
||||
**Skeletal models — FIXED (session M-5, D112).** The "3D line" / missing
|
||||
characters were `tools_pc/d43_emit.py`'s `put_f32` reversing the wrong 4
|
||||
bytes (`src[doff+4:doff:-1]` → bytes doff+1..doff+4, dropping the MSB),
|
||||
corrupting every f32 in converted model rodata (joint `Origin`s, LOD
|
||||
distances, BSP planes). Compiled-in front-end models were unaffected
|
||||
(native LE), hence "logo fine, every guard broken". Fix: one line,
|
||||
`src[doff:doff+4][::-1]`; regen with `python tools_pc/d43_emit.py
|
||||
ntsc-final`. BUNKER guards now render as coherent humanoids, monitor
|
||||
screens draw content. See §F "D108–D112".
|
||||
|
||||
**"props emit no geometry" was a STALE premise** — props/doors emit
|
||||
complete leaf DLs (~15k/run, valid ptrs; fast3d transforms them). The
|
||||
storage-room void is NOT closed doors failing to render.
|
||||
|
||||
**Real remaining work, in order:**
|
||||
1. **Prop / character model rendering** — `chrpropsRenderPass` enumerates
|
||||
props but emits no geometry; door models (storage void), weapon model,
|
||||
and skeletal characters all ride this. Overlaps the `struct player`
|
||||
offset pass and D75(b). Start here — highest visual + playability
|
||||
leverage. `GE_D96` probe in `chrprop.c`.
|
||||
2. **`struct player` offset pass** — weapon model doesn't draw; gate to
|
||||
1. **Portal-BFS under-reach in the storage area** — per-frame visible
|
||||
room count drops to 1–2 in rooms 27–29 (`GE_D104`/probes now removed).
|
||||
`projmatrix` + `screensize` verified valid; the 200→3 `g_RoomLoadBudget`
|
||||
drop is intentional N64 FP-cam behaviour. Likely `bgQueuePortalTraversal`
|
||||
/ `bgDetermineVisibleRooms` portal-projection. This is the void.
|
||||
2. **Character pose / orientation polish** — post-D112 a BUNKER guard
|
||||
renders but appears inverted; suspect a matrix-handedness / lookat
|
||||
sign item in the joint base matrix. Also the mispositioned static
|
||||
crate prop (top-left in the control room).
|
||||
3. **`struct player` offset pass** — weapon model doesn't draw; gate to
|
||||
playability (landmine below + D102).
|
||||
3. **D75(b)** — animated/skeletal character models (see §F "D75" and
|
||||
"Known rendering bugs"). All three intro-model failures traced to the
|
||||
game `matrixmath.c` → `modelUpdateMatrices`/`process_02_position` →
|
||||
raw `render_pos` `i*0x40` re-pack path (NOT the D73 sin/cos path);
|
||||
static prop = mispositioned, animated `setup_chr_instance` = missing.
|
||||
4. Add an f32 value spot-check to `d43_emit.py`'s verify pass (it only
|
||||
checks pointers/opcodes today — this bug passed "ALL CHECKS PASSED").
|
||||
|
||||
**This session's fixes (all committed, master):**
|
||||
|
||||
|
||||
@@ -3401,6 +3401,46 @@ table via `bgSwapRoomVtx` or the point-index blob length); front-end
|
||||
text draws mirrored. Next: prop/door model rendering (unblocks the void
|
||||
AND the missing weapon), then D75(b) skeletal models.
|
||||
|
||||
**D108–D112 (session M-5) — the "props emit no geometry" premise was
|
||||
stale; the real bug was a converter byte-swap off-by-one, FIXED.**
|
||||
Re-probing `chrpropsRenderPass` / `chrpropRender` / `modelRenderNodeDl`
|
||||
(`GE_D96*`) showed props *do* emit complete leaf DLs now (~15k
|
||||
`nodeDl` EMITs/run, valid `gdl`/`vtx`/`BaseAddr`; fast3d transforms
|
||||
~300–600 prop verts/frame with sane `w`). Two separate residual bugs
|
||||
were isolated: (1) in the BUNKER storage area the per-frame visible-room
|
||||
count drops to 1–2 while `cameramode` goes 1→0 and `g_RoomLoadBudget`
|
||||
200→3 — but the 200→3 is *intentional* N64 behaviour
|
||||
(`bgRoomVisibilityRelated`: 0xC8 for intro/swirl cams, 3 for FP) and
|
||||
`currentPlayerGetProjectionMatrix()` + `g_CurrentPlayer->screensize`
|
||||
were both verified valid, so this is a portal-BFS under-reach, still
|
||||
open. (2) **Skeletal characters rendered as a "3D line" / not at all**
|
||||
(also visible in attract mode): `drawjointlist` → `subcalcmatrices` →
|
||||
`modelUpdateMatrices` → `process_02_position` → `modelBuildGroupMatrices`
|
||||
produced `render_pos[]` joint matrices with **sane rotations but garbage
|
||||
/ 1e27 / NaN positions**. `basemtx` (`camGetWorldToScreenMtxf()`) was a
|
||||
clean orthonormal lookat; joint *rotations* from the anim bitstream were
|
||||
fine; but `group->Origin` (`ModelRoData_GroupRecord.Origin`, a
|
||||
`coord3d`) read as garbage for every joint whose bytes weren't
|
||||
zero — while the adjacent `JointID`/`MatrixIDs` (u16/s16) read fine.
|
||||
Root cause: **`put_f32` in `tools_pc/d43_emit.py` had an off-by-one in
|
||||
its BE→LE byte reversal** — `buf[o:o+4] = src[doff+4:doff:-1]` yields
|
||||
bytes `doff+1..doff+4` (dropping the value's MSB, pulling in one byte of
|
||||
the next field) instead of `doff..doff+3`. This corrupted *every* f32
|
||||
field in converted model rodata (joint `Origin`s, LOD near/far, BSP
|
||||
planes, bounding radii) for every sidecar-loaded model; the compiled-in
|
||||
front-end intro models (native-LE C structs, not run through the
|
||||
converter) were unaffected, which is why the Rareware logo looked right
|
||||
but every in-level character collapsed. Fix: `src[doff:doff+4][::-1]`.
|
||||
After regen (`python tools_pc/d43_emit.py ntsc-final`), all 20
|
||||
`render_pos` entries of a BUNKER guard are coherent (~±60 units around
|
||||
the body), monitor screens draw their content, and character models
|
||||
render as recognisable humanoids (still some pose/orientation polish
|
||||
owed — a guard appears inverted — a separate matrix-handedness item).
|
||||
`d43_emit.py`'s verify pass only checks pointers/opcodes, not float
|
||||
values — a float spot-check is worth adding. Probes `GE_D96GATE /
|
||||
D96DL / D108 / D109 / D110 / D111 / D112 / GE_TRICNT` were all removed
|
||||
after the fix.
|
||||
|
||||
**`data/` deletion + recovery (session M-3).** `git worktree remove
|
||||
--force` on an agent worktree that had a directory *junction*
|
||||
`worktree/data → main/data` followed the junction and deleted the real
|
||||
|
||||
@@ -490,7 +490,7 @@ def process(name):
|
||||
def put_u16(o, v): buf[o:o + 2] = struct.pack("<H", v & 0xFFFF)
|
||||
def put_s16(o, v): buf[o:o + 2] = struct.pack("<H", v & 0xFFFF) # bytes identical to <h
|
||||
def put_u32(o, v): buf[o:o + 4] = struct.pack("<I", v & 0xFFFFFFFF)
|
||||
def put_f32(o, doff): buf[o:o + 4] = src[doff + 4:doff:-1] # bswap32 (4 bytes!)
|
||||
def put_f32(o, doff): buf[o:o + 4] = src[doff:doff + 4][::-1] # bswap32 (BE->LE)
|
||||
def put_ptr(o, old_off):
|
||||
if not old_off:
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user