diff --git a/docs/building.md b/docs/building.md index 9531f722..96b42c23 100644 --- a/docs/building.md +++ b/docs/building.md @@ -102,10 +102,12 @@ builds are named `ge007.pal-final.x86_64` / `ge007.jpn-final.x86_64`. ## 4. Generate the PC asset sidecars (required to run) -The port does **not** read model geometry or stage bg/stan data from the raw -ROM at runtime — it reads them from PC-layout *sidecar* files under `data/`, -produced offline by two converters. **Without them the game shows the intro -logos and then crashes** in `modelPromoteNodeOffsetsToPointers` (finding D179). +The port does **not** read model geometry, stage bg/stan data, or per-level +setup data from the raw ROM at runtime — it reads them from PC-layout *sidecar* +files under `data/`, produced offline by three converters. **Without them the +game shows the intro logos and then crashes** in +`modelPromoteNodeOffsetsToPointers` (finding D179) or on the first level load +(missing stage setup). Put your ROM in `data/` first (same file the game runs from): @@ -114,11 +116,13 @@ mkdir -p data cp /path/to/your/rom.z64 data/ge007.ntsc-final.z64 # or pal-final / jpn-final ``` -Then run both emit passes for that region: +Then run all three emit passes for that region, **in this order** (d88 appends +to d69's output): ```sh -python3 tools_pc/d43_emit.py ntsc-final # -> data/pcmodels-ntsc-final/{pcmodels.bin,manifest.csv} (~1.3 MB) -python3 tools_pc/d69_emit.py ntsc-final # -> data/pccg-ntsc-final/{pccg.bin,manifest.csv} (~3.6 MB) +python3 tools_pc/d43_emit.py ntsc-final # -> data/pcmodels-ntsc-final/{pcmodels.bin,manifest.csv} (~1.3 MB) +python3 tools_pc/d69_emit.py ntsc-final # -> data/pccg-ntsc-final/{pccg.bin,manifest.csv} (bg + stan) +python3 tools_pc/d88_emit.py ntsc-final --regen # appends the 21 per-level Usetup*Z stage-setup files -> ~3.6 MB ``` These are **pure-stdlib Python 3** (no MIPS toolchain, independent of the @@ -126,7 +130,11 @@ step-2 asset extraction) and read only the ROM plus files already committed to the repo (`scripts/filelist.u.csv`, `assets/obseg/file_resource_table.inc.c`, `assets/**/ModelFileHeader.inc.c`, the bg/stan `.inc.c`). Output is a deterministic function of the ROM. Re-run after any change to `d43_emit.py` / -`d69_emit.py` or the model/bg converters (`d43_*`, `d69_*`). +`d69_emit.py` / `d88_emit.py` or the model/bg converters (`d43_*`, `d69_*`, +`d88_propdefs.py`). + +> The release bundle ships `prepare-assets/prepare-assets.py`, which runs all +> three passes against your ROM automatically — see the bundled `README.md`. > `data/pcmodels-*/` and `data/pccg-*/` are gitignored ROM-derived game data — > never commit or redistribute them. diff --git a/docs/dev/findings.md b/docs/dev/findings.md index dbfe3668..9e96f10e 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -386,6 +386,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D161 | Depot (`-level_30`) ceiling = bright-blue speckle + radial rays (B2). A CI8 tile drawn with `gsDPSetTextureLUT(G_TT_NONE)` was decoded against the stale `rdp.palette` → garbage. Fix: `#ifdef`-free narrow route CI→I when `palette_fmt == G_TT_NONE` in `gfx_pc.cpp import_texture()`. | FIXED (`port/fast3d/gfx_pc.cpp`) | | D165 · D166 | input-layer polish (M-31, port-only, `port/src/input.c`): D165 front-end cursor is now a true ~1:1 pointer (P-controller estimating the game cursor via front.c's own integrator) instead of velocity²; D166 hipfire mouse pitch emits speed-proportional C-button pulses instead of a fixed digital threshold. | FIXED | | D180 · D181 | native-PC input pass (QoL run, `qol/native-pc-input-menu`): D180 = `Input.MouseCaptureMode` click-to-lock + absolute-cursor menu tracking + aim-speed default retune (`port/src/input.c`, `video.c`, port-only); D181 = `Game.ScreenShakeIntensity` route-(b) hook in `src/fr.c viShake` (`#ifdef PORT`, default 1.0 = no-op). | LANDED, config-gated, feel-checks owed | +| D186 | **`Video.FpsCap` throttles the sim, not just presentation (M-39 diag, M-42 clamp).** The frame-pacing `sysSleep`+busy-wait in `sync_framerate_with_timer` (`port/fast3d/gfx_sdl2.cpp`) runs inline on the scheduler thread (`osSpTaskStartGo`→`gfx_run`→`swap_buffers_begin`), so a low cap blocks VI-retrace delivery and drags every game thread down to the cap rate (no N64 analogue — RSP/RDP are separate silicon). **Landed:** `0 < FpsCap < 30` → treated as `0` (uncapped) + warning, at both `videoInit` (normalises a bad `ge007.ini` for the next `configSave`) and `gfx_sdl_set_target_fps` (covers the F10-overlay live path); caps ≥ 30 unchanged. Verified: default `FpsCap=0` framediff 3/3 golden-identical; `FpsCap=10` now runs at the uncapped rate; `FpsCap=60` still paces. **Owed:** move pacing off the scheduler thread so any cap only drops presented frames. See §F "D186" + porting-notes.md §E. | CLAMP LANDED (`port/fast3d/gfx_sdl2.cpp`, `port/src/video.c`); real fix owed | | D152+ | D152 addendum (M-31): static audit of every compiled-audio `osSetIntMask(OS_IM_NONE)` — **all balanced**, no unbalanced early-return. Real fixes: `sndSetSfxSlotVolume` now holds the mask across its list walk (matches its twin `sndDeactivateAllSfxByFlag`) + `sndApplyVolumeAllSfxSlot` batches the slot loop under one recursive hold (kills the fade-out lock-acquire storm); `portThreadWrapper` calls `imThreadExitRelease()` on thread exit (kills the "transient thread acquired `OS_IM_NONE` and died" leak + the pthread-id-reuse re-wedge). Steal-lock kept as backstop. | FIXED (`src/snd.c`, `port/src/libultra.c`, `#ifdef PORT`) — fade-out repro playtest-gated, not headless-verified | | RC3 · D167 | **Non-power-of-two texture wrap period (`docs/dev/TEXTURE-GLITCH-ANALYSIS.md` §6 RC3 — "textures repeat oddly", residual Depot-ceiling noise after D161).** The N64 RDP masks the texel coordinate of a wrapping render tile at `1< gfx_run -> swap_buffers_begin), so a low + * cap stalls VI-retrace delivery and throttles the whole sim, not just + * presentation. Until pacing is moved off that thread, refuse caps low + * enough to be user-visible as a slowdown: treat 1..29 as uncapped. */ + if (fps > 0 && fps < 30) { + sysLogPrintf(LOG_WARNING, "gfx_sdl: ignoring FpsCap=%d (< 30 throttles the sim); running uncapped", fps); + fps = 0; + } target_fps = fps; } diff --git a/port/src/video.c b/port/src/video.c index 9e87305f..10fef104 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -147,6 +147,14 @@ int videoInit(void) /* VSync + optional fps cap; fast3d paces the window itself. */ wmAPI->set_swap_interval(cfgVSync ? 1 : 0); + /* D186: a low cap does not just drop frames -- the pacing wait blocks the + * scheduler thread and throttles the sim with it. Normalise a bad + * ge007.ini value (e.g. dinged to 10 via the options overlay) to uncapped + * so it persists sane on the next configSave(). */ + if (cfgFpsCap > 0 && cfgFpsCap < 30) { + sysLogPrintf(LOG_WARNING, "video: Video.FpsCap=%d too low (throttles the sim); using 0 (uncapped)", cfgFpsCap); + cfgFpsCap = 0; + } gfx_set_target_fps(cfgFpsCap); /* 0 = uncapped */ /* Texture filtering. 1 = bilinear (default, matches prior behaviour),