From 8f8d5aa1e2182c9bcbaf2f2d45ec29ee4f4869d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Jun 2026 17:35:24 +0000 Subject: [PATCH] Fix title Pikachu mirror and post-title window artifact Two visual bugs both rooted in the 20x18 -> 40x25 viewport widening (SCREEN_TILES_W 20->40, SCREEN_TILES_H 18->25), which silently broke two spots that still assumed the GB's 32-wide tilemap / 20-wide screen. Bug 1 (title Pikachu split/mirrored): the non-overworld render path read the 40-wide wTileMap through the 32-wide GB VRAM tilemap. render_bg's .decode_vram wrapped columns at 32 (`and edx,31`), duplicating Pikachu's left columns onto the far right. Rewrite .decode_vram to read wTileMap directly with row/col bounds (blank $7F past col 40 / row 25), mirroring the overworld path's native-width read of wSurroundingTiles. This removes the lossy VRAM hop and the column wrap entirely, and also lets menus/text wider than 32 tiles render correctly. The window layer (TILEMAP1) is untouched. Bug 2 (post-title blank rectangle): LCDC default $E3 leaves window-enable (bit 5) permanently set, so render_window runs every frame gated only on WY/WX. The title's go_to_main_menu leaves H_WY=0, and ResetMapVariables never reset the window registers, so a stale window block painted over the overworld. Park the window off-screen (WY=RENDER_H, WX=7) in ResetMapVariables; dialog code re-shows the box at WY=152/WX=87 when needed. Both verified to assemble clean (nasm -f coff). Neither bug reproduces under SKIP_TITLE=1, consistent with both being title-path issues. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01GcHpAsg8pwsVATD6LWPsoR --- dos_port/src/engine/overworld/overworld.asm | 8 ++++++ dos_port/src/ppu/ppu.asm | 30 +++++++++++++-------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/dos_port/src/engine/overworld/overworld.asm b/dos_port/src/engine/overworld/overworld.asm index b81bab8c..73c62629 100644 --- a/dos_port/src/engine/overworld/overworld.asm +++ b/dos_port/src/engine/overworld/overworld.asm @@ -884,6 +884,14 @@ ResetMapVariables: mov byte [ebp + W_UNUSED_CUR_MAP_TILESET_COPY], al mov byte [ebp + W_SPRITE_SET_ID], al mov byte [ebp + W_WALK_BIKE_SURF_STATE_COPY], al + ; Park the window layer off-screen on map entry. LCDC bit 5 (window enable) + ; is permanently set (LCDC default $E3), so render_window runs every frame + ; gated only on WY/WX. The title's go_to_main_menu leaves H_WY=0, which would + ; otherwise leak in here and paint a stale window block over the overworld. + ; RENDER_H = off-screen; dialog code re-shows the box at WY=152/WX=87. + mov byte [ebp + H_WY], RENDER_H + mov byte [ebp + IO_WY], RENDER_H + mov byte [ebp + IO_WX], 7 ret ; --------------------------------------------------------------------------- diff --git a/dos_port/src/ppu/ppu.asm b/dos_port/src/ppu/ppu.asm index 45045b94..7e3f0739 100644 --- a/dos_port/src/ppu/ppu.asm +++ b/dos_port/src/ppu/ppu.asm @@ -155,20 +155,28 @@ render_bg: jmp .got_tile .decode_vram: + ; Non-overworld path (title / menus / text). Read the 40-wide wTileMap WRAM + ; buffer DIRECTLY into bg_surface, mirroring the overworld branch's + ; native-width read of wSurroundingTiles above. The old code funnelled the + ; 40-wide buffer through the 32-wide GB VRAM tilemap (do_bg_transfer) and + ; re-read it with `and edx,31`, which wrapped surface cols 32-47 back to + ; cols 0-15 — duplicating the left of the screen onto the right (the title + ; Pikachu "mirror"). wTileMap is 40 (SCREEN_TILES_W) x 25 (SCREEN_TILES_H); + ; the 48x36 surface's extra cols (>=40) and rows (>=25) render as blank $7F. mov eax, ebx mov ecx, 48 xor edx, edx - div ecx - and edx, 31 - shl eax, 5 - add eax, edx - mov ecx, GB_TILEMAP0 - test byte [ebp + IO_LCDC], 1 << 3 - jz .read_vram - mov ecx, GB_TILEMAP1 -.read_vram: - add eax, ecx - mov al, [ebp + eax] + div ecx ; EAX = surface row, EDX = surface col + cmp eax, SCREEN_TILES_H ; row >= 25 -> off-buffer + jae .vram_blank + cmp edx, SCREEN_TILES_W ; col >= 40 -> right padding + jae .vram_blank + imul eax, eax, SCREEN_TILES_W ; row * 40 + add eax, edx ; + col + mov al, [ebp + W_TILEMAP + eax] + jmp .got_tile +.vram_blank: + mov al, 0x7F ; blank space tile (matches ClearScreen fill) .got_tile: