psx map standalone exporter
This commit is contained in:
parent
a9153546ae
commit
2f243976b6
16 changed files with 3254 additions and 5 deletions
|
|
@ -101,6 +101,51 @@ Those counts are now historical rather than current for the focused `map 104` ex
|
|||
- The immediate export-side blocker was config: `psx-remorse` was excluded from static export even though the prebuilt catalog/build-manager path already supports multi-map PSX scenes.
|
||||
- The renderer config now includes `psx-remorse` in static export so full PSX exports can surface the full processed map set instead of dropping the version entirely.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Main-Visible Palette-Token Submit Normalization
|
||||
|
||||
- Scope for this focused pass: exact submit-flag packing and pre-submit normalization centered on `psx_draw_main_visible_object` (`0x80041458`), wrapper context in `psx_lset_world_frame_wrapper` (`0x80031f0c`) and `psx_draw_world_visible_passes` (`0x80041378`), with submitter override gates at `0x80044e10` and `0x80044eb8`.
|
||||
- Main-visible now has instruction-level confirmation for flag packing at the call sites (`0x800415c0` / `0x800415e0`):
|
||||
- `a3 = (obj_flags & 0x0002) | token_hi`
|
||||
- `token_hi` is normalized earlier as `source_palette_word & 0xFF00` at `0x80041590`.
|
||||
- Exact palette-token carriage for this lane is therefore bits `15:8` of submit flags (`token = flags >> 8`). Low nibble bits remain non-palette control bits.
|
||||
- Submitter override gate behavior is now explicitly aligned across image-table and sprite submitters:
|
||||
- gate expression is `(flags & ~0xF) != 0` (equivalent to `(flags & 0xfffffff0) != 0`)
|
||||
- because world callers only contribute `obj_flags&0x0002` plus token high byte, bit `0x0002` alone does not trigger override; nonzero token high byte is the effective palette-override activator.
|
||||
- Non-obvious normalization outcome for exporter logic: no additional wrapper-stage or no-op-hook mutation exists before `0x80041458` submits; palette-relevant normalization is local to main-visible draw and consists of high-byte extraction only.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- nearby helper renames:
|
||||
- `0x8003a3b0 -> psx_world_draw_tint_fade_step`
|
||||
- `0x80038f10 -> psx_noop_frame_hook_38f10`
|
||||
- `0x80044018 -> psx_noop_frame_hook_44018`
|
||||
- targeted decompiler comments:
|
||||
- `0x80041590` (token high-byte normalization)
|
||||
- `0x800415c0` (final submit-flag packing)
|
||||
- `0x80044e10` / `0x80044eb8` (shared override gate and token indexing)
|
||||
- `0x80031f34` / `0x80031f3c` (wrapper no-op hooks do not mutate submit flags)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): World Draw Pass + CLUT Routing Refresh
|
||||
|
||||
- Scope for this focused pass: live `SLUS_002.68` world draw and submitter routing at `0x80041378`, `0x80041458`, `0x80041144`, `0x80044bdc`, and `0x80044e9c`, plus CLUT table lanes `0x800a9f48` and `0x800a9f66`.
|
||||
- World draw pass ordering remains fixed and explicit: stage-1 main-visible sorted slice first, then stage-2 special-visible queue, then HUD/overlay.
|
||||
- Stage-1 and stage-2 world lanes still share submitter dispatch by bound resource kind (`kind==5` image-table submitter, otherwise sprite submitter).
|
||||
- Palette-token handling remains lane-split and exporter-critical: main-visible injects authored high-byte palette token into submit flags; special-visible does not.
|
||||
- CLUT override gate remains shared (`submit_flags & 0xfffffff0`), but CLUT table resolution still branches by submitter/resource-format lane:
|
||||
- `psx_image_table_submit_frame`: high-byte token selects `psx_clut_override_table_by_palette_token[token]`, otherwise default bank CLUT.
|
||||
- `psx_sprite_resource_submit_frame`: format-2 lane follows override table path; non-format-2 lane remaps token through bank CLUT indexing.
|
||||
- Nearby anonymous helper cleanup in the same draw wrapper lane:
|
||||
- `0x8002e534 -> psx_marker_channel_runtime_get_u16_86`
|
||||
- `0x8002eee8 -> psx_marker_channel_runtime_get_u16_84`
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x80041378`: decompiler comment clarifying stage-1 -> stage-2 -> HUD order.
|
||||
- `0x800415c0`: decompiler comment clarifying main-visible authored token injection before image-table submit.
|
||||
- `0x800412dc`: decompiler comment clarifying special-visible omits authored high-byte token injection.
|
||||
- `0x80044ed0`: decompiler comment clarifying image-table CLUT override-table path.
|
||||
- `0x80044e5c`: decompiler comment clarifying sprite default bank-CLUT path when override gate is inactive.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-12): Wall-Family Split Failure Mode
|
||||
|
||||
- Scope for this focused pass: live `SLUS_002.68` around the wall-heavy generic family band (`0x003e..0x004f`) and exporter donor-heavy bundles (`0x0008b48c`, `0x00085c40`).
|
||||
|
|
@ -143,9 +188,220 @@ Conservative live-artifact updates applied in Ghidra for this pass:
|
|||
- `0x80044e10`: comment clarifying sprite submit override gate and token-0 fallthrough.
|
||||
- `0x80044eb8`: comment clarifying image-table override keying behavior.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Selector Install, Transition Selection, and Final Latch Closure
|
||||
|
||||
- Scope for this focused pass: selector-install and post-construction reselection chain centered on `psx_object_select_state_script` (`0x800260e8`), `psx_object_advance_state_script` (`0x80025d68`), `psx_object_select_state_from_transition_table` (`0x8001bca0`), `psx_type42_transition_selector_tick` (`0x80018578`), and delayed type-4 reselection around `0x8002906c`.
|
||||
- `psx_object_select_state_script` is confirmed as install-only in exporter terms: it writes selector `obj+0x9e`, seeds state-script cursor (`obj+0x8c/0x90`), and does not write final visible frame token.
|
||||
- Final visible frame/state token is latched in `psx_object_advance_state_script` where current script word is copied to `obj+0x94`; projection/draw lanes consume this live token.
|
||||
- Transition-table selection remains two-stage and row-driven: transition code from `psx_type_transition_mode_policy_rows` (`0x80063a00`) selects selector base from `psx_type_transition_selector_rows` (`0x80063b4c`), then `psx_object_select_state_script` installs selector.
|
||||
- In that transition path, runtime flag mutation is narrow and explicit: selector logic toggles `obj+0x1c` bit `0x0002` only; broad authored lane bits such as `0x0020` are not synthesized by this function.
|
||||
- `psx_type42_transition_selector_tick` adds an early pre-latch gate before reseat/turn-driven selector dispatch: object must be within view margin and pass the object-lane `obj+0x1c & 0x0020` condition. Selector updates there still occur before the later `obj+0x94` latch point.
|
||||
- The unresolved `FUN_8002906c` path is now closed by symbol state in live Ghidra: `0x8002906c` is `psx_type4_reselect_motion_state`, reached from `psx_type4_update_delayed_interaction` (`0x80029dac`) when delayed countdown reaches trigger. This is a post-construction reselection lane, not constructor-side initial bind.
|
||||
|
||||
Exporter-facing implication from executable evidence:
|
||||
|
||||
- A standalone JS exporter should treat selector install (`obj+0x9e`) and final latch (`obj+0x94`) as distinct channels.
|
||||
- Transition-table and type-`0x0042` reselection may alter pre-latch selector/runtime flag state without directly proving final frame token at draw time.
|
||||
- Cohort split logic should therefore prioritize latched `obj+0x94` capture (or strong proxy) over authored selector or transition slot alone.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x800260e8`: comment clarifying install-only selector semantics and no direct `obj+0x94` write.
|
||||
- `0x80025d68`: comment clarifying final frame/state latch into `obj+0x94`.
|
||||
- `0x8001bca0`: comment clarifying two-stage transition-row lookup and `0x0002`-only bit toggle scope.
|
||||
- `0x80018578`: comment clarifying type-`0x0042` pre-latch gate and reseat ordering.
|
||||
- `0x8002906c`: comment clarifying delayed post-construction reselection role.
|
||||
- `0x80029dac`: comment clarifying delayed countdown trigger into post-construction reselection.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Authored Family Descriptor Convergence and Constructor Bind Closure
|
||||
|
||||
- Scope for this focused pass: authored section-0 family dispatch and constructor bind semantics on active `SLUS_002.68` at `psx_dispatch_section0_dispatch_roots` (`0x800256b0`), `psx_dispatch_section0_constructor_placements` (`0x800258cc`), `psx_object_create_simple_record` (`0x800249f4`), `psx_object_create_compound_record` (`0x80024eec`), and descriptor row `0x800626f8`.
|
||||
- Section-0 root and constructor-placement records are now reconfirmed as one convergence lane for unresolved families (`0x0042`, `0x0049`, `0x0055..0x0063`): both dispatch through descriptor slot0 and converge on row `0x800626f8` callback `0x80013618`.
|
||||
- Descriptor row role at `0x800626f8` is now explicitly preserved in disassembly comments as:
|
||||
- slot0 `0x80013618` (`psx_spawn_compound_record_advance_state_once`)
|
||||
- slot1 `0x80013688` (`psx_object_refresh_main_visible_and_cleanup`)
|
||||
- slot2 `0x800254c8` (`psx_object_release_to_free_list`)
|
||||
- Constructor bind semantics are now restated at function entry for exporter extraction:
|
||||
- simple path copies authored route word `record+0x10 -> obj+0x1c`
|
||||
- compound path copies authored route word `record+0x0A -> obj+0x1c`
|
||||
- both read active art header from `DAT_800758d8[type]`
|
||||
- both reuse `DAT_800758c8[type]` for kind-5 resources and otherwise build per-instance resource.
|
||||
- Practical exporter consequence: authored-family divergence should continue to be modeled post-constructor (state/policy/route/latch channels), not as a section-0 descriptor callback split.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x80031c34`: `FUN_80031c34` renamed to `psx_spawn_type0b_compound_burst_for_active_object_sweep`.
|
||||
- `0x800256b0`: decompiler comment clarifying root-dispatch descriptor convergence.
|
||||
- `0x800258cc`: decompiler comment clarifying constructor-placement descriptor convergence.
|
||||
- `0x800249f4`: decompiler comment clarifying simple constructor route-word copy and art-bind/cache split.
|
||||
- `0x80024eec`: decompiler comment clarifying compound constructor route-word copy and art-bind/cache split.
|
||||
- `0x800626f8`: disassembly comment clarifying shared descriptor-row slot mapping.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Source-Record Palette Token Provenance (`obj+0xa0`) and Region00 12-byte Fit
|
||||
|
||||
- Scope for this focused pass: live `SLUS_002.68` constructor/source-pointer storage and world main-visible token read at `0x80024b50`, `0x80025048`, `0x800258cc`, and `0x80041458`.
|
||||
- Main-visible draw token read is now source-exact and band-split:
|
||||
- for `0x003e..0x00ab`: token high byte from `(*(obj+0xa0)+0x06) & 0xff00`
|
||||
- for `>=0x00ac`: token high byte from `(*(obj+0xa0)+0x0c) & 0xff00`
|
||||
- Constructor storage of `obj+0xa0` is now instruction-explicit in both create paths:
|
||||
- simple record path writes source pointer at `0x80024b50`
|
||||
- compound/region00 path writes source pointer at `0x80025048`
|
||||
- Section0 constructor-placement dispatch (`0x800258cc`) steps records by `+0x0c`, confirming region00-style authored records are 12 bytes in this lane.
|
||||
- For currently visible unresolved families in this workflow (`0x0042`, `0x0049`, `0x0055..0x0063`), type band is `<0x00ac`, so main-visible token read uses source offset `+0x06` only; this offset is inside 12-byte records and is therefore a usable authored palette-token carrier.
|
||||
- Consequence for exporter assumptions: treating region00 12-byte records as inherently unable to carry palette override bits is incorrect for these current families; only the `>=0x00ac` `+0x0c` read requires a longer source layout.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x80027f38`: `FUN_80027f38` renamed to `psx_alloc_runtime_snapshot_record_payload`.
|
||||
- `0x80024b50`: decompiler comment clarifying simple-path `obj+0xa0` source-record pointer storage and later main-visible `+0x06/+0x0c` token reads.
|
||||
- `0x80025048`: decompiler comment clarifying compound-path `obj+0xa0` storage and 12-byte-record compatibility with `<0x00ac` `+0x06` token read.
|
||||
- `0x8004156c`: decompiler comment clarifying the exact type-band split and source offsets used for main-visible palette-token injection.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Trace the remaining high-volume band `0x0055..0x0063` in Ghidra with the same question used for `0x0042`: why does `DAT_800758d8` stay zero-sized while visible art still exists at runtime?
|
||||
2. Use `map 104` as the primary regression target and dump its remaining fallback type/state/lane distribution before doing any broader heuristic expansion.
|
||||
3. Compare unresolved zero-block types against nearby resolved donor types at the constructor/resource level, not only at the script-signature level, so borrowed bundles can be replaced with an executable-backed alias rule.
|
||||
4. Keep the `DAT_800758d4` work on the bounds side unless a family-specific caller proves otherwise; this pass did not reopen that conclusion.
|
||||
4. Keep the `DAT_800758d4` work on the bounds side unless a family-specific caller proves otherwise; this pass did not reopen that conclusion.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Art Payload Decode Semantics For Standalone Exporters
|
||||
|
||||
- Scope for this focused pass: active PSX `SLUS_002.68` type-4/type-5 install and submit corridor centered on `psx_resource_bind_single_image_vram_slot` (`0x800444e4`), `image_bundle_load_to_vram` (`0x80044614`), `sprite_rle_decode_rows` (`0x80045264`), and frame-geometry helpers (`0x80045014`, `0x800450a8`, `0x8004513c`, `0x800451d0`).
|
||||
- Kind-4 decode lane is now extractor-explicit: single-image descriptors bind one VRAM slot and preserve descriptor width/height/format/payload metadata in the runtime resource; this is the minimal schema a standalone decoder must mirror before frame submission.
|
||||
- Kind-5 decode lane is now exporter-explicit: bundle install builds a runtime frame table (`0x10` stride), allocates frame VRAM slots, and uploads either raw rows or RLE-decoded rows depending on frame flag bit0.
|
||||
- RLE semantics are now pinned in live comments: positive control repeats a byte value, negative control copies literal run bytes, and zero terminates each row. This is the required offline decode contract for compressed WDL image payloads.
|
||||
- Geometry extraction rule is now explicit for offline export: width/height/origin come from kind-specific frame schemas (`0x14` stride kind-4 descriptor rows versus `0x10` stride kind-5 runtime rows), not from visibility-lane flags.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Renames:
|
||||
- `0x80045440` -> `psx_ui_image_bundle_get_frame_payload`
|
||||
- `0x800455d4` -> `psx_ui_image_bundle_draw_temp_vram_frame`
|
||||
- `0x80045d78` -> `psx_ui_image_bundle_draw_temp_vram_frame_static`
|
||||
- Decompiler comments:
|
||||
- `0x800444e4` (kind-4 single-image bind semantics)
|
||||
- `0x80044614` (kind-5 bundle upload table and raw-vs-RLE branch)
|
||||
- `0x80045264` (row-RLE decode contract for offline tools)
|
||||
- `0x80045014`, `0x800450a8`, `0x8004513c`, `0x800451d0` (kind-split frame geometry schema for exporter parity)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Loader Bundle Install, Stream Runtime Banks, and Inflate Lane
|
||||
|
||||
- Scope for this focused pass: `wdl_resource_bundle_load_by_index` (`0x80039444`), `psx_stream_install_type_runtime_banks` (`0x80038f18`), `psx_install_type_state_script_component_extents_banks` (`0x8003917c`), `psx_install_type_art_active_header_and_built_resource` (`0x80045ffc`), detached-stream installer (`0x80040768`), and compressed-state inflate (`0x8003b00c`).
|
||||
- `psx_stream_install_type_runtime_banks` now has exporter-relevant record layout closure: each streamed type entry begins with a fixed `0x14` header `(type_id, state_size, component_size, extents_size, active_art_header_size)` before payload bytes.
|
||||
- Stream-lane install behavior is now role-split and explicit:
|
||||
- installs state/script, component, and extents pointers into `DAT_800758cc/d0/d4`
|
||||
- clears `DAT_800758c8[type]` (`psx_type_art_built_resource_bank`) to null
|
||||
- installs only raw active-header pointer into `DAT_800758d8[type]` when `active_art_header_size != 0`.
|
||||
- Practical consequence for standalone exporters: stream-runtime-bank lane seeds metadata/header pointers only; built drawable resources are resolved in the separate WDL art installer (`psx_install_type_art_active_header_and_built_resource`) through kind-4 bind and kind-5 image-table build.
|
||||
- `wdl_resource_bundle_load_by_index` is now preserved as a multi-pass install sequence with two art/state waves, section-pack pointer install, detached runtime-stream install, optional compressed-state inflate, and only then root-record dispatch.
|
||||
- Compressed-state lane remains pre-dispatch and persistent-state-gated: `psx_lzss_unpack_into_level_buffer` inflates a `0x3e00` block into `psx_level_decompressed_state_buffer` before runtime-header apply and root replay; a zero backref token terminates decode.
|
||||
- Detached runtime-stream blob install (`0x80040768`) is now extraction-structured: header carries three leading lengths, then two 9-entry size arrays, then tail-transfer length used for SPU upload and sequence/VAB setup.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Renames:
|
||||
- `0x8002b6b8` -> `psx_level_heap_push_cursor_mark`
|
||||
- `0x8002b6e0` -> `psx_level_heap_pop_cursor_mark`
|
||||
- `0x80024720` -> `psx_level_runtime_node_pool_init_0x32`
|
||||
- Decompiler comments:
|
||||
- `0x80038f18` (stream runtime-bank install role split and built-resource clear)
|
||||
- `0x80040768` (detached runtime-stream blob format/install semantics)
|
||||
- `0x8003b00c` (compressed-state inflate role, size lane, and termination)
|
||||
- `0x80024720` (0x32-node cyclic runtime-node pool initialization)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Late Art-Bank Dual Feed and Constructor `0x58` Raw-Header Fast Path
|
||||
|
||||
- Scope for this focused pass: `wdl_resource_bundle_load_by_index` (`0x80039444`), late write sites `0x8003977c` / `0x80039a64`, `psx_install_type_art_active_header_and_built_resource` (`0x80045ffc`), `psx_create_image_resource_from_descriptor` (`0x80044434`), constructors `0x80024ab4` / `0x80024fac`, and sibling packed-stream helper `psx_stream_install_type_runtime_banks` (`0x80038f18`).
|
||||
- `wdl_resource_bundle_load_by_index` does not leave `DAT_800758d8` from one monolithic late art bank. For each WDL pass (`SPEC_A.WDL` first, selected `LSET*.WDL` second), it performs two distinct art-facing installs:
|
||||
- an earlier art-install blob (`header` field used as `local_a0`) that calls `psx_install_type_art_active_header_and_built_resource`
|
||||
- a later header-only override blob (`header` field used as `local_98`) whose `8`-byte rows write raw active-header pointers directly into `DAT_800758d8[type]`
|
||||
- The earlier art-install blob is now role-exact but still only medium confidence for raw standalone parsing:
|
||||
- `psx_install_type_art_active_header_and_built_resource` first stores the incoming header pointer to `DAT_800758d8[type]`
|
||||
- it then resolves kind `4` versus kind `5` resource build and writes the materialized resource to `DAT_800758c8[type]`
|
||||
- it finally mirrors that built resource pointer back into `DAT_800758d8[type]`
|
||||
- practical consequence: this pass is an install/build lane, not the final raw-header state seen by constructors after load completes
|
||||
- The later header-only override blob is the safer standalone parsing target and now has a tighter in-memory schema:
|
||||
- blob header begins with `count` and a directory offset
|
||||
- payload base is `blob + 0x08`
|
||||
- directory rows are `8` bytes each and are consumed as `(active_header_size, type_id)`
|
||||
- when `active_header_size != 0`, loader stores the current payload cursor to `DAT_800758d8[type]`
|
||||
- when `active_header_size == 0`, loader clears `DAT_800758d8[type]`
|
||||
- payload cursor then advances by `active_header_size`
|
||||
- Constructor-side reuse closure is now disassembly-backed and corrects an older decompiler-shaped reading: both constructors branch on `*(DAT_800758d8[type]) == 0x58`, not on `kind == 5`.
|
||||
- `0x80024b0c`: simple constructor raw-header fast path
|
||||
- `0x80025004`: compound constructor raw-header fast path
|
||||
- when the first dword is `0x58`, constructors treat `DAT_800758d8[type]` as a raw active header and reuse `DAT_800758c8[type]` instead of calling `psx_create_image_resource_from_descriptor`
|
||||
- `psx_create_image_resource_from_descriptor` remains the per-instance fallback builder for descriptors that do not arrive on that raw-header fast path. Its role did not change, but the exact condition for constructor reuse is now narrower and stronger.
|
||||
- `psx_stream_install_type_runtime_banks` still matters as a sibling negative-evidence lane: it proves there is a separate packed per-type bank format with a fixed `0x14` entry header `(type_id, state_size, component_size, extents_size, active_art_header_size)`. That stream format should not be conflated with the later `8`-byte header-only override blob used by `wdl_resource_bundle_load_by_index`.
|
||||
|
||||
Candidate standalone raw-schema read after this pass:
|
||||
|
||||
- High confidence: the late header-only override blob is the final post-load source that leaves raw `0x58`-byte active headers in `DAT_800758d8`, and its row walk is `8`-byte `(size,type)` with payloads packed immediately after the blob header.
|
||||
- Medium confidence: those `0x58`-byte active headers are the right standalone parser target for executable-faithful direct art binding because constructors discriminate on `0x58` and then reuse `DAT_800758c8`.
|
||||
- Low to medium confidence: the earlier art-install blob also feeds the same type lane, but its raw on-disk row encoding is still unresolved for standalone parsing because the runtime walk consumes pointer-like aux entries without an intervening relocation helper.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Decompiler comments:
|
||||
- `0x8003977c` (late header-only override writes raw active-header pointers)
|
||||
- `0x80039a64` (map-local repeat of the same override lane)
|
||||
- `0x800460d4` (built-resource mirror into `DAT_800758d8` is later overwritten by header-only pass)
|
||||
- `0x80024b0c` (simple constructor `0x58` raw-header fast path)
|
||||
- `0x80025004` (compound constructor `0x58` raw-header fast path)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Visibility Routing, Stage Lane Choice, and Main-Visible Ordering
|
||||
|
||||
- Scope for this focused pass: active PSX `SLUS_002.68` around `psx_object_integrate_motion_and_route_visible` (`0x800131a8`), neighboring player/object update corridor (`0x8001263c..0x80013688`), and main-visible ordering helpers centered on `0x8002be6c`, `0x8002c89c`, `0x8002ca74`, `0x8002d778`, and `0x8002e064`.
|
||||
- Route split is now pinned as object-local in executable terms: `psx_object_integrate_motion_and_route_visible` chooses stage-2 only when `type==4` or `obj+0x1c` has bit `0x0400`; otherwise it remains in stage-1 main-visible projection/sort lane.
|
||||
- In the same function, policy table reads (`DAT_800675f8[type]`) are downstream gating and ordering controls, not lane selectors. The key stage route decision remains the object-local `0x0400` branch.
|
||||
- Main-visible ordering is now graph-explicit: `psx_main_visible_order_compare_pair_for_graph` computes relation codes from projected extents and policy bits, `psx_main_visible_order_graph_link_new_object` records edges, and `psx_main_visible_list_sort_range` resolves a dependency-eligible ordered slice while unlinking conflicts.
|
||||
- Stage-1 ordering is therefore not a simple distance sort. It is a dependency-graph sort with policy-biased tie resolution, and that graph order feeds the main-visible draw lane.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Renames:
|
||||
- `0x8002cd60` -> `psx_main_visible_order_graph_release_node`
|
||||
- `0x8002ce38` -> `psx_main_visible_order_graph_compact_nodes`
|
||||
- `0x8002cf3c` -> `psx_main_visible_order_graph_reset_node_slot`
|
||||
- `0x8002cfb0` -> `psx_main_visible_order_graph_swap_node_slots`
|
||||
- Decompiler comments:
|
||||
- `0x800131a8` (stage-1 vs stage-2 route split for exporter lane choice)
|
||||
- `0x8002be6c` (pair-order relation semantics and policy bit role)
|
||||
- `0x8002d778` (dependency-aware main-visible sort behavior)
|
||||
- `0x8002cd60` (node release semantics)
|
||||
- `0x8002ce38` (node compaction/prune semantics)
|
||||
- `0x8002cf3c` (node slot reset semantics)
|
||||
- `0x8002cfb0` (node slot swap semantics during compaction)
|
||||
|
||||
Exporter-facing implication from executable evidence:
|
||||
|
||||
- A standalone JS exporter should keep route lane and order phase separate in diagnostics and matching:
|
||||
- lane selection key: `type==4 || (obj+0x1c & 0x0400)`
|
||||
- stage-1 ordering key family: graph relation codes plus policy-adjusted compare/unlink behavior
|
||||
- Flattening stage-1 order to simple Y/depth or ignoring graph edge pruning will diverge from executable main-visible draw order even when lane choice is correct.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Kind-4/Kind-5 Palette Selection Field Closure
|
||||
|
||||
- Scope for this focused pass: active PSX `SLUS_002.68` around `psx_resource_bind_single_image_vram_slot` (`0x800444e4`), `image_bundle_load_to_vram` (`0x80044614`), and submitters `psx_sprite_resource_submit_frame` (`0x80044bdc`) / `psx_image_table_submit_frame` (`0x80044e9c`) with lane callers in `psx_draw_main_visible_object` (`0x80041458`) and `psx_draw_special_visible_queue` (`0x80041144`).
|
||||
- Default CLUT source for both kind-4 and kind-5 remains resource field `resource+0x08`, seeded from descriptor/bundle header `+0x14` during bind.
|
||||
- No additional per-frame resource header field in the `0x800444e4/0x80044614` bind corridor directly selects CLUT index at submit time; frame-table records in this corridor drive geometry/payload upload, not palette-bank selection.
|
||||
- One additional resource header field does materially affect palette-routing semantics: resource format (`resource+0x04`, sourced from header `+0x10`) changes sprite override behavior.
|
||||
- format `== 2`: override token uses `psx_clut_override_table_by_palette_token[token]` directly.
|
||||
- format `!= 2`: override token is remapped as a bank-table row key in `psx_clut_table_by_resource_bank` (`(token<<4)` halfword lane).
|
||||
- Submit high-byte token source remains draw-lane/object-authored, not resource-header-local:
|
||||
- main-visible may inject authored high byte (`source+0x06` for `0x003e..0x00ab`, `source+0x0c` for `>=0x00ac`).
|
||||
- special-visible does not inject authored high byte.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Decompiler comments:
|
||||
- `0x800444e4` (kind-4 default palette-bank seed from header `+0x14`)
|
||||
- `0x80044614` (kind-5 default palette-bank seed and format-2 `+0x10` offset behavior)
|
||||
- `0x80044bdc` (sprite submit default/override CLUT resolution split)
|
||||
- `0x80044e9c` (image-table submit default/override CLUT resolution)
|
||||
|
||||
Exporter-facing implication from executable evidence:
|
||||
|
||||
- Standalone palette selection should treat header `+0x14` as the default bank key only.
|
||||
- Additional CLUT selection must come from runtime submit flags (lane/object authored token), with sprite format-aware override routing.
|
||||
- Do not infer palette index from frame-table width/height/origin/offset fields in the bind/upload helpers; those fields are geometry/payload metadata, not CLUT selectors.
|
||||
Loading…
Add table
Add a link
Reference in a new issue