gfx_opengl_set_sampler_parameters set GL_TEXTURE_MAX_ANISOTROPY only for
mipmapped samplers and never reset it. GL ids freed by
gfx_texture_cache_delete_range are recycled in unordered_map order (keyed by
texture address), so a non-mipmapped glyph could inherit a world texture's
4x anisotropy depending on the binary's data layout -> +-1-2 per channel on
the MP pause-menu text in couch 2P (frame 2400). Now always written (level
when mipmapped, 1 otherwise). #ifdef PORT, render-only.
Verified: couch 2P frames 2300-2500 fix vs fix+3KB array 0/21 differ
(before: 13/21); base vs fix: couch 2P 0/21, solo -level_09 f1800 and couch
4P f2400 byte-identical; netplay 2P SH identical (2 671 ticks).
Findings D430 + index row, porting note.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit ec5057f026259f35d4075833e89bf6fd0b6c467f)
crouched_rifle_firing_animation_group1 (chr.c) has one entry and no
terminator; on the N64, .data is in source order, so
crouched_rifle_firing_animation_groupA follows it and the single
initResolveAnimGroupTable pass over group1 also resolves groupA (len 2).
GCC places groupA below group1, so groupA[0] kept the raw anim offset
0xB84 (PTR_ANIM_fire_kneel_left_leg). playerTick (bondview2.c:11021) passes
it to modelSetAnimation for a player's crouched rifle fire
(firing_animation_groups[1][5]) -> SIGSEGV in modelConstrainOrWrapAnimFrame
(fault 0xb88). Crouching rifle guards also saw len 1 instead of 2.
#ifdef PORT: one array {right_leg, left_leg, terminator} (the N64 layout),
groupA = &group1[1] (chr.h). ABI/layout exception, porting-notes D5 class
(D164 precedent). Verified: 4-seat repro (M16, Complex, frame 5030) runs
5 min x3 SH-identical, no crash; gdb scan of all firing_animation_groups
entries: 1 bad pointer before, 0 after; P1 corpus (1324 recordings) verdicts
identical; solo/couch frames byte-identical; netplay 2P/4P identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 8595a06edd40ca22ac9ba4955b13a9ce61064475)
- v0.4.0 status framing (the most complete release to date; the common
defect classes fixed; a short list of known caveats) and the pre-1.0
note, on both the README and the Pages home page.
- Dated release news section with links to the GitHub release tags.
- Keyword-reinforced meta descriptions; site masthead tagline.
- Accuracy: options section list per the shipped overlay, Xbox 1.1 (Jinx)
controller roles (D394), Select opens the overlay, Deck 2x MSAA / 250%
preset, background stats, footer last-updated stamp.
11 rows per page now (was 13) so the bottom line of the paper is always
free for the page hint -- page 1 of a multi-page section shows
'Down: next page' after all (a full 13-row page had no room and no
hint, reported from the Deck). Hint wording drops the confusing
chevrons: 'Down: next page' / 'Up: previous page'.
Per user reports on the v0.4.0 front screen: the X/Y axis look
sensitivity (controller) labels ran into the fixed 232px slider track.
Bars now start 10px past each row's measured label (rows too long for
any track show the value only); drag hit-test and A-hold mapping use
the same per-row origin. Page 2 of a multi-page section now carries an
explicit dim 'Page p/N' marker right of the title plus a bottom hint
('Down: more rows >' / 'Up: previous page <') wherever the page has
room below; the (p/N) title suffix is retired. GE_FRONTOPTS_WIDTHS
one-shot label-metrics log added (same env-gated diagnostic
convention).
INPUT (17 visible rows) outgrew the fixed 440x330 paper: the 18px pitch
was sized before the D356 profile row, so a full page's last row landed
at y=335 (off the bottom of the screen) and rows past the silent 14-row
cap (Crouch mode, Reset to defaults, Bindings...) were unreachable from
the front screen. Sections now page at 13 rows (the largest that fits);
the vertical stepper crosses page boundaries in both directions and the
title carries a (p/N) marker. F10 overlay untouched (it scrolls its own
window). Headless verification (SkipIntro boot + scripted D-pad stepping
+ GE_FRONTNAVLOG): page 1 -> page 2 down and back up, all 17 rows
reachable. GE_FRONTOPTIONS_AUTO test hook added (diagnostic-only, same
convention as GE_FRONTOPTIONS_SECTION). Findings D406 + index; release
notes: options section list corrected to the shipped Input/Gameplay/HUD/
Graphics/Audio/Display and the D406 line added.
Plain declarative prose throughout the overview and section intros - no
product-page register, no first-person winks. Structure carries the period
feel: top anchor-nav line (middot separators), a dated news line for the
release, --- section rules, and a last-updated footer stamp.
- Docs site: drop jekyll-theme-cayman for a hand-rolled _layouts/default.html
(masthead band + middot text nav + footer with last-updated stamp and legal
line; head re-plumbed with {% seo %}, viewport, favicon); head-custom.html
fully rewritten to the chosen design tokens - charcoal/off-white/amber,
Libre Baskerville headings over system sans, square corners, 1px borders,
flat (no gradients/shadows), mermaid wrapper re-skinned.
- docs/index.md: v0.4.0 status (native widescreen, aim system, rebinding,
crosshair, rumble, rebuilt overlay); Honest status replaced by the v0.4.0
release-notes known issues; body anchor-nav line; legal footer moved to
layout.
- security-and-fidelity-status.md: front matter so {% seo %} titles it.
- README.md: v0.4.0 truth pass (status, Working/Known issues, Deck preset
2x MSAA / 250% per code, background stats 981 commits / 283 findings,
comparison table, GEPD-default controls paragraph, earlier builds) plus
markdown-native motifs matching the site: top anchor-nav line, --- section
rules, last-updated footer stamp, license badge in the amber accent.
- release-notes: SFTP sideload mention (leftover from the Deck session).
Port-layer only: resolve_msaa_color_buffer clamps msaa_level to the driver's
GL_MAX_SAMPLES (pre-fix: unallocated multisample renderbuffers -> black
screen when MSAA is set beyond driver support); the resolve/copy paths now
bind current_framebuffer ? framebuffers[i].fbo : 0 (the default framebuffer
is GL name 0, not framebuffers[0]). Affects both Windows (opengl32) and
Linux builds. Code file from the PR head (fc092d99); docs in house style,
label rebased D323 -> D405 (collision with our G_TL_LOD finding).
Port-layer only (port/src/input.c, optionsoverlay.c); zero src/game edits.
All new knobs off/neutral at default = byte-identical at defaults.
New controller input options (CONTROLLER-INPUT-PLAN Wave A):
- Input.PadLookSensX/Y: per-axis right-stick look sensitivity (100 = native)
- Input.PadSouthpaw: swap fire<->grenade triggers (applied after edge capture,
so edge-detection stays consistent)
- Input.PadDeadzoneL/R: per-stick deadzone; legacy Input.PadDeadzone key kept
registered (no row) + one-time migration in inputInit() seeds any unset L/R
from it (C-init sentinel PAD_DZ_UNSET) before the first configSave
- Input.PadLookSmooth: 0-10 per-pad EMA low-pass on the natural-pitch look
output (default 0 = off), reset on pad hot-unplug
- Input.MouseYScale: pre-existing registered key finally gets an INPUT row
Verbiage baseline (Turok PC options menu, user-provided verbatim): Mouse
horizontal/vertical sensitivity, X axis/Y axis look sensitivity, Look
smoothing, Southpaw, Vibration (was "Rumble strength"), Deadzone
(left/right stick). GE keeps one flat INPUT section (D356), so the two
Invert-look rows retain their (mouse)/(controller) suffixes.
Display baseline (Turok scales): sensitivity + deadzone rows render 0-100
with 50 = default (existing calibratedDefault path); look smoothing renders
0-10 via a new dispMax "N/M" row formatter (alongside the existing N/100 and
N/255 special cases).
Tested on a real pad (Windows build) - all six options behave as intended.
Low-hanging-fruit controller/input options ported from the Turok PC port's
menu, scoped as port-layer-only (zero src/ edits): right-stick look X/Y
sensitivity, southpaw trigger swap, per-stick deadzone (with the legacy
single-deadzone migration), look smoothing, and a mouse-vertical-sensitivity
row. All off-by-default (byte-identical at defaults, golden gate preserved).
Documents what the GE port already has, the per-item code shape + insertion
points in input.c, and the Tier B/C items explicitly out of scope (head bob,
bloom/shadows, death-cam, uncapped-FPS -> UNLOCKED-FPS-PLAN, controller
rebind -> PR #109).
After regenerating the Deck's pcmodels/pccg sidecars from the current
converter (M-197 blob fix + D303) and pushing them, the user re-checked
the front end on the Steam Deck and confirmed the Nintendo/GoldenEye logo
+ copyright/legal page now render correctly. D403 was the stale-sidecar
test artifact all along; no code was ever at fault.
The Deck bundle's stale 0.3.0-era pcmodels/pccg sidecars were regenerated
from the current Python-source converter (prepare-assets.py + d43/d69/d88,
ALL CHECKS PASSED) on the NTSC ROM and pushed to the Deck (sha256-verified),
preserving the user's ge007.eep + ge007.ini. Awaiting the user's by-eye
front-end recheck (logo/copyright page) to close the loop.
- D402: first clean Linux build fix (shim include-cycle + _SHIFTL).
- D403 (new): Deck front-end logo/copyright page broken + graphics not
updated is a test artifact — the bundle was seeded with 0.3.0-era
sidecars that predate the D75/M-197 blob fix and D303; not a code
regression. Disambiguation: regenerate the Deck's data/ sidecars.
- D404 (new): 'Aim style: Centred (PC)' is inert on a gamepad; the row's
doc comment over-promises (applies to pad trigger) but the centred
path is mouse-only (input.c:1783, D337 device-aware gate).
- Deck test confirmations: D175 gains a low-utilisation (~15-30%)
frame-pacing/present data point; D395 pad-binding retest satisfied
(not stuck); D401 rumble + D287 idle/resume-from-sleep confirmed on
the Deck's Steam Controller / SteamOS.
The release/v0.4.0 branch had never been compiled on Linux; two
port-layer include-resolution spots that MinGW tolerated break under
glibc. Shim-only fixes, zero src/ edits, no rule-2:
- port/shim/PR/ucode.h + port/shim/bondconstants.h: break the
bondconstants.h -> ultra64.h -> pc_protos.h -> bondtypes.h ->
bondconstants.h first-include re-entry by deferring pc_protos.h during
bondconstants.h's own ultra64.h pass (_PORT_DEFER_PC_PROTOS).
- port/shim/PR/gbi.h: define _SHIFTL/_SHIFTR when absent, so video.c's
gbi.h macros keep their mbi.h definitions on Linux.
Builds + links clean on Ubuntu 24.04 (glibc 2.39 <= SteamOS 2.41).
Per the user's release decision, keep the toggle (default OFF) but make it
impossible to miss in-game: the row is now labelled 'All unlocked
(EXPERIMENTAL)' and its ON value renders 'ON - UNSAFE' in both the F10
overlay and the front PC Options screen (both read the shared row table).
ON value now bright-highlights like a normal On. Port-only, display-only
(config still stores 0/1); a safe architecture is v0.5.0 work.
Housekeeping: track docs/dev/M7-ALLUNLOCKED-PLAN.md (records the decision);
gitignore the stray repo-root Python/ install; refresh the D387 status.
Port layer only (zero src/ edits), per docs/dev/RUMBLE-PLAN.md:
- port/src/input.c: inputRumbleSupported/inputRumble -> SDL_GameControllerRumble;
detection via SDL_GameControllerHasRumble (SDL >= 2.0.18) else
SDL_JoystickIsHaptic + known-type Windows fallback; zeroed on pad close.
Single global gRumbleScale (dflt 0.5) registered as Input.RumbleScale.
- port/src/libultra.c: the two M-87 blockers resolved - g_contStatus[i].status
now sets CONT_CARD_ON for connected rumble-capable pads (so
joyRumblePakInit arms) and osPfsInit returns PFS_ERR_DEVICE for them (so
osMotorInit is attempted); osMotorInit/Start/Stop drive the haptics API.
- port/src/optionsoverlay.c: one global 'Rumble strength' ROW_SLIDER
(Input.RumbleScale, 0.05 detents, %.2f) in the INPUT section +
kResetDefaults entry. The four per-player Input.PlayerN.RumbleScale keys
were dropped (user decision 2026-09-28); stale keys in an existing ini
log four 'unknown key' LOG_NOTE lines and self-clean on next configSave.
- Real-pad haptics confirmed working by the user (2026-09-28).
Build env: build-pc.sh self-heal guard revision - re-exec now writes a
self-contained .ps1 (msys->native argv conversion mangles $-bearing
-Command strings; file write is conversion-free), builds PATH explicitly,
picks TMP from writable candidates (GetTempPath honours the broken
inherited TMP), self-logs to build-pc/ge007-native-reexec-*.log, and
treats a null LASTEXITCODE as 'did not execute' (PS 5.1 piped native
commands error non-terminating). OPEN: the guard still fails inside
build-pc.sh while the identical standalone .ps1 invocation works - AGENTS.md
documents the workaround. docs: RUMBLE-PLAN.md (new, tracked), findings.md
D401 entry + index rows, QOL-INVENTORY D224 -> DONE (D401),
findings-index.csv regenerated.
Root cause H2 confirmed: the gun-barrel / file-select vertical gradient is
built from 0.75-native-pixel-tall gSPTextureRectangle row strips (title2.c
(<<2)-1 bottom idiom). On the N64 RDP the scan converter floors the U10.2
edges to whole scanlines, so each strip rasterizes to exactly one scanline;
gfx_draw_rectangle passed the fractional edges straight to the GPU's
continuous rasterizer, aliasing the 0.75px pitch into a periodic 'comb'
(fixed ~3-native-row period; window period = 3*scale — confirmed by a
3-scale 640/1024/1280 GE_PCDUMP test).
Fix (port-layer, surgical): after the sub-pixel offset, floor the top edge to
its scanline and the bottom edge to the last covered scanline (the RDP
scanline range [top_scan, bot_scan+1]) before NDC conversion. No-op for
whole-pixel rects (edges already 4k/4k-1), so only sub-pixel strips change
and normal fills are untouched.
Also: remove the temporary GE_D397SH / D397SHM env-gated shader probes
(gfx_opengl.cpp, gfx_pc.cpp) now that the root cause is settled.
Docs: findings.md D397 -> RESOLVED (+3-scale confirmation + fix record),
findings-index.csv regenerated, porting-notes.md section D15 marked resolved
with the landed fix.
Verified by playtest: gun-barrel + file-select gradient render clean, comb
gone.
New env-gated D397SHM probe in gfx_generate_cc dumps which G_CCMUX
inputs a combine feeds as vInput1..N. For the gun-barrow row-strip
shader (id0=0000000010001218): vInput1=PRIMITIVE, vInput2=ENV_ALPHA,
so the front.c LERP renders out = PRIM + (TEXEL-PRIM)*(envA/255).
The PD ground-truth port feeds the identical env_color.a/255 factor for
the same ENV_ALPHA LERP input, so the LERP factor is not a port-side
scaling bug (H1's 1/255-vs-1/32 variant refuted). A uniform factor
cannot produce the *periodic* comb, which points to H2 (row-strip
geometry / 256-tri vertex-ring wrap). Next: Q3 gfx_flush() probe +
Q5 native FBO capture. Findings §D397 + handoff updated.