v2.7.0 "True Colors"
Rusty2600 v2.7.0 "True Colors"
Fourth release of the RustyNES gap-closure arc — builds the TIA object-ID
mask rusty2600-frontend::sprite_pack's own doc comment has flagged as
the missing prerequisite since v1.4.0, then wires the live HD-pack
rendering splice that mask enables.
Shipped through PR #17, reviewed by GitHub Copilot and Gemini Code
Assist — 3 findings, all genuine, all fixed and re-verified before merge.
TIA object-ID mask (the real prerequisite)
rusty2600-tia gains a new, parallel per-pixel output channel behind the
off-by-default hd-pack feature: Tia::object_mask: Vec<ObjectTag>,
indexed identically to video_buffer (scanline * 160 + x). Each
ObjectTag names which object (Background/Playfield/Ball/
Missile0/Missile1/Player0/Player1) won color-priority resolution
at that dot, plus — for player pixels — the exact live GRPx
(VDELP-resolved)/NUSIZx at the moment that pixel was rendered.
Capturing GRPx/NUSIZx fresh per-pixel (not once per frame or
scanline) is what makes sprite multiplexing — a game rewriting GRP0/
GRP1 mid-scanline to draw more than 2 player objects per line, a real
historical 2600 programming technique — resolve correctly.
Honest verification, stated plainly: this touches rusty2600-tia,
the crate carrying this project's cycle-exact accuracy guarantees, so it
got the same review scrutiny as CDF/CDFJ/CDFJ+ in v2.3.0. Confirmed by
direct line-number inspection that self.current_object_tag is assigned
strictly after self.current_color is already resolved — the new code
cannot possibly alter the existing, accuracy-critical color computation.
Independently re-verified (not just the implementing work's own report):
333 tests passing on default features and 337 with --features test-roms, both exactly unchanged from v2.6.0's own baseline, proving
zero regression with hd-pack off.
Live HD-pack rendering splice
rusty2600-frontend::emu_thread::EmuCore gains a sprite_pack field and
set_sprite_pack setter. When a SpritePack is installed,
step_frame consults the object mask: a player pixel whose captured
(GRPx, NUSIZx) matches a loaded replacement bitmap gets that bitmap's
pixel instead of the flat resolved TIA color, nearest-neighbor scaled
onto the object's on-screen footprint (honoring NUSIZx size bits) and
alpha-blended against the underlying color. Missile/ball/playfield/
background pixels are untouched — sprite_pack's data model stays
player-only by design, unchanged since v1.4.0.
Proof-of-mechanism replacement-art pack
No replacement-art content existed anywhere in this project before this
release. A small fixture (tests/fixtures/hd_pack_demo/) plus a
hand-assembled synthetic 2600 ROM with known, static player-0 graphics
prove the splice mechanism works end-to-end: the test ROM runs a real
VSYNC(3 lines)/VBLANK(37 lines)/active-picture(192 lines) kernel
paced by WSYNC, and the integration test asserts the produced frame
actually shows the replacement bitmap's placeholder color — with a
control run (same ROM, no pack loaded) confirming that color never
appears without the splice active.
PR review, for real
PR #17 was reviewed by GitHub Copilot and Gemini Code Assist — 3
findings, all genuine, all fixed:
- A real rendering bug (Gemini Code Assist): the splice's contiguous
sprite-footprint run reset on everyGRPx0-bit (a transparent gap
inside real sprite art, as opposed to this release's fully-opaque
proof-of-mechanism bitmap), distorting the coordinate mapping onto the
replacement bitmap. The same finding also caught that the replacement
bitmap's alpha channel was ignored entirely, so any non-opaque
replacement pixel would render as solid black. Both fixed: the run
now survives transparent gaps within its own footprint width, and the
alpha channel is alpha-tested/blended against the original TIA color. - A stale-state bug (Copilot):
EmuCore::load_romnever cleared a
previously installedsprite_pack, so a prior cartridge's HD-pack
replacements could bleed into a newly loaded ROM's graphics. Fixed —
load_romnow clears it. - A test-robustness finding (Copilot): the integration test's
synthetic ROM never assertedVSYNC, sostep_frameended the
captured frame via its 200,000-instruction safety timeout rather than
a real frame boundary. Rewrote the ROM with a genuine NTSC kernel
(VSYNC/VBLANK/active-picture,WSYNC-paced) so the test now ends
on an actualVSYNC1->0 transition.
Test count
333 tests passing on default features (337 with --features test-roms)
— unchanged from v2.6.0, since the object-ID mask and HD-pack splice
are both gated behind the off-by-default hd-pack feature. 147 tests
passing across rusty2600-{tia,core,frontend} with --features hd-pack enabled (independently re-run and confirmed, not just the
implementing work's own report). Full CI green — Linux/macOS/Windows,
the perf regression gate, and the no_std gate.
What's next
v2.8.0 "Touchpoint" — Web Parity Wave 1: on-screen touch controls, a
working Settings panel in wasm32, console-switch on-screen buttons,
and localStorage/IndexedDB persistence, building on v2.5.0's bare
wasm render. See to-dos/ROADMAP.md for the complete v2.4.0 -> v3.0.0
roadmap.