Commit Graph
222 Commits
Author SHA1 Message Date
James Dansereau 8337a87fb2 D118: implement SDL input layer (kbd/mouse/gamepad -> N64 pad)
port/src/input.c was a stub; input only worked via libultra.c's minimal
contSnapshotFromKeyboard (no C-buttons, mouse, or gamepad).

- input.c: keyboard+mouse + SDL_GameController -> OSContPad. Analog stick
  = move, C-buttons = aim. Mouse-look bridged to digital C-buttons via a
  clamped per-axis accumulator (proportional press dwell). RMB/LT = aim
  mode, LMB/RT = fire. Config: ge007.ini [Input] MouseEnabled /
  MouseAimSpeed / MouseInvertY.
- input.h: add inputConnectedMask() + inputComputePad().
- libultra.c SI section: contSnapshotFromKeyboard() now delegates to the
  input module (single source of controller state); osContGetReadData()
  fills all MAXCONTROLLERS channels, not just controller 0.
- GE_INPUTLOG=1 gates a per-poll OSContPad trace (zero-cost when unset).

Build green (ntsc-final); boots -level_09 crash-free 35s. Live input
untested from headless agent - human playtest owed.
2026-08-29 11:11:08 -04:00
James Dansereau 93b31c8c1d D116 part 3: buf_vbo + texture-upload runtime-verified non-mirrored; contradiction documented, deprioritised (cosmetic). GE_D116/vbo probe kept 2026-08-29 11:03:13 -04:00
James Dansereau 8fdf473dc8 D116: probe finds HUD mirror is per-quad texture-U flip, not proportional-font-specific; ammo digits also mirrored; re-opens D114 2026-08-29 10:31:07 -04:00
James Dansereau 1fe85339f2 D107: fast3d sampled unloaded mip tile for GE's LOD textures (blurry ceilings)
GE's room GDLs emit G_TL_LOD + G_TD_DETAIL for mip-mapped textures, but
gfx_detail_textures_enabled is false for this port. gfx_lod_tile_offset's
'rdp.tex_lod ? rdp.tex_detail : i' then returned tex_detail (1) for every
texel, so fast3d sampled GE's first mip (render tile 1). GE loads the
whole mip chain with one G_LOADBLOCK to TMEM 0 and just points tiles 1..5
at offsets inside it; fast3d keys loaded_texture[] by TMEM addr and has
no entry for tile 1's offset, so import_texture fabricated a 16x16 from
the top-left 256 bytes of the base image and magnified it across the
polygon -- the blurry brown/grey ceilings and wall panels in BUNKER1.

Fix: when detail textures are disabled, gfx_lod_tile_offset always
returns 0 (the base render tile, the only correctly-loaded level). Sharp
near surfaces, matching what the N64 shows at close range.

Verified -level_09: BUNKER1 ventilation room ceilings/walls/light panels
now render crisp instead of brown mush. Single-level textures (racks,
room 1) were already fine and are unaffected.
2026-08-28 22:02:25 -04:00
James Dansereau 82f71855ca D103: native-res height from yScale, not hard-coded 480 (viewport was half-height)
osViSetMode hard-coded the fast3d native resolution to the visible
scanline count (pal ? 400 : 480) instead of the 320x240 CFB space GE
authors its GBI in. SCREEN_WIDTH/SCREEN_HEIGHT alias the native viewport;
RATIO_X came out 2.0 but RATIO_Y 1.0, so every gSPViewport/G_SETSCISSOR
was a 220px band (~46% of frame) shown in the lower half after invert_y.
gfx_current_native_aspect was wrong too (320/480).

Recover CFB height from vm->fldRegs[0].yScale (bufy*0x800/480, fr.c:417)
with a pal ? 272 : 240 fallback. comRegs.width already carried bufx.

Verified -level_09: GE_PCDUMP frames 46%/lower-band -> 91.7%/bbox
(0,20)-(639,459), correct letterbox + HUD placement. Reveals next layer:
room geometry (D85) and weapon model still don't draw (flat blue + HUD).
2026-08-28 20:38:07 -04:00
James Dansereau d13105147d D95: raise the PC mempool ceiling to reclaim ~4 MB of unused DRAM
The N64-fidelity mempool end (0x702F4400, tlbmanageGetTlbAllocatedBlock)
leaves ~5 MB of live, mapped, unused DRAM below the 8 MB top (only
animations_frame_buffer at 0x707FFD30 lives up there). PC structs are
larger everywhere, so the per-level -m* budget no longer fits and
MEMPOOL_STAGE OOMs (zbufAllocate spins in mempAllocBytesInBank). Raise
the ceiling to 0x70700000; the ~4 MB gain goes to MEMPOOL_STAGE.

With this + the reapplied 2x g_GfxBuffers (128f7644), -level_09 renders
~5 frames (previously: OOM hang, or non-deterministic overrun within
seconds). It then still faults in bgScissorCurrentPlayerView writing at
0x70800000 -- but deterministically at ~frame 5 and regardless of -mgfx
size (tested up to 1.6 MB/half), so that is a RUNAWAY GDL append in the
prop-render path (chrpropsRenderPass/chrpropRender), not a buffer-size
problem. Next blocker.
2026-08-28 16:11:49 -04:00
James Dansereau 03dcda7bc3 port: feed host argv into the game token string
osPiReadIo was stubbed to return 0, so token.c's cartridge-token read
always produced an empty string and N64 debug switches (-level_09,
-hardN, -m*) were silently ignored -- the game could only ever reach a
level via attract-mode demo playback. Synthesise the token string from
argv[1..] (sysGetTokenString) and serve its bytes from the 0xFFB000
range in osPiReadIo, so -level_09 now boots straight into BUNKER1.

Empty when no args are passed, so no-arg (attract) runs are unchanged.
2026-08-28 09:58:02 -04:00
James Dansereau c09bf37c66 D63: gate dram-branch G_DL trace behind GE_D63 (was flooding -level_09) 2026-08-28 09:04:46 -04:00
James Dansereau 4e1b891fc6 D88.1/D88.3: SetupIntroCamera narrow-pointer ABI + pccg wiring
- bondtypes.h: SetupIntroCamera lang1c/lang20/prev kept u32 under
  #ifdef PORT so sizeof stays 40 and the fixed-stride intro-record walk
  in bondview_r.c/bondview2.c still matches 40-byte file records. Fields
  are write-before-read (bondview_r.c:276-300 writes all three before any
  read via langGet()/list-link), verified. Same class as D79/D53.1.
- bondview2.c/bondview_r.c: cast (char *)(uintptr_t) at each use site.
- pccg.c: PCCG_MAX_FILES 128 -> 256 to also hold the Usetup*Z rows.
2026-08-28 08:30:56 -04:00
James DansereauandClaude Sonnet 5 81d5614fbd D69.3: bg/stan sidecar port-layer wiring (port/src/pccg.c)
Serves the offline-converted sidecars from tools_pc/d69_emit.py, cloned
from port/src/pcmodels.c (D50 Plan-B pattern): pccgReserveSize/
pccgLoadSidecars/pccgPatchTable/pccgTotalSize/pccgSidecarBase.

Wiring: romdata.c extends the CART_BASE VirtualAlloc reservation to
include pccgReserveSize() right after the pcmodels extension and loads the
sidecar image there; romdataCartAddrValid's bounds check and libultra.c's
D60 DMA-source diagnostic both extended to cover the pccg byte range.
One-shot pccgPatchTable() call added next to pcmodelsPatchTable() in
load_object_fill_header (objecthandler_2.c) -- reused purely as a
"definitely after obInit()" hook, unrelated to model loading.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3xib6jjMV8o2iE4JfixAo
2026-08-27 21:02:12 -04:00
James Dansereau 978306d14f 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.
2026-08-24 22:32:27 -04:00
James Dansereau 8ed411d3f1 D70-D72: PPM capture tool, C-array texture byte-order fix, tc[] UV restore
- D70: GE_PCDUMP env-gated PPM frame dump (video.c + gfx_opengl.cpp); ppm/ gitignored
- D71: per-source bswap of C-array texture sources in import_texture (the four
  rarewarelogo.c RGBA16 images are LE u32 arrays on PC -> pink/green logo)
- D72: removed PD-inherited normal/lookat UV override; lookat_enabled defaults
  false (GE always uses authored tc[] UVs; N64 boots with RSP mem zeroed)
- D72.3 OPEN: logo triangles still project off-screen; a flat dark-blue
  checkerboard triangle is rasterized instead - identity pending
  (GE_DBGUV/GE_DBGTALL env-gated traces added)
- Docs: PCPortResearch.md F/D70-D72, HANDOFF refreshed, D71 log gated
2026-08-24 19:12:40 -04:00
James Dansereau 8f631462f3 PC port: phase 2 — D59-D68 milestone: full intro renders; blocker is D69 (BG-file BE headers)
D59/D64: the 'external 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 at ptr_logo_and_walletbond_DL+0x200.
D60: osPiStartDma DMA-target validation (VirtualQuery-based) in libultra.c.
D61/D63: TEMP env-gated ROM-read / VTX-pool / menu probes (strip list in
HANDOFF Task 3). D62: OSMesgQueue/OSScMsg PC layout verification.
D65/D65b: enum HEADS/BODIES signed sentinels under PORT (PC GCC picks
unsigned underlying types; N64 semantics were signed).
D66: romCopyAligned + ramrom replay 64-bit pointer width (s32 truncation
of .bss targets > 4 GiB). D67: struct image_entry N64 layout
reconstruction (dataoffset:24 first, all-u32 bitfields, sizeof==8).
D68: Globalimagetable BE->LE fixup (port/src/gimgfixup.c): bswap the
IMAGESEG-marked Gfx w1 words in the 17 ROM-copied DLs + sImageTableEntry.
index in the 32 tables after texReset's romCopy; marker scan moved to
bytes 6..7 under PORT; compiled globalDL shadows synced post-texLoad for
explosion.c's g_ExplosionDisplayLists.

Result: game boots, plays intro music, and renders the entire ~3.5-minute
intro (logo -> gun barrel with Brosnan -> cast screen) at ~59 fps. New
blocker D69: load_bg_file faults on first stage load - BG-file headers are
N64 big-endian segment-0x0F offsets read LE on PC. Full analysis + strategy
in PCPortResearch.md §F/D69; HANDOFF rewritten for the D69 session.
2026-08-24 03:27:29 -04:00
James Dansereau 330b2bae46 PC port: phase 2 — Plan B executed (D50): offline model sidecars + port plumbing; texCopyGdls w1 fix
- tools_pc/d43_emit.py: full emit pass, 512/512 round-trip validated;
  data/pcmodels-<region>/pcmodels.bin + manifest.csv (gitignored, regenerate)
- port/src/pcmodels.c(+h): cart-extension reservation, sidecar copy, one-shot
  file_resource_table patch; romdata.c/h extended
- objecthandler_2.c: #ifdef PORT hook — pcmodelsPatchTable() + poolRemaining=0
  reset (closes D48.3/R6 reload hazard)
- language.c/textrelated.c: runtime C fixups for lang-bank BE offset tables
  (romdataFixupLangBank) and font re-layout (romdataFontPcSize/FixupFont)
- front.c: legal-screen uninitialized-pointer UB seed (N64 survived by luck)
- tex.c (D50.6): texCopyGdls copied only w0 of each 16B Gfx slot on PC —
  compaction scratch kept stale mempool w1s -> garbage G_SETTIMG -> OOB in
  import_texture_rgba16. Full-slot copy under #ifdef PORT; byte-proven vs
  PlegalpageZ sidecar (w0s match, w1s stale). Model GDLs now execute.
2026-08-23 10:22:03 -04:00
James Dansereau 181f6db07d PC port: phase 2 — D43 mechanical ABI edits + D46 buffer sizing + fast3d seg-5 case; converter spec validated (D47)
- bondtypes.h/model.c/chr.c/objecthandler_2.c/tex.c: PORT-guarded pointer-width
  and Gfx-size fixes (D43 step 2, uncommitted since prior session)
- front.c cast-screen bufferRemaining 0x1C000->0x25000, initmenus.c logo
  buffer 0x7C000->0x85000 (D46 strict bound)
- gfx_pc.cpp seg_addr: resolve raw 0x05xxxxxx via segmentPointers[5] + low24
  (unmarked segmented addresses, ROM convention)
- docs: D47 finding — converter contract finalized (compaction delta=R-P,
  accessors at 0x80090000, G_VTX GBI1 encoding, opcode-aware w1 remap rule,
  vertex formats, no embedded blobs, zero-vtx-array rule, staging contract,
  reload-hazard poolRemaining reset); HANDOFF rewritten around the remaining
  C implementation
- build-pc/d43_convert.py (gitignored, local): reference converter + validator —
  full N64->PC conversion spec run on all 512 ROM files, ALL CLEAN (max D_PC=0xB7E0)
2026-08-22 18:24:31 -04:00
James Dansereau 3458a4e868 PC port: fix crash-handler Phase 2 self-fault, auto-backtrace on crash (D44) 2026-08-22 08:24:11 -04:00
James Dansereau 98412c281c PC port: Phase 1.5 done, first frames render (D38-D42)
- D38: implicit function declarations truncated pointer returns on x86-64;
  added port/include/pc_protos.h prototype shim (398 decls, C-only, anchored
  in port/shim/PR/ucode.h) + pc_netorder.c for ntohl/ntohs; build warning-clean.
- D39: Globalimagetable rebasing - per-symbol offsets + GIMG_OFF() in
  image_bank.c (== N64 (u32)&sym incl. the 0x02000000 base); segment end
  markers extended to the true 0x13F8 size (CSV entry truncated by 0x930).
- D40: g_ModelHitEntries pool sized for the 40-byte PC ModelHitEntry stride
  (was a 12KB .bss overflow clobbering is_ramrom_flag -> demo-replay SIGSEGV).
- D41: release the GL context from the host main thread after videoInit so
  the game scheduler thread can bind it (WGL single-thread currency; this
  SDL2 build's MakeCurrent return value is an inverted ABI artifact).
- D42: rsp.c g_gfxTaskSettingsList XOR toggle -> explicit toggle on x86-64.

Boot now renders real frames ([NOTE] frame N rendered in ... us). Next
blocker D43 (model-file loading ABI mismatch) documented in PCPortResearch.md
section F/H; HANDOFF.md rewritten for it.
2026-08-22 04:07:07 -04:00
James Dansereau dbeee7353f PC port: Phase 1.5 — fix langInit decompression (D31), start D32 ABI layout
- D31 (resolved): replace GE's gzip-1.2.4 inflate with real-zlib
  decompressdata() in port/src/rzdecomp.c; exclude src/game/decompress.c +
  zlib.c from the PC build. Root cause: struct huft is 8B on MIPS but 16B on
  x86-64, overflowing load_resource's fixed 0x2100 buffer and clobbering its
  frame/retaddr on the first file load. mainThread now boots past all language
  files into bossInitMainthreadData().

- D32 (in progress): ROM-serialized structs with 32-bit pointer fields
  misalign when read as 64-bit pointers. Part A done: ModelAnimation's
  bitDescriptors/bitStream are now u32 (N64 layout preserved) with casts at the
  two use sites in model.c. Part B (load-time rebase in expand_ani_table_entries)
  is open — see docs §F/D32 + §H.

- Docs: D31 resolved, D32 recorded (A done / B open), Phase 1.5 added, new §H
  handoff section. AGENTS.md: refined non-negotiable #2 to "game logic is
  unmodified" with a narrow ABI/layout exception; refreshed phase status.
2026-08-21 16:01:49 -04:00
James Dansereau 13ca03a6db PC port: Phase 2 — real threads, dual-mapped DRAM, fast3d integration
- Replace setjmp/longjmp green threads with real pthreads (8MB stacks);
  PortQueue side table (mutex+condvar) for OSMesgQueue; dedicated tick
  thread posts VI retrace + services timers (D24).
- Dual-mapped N64 DRAM: one 8MB store at V1 0x70000000 (s32-safe, all game
  RAM symbols) and V2 0x80000000 (KSEG0 mirror for offset|0x80000000
  rebuilds). Windows: CreateFileMappingW + MapViewOfFileEx; POSIX: memfd
  + MAP_FIXED. dram_syms.s pins cfb_16/_bssSegmentEnd/tlb block (D25).
- Address-width shims: PHYS_TO_K0 identity, OS_K0_TO_PHYSICAL = offset from
  V1 base, OS_PHYSICAL_TO_K0 identity; fast3d seg_addr() remaps small
  offsets into V2 (D26).
- ASLR off (-Wl,--disable-dynamicbase): absolute symbols referenced through
  pointer-typed externs (.refptr + BASE reloc) must not rebase; startup
  sanity check on image base 0x140000000 (D27).
- osPiStartDma posts its completion message on every path (fixes
  romReceiveMesg deadlock) (D29).
- SEH-free crash handler: raw fault log first, validated manual EBP-chain
  walk second (-fno-omit-frame-pointer), TerminateProcess; crashDumpThreads
  via Toolhelp32 for heartbeat hang dumps (D30).
- PD fast3d integrated (port/fast3d/), replaces gfxstub.c; real src/sched.c
  compiled; mainproc runs as a real pthread, host thread pumps SDL events.
- Docs: findings D24-D31 + Phase 2 status (section F/G).

Current state: boots through bossInitMainthreadData to langInit(), then
SIGSEGVs on the first file load — stack frame clobbered by a table of
truncated s32 pointers (D31, open). Next: attribute the write with
'set scheduler-locking on' + hardware watchpoint.
2026-08-21 14:42:19 -04:00
James Dansereau 2aad171344 PC port: Phase 1 boot-to-window (ROM load + map + SDL2 clear loop)
- scripts/gen_romassets.py: emit absolute cart-address asset symbols
  (0x10000000 + rom_offset) from filelist.<r>.csv + the asset .s files,
  in file_resource_table.inc.c order. US region (romassets_u.s).
- romdata.c: load/validate the GE-specific header (magic, name @0x20,
  cart ID @0x3C, country @0x3E) and map the .z64 at cart base 0x10000000
  so every &asset-symbol is a live host pointer.
- libultra.c: osPiStartDma/osPiRawStartDma now service reads as
  bounds-checked memcpys from the mapped ROM (synchronous completion).
- system.c: implement sysResolvePath ($S data dir, $E exe dir).
- video.c: real SDL2 window + GL context + clear/swap frame loop with
  FPS accounting; main.c runs a Phase 1 demo loop (ESC quits) until the
  software RSP/scheduler can drive mainproc().
- CMakeLists: project(... ASM), wire romassets_<region>.s, drop
  assetstubs.c (replaced by generated symbols); n64stubs.c keeps only
  pure-RAM segment markers.
- docs: findings D18-D23 (header offsets, BE music table, .rz tracks,
  scanner-prefixed manifest names, CMake ASM gotcha, absolute-symbol
  approach).

Verified: baserom.u.z64 (12MB) passes validation and maps at 0x10000000;
window opens and renders until killed; asset offsets spot-checked against
ROM bytes (music bank seqCount=63 BE, first track offset 508).
2026-08-20 22:19:45 -04:00
James Dansereau 5ea46fabc1 PC port: full compile + link milestone (ge007.x86_64.exe builds clean)
All ~235 translation units now compile and the target links under MSYS2
GCC 16 + CMake/Ninja (ninja ge007 -k 0: 236/236, zero errors). N64 build
untouched; every src/ change is -DPORT-gated.

Portability fixes (findings D7-D17 in docs/PCPortResearch.md section 11):
- AI X-macro system: SWITCH() call sites activated to the author's
  hand-written byte-identical references under PORT; port/shim/
  bondaicommands.h + bondconstants.h + CPPLib.h re-emit the IDO paste
  tricks (isSubroutine, file-record macros, generated CALL) GCC-clean.
- 64-bit pointer-in-word initializers: monAnim jump targets now go
  through an index table resolved by the interpreter (chrai.h/propobj.c);
  UsetuplenZ.c credits pointer PORT-gated to 0.
- IDO printf engine compiled for PC (xprintf/xlitob/xldtob) with a
  shadow xstdio.h resolving the _Printf prototype clash.
- Host-libc gaps stubbed in port/: bcopy/bzero, __libm_qnan_f,
  tlbmanage*, g_ViXScales/YScales; chrObjRandom PRNG ported from .s.

Asset data strategy (D16): single-file assets compiled for real
(animation tables, fonts, textures, rareware logo); obseg per-file .c
excluded (colliding file-local globals the N64 build isolates via
per-ELF linking); 758 ROM-derived table symbols + ramrom_* + segment
markers stubbed in port/src/assetstubs.c / n64stubs.c.

fast3d is a no-op placeholder (port/src/gfxstub.c) until Phase 2 brings
in the real software RSP. Binary not yet runnable end-to-end: ROM
loading in romdata.c is still a TODO.
2026-08-20 20:27:06 -04:00
James Dansereau cd6cc158b6 Add PC port scaffolding (CMake build + port layer)
Initial scaffolding for a PC port of GoldenEye 007, modeled on the
Perfect Dark PC port (same Rare "Indy" engine). The N64 build
(Makefile + IDA) is untouched; the PC build is a parallel CMake build.

Build:
- CMakeLists.txt: SDL2 + zlib + OpenGL. Compiles src/game/*.c + curated
  engine files + libultra audio/gu + port/. Per-region macro sets
  (ROMID US/EU/JP) mirror the N64 Makefile's LCDEFS exactly.
- build-pc.sh, cmake/: configure+build helper and target/SDL2 modules.

Port layer (port/):
- video/audio/input/fs/romdata/config/system/mixer: stubs with
  TODO(Phase N) markers and correct interfaces.
- libultra.c: libultra OS shims (message queues, VI, PI, AI, EEPROM,
  controller, PFS/motor no-ops, region-gated osTvType).
- gesched.c: software-RSP scheduler replacing src/sched.c task submission.
- n64stubs.c: inert stubs for N64-boot + rmon symbols.
- random.c: PRNG ported verbatim from src/random.s (bit-exact).
- ucode.c: RSP/ASP/GSP microcode segment markers (dummies; Phase 3 TODO).

Docs:
- docs/PCPortResearch.md: architecture, GE-specific deltas, phased plan,
  and the scaffolding review (findings A1-A4/B1-B4/C1-C2 + resolutions).
- PORTING.md: top-level entry point.

See docs/PCPortResearch.md for the full plan.
2026-08-17 19:17:06 -04:00