diff --git a/Makefile b/Makefile index 5540b88..69ea883 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,10 @@ CC = gcc LD = $(CC) -PFLAGS = -g #-DE6502_DEBUG +PFLAGS = -g +#PFLAGS += -DDEBUG_MAPPER +#PFLAGS += -DDEBUG_RENDER +#PFLAGS += -DDEBUG_PPU +#PFLAGS += -DE6502_DEBUG CFLAGS = $(PFLAGS) -Wall -Werror -Wshadow -I.. LDFLAGS = $(PFLAGS) @@ -22,7 +26,7 @@ SRC_SRCS_1 += sdl_render.c sdl_input.c MAPDIR = src/map MAP_SRCS_1 = nrom.c mmc1.c cnrom.c mmc3.c -EXT_SRCS_1 = e6502/e6502.c +EXT_SRCS_1 = e6502/e6502.c e6502/opcodes.c SRCS_1 = $(SRC_SRCS_1:%=$(SRCDIR)/%) diff --git a/src/map/mmc3.c b/src/map/mmc3.c index 9914f27..4dcb5d2 100644 --- a/src/map/mmc3.c +++ b/src/map/mmc3.c @@ -5,6 +5,7 @@ typedef enum { mmc3_Flag_Horizontal = 0b00000001, mmc3_Flag_IRQ_Enabled = 0b00000010, + mmc3_Flag_IRQ_Reload = 0b00000100, mmc3_Flag_WRAM_Protect = 0b01000000, mmc3_Flag_WRAM_Enabled = 0b10000000, } mmc3_Flag; @@ -69,8 +70,8 @@ static inline void mmc3_map_2k_chr(mmc3_mapper* map, MAP_LOG("CHR ROM OOB: %d > %d", bank, map->chr_rom_banks); bank = bank % map->chr_rom_banks; } - MAP_LOG("CHR ROM: 2k $%04x <- bank %d + %d", reg << 10, bank & ~1, bank | 1); - map->chr_bank[reg + 0] = mmc3_chr_bank(map, bank & ~1); + MAP_LOG("CHR ROM: 2k $%04x <- bank %d + %d", reg << 10, bank, bank | 1); + map->chr_bank[reg + 0] = mmc3_chr_bank(map, bank); map->chr_bank[reg + 1] = mmc3_chr_bank(map, bank | 1); } @@ -145,9 +146,6 @@ static inline void mmc3_update_vram(mmc3_mapper* map) { static void mmc3_reset(nes_mapper* nes_map) { mmc3_mapper* map = (mmc3_mapper*)nes_map->data; - map->flags = 0; - map->bank_select = mmc3_Bank_Select_PRG | - mmc3_Bank_Select_CHR; map->irq_count = 0; map->irq_latch = 0; mmc3_update_rom_mode(map, 0); @@ -165,6 +163,8 @@ static int mmc3_init(nes_mapper* nes_map, nes_cart* cart) { map->chr_rom_banks = cart->chr_rom_banks * 4; map->flags = (cart->flags & Cart_Flag_Horizontal) ? mmc3_Flag_Horizontal : 0; + map->bank_select = mmc3_Bank_Select_PRG | + mmc3_Bank_Select_CHR; mmc3_reset(nes_map); } return (NULL == map ? -1 : 0); @@ -251,7 +251,8 @@ static void mmc3_write(nes_mapper* nes_map, } else if (addr < 0xE000U) { if (addr & 1) { MAP_LOG("IRQ Reload"); - map->irq_count = 0; + map->flags |= mmc3_Flag_IRQ_Reload; +// map->irq_count = 0; } else { MAP_LOG("IRQ Latch: %d", val); map->irq_latch = val; @@ -271,17 +272,21 @@ static void mmc3_write(nes_mapper* nes_map, static void mmc3_scanline(nes_mapper* nes_map) { mmc3_mapper* map = (mmc3_mapper*)nes_map->data; - if (map->irq_count == 0) { + if ( map->irq_count <= 0 || + (map->flags & mmc3_Flag_IRQ_Reload)) { map->irq_count = map->irq_latch; - + map->flags &= ~mmc3_Flag_IRQ_Reload; } else { map->irq_count--; - if ( map->irq_count <= 0 && - (map->flags & mmc3_Flag_IRQ_Enabled)) { - MAP_LOG("IRQ Trigger"); - nes_map_trigger_irq(nes_map, 1); - } } + + if ( map->irq_count <= 0 && + (map->flags & mmc3_Flag_IRQ_Enabled)) { + MAP_LOG("IRQ Trigger"); + nes_map_trigger_irq(nes_map, 1); + map->irq_count = 0; + } + } static uint8_t* mmc3_chr_addr(nes_mapper* nes_map, diff --git a/src/mapper.h b/src/mapper.h index e98b36d..8d415bc 100644 --- a/src/mapper.h +++ b/src/mapper.h @@ -3,9 +3,11 @@ #include - +#ifdef DEBUG_MAPPER #define MAP_LOG(fmt, ...) printf("MAP: " fmt "\n" __VA_OPT__(,) __VA_ARGS__) - +#else +#define MAP_LOG(...) do {} while (0) +#endif struct nes_cart_t; diff --git a/src/nes.c b/src/nes.c index 985198e..47bd2ae 100644 --- a/src/nes.c +++ b/src/nes.c @@ -40,8 +40,9 @@ void nes_mem_write(nes* sys, uint16_t addr, uint8_t val) { } else if (nes_ppu_dma_reg == addr) { OAM_LOG("PPU: OAM DMA $%02x00 > $%02x\n", val, sys->ppu.oam_addr); + uint8_t* buf = (uint8_t*)sys->ppu.oam; for (int i = 0; i < nes_ppu_oam_size; ++i) { - sys->ppu.oam[(uint8_t)(i + sys->ppu.oam_addr)] = + buf[(uint8_t)(i + sys->ppu.oam_addr)] = nes_mem_read(sys, ((uint16_t)val << 8) + i); } sys->cpu.cycle += 513U; diff --git a/src/ppu.c b/src/ppu.c index ff48d78..dffd896 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -28,7 +28,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { } else if (oam_reg_data == addr) { OAM_LOG("PPU: OAM READ %02x > %02x\n", ppu->oam_addr, val); - val = ppu->oam[ppu->oam_addr]; + val = ((uint8_t*)ppu->oam)[ppu->oam_addr]; } else if (ppu_reg_data == addr) { if (ppu->addr >= nes_ppu_mem_pal_start) { @@ -82,7 +82,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { } else if (oam_reg_data == addr) { OAM_LOG("PPU: OAM %02x < %02x\n", ppu->oam_addr, val); - ppu->oam[ppu->oam_addr++] = val; + ((uint8_t*)ppu->oam)[ppu->oam_addr++] = val; } else if (ppu_reg_mask == addr) { ppu->mask = val; @@ -119,6 +119,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { ppu->scroll_y &= 0b00111000; ppu->scroll_y |= (val & 0b11) << 6; ppu->scroll_y |= (val & 0b110000) >> 4; + } ppu->latch = !ppu->latch; @@ -232,15 +233,18 @@ int nes_ppu_run(nes_ppu* ppu, int cycles) { result = ppu_Result_VBlank_On; } - } else if (ppu->scanline % 8 == 1) { + } else /*if (ppu->scanline % 8 == 1)*/ { result = ppu_Result_Ready; } } - if ( 0 != ppu->hit_line && + if ( ppu->hit_line > 0 && ppu->scanline > ppu->hit_line && ppu->cycle >= ppu->hit_dot) { -// if (!(ppu->status & ppu_Status_Hit)) printf("PPU: Hit @ %d, %d\n", ppu->hit_line + 1, ppu->hit_dot); + if (!(ppu->status & ppu_Status_Hit)) { + PPU_LOG("PPU: Hit @ %d, %d\n", ppu->hit_line + 1, ppu->hit_dot); + PPU_LOG("(Currently @ %d, %d)\n", ppu->scanline, ppu->cycle); + } ppu->status |= ppu_Status_Hit; } diff --git a/src/ppu.h b/src/ppu.h index 3cfdcc1..25b6cc8 100644 --- a/src/ppu.h +++ b/src/ppu.h @@ -66,13 +66,6 @@ struct nes_cart_t; #define nes_ppu_mem_pal_start (0x3F00U) #define nes_ppu_mem_pal_size (0x0020U) - -#define nes_ppu_oam_size (256U) - -#define nes_ppu_oam_sprite_size (4U) -#define nes_ppu_oam_sprite_count (nes_ppu_oam_size / \ - nes_ppu_oam_sprite_size) - typedef enum { ppu_Control_Nametable_Mask = 0b00000011, ppu_Control_Scroll_Page_X = 0b00000001, @@ -103,10 +96,34 @@ typedef enum { ppu_Mask_More_Blue = 0b10000000, } nes_ppu_Mask; + +typedef struct { + uint8_t y; + uint8_t index; + uint8_t attr; + uint8_t x; +} oam_sprite; + +typedef enum { + oam_Attr_Pal_Mask = 0b00000011, + oam_Attr_Background = 0b00100000, + oam_Attr_Flip_X = 0b01000000, + oam_Attr_Flip_Y = 0b10000000, +} oam_Attribute; + +typedef enum { + oam_Index_Bank = 0b00000001, + oam_Index_Tile_Mask = 0b11111110, +} oam_Index; + +#define nes_ppu_oam_sprite_count (64U) +#define nes_ppu_oam_size (nes_ppu_oam_sprite_count * 4U) + + typedef struct { // Memory struct nes_mapper_t* mapper; - uint8_t oam[nes_ppu_oam_size]; + oam_sprite oam[nes_ppu_oam_sprite_count]; uint8_t palette[nes_ppu_mem_pal_size]; // Timing diff --git a/src/sdl_render.c b/src/sdl_render.c index 43c7f36..c4cdad9 100644 --- a/src/sdl_render.c +++ b/src/sdl_render.c @@ -39,6 +39,7 @@ typedef struct { SDL_Renderer* renderer; SDL_Surface* background; SDL_Surface* background_line; + SDL_Surface* foreground; SDL_Surface* sprite; SDL_Surface* target; } sdl_render_data; @@ -110,12 +111,30 @@ static int sdl_render_init(nes_Renderer* rend) { } } + if (0 == status) { + data->foreground = SDL_CreateRGBSurfaceWithFormat( + 0, nes_ppu_render_w, nes_ppu_render_h, + 8, SDL_PIXELFORMAT_INDEX8 + ); + + if (NULL == data->foreground) { + fprintf(stderr, "SDL: Failed to create foreground\n"); + SDL_FreeSurface(data->background_line); + SDL_FreeSurface(data->background); + SDL_DestroyRenderer(data->renderer); + SDL_DestroyWindow(data->window); + SDL_Quit(); + status = -1; + } + } + if (0 == status) { data->sprite = SDL_CreateRGBSurfaceWithFormat( 0, 8, 16, 8, SDL_PIXELFORMAT_INDEX8 ); if (NULL == data->sprite) { fprintf(stderr, "SDL: Failed to create sprite\n"); + SDL_FreeSurface(data->foreground); SDL_FreeSurface(data->background_line); SDL_FreeSurface(data->background); SDL_DestroyRenderer(data->renderer); @@ -133,6 +152,7 @@ static int sdl_render_init(nes_Renderer* rend) { if (NULL == data->target) { fprintf(stderr, "SDL: Failed to create target\n"); SDL_FreeSurface(data->sprite); + SDL_FreeSurface(data->foreground); SDL_FreeSurface(data->background_line); SDL_FreeSurface(data->background); SDL_DestroyRenderer(data->renderer); @@ -147,6 +167,10 @@ static int sdl_render_init(nes_Renderer* rend) { nes_palette, 0U, 64U); SDL_SetColorKey(data->background, SDL_TRUE, 0xFFU); + SDL_SetPaletteColors(data->foreground->format->palette, + nes_palette, 0U, 64U); + SDL_SetColorKey(data->foreground, SDL_TRUE, 0xFFU); + SDL_SetPaletteColors(data->sprite->format->palette, nes_palette, 0U, 64U); SDL_SetColorKey(data->sprite, SDL_TRUE, 0xFFU); @@ -161,6 +185,7 @@ static void sdl_render_done(nes_Renderer* rend) { sdl_render_data* data = (sdl_render_data*)rend->data; SDL_FreeSurface(data->target); SDL_FreeSurface(data->sprite); + SDL_FreeSurface(data->foreground); SDL_FreeSurface(data->background_line); SDL_FreeSurface(data->background); SDL_DestroyRenderer(data->renderer); @@ -168,6 +193,52 @@ static void sdl_render_done(nes_Renderer* rend) { SDL_Quit(); } +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* 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]; + dst++; + hi <<= 1; + lo <<= 1; + } +} + +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* 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]; + dst++; + hi >>= 1; + lo >>= 1; + } +} + +static inline void render_bg_sprite_line( + const nes_ppu* ppu, int index, int y, const uint8_t* pal, + uint8_t* dst, int start, int end) { + uint8_t* sprite = chr_mem(ppu, index * 16U); + uint8_t lo = sprite[0U + y] << (start % 8); + uint8_t hi = sprite[8U + y] << (start % 8); + for (int x = start; x < end; ++x) { + int pal_idx = (((hi & 0x80) >> 6) | ((lo & 0x80) >> 7)); + *dst = (pal_idx ? pal[pal_idx] : 0xFFU); + dst++; + hi <<= 1; + lo <<= 1; + } +} + +/* static void render_bg_sprite(const nes_ppu* ppu, int index, const uint8_t* pal, void* loc, int pitch) { @@ -216,7 +287,62 @@ static void render_background_area(const nes_ppu* ppu, int page, index_line += nes_ppu_blocks_w; } } +*/ + +static inline void render_bg_scanline_area( + const nes_ppu* ppu, int page, + uint8_t* dst, int x, int y, int w) { + int block_x = x / 8; + int line_end = x + w; + int block_y = y / 8; + y = y % 8; + int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0; + const uint8_t* indexes = nes_map_vram_addr(ppu->mapper, + page << 10); + const uint8_t* attrs = indexes + 960U; + const uint8_t* index = indexes + + (block_y * nes_ppu_blocks_w) + + block_x; + + while (x < line_end) { + int attr_idx = ((block_y / 4) * 8) + (block_x / 4); + int shift = 2 * ((block_y & 0b10) | + ((block_x & 0b10) >> 1)); + int pal_idx = (attrs[attr_idx] >> shift) & 3; + const uint8_t* pal = &ppu->palette[pal_idx * 4]; + + int end = (x + 8) & ~7; + if (end > line_end) end = line_end; + + render_bg_sprite_line(ppu, bank + *index, y, + pal, dst, x, end); + + ++index; + ++block_x; + dst += (end - x); + x = end; + } +} + +static void render_bg_scanline(const nes_ppu* ppu, int scanline, + uint8_t* dst) { + // TODO: Handle column 0 flag + + int page = (ppu->control & ppu_Control_Nametable_Mask); + int x = ppu->scroll_x; + 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); + render_bg_scanline_area(ppu, page, dst, x, y, w); + render_bg_scanline_area(ppu, page ^ 1, dst + w, 0, y, x); +} +/* static void render_background_line(const nes_ppu* ppu, int line, void* buffer, int pitch) { // TODO: Handle column 0 flag @@ -246,27 +372,6 @@ static void render_background_line(const nes_ppu* ppu, int line, ); } - -typedef struct { - uint8_t y; - uint8_t index; - uint8_t attr; - uint8_t x; -} oam_sprite; - -typedef enum { - oam_Attr_Pal_Mask = 0b00000011, - oam_Attr_Background = 0b00100000, - oam_Attr_Flip_X = 0b01000000, - oam_Attr_Flip_Y = 0b10000000, -} oam_Attribute; - -typedef enum { - oam_Index_Bank = 0b00000001, - oam_Index_Tile_Mask = 0b11111110, -} oam_Index; - - static void render_sprite(nes_ppu* ppu, int index, const uint8_t* pal, uint8_t attr, void* loc, int pitch) { @@ -299,7 +404,62 @@ static void render_sprite(nes_ppu* ppu, int index, ++sprite; } } +*/ + +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]; + 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; + if (ppu->control & ppu_Control_Sprite_Size) { + bank = (index & 1) ? 0x100 : 0; + index &= 0xFEU; + } + index += bank; + + if (ppu->control & ppu_Control_Sprite_Size) { + if (y >= 8) { + index ^= 1; + y -= 8; + } + if (sprite->attr & oam_Attr_Flip_Y) { + index ^= 1; + } + } + + int pal_idx = (sprite->attr & oam_Attr_Pal_Mask); + const uint8_t* pal = &ppu->palette[16 + (pal_idx * 4)]; + + if (sprite->attr & oam_Attr_Flip_Y) y = 7 - y; + int end = nes_ppu_render_w - sprite->x; + if (end > 8) end = 8; + if (sprite->attr & oam_Attr_Flip_X) { + render_sprite_line_flip(ppu, index, y, pal, + dst_line + sprite->x, 0, end); + } else { + render_sprite_line(ppu, index, y, pal, + dst_line + sprite->x, 0, end); + } + } +} + +/* static void render_sprites(nes_ppu* ppu, SDL_Surface* buffer, SDL_Surface* target, @@ -363,30 +523,30 @@ static void render_sprites(nes_ppu* ppu, target, &target_rect); } } +*/ // Check sprite (0 only) collision on a scanline // This assumes that we've verified that this sprite // intersects with this scanline. // Scanline is 0-239 from inside the rendering window // (though we should never see this called with 0). -static int eval_sprite_line(const nes_ppu* ppu, int line, +static int eval_sprite_line(const nes_ppu* ppu, int y, const oam_sprite* sprite, const uint8_t* chr, const uint8_t* back) { int hit_pos = -1; - int y = line - (sprite->y + 1); - if (sprite->attr & oam_Attr_Flip_Y) y = 7 - y; uint8_t lo = chr[0U + y]; uint8_t hi = chr[8U + y]; back += sprite->x; - for (int x = sprite->x; x < nes_ppu_render_w; ++x) { + int end = nes_ppu_render_w; + if (end > sprite->x + 8) end = sprite->x + 8; + for (int x = sprite->x; x < end; ++x) { int pal_idx = (sprite->attr & oam_Attr_Flip_X) ? (((hi & 1) << 1) | (lo & 1)) : - ( ((hi & 0x80) >> 6) | - ((lo & 0x80) >> 7)); + (((hi & 0x80) >> 6) | ((lo & 0x80) >> 7)); if (pal_idx && *back != 0xFFU) { hit_pos = x; break; @@ -404,6 +564,7 @@ static int eval_sprite_line(const nes_ppu* ppu, int line, return hit_pos; } +#if 0 static void update_sprite_hit(nes_ppu* ppu, int block_line, const void* back_pixels, int back_pitch) { @@ -498,6 +659,102 @@ static void render_block_line(nes_ppu* ppu, int line, data->background, &render_rect); */ } +#endif + +static void update_scanline_hit(nes_ppu* ppu, uint8_t* back_line, + int scanline) { + const oam_sprite* sprite = &ppu->oam[0]; + int bank = (ppu->control & ppu_Control_Sprite_Bank) ? + 0x100 : 0; + + if ( !(ppu->mask & ppu_Mask_Left_Sprite) && + sprite->x < 8) { + return; + } + int y_pos = (sprite->y + 1); + int y = scanline - y_pos; + if (0 > y) return; + int h = (ppu->control & ppu_Control_Sprite_Size) ? 16 : 8; + if (y >= h) return; + + int index = sprite->index; + if (ppu->control & ppu_Control_Sprite_Size) { + bank = (index & 1) ? 0x100 : 0; + index &= 0xFEU; + } + index += bank; + + if (ppu->control & ppu_Control_Sprite_Size) { + if (y >= 8) { + index ^= 1; + y -= 8; + } + if (sprite->attr & oam_Attr_Flip_Y) { + index ^= 1; + } + } + + const uint8_t* chr = chr_mem(ppu, index * 16U); + int hit = eval_sprite_line(ppu, y, sprite, chr, back_line); + + if (hit >= 0) { + REND_LOG("Upcoming hit @ %d, %d\n", scanline + 1, hit); + REND_LOG("(Currently @ %d, %d)\n", ppu->scanline, ppu->cycle); + ppu->hit_line = scanline; + ppu->hit_dot = hit; + } +} + +static void render_scanline(nes_ppu* ppu, int line, + sdl_render_data* data) { + if (!(ppu->mask & (ppu_Mask_Sprite | ppu_Mask_Back))) { + // Do nothing if BOTH are disabled. + return; + } + + SDL_Rect src_rect = { + .x = 0, + .y = 0, + .w = nes_ppu_render_w, + .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); + 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 (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); + } +} static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { int status = 0; @@ -513,9 +770,21 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { 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); + + if (ppu->mask & ppu_Mask_Sprite) { + render_sprites(ppu, data->sprite, data->target, + oam_Attr_Background); + + render_sprites(ppu, data->sprite, data->foreground, 0); + } +*/ } else if (ppu->scanline < nes_ppu_prerender + nes_ppu_height) { +/* int line = (ppu->scanline - (int)nes_ppu_prerender) / 8; REND_LOG("Scanline %3d -> Line %2d @ X %d\n", ppu->scanline, line, ppu->scroll_x); @@ -524,26 +793,44 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { if (ppu->mask & ppu_Mask_Back) { render_block_line(ppu, line, data); } +*/ + REND_LOG("Scanline %3d : X %d Y %d\n", ppu->scanline, ppu->scroll_x, ppu->scroll_y); + int line = ppu->scanline - (int)nes_ppu_prerender; + render_scanline(ppu, line, data); } else { REND_LOG("Scanline %3d -> Postrender\n", ppu->scanline); - +/* if (ppu->mask & ppu_Mask_Sprite) { render_sprites(ppu, data->sprite, data->target, oam_Attr_Background); } +*/ +/* if (ppu->mask & ppu_Mask_Back) { // Render final partial line if (0 != (ppu->scroll_y % 8)) { - render_block_line(ppu, nes_ppu_blocks_h, data); + if (ppu->mask & ppu_Mask_Sprite) { + // TODO: Render background sprites that start this block + } + if (ppu->mask & ppu_Mask_Back) { + render_block_line(ppu, nes_ppu_blocks_h, data); + } + if (ppu->mask & ppu_Mask_Sprite) { + // TODO: Render foreground sprites that end this block + } } SDL_BlitSurface(data->background, NULL, data->target, NULL); } + if (ppu->mask & ppu_Mask_Sprite) { render_sprites(ppu, data->sprite, data->target, 0); + SDL_BlitSurface(data->foreground, NULL, + data->target, NULL); } +*/ SDL_Texture* texture = SDL_CreateTextureFromSurface( data->renderer, data->target );