The harness that compares the port against the game's own memory existed but had never been compiled: tools/trace did not build (27 errors, all in the argument plumbing), and the tfrag_light.rs light-bank correction it motivated was unverified. This finishes it and runs it, and the run finds two real bugs. Result, on level 0 against three inputs -- the live emulator over PINE and two PCSX2 savestates from the same level, agreeing byte for byte: headers matching the disc on invariant bytes: 833/833 data pointers relocated as table + disc offset: 833/833 light bank in RAM at 0x50ab20, byte-identical to the disc's vertices compared: 40600 (162400 colour bytes) equal: 162400 (100.00%) The locator finds the level's tfrags block in RAM by tfrag 0's bounding sphere and accepts a candidate only when every header matches the disc on the bytes the game leaves alone and every data pointer is the relocated form, so "the block was found" is itself a verification rather than an assumption. The bank is searched in RAM by its exact section bytes, which is what settles its framing: offset at +0x04, an i32 set count, twelve bytes of pad, then the sets. The previous reading (offset at +0x00, count at +0x04) was wrong. Two bugs the comparison found, both of which produced plausible output: 1. vertex_normal_bits negated x and y and left z positive, while NormalTable::normal negates all three. dA came out -0.707 where the game had +0.707, so max(dA, dA*wA) took the wrong branch and every vertex lit near its base colour: dark, but not wrong-dark. 95.88% agreement with the bug, 100.00% without. 2. A record whose select names a set the bank lacks drew transparent black. The game writes the record's base colour; 3,130 of level 0's 40,600 vertices do this (select 0x000f, set 15 -- a runtime slot the level's directional bank does not have). The vertex is unlit, not invisible. Both are now regression tests in the engine. The comparison prints the pass's per-vertex terms (light_vertex_terms) for the first mismatches, because a colour mismatch alone cannot be attributed and the comparison is worthless without attribution -- that is how the second bug was identified from a three-line read rather than guessed at. Docs: docs/plan/pcsx2-verification.md records the harness, the result, the two bugs and what to compare next; roadmap and level-assets.md stop carrying lighting magnitudes as an open item. Findings reach tests only as numbers -- no test reads a savestate, a dump or a live emulator.
91 lines
2.4 KiB
TOML
91 lines
2.4 KiB
TOML
[workspace]
|
|
resolver = "2"
|
|
members = [
|
|
"crates/gc-formats",
|
|
"crates/gc-extract",
|
|
"crates/gc-engine",
|
|
"crates/gc-game",
|
|
"crates/gc-video",
|
|
"tools/trace",
|
|
]
|
|
|
|
[workspace.package]
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
rust-version = "1.85"
|
|
license = "MIT OR ISC"
|
|
publish = false
|
|
|
|
# The PS2's Emotion Engine is a MIPS R5900 with a 128-bit vector unit and a
|
|
# float model that differs from x86 in ways that matter for this game (no
|
|
# denormals, specific rounding). Every ported routine must reproduce that model
|
|
# rather than Rust's native f32, or the game will subtly not feel right.
|
|
# See docs/plan/float-model.md.
|
|
[workspace.dependencies]
|
|
gc-formats = { path = "crates/gc-formats" }
|
|
gc-extract = { path = "crates/gc-extract" }
|
|
gc-engine = { path = "crates/gc-engine" }
|
|
gc-game = { path = "crates/gc-game" }
|
|
gc-video = { path = "crates/gc-video" }
|
|
gc-trace = { path = "tools/trace" }
|
|
|
|
# Dev tools. PCSX2's savestates are zip archives whose entries are
|
|
# zstd- or deflate-compressed; both backends are pure Rust and are already
|
|
# in the lockfile through Bevy, so the trace tool adds no new sources.
|
|
ruzstd = "0.8"
|
|
flate2 = { version = "1", default-features = false, features = ["rust_backend"] }
|
|
|
|
anyhow = "1"
|
|
thiserror = "2"
|
|
bytemuck = { version = "1", features = ["derive", "min_const_generics"] }
|
|
sha1 = "0.10"
|
|
|
|
# Bevy 0.19.1 is the engine ReRAC uses; matching it keeps the GS/VU work portable.
|
|
#
|
|
# default-features = false avoids the cpal audio backend, which needs system
|
|
# ALSA development headers on Fedora (alsa-lib-devel). Audio decode lives in
|
|
# gc-video and is the last phase of the port, so the host audio backend is not
|
|
# needed to build. Re-enable "audio" and install alsa-lib-devel when it is.
|
|
bevy = { version = "0.19.1", default-features = false, features = [
|
|
"std",
|
|
"bevy_asset",
|
|
"bevy_color",
|
|
"bevy_core_pipeline",
|
|
"bevy_gizmos",
|
|
"bevy_log",
|
|
"bevy_mesh",
|
|
"bevy_pbr",
|
|
"bevy_render",
|
|
"bevy_shader",
|
|
"bevy_sprite",
|
|
"bevy_state",
|
|
"bevy_text",
|
|
"bevy_ui",
|
|
"bevy_window",
|
|
"bevy_winit",
|
|
"bevy_animation",
|
|
"bevy_gltf",
|
|
"png",
|
|
"ktx2",
|
|
"zlib",
|
|
"zstd_rust",
|
|
"tonemapping_luts",
|
|
"multi_threaded",
|
|
"x11",
|
|
"wayland",
|
|
"keyboard",
|
|
"mouse",
|
|
"gamepad",
|
|
] }
|
|
|
|
[profile.dev]
|
|
# Iterate fast on our own code; do not rebuild dependencies unoptimised.
|
|
opt-level = 1
|
|
|
|
[profile.dev.package."*"]
|
|
opt-level = 3
|
|
debug = false
|
|
|
|
[profile.release]
|
|
lto = "thin"
|
|
codegen-units = 1 |