|
|
|
@@ -324,17 +324,17 @@ static inline void render_bg_scanline_area( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void render_bg_scanline(const nes_ppu* ppu, int scanline, |
|
|
|
static void render_bg_scanline(const nes_ppu* ppu,/* int scanline,*/ |
|
|
|
uint8_t* dst) { |
|
|
|
int page = (ppu->control & ppu_Control_Nametable_Mask); |
|
|
|
int x = ppu->scroll_x; |
|
|
|
int y = ppu->scroll_y + scanline; |
|
|
|
|
|
|
|
int y = ppu->scroll_y /*+ scanline*/; |
|
|
|
/* |
|
|
|
if (y >= nes_ppu_render_h) { |
|
|
|
y -= nes_ppu_render_h; |
|
|
|
page ^= 0b10; |
|
|
|
} |
|
|
|
|
|
|
|
*/ |
|
|
|
int w = (nes_ppu_render_w - x); |
|
|
|
if (!(ppu->mask & ppu_Mask_Left_Back)) { |
|
|
|
// Handle column 0 flag - need to fill with transparency |
|
|
|
@@ -413,32 +413,26 @@ 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 bank = (ppu->control & ppu_Control_Sprite_Bank) ? |
|
|
|
0x100 : 0; |
|
|
|
for ( int i_sprite = nes_ppu_oam_sprite_count - 1; |
|
|
|
i_sprite >= 0; --i_sprite) { |
|
|
|
const oam_sprite* sprite = &ppu->oam[i_sprite]; |
|
|
|
int scanline, int background, |
|
|
|
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; |
|
|
|
} |
|
|
|
if ( !(ppu->mask & ppu_Mask_Left_Sprite) && |
|
|
|
sprite->x < 8) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
int y_pos = (sprite->y + 1); |
|
|
|
int y = scanline - y_pos; |
|
|
|
if (0 > y) continue; |
|
|
|
int h = (ppu->control & ppu_Control_Sprite_Size) ? 16 : 8; |
|
|
|
if (y >= h) continue; |
|
|
|
|
|
|
|
int index = sprite->index; |
|
|
|
int bank = (ppu->control & ppu_Control_Sprite_Bank) ? |
|
|
|
0x100 : 0; |
|
|
|
if (ppu->control & ppu_Control_Sprite_Size) { |
|
|
|
bank = (index & 1) ? 0x100 : 0; |
|
|
|
index &= 0xFEU; |
|
|
|
} |
|
|
|
index += bank; |
|
|
|
|
|
|
|
int y = scanline - (sprite->y + 1); |
|
|
|
if (ppu->control & ppu_Control_Sprite_Size) { |
|
|
|
if (y >= 8) { |
|
|
|
index ^= 1; |
|
|
|
@@ -455,12 +449,19 @@ static void render_line_sprites(nes_ppu* ppu, uint8_t* dst_line, |
|
|
|
if (sprite->attr & oam_Attr_Flip_Y) y = 7 - y; |
|
|
|
int end = nes_ppu_render_w - sprite->x; |
|
|
|
if (end > 8) end = 8; |
|
|
|
int start = 0; |
|
|
|
if ( !(ppu->mask & ppu_Mask_Left_Sprite) && |
|
|
|
sprite->x < 8) { |
|
|
|
start = 8 - sprite->x; |
|
|
|
} |
|
|
|
if (sprite->attr & oam_Attr_Flip_X) { |
|
|
|
render_sprite_line_flip(ppu, index, y, pal, |
|
|
|
dst_line + sprite->x, 0, end); |
|
|
|
dst_line + sprite->x + start, |
|
|
|
start, end); |
|
|
|
} else { |
|
|
|
render_sprite_line(ppu, index, y, pal, |
|
|
|
dst_line + sprite->x, 0, end); |
|
|
|
dst_line + sprite->x + start, |
|
|
|
start, end); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -711,8 +712,48 @@ static void update_scanline_hit(nes_ppu* ppu, uint8_t* back_line, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static int select_line_sprites(const nes_ppu* ppu, int scanline, |
|
|
|
oam_sprite* sprites, int max) { |
|
|
|
int n_sprites = 0; |
|
|
|
|
|
|
|
for ( int i_sprite = 0; |
|
|
|
i_sprite < nes_ppu_oam_sprite_count && n_sprites < max; |
|
|
|
++i_sprite) { |
|
|
|
const oam_sprite* sprite = &ppu->oam[i_sprite]; |
|
|
|
int y_pos = (sprite->y + 1); |
|
|
|
int y = scanline - y_pos; |
|
|
|
if (0 > y) continue; |
|
|
|
int h = (ppu->control & ppu_Control_Sprite_Size) ? 16 : 8; |
|
|
|
if (y >= h) continue; |
|
|
|
|
|
|
|
*sprites = *sprite; |
|
|
|
++sprites; |
|
|
|
++n_sprites; |
|
|
|
} |
|
|
|
|
|
|
|
return n_sprites; |
|
|
|
} |
|
|
|
|
|
|
|
static void render_scanline(nes_ppu* ppu, int line, |
|
|
|
sdl_render_data* data) { |
|
|
|
|
|
|
|
SDL_Rect dst_rect = { |
|
|
|
.x = 0, |
|
|
|
.y = line, |
|
|
|
.w = nes_ppu_render_w, |
|
|
|
.h = 1, |
|
|
|
}; |
|
|
|
|
|
|
|
if (line >= 0) { |
|
|
|
// Emulate the happy part of the backdrop override quirk |
|
|
|
int pal_idx = (ppu->addr >= nes_ppu_mem_pal_start) ? |
|
|
|
(ppu->addr & (nes_ppu_mem_pal_size - 1)) : 0; |
|
|
|
SDL_Color ext = nes_palette[ppu->palette[pal_idx]]; |
|
|
|
SDL_FillRect(data->target, &dst_rect, ((int)ext.r << 16) | |
|
|
|
((int)ext.g << 8) | |
|
|
|
ext.b); |
|
|
|
} |
|
|
|
|
|
|
|
if (!(ppu->mask & (ppu_Mask_Sprite | ppu_Mask_Back))) { |
|
|
|
// Do nothing if BOTH are disabled. |
|
|
|
return; |
|
|
|
@@ -725,40 +766,58 @@ static void render_scanline(nes_ppu* ppu, int line, |
|
|
|
.h = 1, |
|
|
|
}; |
|
|
|
|
|
|
|
SDL_Rect dst_rect = { |
|
|
|
.x = 0, |
|
|
|
.y = line, |
|
|
|
.w = nes_ppu_render_w, |
|
|
|
.h = 1, |
|
|
|
}; |
|
|
|
|
|
|
|
uint8_t* foreground = data->foreground->pixels; |
|
|
|
uint8_t* background = data->background->pixels; |
|
|
|
|
|
|
|
if (ppu->mask & ppu_Mask_Sprite) { |
|
|
|
memset(foreground, 0xFFU, nes_ppu_render_w); |
|
|
|
render_line_sprites(ppu, foreground, line, |
|
|
|
oam_Attr_Background); |
|
|
|
SDL_BlitSurface(data->foreground, &src_rect, |
|
|
|
data->target, &dst_rect); |
|
|
|
} |
|
|
|
|
|
|
|
// We check for hits if EITHER layer is enabled. |
|
|
|
render_bg_scanline(ppu, line, background); |
|
|
|
render_bg_scanline(ppu, background); |
|
|
|
if (ppu->hit_line <= 0) { |
|
|
|
update_scanline_hit(ppu, background, line); |
|
|
|
} |
|
|
|
|
|
|
|
if (ppu->mask & ppu_Mask_Back) { |
|
|
|
SDL_BlitSurface(data->background, &src_rect, |
|
|
|
data->target, &dst_rect); |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
if (ppu->mask & ppu_Mask_Back) { |
|
|
|
SDL_BlitSurface(data->background, &src_rect, |
|
|
|
data->target, &dst_rect); |
|
|
|
} |
|
|
|
|
|
|
|
if (ppu->mask & ppu_Mask_Sprite) { |
|
|
|
memset(foreground, 0xFFU, nes_ppu_render_w); |
|
|
|
render_line_sprites(ppu, foreground, line, 0, |
|
|
|
line_sprites, n_sprites); |
|
|
|
SDL_BlitSurface(data->foreground, &src_rect, |
|
|
|
data->target, &dst_rect); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (ppu->mask & ppu_Mask_Sprite) { |
|
|
|
memset(foreground, 0xFFU, nes_ppu_render_w); |
|
|
|
render_line_sprites(ppu, foreground, line, 0); |
|
|
|
SDL_BlitSurface(data->foreground, &src_rect, |
|
|
|
data->target, &dst_rect); |
|
|
|
/*if (line + 1 < nes_ppu_height)*/ { |
|
|
|
ppu->scroll_y++; |
|
|
|
if (ppu->scroll_y >= nes_ppu_render_h) { |
|
|
|
ppu->scroll_y -= nes_ppu_render_h; |
|
|
|
ppu->control ^= 0b10; |
|
|
|
} |
|
|
|
/* |
|
|
|
// 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 + 1); |
|
|
|
} |
|
|
|
*/ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@@ -768,14 +827,6 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { |
|
|
|
|
|
|
|
if (ppu->scanline < nes_ppu_prerender) { |
|
|
|
REND_LOG("Scanline %3d -> Prerender\n", ppu->scanline); |
|
|
|
|
|
|
|
// Emulate the happy part of the backdrop override quirk |
|
|
|
int pal_idx = (ppu->addr >= nes_ppu_mem_pal_start) ? |
|
|
|
(ppu->addr & (nes_ppu_mem_pal_size - 1)) : 0; |
|
|
|
SDL_Color ext = nes_palette[ppu->palette[pal_idx]]; |
|
|
|
SDL_FillRect(data->target, NULL, ((int)ext.r << 16) | |
|
|
|
((int)ext.g << 8) | |
|
|
|
ext.b); |
|
|
|
/* |
|
|
|
memset(data->foreground->pixels, 0xFFU, |
|
|
|
data->foreground->pitch * data->foreground->h); |
|
|
|
@@ -787,6 +838,10 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { |
|
|
|
render_sprites(ppu, data->sprite, data->foreground, 0); |
|
|
|
} |
|
|
|
*/ |
|
|
|
/* |
|
|
|
int line = ppu->scanline - (int)nes_ppu_prerender; |
|
|
|
render_scanline(ppu, line, data); |
|
|
|
*/ |
|
|
|
|
|
|
|
} else if (ppu->scanline < nes_ppu_prerender + |
|
|
|
nes_ppu_height) { |
|
|
|
@@ -800,7 +855,10 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { |
|
|
|
render_block_line(ppu, line, data); |
|
|
|
} |
|
|
|
*/ |
|
|
|
REND_LOG("Scanline %3d : X %d Y %d\n", ppu->scanline, ppu->scroll_x, ppu->scroll_y); |
|
|
|
REND_LOG("Scanline %3d : N %d X %d Y %d\n", |
|
|
|
ppu->scanline, |
|
|
|
ppu->control & ppu_Control_Nametable_Mask, |
|
|
|
ppu->scroll_x, ppu->scroll_y); |
|
|
|
int line = ppu->scanline - (int)nes_ppu_prerender; |
|
|
|
render_scanline(ppu, line, data); |
|
|
|
|
|
|
|
|