mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
D73+D74: intro logo fixed (sinf/cosf endianness + texture import/sub-tile wrap)
D73 (root cause of old D72.3): GE's sinf/cosf build their double
constants through the du bit-union with big-endian word pairs {hi,lo};
on LE PC the .d read has the words swapped (rpi.d ~ 2^733), range
reduction overflows, and FTOFIX32 saturates to -32768 for every
sin/cos entry of guMtxF2L — so the Rareware logo's rotation matrix was
garbage and all its triangles projected off-screen. Fix: DVAL() macro
in src/libultra/gu/guint.h (PORT-only; #else branch is the original
expression) re-packing hi/lo into the correct LE double; sinf.c/cosf.c
.d reads replaced. N64 build untouched.
D74 (texture side, three port-layer bugs in fast3d):
- import_texture's fallback condition (rdp.tex_lod && tile >=
first+detail) overwrote valid gDPLoadBlock tmem data with
line*tile.height: letter mip chains 2744B -> 2048B (mips 1-5 dropped),
D_02005FF0 32x32 -> 32x3 (stale tile.height from gsDPSetTileSize).
Now falls back only when the tmem slot was never written.
- TextureCacheKey gains size_bytes so a truncated first import cannot
poison later full imports of the same address.
- VBO UV path now wraps by TILE size for WRAP sub-tiles (N64 semantics);
the logo's 20x3 tile at offset (11.5,29) was sampling row 0 instead
of rows 29-31. Per-vertex pre-wrap; known limits: half-texel edge
bleed, mirror sub-tiles unhandled.
Verified: clean runs reach frame ~2100 then hit the D69 load_bg_file
fault (unchanged — still the milestone blocker); PPM frame ~555 shows
the four gold RARE letters on the dark-blue plate (final pixel-perfect
check vs N64 footage left as a low-priority task). All env-gated probes
from this session (GE_DBGUV/DBGTRI/DBGTALL/DBGMAT/D74IMP/D74DUMP/
GE_DBGLOAD) stripped; previously committed TEMP D63 blocks + GE_D71LOG
remain on the HANDOFF strip list.
Docs: PCPortResearch.md §F D73/D74 entries, §G/§H status updated;
HANDOFF.md rewritten for Session I (D69 primary); AGENTS.md phase line.
This commit is contained in:
1 parent
5f4e90ddfc
commit
978306d14f
8 files changed
+237
-173
No files matched your search
@@ -48,6 +48,6 @@ Run `/linkcheck` for this sweep. Record new findings in `docs/PCPortResearch.md`
|
||||
- **Compile+link milestone:** all ~235 TUs compile and `ge007.x86_64.exe` links clean (`ninja ge007 -k 0`, 236/236). Findings D7–D17 in `docs/PCPortResearch.md` §11; asset stubs in `port/src/assetstubs.c`, fast3d no-ops in `port/src/gfxstub.c` (delete when real fast3d lands).
|
||||
- **Phase 1 (boot to window):** done — ROM loads/validates/maps at cart base 0x10000000 (`romdata.c`), SDL2 window + GL clear loop (`video.c`), absolute asset symbols from `scripts/gen_romassets.py` → `port/src/romassets_<r>.s` (findings D18–D23).
|
||||
- **Phase 1.5 (boot to first frame):** DONE — boot chain complete AND real frames render (`[NOTE] frame N rendered in … us`). D34–D42 closed the blockers on top of D31–D33: ANIM_DATA lvalues, music seq-table ABI+endianness, music-heap sizing, libaudio bank-tree re-layout, implicit-declaration prototype shim (D38), Globalimagetable rebasing + true segment size (D39), ModelHitEntry pool sizing (D40), cross-thread GL context release (D41), rsp task-settings toggle (D42). ROM dump verified against the No-Intro good dump (byte-identical, header CRCs re-checked — `tools_pc/romverify.c`).
|
||||
- **Phase 2 (rendering):** IN PROGRESS — fast3d integrated + real frames render. **Plan B EXECUTED (D50, committed):** all 512 NTSC model files converted offline by `tools_pc/d43_emit.py` → `data/pcmodels-ntsc-final/pcmodels.bin` + manifest.csv (single concatenated RZ image; regenerate per region with the script — sidecars are gitignored), served through the existing load path via a port-layer table patch (`port/src/pcmodels.c`, romdata cart-extension, one-shot `pcmodelsPatchTable()` + poolRemaining reset hook in `load_object_fill_header`); runtime C fixups for language-bank BE offset tables + font re-layout (D50.3/D50.4); legal-screen UB seed (D50.5); **D50.6 fixed the first model-render crash** — `texCopyGdls` copied only w0 of each 16-byte Gfx slot on PC (the union's trailing `long long` is 8 bytes), leaving stale mempool w1s in the compacted GDLs; byte-proven against PlegalpageZ, fixed with a full-slot copy under #ifdef PORT. Model GDLs now execute to completion (PlegalpageZ sub-DLs). **D51 RESOLVED** (font `pixeldata` fixup wrote the pointer at the wrong offsets — frame-5 `import_texture_i8` crash gone; GE opcode space decoded along the way, G_TEXRECT=0xE4/0xE5 non-F3DEX numbering), **D52 RESOLVED** (`osGetCount` now advances at the N64 RSP counter rate ≈ 46.5525 ticks/µs — fixed the non-deterministic post-frame-2 hang), **D53 RESOLVED** (model RW-data pool addressing: D53.1 `Model.datas` word-stride → `u32 *` under PORT + casts; D53.2 ModelSlot/AnimModelSlot re-laid on top of the PC struct Model — in-use@0x10 / pool@0x20, slot size = sizeof(Model) = 0xE8 — plus PORT-guarded heap-fallback bumps in model.c), **D54 RESOLVED** (cseq ALCMidiHdr BE header: port-layer `romdataFixupCseq` bswap32 of the first 17 u32s, called from music.c after each decompress), **D54b RESOLVED** (synth param slots sized for ALStartParamAlt = 0x28 in synthesizer.c alSynInit under PORT), **D55 RESOLVED** (RLE folder-menu background BE w/h header: bswap32 of the first word at `(u32 *)&unknown2` at cart-map time in romdataInit, guarded). Build GREEN; game boots, plays intro music, renders through logo/gun-barrel, instantiates Brosnan, and executes the gun-barrel hole DL clean to ENDDL. **D56 RESOLVED** (watch Model/RW-pool raw offsets: field-name Model access + static 0xC8-byte pool under PORT in bondview2.c), **D57 RESOLVED** (pointer-grown rwdata records overflowed N64-sized spare pools — Brosnan PC numRecords 153 > 140: capacities grown in initunk_005520.c + dynamic slot+pool fallback in model.c), **D58 RESOLVED** (gun-barrel DL: vertex-pointer K0 idiom rebuilt via `OS_K0_TO_PHYSICAL(…) | 0x80000000` in title.c + DL reserve 0x100→0x200 because `sizeof(Gfx)` is 16 on PC). **D59–D68 RESOLVED (committed):** the "GL DLL" crash was D64's unbounded blood-RLE write (sentinel section-adjacency lost on PC) clobbering the gun-barrel sub-DL; then D60–D62 (DMA target validation, OSMesgQueue layout), D65/D65b (HEADS/BODIES enum signed sentinels under PORT), D66 (romCopyAligned + ramrom replay 64-bit pointer width), D67 (struct image_entry N64 layout), **D68 (Globalimagetable BE→LE fixup** — `port/src/gimgfixup.c` bswaps IMAGESEG Gfx w1 words + sImageTableEntry.index after texReset's romCopy; compiled globalDL shadows synced for explosion.c). The game now renders the **entire ~3.5-minute intro** (logo → gun barrel w/ Brosnan → cast) at ~59 fps. **Current blocker D69:** `load_bg_file` (bg.c:830) faults on first stage load — BG-file headers/records are N64 big-endian segment-0x0F offsets, read LE on PC; the bg `.seg` + `Tbg_*_stanZ` format work is next (decode from bg.c/stan.c → offline sidecar conversion per the D43 pattern or runtime port-layer fixup; PD `preprocess/filebg.c` is approach-reference only — its BG format differs). **D70–D72 (intro-logo pixels):** D70 env-gated PPM frame capture (`GE_PCDUMP` → `./ppm/`, gitignored); **D71 RESOLVED** — C-array texture sources (the four rarewarelogo.c RGBA16 images) byte-swapped on LE PC → pink/green logo; port-layer per-source bswap in `import_texture`; **D72 RESOLVED** the UV path (GE always uses authored `tc[]` UVs — no G_TT_BASE/CLAMP anywhere; `lookat_enabled` defaults false since N64 boots with RSP mem zeroed) but **D72.3 OPEN**: all logo triangles project off-screen and a flat dark-blue checkerboard triangle rasterizes instead (identity pending via `GE_DBGUV`/`GE_DBGTALL` traces); D69 remains the milestone blocker. Committed through D72. Recurring sub-task: ABI/layout fixes per the D32 procedure (§H) as more asset types are first touched (PD's `preprocess/` module already solves most of them; prefer the offline pattern for format work — D48; full-struct Gfx copies on PC — D50.6; audit struct type-puns after pointer-width changes — D53.2; raw byte offsets into pointer-containing structs shift on PC — D56; N64-sized reservations must be re-checked against 16-byte Gfx/Vtx widths — D58).
|
||||
- **Phase 2 (rendering):** IN PROGRESS — fast3d integrated + real frames render. **Plan B EXECUTED (D50, committed):** all 512 NTSC model files converted offline by `tools_pc/d43_emit.py` → `data/pcmodels-ntsc-final/pcmodels.bin` + manifest.csv (single concatenated RZ image; regenerate per region with the script — sidecars are gitignored), served through the existing load path via a port-layer table patch (`port/src/pcmodels.c`, romdata cart-extension, one-shot `pcmodelsPatchTable()` + poolRemaining reset hook in `load_object_fill_header`); runtime C fixups for language-bank BE offset tables + font re-layout (D50.3/D50.4); legal-screen UB seed (D50.5); **D50.6 fixed the first model-render crash** — `texCopyGdls` copied only w0 of each 16-byte Gfx slot on PC (the union's trailing `long long` is 8 bytes), leaving stale mempool w1s in the compacted GDLs; byte-proven against PlegalpageZ, fixed with a full-slot copy under #ifdef PORT. Model GDLs now execute to completion (PlegalpageZ sub-DLs). **D51 RESOLVED** (font `pixeldata` fixup wrote the pointer at the wrong offsets — frame-5 `import_texture_i8` crash gone; GE opcode space decoded along the way, G_TEXRECT=0xE4/0xE5 non-F3DEX numbering), **D52 RESOLVED** (`osGetCount` now advances at the N64 RSP counter rate ≈ 46.5525 ticks/µs — fixed the non-deterministic post-frame-2 hang), **D53 RESOLVED** (model RW-data pool addressing: D53.1 `Model.datas` word-stride → `u32 *` under PORT + casts; D53.2 ModelSlot/AnimModelSlot re-laid on top of the PC struct Model — in-use@0x10 / pool@0x20, slot size = sizeof(Model) = 0xE8 — plus PORT-guarded heap-fallback bumps in model.c), **D54 RESOLVED** (cseq ALCMidiHdr BE header: port-layer `romdataFixupCseq` bswap32 of the first 17 u32s, called from music.c after each decompress), **D54b RESOLVED** (synth param slots sized for ALStartParamAlt = 0x28 in synthesizer.c alSynInit under PORT), **D55 RESOLVED** (RLE folder-menu background BE w/h header: bswap32 of the first word at `(u32 *)&unknown2` at cart-map time in romdataInit, guarded). Build GREEN; game boots, plays intro music, renders through logo/gun-barrel, instantiates Brosnan, and executes the gun-barrel hole DL clean to ENDDL. **D56 RESOLVED** (watch Model/RW-pool raw offsets: field-name Model access + static 0xC8-byte pool under PORT in bondview2.c), **D57 RESOLVED** (pointer-grown rwdata records overflowed N64-sized spare pools — Brosnan PC numRecords 153 > 140: capacities grown in initunk_005520.c + dynamic slot+pool fallback in model.c), **D58 RESOLVED** (gun-barrel DL: vertex-pointer K0 idiom rebuilt via `OS_K0_TO_PHYSICAL(…) | 0x80000000` in title.c + DL reserve 0x100→0x200 because `sizeof(Gfx)` is 16 on PC). **D59–D68 RESOLVED (committed):** the "GL DLL" crash was D64's unbounded blood-RLE write (sentinel section-adjacency lost on PC) clobbering the gun-barrel sub-DL; then D60–D62 (DMA target validation, OSMesgQueue layout), D65/D65b (HEADS/BODIES enum signed sentinels under PORT), D66 (romCopyAligned + ramrom replay 64-bit pointer width), D67 (struct image_entry N64 layout), **D68 (Globalimagetable BE→LE fixup** — `port/src/gimgfixup.c` bswaps IMAGESEG Gfx w1 words + sImageTableEntry.index after texReset's romCopy; compiled globalDL shadows synced for explosion.c). The game now renders the **entire intro** (logo → gun barrel w/ Brosnan → cast; ~frame 2100, ≈2 min wall-clock at the current ~20 fps clean-run rate). **Current blocker D69:** `load_bg_file` (bg.c:830) faults on first stage load — BG-file headers/records are N64 big-endian segment-0x0F offsets, read LE on PC; the bg `.seg` + `Tbg_*_stanZ` format work is next (decode from bg.c/stan.c → offline sidecar conversion per the D43 pattern or runtime port-layer fixup; PD `preprocess/filebg.c` is approach-reference only — its BG format differs). **D70–D74 (intro-logo pixels, RESOLVED):** D70 env-gated PPM frame capture (`GE_PCDUMP` → `./ppm/`, gitignored — kept as permanent dev tooling); **D71** C-array texture sources (the four rarewarelogo.c RGBA16 images) byte-swapped on LE PC → port-layer per-source bswap in `import_texture`; **D72** the UV path (GE always uses authored `tc[]` UVs; `lookat_enabled` defaults false); **D73 = root cause of old D72.3** — sinf/cosf `du` double constants are big-endian word pairs, garbage on LE PC → guMtxF2L emitted −32768 for every sin/cos entry → logo triangles projected off-screen; fixed with the PORT-only `DVAL()` macro in `src/libultra/gu/guint.h` (sinf.c/cosf.c `.d` reads replaced; N64 build untouched); **D74** texture import fallback no longer truncates valid gDPLoadBlock data (was dropping letter mip chains + reducing D_02005FF0 to 32×3), `TextureCacheKey` gained `size_bytes`, and the VBO path wraps UVs by tile size for WRAP sub-tiles (N64 semantics). The Rareware logo now renders its four gold letters on the dark-blue plate (PPM-verified ~frame 555; final pixel-perfect check vs N64 footage optional). D69 remaLine truncated
|
||||
- **Phase 3 (audio + input):** libaudio → SDL — largely copy-and-adapt from PD (`mixer.c` 722 lines vs our 31-line stub; `input.c` SDL_GameController backend; §2.4); decide the ASP strategy (C2: `aspMain*` dummies in `ucode.c`).
|
||||
- **Phase 4 (saves + polish):** file-backed EEPROM — build on PD's `fs.c` (file-backed save dir); PFS/motor already no-op stubs.
|
||||
+71
-68
@@ -1,62 +1,55 @@
|
||||
# Handoff brief — GoldenEye 007 PC port (Phase 2: Session H — D72.3 intro-logo pixels + D69 BG/stan stage loading)
|
||||
# Handoff brief — GoldenEye 007 PC port (Phase 2: Session I — D69 BG/stan stage loading)
|
||||
|
||||
_Paste-ready briefing. Authoritative detail lives in `AGENTS.md` and
|
||||
`docs/PCPortResearch.md` (§F/D59–D69 findings, §G status, §H procedure); this
|
||||
`docs/PCPortResearch.md` (§F/D59–D74 findings, §G status, §H procedure); this
|
||||
is the summary + the immediate tasks._
|
||||
|
||||
## Your job
|
||||
|
||||
- **Session H:** two live threads, both verified reproducible:
|
||||
1. **D72.3 (intro logo pixels):** after D71 (logo byte order) + D72 (tc[]
|
||||
UVs), the Rareware logo still doesn't appear — all its triangles project
|
||||
off-screen, and a flat dark-blue checkerboard triangle (broken
|
||||
rasterization of something else) fills the lower screen instead. Tools
|
||||
are in place: `GE_PCDUMP` frame capture + `GE_DBGUV`/`GE_DBGTALL`
|
||||
traces in gfx_pc.cpp. Find which triangle draws the checkerboard, then
|
||||
check MP matrix + viewport at logo time (title.c
|
||||
load_display_rare_logo).
|
||||
2. **D69 (milestone):** make the first stage (BUNKER1) load and render —
|
||||
BG-file data is N64 big-endian; reverse-engineer GE's bg `.seg` +
|
||||
`Tbg_*_stanZ` formats from the decompiled consumers, then convert/fix
|
||||
for PC.
|
||||
Work agentically: decode → implement → build (~5 s) → verify → commit at
|
||||
each sub-milestone (document findings as D6x/D7x in §F).
|
||||
- **Session I — D69 (the milestone blocker):** make the first stage (BUNKER1)
|
||||
load and render. BG-file data is N64 big-endian; reverse-engineer GE's bg
|
||||
`.seg` + `Tbg_*_stanZ` formats from the decompiled consumers, then convert
|
||||
or fix them for PC. This is the only thing standing between the intro and
|
||||
gameplay (verified: clean runs reach frame ~2100 in ≈2 min wall-clock, then
|
||||
fault deterministically in `load_bg_file`, bg.c:830).
|
||||
- **Secondary (low priority):** final pixel check of the intro logo. D73 +
|
||||
D74 fixed it at the data level and PPM frames ~550–560 show four gold
|
||||
letters on the dark-blue plate; compare against N64 reference footage if
|
||||
time allows (reference screenshots are at repo root: `Graphics Screenshot
|
||||
2026-08-24 121659.jpg`, `gun barrel.png`).
|
||||
- Work agentically: decode → implement → build (~5 s) → verify → commit at
|
||||
each sub-milestone (document findings as D7x in §F).
|
||||
|
||||
## Current state (verified this session)
|
||||
|
||||
- **Build GREEN.** `export PATH="/c/msys64/mingw64/bin:$PATH" && ./build-pc.sh ntsc-final`.
|
||||
- **D59–D68 all resolved** (details in PCPortResearch.md §F). Highlights:
|
||||
- **D59/D64** — the old "GL DLL" crash was an unbounded blood-RLE write
|
||||
(sentinel `die_blood_image_end` lost its N64 section adjacency on PC)
|
||||
clobbering the gun-barrel sub-DL. Sentinel now defined as one-past-the-
|
||||
end of the array under PORT.
|
||||
- **D65/D65b** — `enum HEADS`/`BODIES` sentinels: N64 semantics were signed
|
||||
(`HEAD_FIXED == -1`); PC GCC 16 picks unsigned underlying types, deleting
|
||||
the guard branches. Negative literals under PORT restore the bit pattern
|
||||
with signed semantics.
|
||||
- **D66** — `romCopyAligned` + ramrom replay did s32 pointer math; targets
|
||||
in `.bss` > 4 GiB truncated to wild addresses. 64-bit version under PORT,
|
||||
returns `void *`.
|
||||
- **D67** — `struct image_entry` re-laid (all-u32 bitfields, `dataoffset:24`
|
||||
first) so texLoad's raw word read + chrprop.c's 8-byte stride agree;
|
||||
sizeof == 8 on both targets.
|
||||
- **D68** — Globalimagetable BE→LE fixup (`port/src/gimgfixup.c`): bswap the
|
||||
IMAGESEG-marked Gfx w1 words (17 DLs) + `sImageTableEntry.index` (32
|
||||
tables, counts from D39 layout) after texReset's romCopy; marker scan in
|
||||
`texLoadFromDisplayList` moved to bytes 6..7 under PORT; compiled
|
||||
globalDL shadows synced after texLoad (`gimgSyncCompiledGlobalDLs`).
|
||||
- **D70–D72 (intro logo pixels, latest session):** D70 env-gated PPM frame
|
||||
capture (`GE_PCDUMP` → `./ppm/`, gitignored); D71 RESOLVED — C-array
|
||||
texture sources (the four rarewarelogo.c RGBA16 images) were byte-swapped
|
||||
on LE PC → pink/green logo; port-layer per-source bswap normalizes them.
|
||||
D72 RESOLVED the UV path (GE always uses authored tc[] UVs; lookat defaults
|
||||
off) but **D72.3 OPEN**: all logo triangles project off-screen and a flat
|
||||
dark-blue checkerboard triangle rasterizes instead — see Your job #1.
|
||||
- **Runtime:** boots → intro music → full intro (logo, gun barrel w/ Brosnan,
|
||||
cast screen) at ~59 fps → **crash in `load_bg_file` (bg.c:830)** on first
|
||||
stage load. EXCEPTION 0xc0000005, FAULT ADDR ≈ header buffer + 0x500000F.
|
||||
- **Committed through D72** (see git log). TEMP diagnostics from the
|
||||
D51–D72 sessions are still in the tree — strip list in Task 3.
|
||||
- **D59–D68 resolved** (details in PCPortResearch.md §F): blood-RLE sentinel,
|
||||
HEADS/BODIES signed sentinels, romCopyAligned/ramrom 64-bit, image_entry
|
||||
layout, Globalimagetable BE→LE fixup (`port/src/gimgfixup.c`), etc.
|
||||
- **D70–D74 (intro logo) resolved:**
|
||||
- D70: `GE_PCDUMP` PPM frame capture (kept — permanent dev tooling).
|
||||
- D71: C-array texture sources (rarewarelogo.c RGBA16 images) bswapped on
|
||||
LE PC → port-layer per-source normalization in `import_texture`.
|
||||
- D72: GE always uses authored `tc[]` UVs; `lookat_enabled` defaults false.
|
||||
- **D73 (root cause of the old D72.3):** sinf/cosf `du` double constants
|
||||
are big-endian word pairs → garbage on LE PC → guMtxF2L emitted −32768
|
||||
for every sin/cos entry → logo triangles projected off-screen. Fixed with
|
||||
the `DVAL()` macro in `src/libultra/gu/guint.h` (PORT-only; N64 build
|
||||
untouched). All scenes using guRotate/guLookAt-derived matrices were
|
||||
affected, not just the logo.
|
||||
- **D74:** texture import fallback no longer truncates valid gDPLoadBlock
|
||||
data (was dropping letter mip chains and reducing D_02005FF0 to 32×3);
|
||||
`TextureCacheKey` gained `size_bytes`; VBO path now wraps UVs by tile
|
||||
size for WRAP sub-tiles (N64 semantics; the logo's 20×3 sub-tile at
|
||||
offset (11.5, 29) was sampling row 0 instead of rows 29–31).
|
||||
- **Runtime:** boots → intro music → full intro (Rareware logo with gold
|
||||
letters, gun barrel w/ Brosnan, cast screen) → **crash in `load_bg_file`
|
||||
(bg.c:830)** on first stage load. EXCEPTION 0xc0000005; the crash log at
|
||||
repo root (`ge007.crash.log`, gitignored) is from this exact fault:
|
||||
PC=0x14000627c, FAULT ADDR = Rax+0x28 (reading `pPointTableBin` through the
|
||||
mis-rebased room-fileposition pointer).
|
||||
- **Committed through D74.** This session's TEMP probes are all stripped;
|
||||
previously committed TEMP diagnostics remain — strip list in Task 3.
|
||||
|
||||
## The blocker, precisely (D69)
|
||||
|
||||
@@ -98,7 +91,8 @@ GE's own consumers (bg.c, stan.c, and the N64 disasm where in doubt).
|
||||
1. `AGENTS.md` — non-negotiables, critical files, build, verification ritual.
|
||||
2. `docs/PCPortResearch.md` **§F/D69** (blocker + strategy), then D68
|
||||
(Globalimagetable fixup — the template for BE data in this segment family),
|
||||
§G status, and the environment reminders at the end of §H.
|
||||
D73–D74 (this session), §G status, and the environment reminders at the end
|
||||
of §H.
|
||||
3. The consumers: `src/game/bg.c` (`load_bg_file` ~line 795+, levelinfotable
|
||||
line 183, BG_SEG_TO_PTR in bg.h:23), `src/game/stan.c` (stanLoadFile /
|
||||
stanDetermineEOF), `src/game/ob.c` (obLoadBGFileBytesAtOffset — note the
|
||||
@@ -135,24 +129,23 @@ GE's own consumers (bg.c, stan.c, and the N64 disasm where in doubt).
|
||||
|
||||
## Task 3 — strip TEMP diagnostics before committing
|
||||
|
||||
Env-gated probes to remove (grep `GE_D` + `TEMP D`):
|
||||
- ob.c: D69 probe (both obLoadBGFileBytesAtOffset versions) + its stdio/stdlib
|
||||
includes.
|
||||
- image.c / image_bank.c: D66 texLoad probe if still present.
|
||||
- gfx_pc.cpp: D59 seg probes, D63 dram-branch/modelRenderNodeGundl/rspGfxTaskStart.
|
||||
- gfx_pc.cpp: D70/D71/D72 TEMP — `GE_DBGUV`/`GE_DBGTALL` UV+triangle loggers
|
||||
(gfx_dbg_uv_enabled + the DBGTRI/DBGTALL blocks in gfx_sp_vertex/gfx_sp_tri1)
|
||||
and the `GE_D71LOG` normalize log. Keep the D71 normalization itself — it's
|
||||
the fix, not a probe.
|
||||
- video.c + gfx_opengl.cpp: D70 `GE_PCDUMP` frame capture (videoEndFrame dump
|
||||
hook, gfx_opengl_pcdump_* implementations).
|
||||
- blood_animation.c: D63 g_GfxMemPos probe.
|
||||
- front.c: D63 menu probes (d63MenuProbe/After + call sites).
|
||||
This session's probes (GE_DBGUV/DBGTRI/DBGTALL/DBGMAT/D74IMP/D74DUMP/DBGLOAD)
|
||||
are already stripped. Previously committed TEMP diagnostics still in the tree
|
||||
(grep `TEMP D` + `GE_D`):
|
||||
- gfx_pc.cpp: **TEMP D63** — the dram-branch trail (`s_d63taskcount`,
|
||||
`d63RecordBranch`/`d63DumpTrail`/`d63LogLastBranchReread` externs near the
|
||||
top of gfx_run_dl, the call in the G_DL case that also spams `[NOTE] D63
|
||||
dram-branch` every frame, the GE_D63 dump block, and the function
|
||||
definitions at the end of the file); D59 seg probes if still present.
|
||||
- gfx_pc.cpp: `GE_D71LOG` one-shot normalize log (keep the normalization
|
||||
itself — it's the D71 fix).
|
||||
- front.c: `d63MenuProbe`/After + call sites. blood_animation.c: D63
|
||||
g_GfxMemPos probe. ob.c: D69 probe (both obLoadBGFileBytesAtOffset
|
||||
versions) + its stdio/stdlib includes — **strip only after D69 is solved**.
|
||||
- rsp.c, model.c, initanitable.c, language.c, title.c, ramromreplay.c,
|
||||
n64stubs.c, libultra.c, romdata.c: leftover TEMP blocks from D51–D66
|
||||
(D51 vi-post logging, D54 music, D56 watch, D57 pool, D60/D61 DMA logging —
|
||||
decide per item whether the guard stays permanent; D60's target validation
|
||||
is a permanent safety net and should stay).
|
||||
(decide per item; D60's DMA target validation is a permanent safety net and
|
||||
should stay).
|
||||
- Scratch files at repo root: `run_*.log`, `d62mesg.log`, `all.txt`, `b3.c`,
|
||||
`btest*.c`, `buildtest.txt`, `err.txt`, `gcout.txt`, `preproc.txt`,
|
||||
`vsize.c/.exe`, `scratch-logs/` — delete (add to .gitignore if they recur).
|
||||
@@ -166,16 +159,21 @@ Env-gated probes to remove (grep `GE_D` + `TEMP D`):
|
||||
duplicates, syntax (`./build-pc.sh` is the final word).
|
||||
- **Run the game from the repo root** (`cd REPO_ROOT &&
|
||||
./build-pc/ge007.x86_64.exe`) — running from build-pc/ picks up the wrong
|
||||
ROM (baserom.u.z64) and misses the sidecar.
|
||||
ROM (baserom.u.z64) and misses the pcmodels.bin sidecar → spurious frame-4
|
||||
crash in modelPromoteNodeOffsetsToPointers.
|
||||
- `Gfx.words.w0/w1` are both uintptr_t (16-byte Gfx on PC); ROM-copied N64
|
||||
Gfx DLs stay 8 bytes in memory — walk them at 8-byte stride when scanning.
|
||||
- N64 CPU/RDP data in ROM is big-endian; any raw `*(u32*)` read of ROM-copied
|
||||
buffers needs a bswap under PORT (D68 pattern) or offline conversion.
|
||||
- Heavy env-gated logging perturbs tick-driven timing (a full-triangle trace
|
||||
hung the kernel heartbeat at ~frame 107 while clean runs run fine past
|
||||
frame 2100) — use short targeted probe windows, and diagnose stability only
|
||||
with clean runs.
|
||||
|
||||
## Environment reminders
|
||||
|
||||
- MSYS2 tools: `export PATH="/c/msys64/mingw64/bin:$PATH"`. Build ~5 s.
|
||||
- Crash log `ge007.crash.log` now includes FAULT ADDR, STACK@RSP window, and
|
||||
- Crash log `ge007.crash.log` includes FAULT ADDR, STACK@RSP window, and
|
||||
module list — first stop for any fault. Symbolicate offline:
|
||||
`addr2line -e build-pc/ge007.x86_64.exe -f -C <pc>`.
|
||||
- gdb is launch-mode only and far too slow for timing-dependent crashes —
|
||||
@@ -186,3 +184,8 @@ Env-gated probes to remove (grep `GE_D` + `TEMP D`):
|
||||
- ROM: data/ge007.ntsc-final.z64 (byte-identical to the No-Intro good dump);
|
||||
sidecar: data/pcmodels-ntsc-final/ (gitignored, regenerate with
|
||||
tools_pc/d43_emit.py per region).
|
||||
- Artifacts from this session: `ppm/` frames ~510–590 are the logo sequence
|
||||
(frame ~555 is the best front-facing "RARE" shot); `tools_pc/mtxtest.c` is a
|
||||
scratch matrix-convention harness (kept for reference). PPM files from
|
||||
timeout-killed runs can be truncated — validate header + pixel count before
|
||||
parsing.
|
||||
+108
-30
@@ -2214,28 +2214,40 @@ was D64's unbounded blood-RLE write clobbering the barrel sub-DL),
|
||||
**D67 resolved** (struct image_entry N64 layout reconstruction),
|
||||
**D68 resolved** (Globalimagetable BE→LE fixup for IMAGESEG Gfx words +
|
||||
sImageTableEntry.index; compiled globalDL shadows synced after texLoad).
|
||||
The game now boots, plays the intro music, and renders the **entire ~3.5-
|
||||
minute intro** (Nintendo logo → gun barrel with Brosnan → cast screen) at
|
||||
~59 fps, then crashes in `load_bg_file` on the first stage load —
|
||||
The game now boots, plays the intro music, and renders the **entire intro**
|
||||
(Nintendo logo → gun barrel with Brosnan → cast screen; ~frame 2100, ≈2 min
|
||||
wall-clock at the current ~20 fps clean-run rate), then crashes in
|
||||
`load_bg_file` on the first stage load —
|
||||
**D69, the milestone blocker**: BG-file headers are N64 big-endian
|
||||
(segment-0x0F offsets) and PC reads them LE. Details in §F/D59–D69.
|
||||
|
||||
**D70–D72 (intro-logo pixel work):** D70 env-gated PPM frame capture
|
||||
**D70–D74 (intro-logo pixel work):** D70 env-gated PPM frame capture
|
||||
(`GE_PCDUMP` → `./ppm/`) for numerical visual debugging; **D71 resolved** —
|
||||
C-array texture sources (the four rarewarelogo.c RGBA16 images) were
|
||||
byte-swapped on LE PC (pink/green logo); port-layer per-source bswap in
|
||||
`import_texture`. **D72 resolved** the UV path (GE always uses authored tc[]
|
||||
UVs; `lookat_enabled` defaults false) but **D72.3 is OPEN**: all logo
|
||||
triangles project off-screen and a flat dark-blue checkerboard triangle
|
||||
rasterizes instead — identity pending (GE_DBGUV/GE_DBGTALL traces).
|
||||
UVs; `lookat_enabled` defaults false). **D73 resolved** — root cause of
|
||||
D72.3: sinf/cosf `du` double constants are big-endian word pairs, garbage on
|
||||
LE PC → guMtxF2L emitted −32768 for every sin/cos entry → logo triangles
|
||||
projected off-screen; DVAL() macro fix in guint.h/sinf.c/cosf.c under PORT.
|
||||
**D74 resolved** — texture import fallback no longer truncates valid
|
||||
gDPLoadBlock data (mip chains + sub-tiled textures), TextureCacheKey gains
|
||||
`size_bytes`, and the VBO path now wraps UVs by tile size for WRAP sub-tiles
|
||||
(N64 semantics). The logo now renders its four gold letters on the dark-blue
|
||||
plate (PPM-verified at frame ~555); a final pixel-perfect comparison against
|
||||
N64 reference footage is still open. **D69 remains the milestone blocker**
|
||||
(stage load).
|
||||
|
||||
**Committed through D72**: D51–D72 fixes + TEMP diagnostics still present
|
||||
(strip list in HANDOFF Task 3); build is GREEN.
|
||||
**Committed through D74**: D51–D74 fixes; this session's TEMP probes are
|
||||
stripped, but previously committed TEMP diagnostics (D63 blocks, GE_D71LOG,
|
||||
and the older D51–D66 leftovers) are still in the tree — strip list in
|
||||
HANDOFF Task 3. Build is GREEN.
|
||||
|
||||
### H. Handoff & plan (current session)
|
||||
|
||||
Full paste-ready brief: **docs/HANDOFF.md** (two live threads: D72.3
|
||||
intro-logo pixels, then D69 BG/stan stage loading). For D69:
|
||||
Full paste-ready brief: **docs/HANDOFF.md** (primary thread: D69 BG/stan
|
||||
stage loading — the milestone blocker; secondary: final pixel check of the
|
||||
now-rendering intro logo). For D69:
|
||||
reverse-engineer GE's bg .seg + Tbg_*_stanZ formats from the decompiled
|
||||
consumers (bg.c, stan.c), then choose offline sidecar conversion (Plan-B
|
||||
pattern, D43) vs runtime port-layer fixup; PD's preprocess/filebg.c is a
|
||||
@@ -2243,25 +2255,28 @@ reference for the *approach* only — its BG format is different (zipped
|
||||
multi-section).
|
||||
Summary:
|
||||
|
||||
**State.** D50–D72 resolved and verified (except D72.3, open); committed
|
||||
through the D72 milestone. The game boots, plays intro music, and renders
|
||||
the entire ~3.5-minute intro (logo → gun barrel with Brosnan → cast screen)
|
||||
at ~59 fps — logo lettering now gold-on-blue (D71/D72) but not yet visible
|
||||
(D72.3). TEMP diagnostics from the D51–D72 sessions are still in the tree
|
||||
(strip list in HANDOFF Task 3); visual-debug tooling: `GE_PCDUMP` frame
|
||||
capture, `GE_DBGUV`/`GE_DBGTALL` UV+triangle traces. Build is GREEN.
|
||||
**State.** D50–D74 resolved and verified (D73 = sinf/cosf endianness, D74 =
|
||||
texture import fallback + sub-tile UV wrap); committed through the D74
|
||||
milestone. The game boots, plays intro music, and renders the entire intro
|
||||
(logo → gun barrel with Brosnan → cast screen) — the Rareware logo now shows
|
||||
its four gold letters on the dark-blue plate (D71–D74; PPM-verified at frame
|
||||
~555, final pixel-perfect check vs N64 footage still open). TEMP diagnostics
|
||||
from earlier sessions are still in the tree (strip list in HANDOFF Task 3);
|
||||
visual-debug tooling: `GE_PCDUMP` frame capture. Build is GREEN.
|
||||
|
||||
**Thread 1 — D72.3 (intro logo).** All logo triangles project off-screen
|
||||
(clip x=y≈−1.6e11, w<0) while a flat dark-blue (0,0,64) checkerboard
|
||||
triangle rasterizes in the lower screen; matrix-format mismatches ruled out
|
||||
(§F/D72). Next: identify the checkerboard's triangle via GE_DBGTALL, then
|
||||
verify MP matrix + viewport at logo time (title.c load_display_rare_logo).
|
||||
|
||||
**Thread 2 — D69 (milestone blocker).** `load_bg_file` (src/game/bg.c:830)
|
||||
faults on the first stage load (BUNKER1): BG-file header words are N64
|
||||
big-endian segment-0x0F offsets; PC reads them LE, so the
|
||||
**Thread 1 — D69 (milestone blocker, now primary).** `load_bg_file`
|
||||
(src/game/bg.c:830) faults on the first stage load (BUNKER1): BG-file header
|
||||
words are N64 big-endian segment-0x0F offsets; PC reads them LE, so the
|
||||
room-fileposition-list pointer lands ~5 MB past the stack header buffer.
|
||||
Full analysis + strategy options in §F/D69.
|
||||
Full analysis + strategy options in §F/D69. This is the next milestone:
|
||||
decode the bg .seg + Tbg_*_stanZ formats, convert/fix for PC, get a stage to
|
||||
load and render.
|
||||
|
||||
**Thread 2 — logo final check (low priority).** Compare the rendered logo
|
||||
frames (ppm/, frame ~550–560) against N64 reference footage; if any letter
|
||||
is still off, re-add a lightweight triangle/texture attribution probe (the
|
||||
D74 probes are stripped; the import sizes and sub-tile wrap are verified at
|
||||
the data level).
|
||||
|
||||
**After D69:** get a stage to load + render (bg .seg + Tbg_*_stanZ format
|
||||
work), then continue the diagnose→fix→verify loop through gameplay; strip
|
||||
@@ -2354,8 +2369,71 @@ gated by `GE_D71LOG`.
|
||||
modified variant writing the interleaved hi16/lo16 s32 Q15.16 packed format
|
||||
that gfx_sp_matrix decodes exactly (FTOFIX32=×65536); `D_8002A7D0` is a
|
||||
zero-init u32 so `[D_8002A7D0]`==`[0]`; alloc_intro_matrices() runs from
|
||||
initmenus. Next: find the checkerboard's triangle via GE_DBGTALL, then
|
||||
verify MP matrix + viewport at logo time (title.c load_display_rare_logo).
|
||||
initmenus. **SUPERSEDED by D73** — the off-screen projection was never a
|
||||
matrix-format or UV problem: guMtxF2L's sinf/cosf inputs were garbage on PC.
|
||||
|
||||
**D73 (RESOLVED — root cause of D72.3):** GE's `sinf`/`cosf`
|
||||
(src/libultra/gu/sinf.c, cosf.c) build their double constants through the
|
||||
`du` bit-union (`{ struct { u32 hi; u32 lo; } word; double d; }`) with
|
||||
big-endian word pairs `{hi, lo}` (rpi, pihi, and the P[] polynomial tables).
|
||||
On an LE PC the `.d` read has the two words swapped: `rpi.d` ≈ 2^733,
|
||||
`pihi.d` ≈ 2^257. Range reduction then overflows: `dn = dx*rpi.d` huge →
|
||||
ROUND(dn) saturates in cvttsd2si (n = −2^31) → `dx = dx − dn*pihi.d` ≈ 2^288
|
||||
→ xsq ≈ 2^576 → the result overflows float → sinf/cosf return ±inf/NaN.
|
||||
FTOFIX32's `(int)(±inf·65536)` is another cvttss2si saturation →
|
||||
0x80000000 (−32768). Every sin/cos-derived entry of guMtxF2L became −32768,
|
||||
so the Rareware logo's guRotate matrix was garbage and all its triangles
|
||||
projected off-screen (the D72.3 symptom; the "checkerboard" was a separate
|
||||
large triangle rasterizing over the empty logo region). The logo scene is the
|
||||
first visually verifiable consumer of guMtxF2L sin/cos output in the intro;
|
||||
other scenes that build matrices via guRotate/guLookAt are affected by the
|
||||
same bug and were fixed by this change. Fix (narrow ABI exception — constant
|
||||
interpretation only, algorithm verbatim): `duD()` static-inline + `DVAL(x)`
|
||||
macro in src/libultra/gu/guint.h under #ifdef PORT re-pack hi/lo into the
|
||||
correct LE double; the 5 `.d` reads in sinf.c and 4 in cosf.c now use
|
||||
`DVAL(...)`. The N64 build is untouched (#else branch = original expression).
|
||||
Only sinf.c/cosf.c use `du` (grep-verified); `fu` (single u32) constants are
|
||||
endian-safe. Verified numerically: P decodes to the expected perspective
|
||||
matrix, Rot(−40°Y) gives clean cos=0.766/sin=−0.643, and logo vertices clip
|
||||
to small finite on-screen NDC values. (tools_pc/mtxtest.c is a standalone
|
||||
scratch harness for the matrix-convention question that was ruled out along
|
||||
the way — GE stores all matrices transposed; row-vector ≡ column pipeline.)
|
||||
|
||||
**D74 (RESOLVED — final pixel check pending):** with D73 in, logo geometry
|
||||
was correct but the texture side was still wrong: a dim red-brown blob plus
|
||||
a flat vertical bar at the right edge, one letter visible at a time. Three
|
||||
port-layer bugs, all in port/fast3d/gfx_pc.cpp (with gfx_pc.h):
|
||||
- **Import fallback truncation.** `import_texture`'s old condition
|
||||
`(rdp.tex_lod && tile >= rdp.first_tile_index + rdp.tex_detail) ||
|
||||
!loaded_texture.addr` overwrote valid gDPLoadBlock tmem data with
|
||||
`line_size_bytes * tile.height`. For the logo: letter mip chains 2744 B →
|
||||
2048 B (mips 1–5 dropped), and D_02005FF0's 32×32 → 192 B (32×3, stale
|
||||
tile.height=3 left by `gsDPSetTileSize(0, 46, 116, 124, 124)` in DL
|
||||
D_02004758). Fix: fall back only when `!loaded_texture.addr` (N64 TMem is
|
||||
persistent — a populated slot is the faithful source).
|
||||
- **Cache poisoning.** TextureCacheKey lacked the upload size, so the first
|
||||
(truncated) import of an address poisoned every later import. Added
|
||||
`size_bytes` to the key (gfx_pc.h + both key initializers + the bucket-only
|
||||
aggregate in gfx_texture_cache_delete).
|
||||
- **Sub-tile UV wrap period.** N64 wraps UVs by the TILE size when a render
|
||||
tile is a sub-region of the image; the port wrapped at the full uploaded
|
||||
image size (GL_REPEAT). D_02004758's 20×3 tile at offset (11.5, 29)
|
||||
therefore sampled row 0 instead of rows 29–31 — the flat bar's color
|
||||
matched texel [0,4] of D_02005FF0 exactly. Fix: per-vertex pre-wrap in the
|
||||
VBO path — for a WRAP sub-tile (`tex_width2 < tex_width`, where
|
||||
`tex_width2 = (lrs−uls+4)/4` is the tile window in texels),
|
||||
`u = fmodf(u, tw); if (u<0) u += tw; u += uls/4.0f` (same for v). Known
|
||||
limitations: half-texel edge bleed at the sub-tile window edges (GL
|
||||
bilinear neighbors may sample just outside [O, O+W)); mirror sub-tiles are
|
||||
not handled (the logo doesn't use them; audit if another scene regresses).
|
||||
Verified: runtime import sizes correct (D_02005FF0 = 2048 B, imgRAre =
|
||||
2744 B); PPM frame ~555 shows the four-letter RARE band with gold/warm
|
||||
colors and per-letter segmentation; clean `GE_PCDUMP` runs are stable past
|
||||
1156 frames. Final pixel-perfect confirmation against N64 reference footage
|
||||
is still open (see HANDOFF Task 1). All env-gated probes added for D72.3/D74
|
||||
(GE_DBGUV/GE_DBGTRI/GE_DBGTALL/GE_DBGMAT/GE_D74IMP/GE_D74DUMP/GE_DBGLOAD)
|
||||
were stripped with this change; the previously committed TEMP D63 blocks and
|
||||
the GE_D71LOG normalize log remain on the HANDOFF strip list.
|
||||
|
||||
**Non-negotiable #2 refinement (applied to AGENTS.md).** The original "game code
|
||||
compiles unmodified / fix belongs in port/" is too absolute: pointer-width layout
|
||||
|
||||
+29
-65
@@ -568,7 +568,7 @@ void gfx_texture_cache_delete(const uint8_t* orig_addr) {
|
||||
}
|
||||
|
||||
while (gfx_texture_cache.map.bucket_count() > 0) {
|
||||
TextureCacheKey key = { orig_addr, { 0 }, 0, 0 }; // bucket index only depends on the address
|
||||
TextureCacheKey key = { orig_addr, { 0 }, 0, 0, 0 }; // bucket index only depends on the address
|
||||
size_t bucket = gfx_texture_cache.map.bucket(key);
|
||||
bool again = false;
|
||||
for (auto it = gfx_texture_cache.map.begin(bucket); it != gfx_texture_cache.map.end(bucket); ++it) {
|
||||
@@ -914,7 +914,12 @@ static void import_texture(int i, int tile, bool importReplacement) {
|
||||
const uint32_t tex_flags = loaded_texture.tex_flags;
|
||||
const uint8_t palette_index = rdp.texture_tile[tile].palette;
|
||||
|
||||
if ((rdp.tex_lod && tile >= rdp.first_tile_index + rdp.tex_detail) || !loaded_texture.addr) {
|
||||
// D74: only fall back when the tmem slot was never written by a load
|
||||
// command. The old `rdp.tex_lod && tile >= first+detail` branch also
|
||||
// overwrote valid gDPLoadBlock data with line*tile.height, which (a) dropped
|
||||
// mip chains and (b) truncated sub-tiled textures to the sub-tile's row
|
||||
// count (e.g. the Rare-logo D_02005FF0 20x3 tile uploaded as 32x3).
|
||||
if (!loaded_texture.addr) {
|
||||
// set up miplevel 0; also acts as a catch-all for when .addr is NULL because my texture loader sucks
|
||||
loaded_texture.addr = rdp.texture_to_load.addr;
|
||||
loaded_texture.line_size_bytes = rdp.texture_tile[tile].line_size_bytes;
|
||||
@@ -935,9 +940,10 @@ static void import_texture(int i, int tile, bool importReplacement) {
|
||||
|
||||
TextureCacheKey key;
|
||||
if (fmt == G_IM_FMT_CI) {
|
||||
key = { orig_addr, { rdp.palette_addrs[0], rdp.palette_addrs[1] }, fmt, siz, palette_index };
|
||||
key = { orig_addr, { rdp.palette_addrs[0], rdp.palette_addrs[1] }, fmt, siz, palette_index,
|
||||
loaded_texture.size_bytes };
|
||||
} else {
|
||||
key = { orig_addr, {}, fmt, siz, palette_index };
|
||||
key = { orig_addr, {}, fmt, siz, palette_index, loaded_texture.size_bytes };
|
||||
}
|
||||
|
||||
if (gfx_texture_cache_lookup(i, key)) {
|
||||
@@ -1255,57 +1261,12 @@ static inline int gfx_lod_tile_offset(const int i) {
|
||||
return (rdp.tex_lod ? rdp.tex_detail : i);
|
||||
}
|
||||
|
||||
// TEMP D72: env-gated UV pipeline logging (GE_DBGUV=1).
|
||||
static bool gfx_dbg_uv_enabled(void) {
|
||||
static int e = -1;
|
||||
if (e < 0) e = getenv("GE_DBGUV") != nullptr;
|
||||
return e;
|
||||
}
|
||||
|
||||
static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bool is_rect) {
|
||||
struct LoadedVertex* v1 = &rsp.loaded_vertices[vtx1_idx];
|
||||
struct LoadedVertex* v2 = &rsp.loaded_vertices[vtx2_idx];
|
||||
struct LoadedVertex* v3 = &rsp.loaded_vertices[vtx3_idx];
|
||||
struct LoadedVertex* v_arr[3] = { v1, v2, v3 };
|
||||
|
||||
// TEMP D72: GE_DBGTRI=1 — trace triangles; GE_DBGTALL=1 logs all.
|
||||
static int dbg_tri_count = 0;
|
||||
if (gfx_dbg_uv_enabled() && getenv("GE_DBGTALL")) {
|
||||
float sx[3] = { v1->x / (v1->w), v2->x / (v2->w), v3->x / (v3->w) };
|
||||
float sy[3] = { v1->y / (v1->w), v2->y / (v2->w), v3->y / (v3->w) };
|
||||
if (dbg_tri_count++ < 4000) {
|
||||
fprintf(stderr, "[DBGTALL] n=%d scr=(%.0f,%.0f)(%.0f,%.0f)(%.0f,%.0f) col=(%d,%d,%d,%d) clip=(%x,%x,%x)\n",
|
||||
dbg_tri_count, sx[0], sy[0], sx[1], sy[1], sx[2], sy[2],
|
||||
v1->color.r, v1->color.g, v1->color.b, v1->color.a,
|
||||
v1->clip_rej, v2->clip_rej, v3->clip_rej);
|
||||
}
|
||||
}
|
||||
if (gfx_dbg_uv_enabled()) {
|
||||
bool gold = false, blue = false;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (v_arr[i]->color.b == 0 && v_arr[i]->color.r > 90) gold = true;
|
||||
if (v_arr[i]->color.b > 100 && v_arr[i]->color.r < 50) blue = true;
|
||||
}
|
||||
if (gold || blue) {
|
||||
float dx1 = v1->x / (v1->w) - v2->x / (v2->w);
|
||||
float dy1 = v1->y / (v1->w) - v2->y / (v2->w);
|
||||
float dx2 = v3->x / (v3->w) - v2->x / (v2->w);
|
||||
float dy2 = v3->y / (v3->w) - v2->y / (v2->w);
|
||||
if (dbg_tri_count++ < 64) {
|
||||
fprintf(stderr, "[DBGTRI] %s cull=%d clip=(%x,%x,%x) cross=%.3f scr=(%.1f,%.1f)(%.1f,%.1f)(%.1f,%.1f) clip4=(%.0f,%.0f,%.0f,%.2f) col=(%d,%d,%d)\n",
|
||||
gold ? "GOLD" : "BLUE",
|
||||
rsp.geometry_mode & G_CULL_BOTH,
|
||||
v1->clip_rej, v2->clip_rej, v3->clip_rej,
|
||||
dx1 * dy2 - dy1 * dx2,
|
||||
v1->x / (v1->w), v1->y / (v1->w),
|
||||
v2->x / (v2->w), v2->y / (v2->w),
|
||||
v3->x / (v3->w), v3->y / (v3->w),
|
||||
v1->x, v1->y, v1->z, v1->w,
|
||||
v1->color.r, v1->color.g, v1->color.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((rsp.extra_geometry_mode & G_NO_CLIPPING_EXT) == 0) {
|
||||
if (v1->clip_rej & v2->clip_rej & v3->clip_rej) {
|
||||
// The whole triangle lies outside the visible area
|
||||
@@ -1567,6 +1528,25 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
u -= rdp.texture_tile[rdp.first_tile_index + tile].uls / 4.0f;
|
||||
v -= rdp.texture_tile[rdp.first_tile_index + tile].ult / 4.0f;
|
||||
|
||||
// D74: N64 wraps UVs by the TILE size when a render tile is a
|
||||
// sub-region of the image (uls/ult offset + lrs/lrt window); GL
|
||||
// would wrap at the full uploaded image size instead. Pre-wrap per
|
||||
// vertex (GE/PD triangles never span more than one tile period).
|
||||
{
|
||||
const uint32_t tw = tex_width2[i];
|
||||
const uint32_t th = tex_height2[i];
|
||||
if ((rdp.texture_tile[rdp.first_tile_index + tile].cms & G_TX_WRAP) && tw < tex_width[i]) {
|
||||
u = fmodf(u, (float)tw);
|
||||
if (u < 0.0f) u += (float)tw;
|
||||
u += rdp.texture_tile[rdp.first_tile_index + tile].uls / 4.0f;
|
||||
}
|
||||
if ((rdp.texture_tile[rdp.first_tile_index + tile].cmt & G_TX_WRAP) && th < tex_height[i]) {
|
||||
v = fmodf(v, (float)th);
|
||||
if (v < 0.0f) v += (float)th;
|
||||
v += rdp.texture_tile[rdp.first_tile_index + tile].ult / 4.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_rect) {
|
||||
if (!(rdp.other_mode_h & G_TP_PERSP)) {
|
||||
u *= 0.5f;
|
||||
@@ -1583,22 +1563,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
buf_vbo[buf_vbo_len++] = u / tex_width[t];
|
||||
buf_vbo[buf_vbo_len++] = v / tex_height[t];
|
||||
|
||||
// TEMP D72: GE_DBGUV=1 — log the UV pipeline per vertex, but
|
||||
// only for C-array (logo) textures so the cap isn't exhausted.
|
||||
if (gfx_dbg_uv_enabled() &&
|
||||
gfx_tex_source_is_c_array(
|
||||
rdp.loaded_texture[rdp.texture_tile[rdp.first_tile_index + tile].tmem].addr)) {
|
||||
static int dbg_uv_count = 0;
|
||||
if (dbg_uv_count++ < 30000) {
|
||||
fprintf(stderr, "[DBGUV] v.u=%d v.v=%d shifts=%d shiftt=%d uls=%d ult=%d -> u=%.4f v=%.4f (tex %dx%d)\n",
|
||||
v_arr[i]->u, v_arr[i]->v, shifts, shiftt,
|
||||
rdp.texture_tile[rdp.first_tile_index + tile].uls,
|
||||
rdp.texture_tile[rdp.first_tile_index + tile].ult,
|
||||
u / tex_width[t], v / tex_height[t],
|
||||
tex_width[t], tex_height[t]);
|
||||
}
|
||||
}
|
||||
|
||||
bool clampS = tm & (1 << 2 * t);
|
||||
bool clampT = tm & (1 << (2 * t + 1));
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ struct TextureCacheKey {
|
||||
const uint8_t* palette_addrs[2];
|
||||
uint8_t fmt, siz;
|
||||
uint8_t palette_index;
|
||||
// D74: the same source address can be loaded with different sizes
|
||||
// (gDPLoadBlock mip chains vs partial loads); include the size so a
|
||||
// truncated first import cannot poison later full imports.
|
||||
uint32_t size_bytes;
|
||||
|
||||
bool operator==(const TextureCacheKey&) const noexcept = default;
|
||||
|
||||
|
||||
@@ -96,18 +96,18 @@ int ix, xpt;
|
||||
|
||||
dx = absx;
|
||||
|
||||
dn = dx*rpi.d + 0.5;
|
||||
dn = dx*DVAL(rpi) + 0.5;
|
||||
n = ROUND(dn);
|
||||
dn = n;
|
||||
|
||||
dn -= 0.5;
|
||||
|
||||
dx = dx - dn*pihi.d;
|
||||
dx = dx - dn*pilo.d; /* dx = x - (n - 0.5)*pi */
|
||||
dx = dx - dn*DVAL(pihi);
|
||||
dx = dx - dn*DVAL(pilo); /* dx = x - (n - 0.5)*pi */
|
||||
|
||||
xsq = dx*dx;
|
||||
|
||||
poly = ((P[4].d*xsq + P[3].d)*xsq + P[2].d)*xsq + P[1].d;
|
||||
poly = ((DVAL(P[4])*xsq + DVAL(P[3]))*xsq + DVAL(P[2]))*xsq + DVAL(P[1]);
|
||||
|
||||
result = dx + (dx*xsq)*poly;
|
||||
|
||||
|
||||
@@ -24,6 +24,21 @@ typedef union
|
||||
double d;
|
||||
} du;
|
||||
|
||||
#ifdef PORT
|
||||
/* The {hi,lo} initializers of du constants are written in big-endian word
|
||||
* order (as on the N64). On a little-endian host the .d member would read
|
||||
* the two words swapped; re-pack them to recover the same double value. */
|
||||
static inline double duD(const du u)
|
||||
{
|
||||
union { unsigned long long b; double d; } t;
|
||||
t.b = ((unsigned long long)u.word.hi << 32) | (unsigned long long)u.word.lo;
|
||||
return t.d;
|
||||
}
|
||||
#define DVAL(x) duD((x))
|
||||
#else
|
||||
#define DVAL(x) ((x).d)
|
||||
#endif
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -96,7 +96,7 @@ int ix, xpt;
|
||||
|
||||
xsq = dx*dx;
|
||||
|
||||
poly = ((P[4].d*xsq + P[3].d)*xsq + P[2].d)*xsq + P[1].d;
|
||||
poly = ((DVAL(P[4])*xsq + DVAL(P[3]))*xsq + DVAL(P[2]))*xsq + DVAL(P[1]);
|
||||
|
||||
result = dx + (dx*xsq)*poly;
|
||||
|
||||
@@ -114,20 +114,20 @@ int ix, xpt;
|
||||
|
||||
/* reduce argument to +/- pi/2 */
|
||||
|
||||
dn = dx*rpi.d;
|
||||
dn = dx*DVAL(rpi);
|
||||
|
||||
n = ROUND(dn);
|
||||
dn = n;
|
||||
|
||||
dx = dx - dn*pihi.d;
|
||||
dx = dx - dn*pilo.d; /* dx = x - n*pi */
|
||||
dx = dx - dn*DVAL(pihi);
|
||||
dx = dx - dn*DVAL(pilo); /* dx = x - n*pi */
|
||||
|
||||
/* compute sin(dx) as before, negating result if n is odd
|
||||
*/
|
||||
|
||||
xsq = dx*dx;
|
||||
|
||||
poly = ((P[4].d*xsq + P[3].d)*xsq + P[2].d)*xsq + P[1].d;
|
||||
poly = ((DVAL(P[4])*xsq + DVAL(P[3]))*xsq + DVAL(P[2]))*xsq + DVAL(P[1]);
|
||||
|
||||
result = dx + (dx*xsq)*poly;
|
||||
|
||||
|
||||
Reference in new issue
Block a user