Files
goldeneye-pc-port/port
James Dansereau 3c11e40c13 fix(D223): directional mouse-wheel weapon cycling (#54)
* fix(D223): directional mouse-wheel weapon cycling

Wheel-up keeps the existing 2-poll A pulse (weaponForwardOffset: fresh
A edge, Z released). Wheel-down now runs a 2-poll backward sequence:
A-only poll, then A+Z_TRIG -- the fresh-Z-edge-while-A-held combo that
weaponBackOffset requires (bondview2.c:5337-5340); ordering matters
because the edge is computed against the game's own previous poll.
moveData.triggerOn (bondview2.c:5419) requires A to be released, so
the synthesized Z edge can never fire a shot.

Roles are stable: the port forces CONTROLLER_CONFIG_HONEY
(bondview.c:1484), whose scheme gives invButtons=A_BUTTON /
shootButtons=Z_TRIG -- the same roles the pre-fix forward pulse
already relied on. While RMB aim is held the game flips controldef to
KISSY, under which neither direction cycles -- identical to the old
forward-only behavior in that state (pre-existing, not a regression).

Port-only; no src/ changes.

* docs(D223/D196): mark D223 FIXED (M-105); correct stale D196 status

D223 row now records the implemented fix and its known aim-mode
limitation. D196 was already fixed and merged (a17d5466, the
prescribed 1-line applyCursorVisibility() after reconcileGrab()) but
its status cell still led OPEN -- same stale-claim class the roadmap
flags; corrected. findings-index.csv regenerated.

* D223 follow-up: fix wheel-down backstep racing the real game tick

User playtest (M-105 cont.) found the backward-cycle combo unreliable:
PP7->AK47->PP7->wheel-down sometimes correctly landed on melee, but
sometimes landed back on AK47, and separately AK47->wheel-down sometimes
skipped past PP7 straight to melee.

Root cause: the wheel-down pulse staggered the synthetic 'hold A, tap Z'
combo across two polls (A alone, then A+Z one poll later). Whenever those
landed in two SEPARATE game ticks -- which happens unpredictably depending
on real-time poll/tick alignment (same D117-class nondeterminism as
everywhere else in the port) -- the 'A alone' tick was itself a fresh A
edge with no Z held, which bondview2.c's weaponForwardOffset formula (both
control-scheme sites) reads as a genuine cycle-FORWARD request, firing a
real, visible weapon change *before* the correcting backward tick ran.
Confirmed with an instrumented trace build: every wheel-down after the
very first one in a session mis-fired as a forward step.

Fix (port/src/input.c only, no game-logic touched): present A and Z
together from the first poll instead of staggering them, so whichever
single tick samples the 0->(A|Z) transition sees them rising
simultaneously. weaponForwardOffset requires Z NOT held, so that's
unambiguous -- only the backward path can fire, regardless of tick
timing. moveData.triggerOn (actual fire) is separately gated off while
A/invButtons is held, so this doesn't introduce an accidental shot.

User-verified: repeated up/down cycling through PP7/AK47/melee/Skorpion
in both directions with no more mismatches.
2026-09-12 09:18:43 -04:00
..
2026-09-01 19:28:59 -04:00

GoldenEye 007 — PC port layer

This directory contains the PC port layer: the code that lets the (unmodified) GoldenEye game sources run on a modern host instead of N64 hardware.

It mirrors the layout of the Perfect Dark PC port, which ports the same Rare engine family. See docs/internals.md (repo root) for the full research write-up and phased plan.

Layout

port/
├── fast3d/            # Software RSP: interprets GBI display lists -> OpenGL
│   ├── gfx_pc.cpp     #   RSP interpreter (matrices, lights, tris, fog)
│   ├── gfx_opengl.cpp #   OpenGL rendering backend (shaders, textures, zbuf)
│   ├── gfx_sdl2.cpp   #   SDL2 window-manager backend
│   ├── gfx_cc.cpp     #   color-combiner -> GLSL shader compiler
│   └── ...
├── include/           # port-facing headers
│   ├── audio.h  config.h  fs.h  input.h  mixer.h
│   ├── platform.h  romdata.h  system.h  video.h  utils.h
│   └── versioninfo.h.in
└── src/
    ├── main.c         # PC entry point (replaces boot.s / init())
    ├── libultra.c     # shims for the libultra OS API
    ├── video.c        # SDL2 window + GL context + frame pacing
    ├── audio.c        # SDL audio device, buffer queueing
    ├── mixer.c        # audio mixing
    ├── input.c        # SDL2 keyboard/mouse/gamepad -> N64 controller structs
    ├── fs.c           # filesystem abstraction over the ROM + data dir
    ├── romdata.c      # loads the .z64 ROM from disk, sets up segments
    ├── config.c       # INI config (ge007.ini)
    ├── system.c       # platform primitives (time, logging, paths)
    ├── crash.c        # crash handler / stack traces
    ├── gesched.c      # replacement RCP scheduler that drives the software RSP
    └── utils.c

How it works (short version)

  • The R4300 game code (src/game, src) is compiled unmodified.
  • The RSP is emulated in software (fast3d/): it interprets the Gfx display list the game builds and emits OpenGL calls, bypassing the RDP.
  • The RCP scheduler (gesched.c) replaces src/sched.c's hardware task submission: instead of writing RSP registers it calls gfx_run().
  • libultra OS functions are shimmed in libultra.c (single-threaded, host clock, VI/PI/SI/AI mapped onto the video/audio/fs/input layers).
  • Saves (Memory Pak / EEPROM) are backed by files in the data dir.

GE-specific RSP work

The PD fast3d already handles G_TRI4 (GE's 4-triangle command). The new work for GE is:

  • G_SETTEX — GE's custom texture-bank command (include/gbi_extension.h, gsSPUseTexture). Must be added to the RSP interpreter + GL backend.
  • Verify GE's custom color-combiner modes (G_CC_*FADE*) and render mode (G_RM_CUSTOM_AA_ZB_XLU_SURF) produce correct GLSL / GL state.

Use rsp/graphics/gmain.s (the real GE RSP ucode) as the ground truth for the exact command encodings.

Status

Scaffolding only. The files in src/ and fast3d/ are stubs that define the interfaces and mark the work to be done. The actual implementation is brought in phase by phase (see docs/internals.md §8), largely by adapting the PD port's port/ layer.