From 5d352fc5c52620af58f2f57acd417dcb76f6b868 Mon Sep 17 00:00:00 2001 From: Nathaniel Walizer Date: Sun, 29 Dec 2024 13:14:59 -0800 Subject: [PATCH] Fix sprite priority (visible in SMB3 powerups and Piranha Plants) --- Makefile | 2 +- src/sdl_render.c | 69 ++++++++++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index e09b033..d3b2ee8 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ PFLAGS = -g #PFLAGS = -O3 #PFLAGS += -DDEBUG_MAPPER #PFLAGS += -DDEBUG_RENDER -#PFLAGS += -DDEBUG_PPU -DDEBUG_VRAM +#PFLAGS += -DDEBUG_PPU -DDEBUG_VRAM -DDEBUG_OAM #PFLAGS += -DE6502_DEBUG CFLAGS = $(PFLAGS) -Wall -Werror -Wshadow -Wunused -I.. LDFLAGS = $(PFLAGS) diff --git a/src/sdl_render.c b/src/sdl_render.c index 4420c15..cdd2d0c 100644 --- a/src/sdl_render.c +++ b/src/sdl_render.c @@ -195,13 +195,18 @@ static void sdl_render_done(nes_Renderer* rend) { static inline void render_sprite_line( const nes_ppu* ppu, int index, int y, const uint8_t* pal, - uint8_t* dst, int start, int end) { + uint8_t* dst, int start, int end, const uint8_t* back) { uint8_t* sprite = chr_mem(ppu, index * 16U); uint8_t lo = sprite[0U + y] << start; uint8_t hi = sprite[8U + y] << start; for (int x = start; x < end; ++x) { - int pal_idx = (((hi & 0x80) >> 6) | ((lo & 0x80) >> 7)); - if (pal_idx) *dst = pal[pal_idx]; + if (back && *back != 0xFFU) { + *dst = *back; + } else { + int pal_idx = (((hi & 0x80) >> 6) | ((lo & 0x80) >> 7)); + if (pal_idx) *dst = pal[pal_idx]; + } + if (back) ++back; dst++; hi <<= 1; lo <<= 1; @@ -210,13 +215,18 @@ static inline void render_sprite_line( static inline void render_sprite_line_flip( const nes_ppu* ppu, int index, int y, const uint8_t* pal, - uint8_t* dst, int start, int end) { + uint8_t* dst, int start, int end, const uint8_t* back) { uint8_t* sprite = chr_mem(ppu, index * 16U); uint8_t lo = sprite[0U + y] >> start; uint8_t hi = sprite[8U + y] >> start; for (int x = start; x < end; ++x) { - int pal_idx = (((hi & 1) << 1) | (lo & 1)); - if (pal_idx) *dst = pal[pal_idx]; + if (back && *back != 0xFFU) { + *dst = *back; + } else { + int pal_idx = (((hi & 1) << 1) | (lo & 1)); + if (pal_idx) *dst = pal[pal_idx]; + } + if (back) ++back; dst++; hi >>= 1; lo >>= 1; @@ -413,16 +423,12 @@ static void render_sprite(nes_ppu* ppu, int index, */ static void render_line_sprites(nes_ppu* ppu, uint8_t* dst_line, - int scanline, int background, + int scanline, const uint8_t* back, const oam_sprite* sprites, int n_sprites) { for (int i_sprite = n_sprites - 1; i_sprite >= 0; --i_sprite) { const oam_sprite* sprite = &sprites[i_sprite]; - if ((sprite->attr & oam_Attr_Background) ^ background) { - continue; - } - int index = sprite->index; int bank = (ppu->control & ppu_Control_Sprite_Bank) ? 0x100 : 0; @@ -455,13 +461,19 @@ static void render_line_sprites(nes_ppu* ppu, uint8_t* dst_line, start = 8 - sprite->x; } if (sprite->attr & oam_Attr_Flip_X) { - render_sprite_line_flip(ppu, index, y, pal, - dst_line + sprite->x + start, - start, end); + render_sprite_line_flip( + ppu, index, y, pal, + dst_line + sprite->x + start, start, end, + (sprite->attr & oam_Attr_Background) ? + (back + sprite->x + start) : NULL + ); } else { - render_sprite_line(ppu, index, y, pal, - dst_line + sprite->x + start, - start, end); + render_sprite_line( + ppu, index, y, pal, + dst_line + sprite->x + start, start, end, + (sprite->attr & oam_Attr_Background) ? + (back + sprite->x + start) : NULL + ); } } } @@ -734,6 +746,16 @@ static int select_line_sprites(const nes_ppu* ppu, int scanline, return n_sprites; } +static void dump_line_sprites(const nes_ppu* ppu, int line, + const oam_sprite* sprites, int n) { + while (n-- > 0) { + PPU_LOG("PPU: Line %3d: Sprite $%02x @ %3d, %3d (%02x)\n", + line, sprites->index, sprites->x, sprites->y, + sprites->attr); + ++sprites; + } +} + static void render_scanline(nes_ppu* ppu, int line, sdl_render_data* data) { @@ -769,27 +791,18 @@ static void render_scanline(nes_ppu* ppu, int line, uint8_t* foreground = data->foreground->pixels; uint8_t* background = data->background->pixels; - // We check for hits if EITHER layer is enabled. render_bg_scanline(ppu, background); if (ppu->hit_line <= 0) { update_scanline_hit(ppu, background, line); } - if (line >= 0) { oam_sprite line_sprites[8] = {0}; int n_sprites = select_line_sprites(ppu, line, line_sprites, 8); - if (ppu->mask & ppu_Mask_Sprite) { - memset(foreground, 0xFFU, nes_ppu_render_w); - render_line_sprites(ppu, foreground, line, - oam_Attr_Background, - line_sprites, n_sprites); - SDL_BlitSurface(data->foreground, &src_rect, - data->target, &dst_rect); - } + dump_line_sprites(ppu, line, line_sprites, n_sprites); if (ppu->mask & ppu_Mask_Back) { SDL_BlitSurface(data->background, &src_rect, @@ -798,7 +811,7 @@ static void render_scanline(nes_ppu* ppu, int line, if (ppu->mask & ppu_Mask_Sprite) { memset(foreground, 0xFFU, nes_ppu_render_w); - render_line_sprites(ppu, foreground, line, 0, + render_line_sprites(ppu, foreground, line, background, line_sprites, n_sprites); SDL_BlitSurface(data->foreground, &src_rect, data->target, &dst_rect);