Correct the tfrag pointer-field claim, and show morphing regenerates VU packets
Two corrections to the previous commit, both from continuing the RAM comparison.
1. The previous commit said the RAM comparison "names two fields the disc-side
work had left as data and an unnamed word". It does not. +0x10 is
TfragHeader::data and +0x38 is TfragHeader::cube_ofs, both already named in the
struct. What RAM adds is that both are POINTERS -- relocated by adding the
block's RAM base -- rather than plain offsets. That is still worth knowing, but
it is not a naming.
2. The previous commit attributed the 8.6% of rewritten bytes to "morphed
positions with topology and UVs left verbatim". That is wrong, and patch 1 shows
why. Comparing 4 KiB, disc 0xdf60 against RAM 0x855f60:
bytes differing 354 of 4,096 = 8.6%
contiguous runs 120
longest run 8 bytes
extent +0xc1 through the end of the window
Patch 1 has 83 positions and 83 vertex-info entries, of which 13 morph. If
morphing rewrote position fields alone, the differing bytes would be a 13/83 slice
of a 498-byte position array -- a couple of dozen bytes in one contiguous region.
Instead 354 bytes differ, spread over 120 short runs across the whole window.
So the loader is not patching positions in place: it REGENERATES the VU packet
stream for the current morph state. That is what morphing is on this hardware --
VU1 GIF packets, not a CPU-side vertex array.
Consequence for verification, and the reason this is worth committing rather than
just noting: the plan of "map RAM vertices to disc indices and solve for the weight"
does not work against this memory image. The positions are inside regenerated
packets, so there is no stable per-vertex correspondence to read a weight out of.
Verifying the morph weight against the original needs the CAMERA DISTANCE at the
savestate, so the weight can be computed from the derivation and compared with the
rendered result, rather than read back out of RAM.
Population figures gathered on the way: 833 of 833 patches parse, carrying 43,613
vertex-info entries; 499 of 833 patches have at least one morphing entry, and
patch 0 -- the first record -- is base-only with none.
Also fixed a measurement error mid-run: I compared patch 1 at disc 0xdf60 against
RAM 0x855f00, off by 0x60, and got "every byte differs". The corrected base is
0x855f60.
This commit is contained in:
+17
-10
@@ -249,16 +249,23 @@ Phase 1 hands over the extents; this phase works out what each one contains.
|
||||
`+0x10` and `+0x38`, verified against PCSX2 across all **833** records: the
|
||||
loader adds the block's RAM base (`0x848000`) to each, every other byte of
|
||||
every record is verbatim, and 1,665 fields differ where 1,666 were possible.
|
||||
This names two fields previously left as `data` and an unnamed word.
|
||||
- [~] Behind those pointers, **8.6% of bytes are rewritten** (14,977 of 16,384
|
||||
identical), spread across many field positions rather than concentrated --
|
||||
consistent with morphed positions with topology and UVs left verbatim.
|
||||
- [ ] What tfrag is **not** yet verified is that the morphed bytes match
|
||||
`resolve_vertex`'s formula. The LOD switch distances, morph weight and
|
||||
collapse edge are derived from the data (tiers classified from the four V4_8
|
||||
parent arrays, weight running zero to one across each band); the framing is
|
||||
now known well enough to map RAM vertices to disc indices and solve for the
|
||||
weight, which is the next step.
|
||||
They are the existing `TfragHeader::data` and `::cube_ofs` -- what RAM adds
|
||||
is that both are **pointers**, not plain offsets. All **833** patches parse,
|
||||
carrying **43,613** vertex-info entries; **499 of 833** have at least one
|
||||
morphing entry.
|
||||
- [~] Behind those pointers, **8.6% of bytes are rewritten** (354 of 4,096 on
|
||||
patch 1), spread over 120 short runs across the whole window rather than
|
||||
concentrated in a position array. Morphing on this hardware is VU1 GIF
|
||||
packets, and the loader **regenerates the packet stream** rather than
|
||||
patching position fields in place.
|
||||
- [ ] What tfrag is **not** yet verified is that the morph matches
|
||||
`resolve_vertex`'s formula. Reading a weight back out of RAM does **not**
|
||||
work -- the positions live inside regenerated VU packets, so there is no
|
||||
stable per-vertex correspondence. The LOD switch distances, morph weight and
|
||||
collapse edge remain derived from the data (tiers classified from the four
|
||||
V4_8 parent arrays, weight running zero to one across each band); verifying
|
||||
them needs the **camera distance at the savestate** so the weight can be
|
||||
computed and compared against the rendered result.
|
||||
- [x] `tie` — **fully chained.** `resolve_tie_class` walks both indirections: the
|
||||
class table is in `core_index.bin`, and the entry's `offset_in_asset_wad`
|
||||
addresses `core_data.bin` (not `core_data.wad`). All **1,864** tie classes
|
||||
|
||||
Reference in New Issue
Block a user