|
- #include <SDL2/SDL.h>
-
- #include "render.h"
- #include "ppu.h"
- #include "mapper.h"
-
-
- static SDL_Color nes_palette[64] = {
- {0x80,0x80,0x80}, {0x00,0x00,0xBB}, {0x37,0x00,0xBF}, {0x84,0x00,0xA6},
- {0xBB,0x00,0x6A}, {0xB7,0x00,0x1E}, {0xB3,0x00,0x00}, {0x91,0x26,0x00},
- {0x7B,0x2B,0x00}, {0x00,0x3E,0x00}, {0x00,0x48,0x0D}, {0x00,0x3C,0x22},
- {0x00,0x2F,0x66}, {0x00,0x00,0x00}, {0x05,0x05,0x05}, {0x05,0x05,0x05},
-
- {0xC8,0xC8,0xC8}, {0x00,0x59,0xFF}, {0x44,0x3C,0xFF}, {0xB7,0x33,0xCC},
- {0xFF,0x33,0xAA}, {0xFF,0x37,0x5E}, {0xFF,0x37,0x1A}, {0xD5,0x4B,0x00},
- {0xC4,0x62,0x00}, {0x3C,0x7B,0x00}, {0x1E,0x84,0x15}, {0x00,0x95,0x66},
- {0x00,0x84,0xC4}, {0x11,0x11,0x11}, {0x09,0x09,0x09}, {0x09,0x09,0x09},
-
- {0xFF,0xFF,0xFF}, {0x00,0x95,0xFF}, {0x6F,0x84,0xFF}, {0xD5,0x6F,0xFF},
- {0xFF,0x77,0xCC}, {0xFF,0x6F,0x99}, {0xFF,0x7B,0x59}, {0xFF,0x91,0x5F},
- {0xFF,0xA2,0x33}, {0xA6,0xBF,0x00}, {0x51,0xD9,0x6A}, {0x4D,0xD5,0xAE},
- {0x00,0xD9,0xFF}, {0x66,0x66,0x66}, {0x0D,0x0D,0x0D}, {0x0D,0x0D,0x0D},
-
- {0xFF,0xFF,0xFF}, {0x84,0xBF,0xFF}, {0xBB,0xBB,0xFF}, {0xD0,0xBB,0xFF},
- {0xFF,0xBF,0xEA}, {0xFF,0xBF,0xCC}, {0xFF,0xC4,0xB7}, {0xFF,0xCC,0xAE},
- {0xFF,0xD9,0xA2}, {0xCC,0xE1,0x99}, {0xAE,0xEE,0xB7}, {0xAA,0xF7,0xEE},
- {0xB3,0xEE,0xFF}, {0xDD,0xDD,0xDD}, {0x11,0x11,0x11}, {0x11,0x11,0x11}
- };
-
-
- static inline uint8_t* chr_mem(const nes_ppu* ppu,
- uint16_t addr) {
- return ppu->mapper->chr_addr(ppu->mapper, addr);
- }
-
-
- typedef struct {
- SDL_Window* window;
- SDL_Renderer* renderer;
- SDL_Surface* background;
- SDL_Surface* background_line;
- SDL_Surface* foreground;
- SDL_Surface* sprite;
- SDL_Surface* target;
- } sdl_render_data;
-
- static sdl_render_data the_render_data = {0};
-
-
- static int sdl_render_init(nes_Renderer* rend) {
- sdl_render_data* data = &the_render_data;
- int status = SDL_Init(SDL_INIT_VIDEO);
-
- if (0 != status) {
- fprintf(stderr, "SDL: Failed to initialize\n");
-
- } else {
- data->window = SDL_CreateWindow(
- "NESe",
- SDL_WINDOWPOS_UNDEFINED,
- SDL_WINDOWPOS_UNDEFINED,
- nes_ppu_scan_w * 4,
- nes_ppu_scan_h * 4,
- 0
- );
- if (NULL == data->window) {
- fprintf(stderr, "SDL: Failed to create window\n");
- SDL_Quit();
- status = -1;
- }
- }
-
- if (0 == status) {
- data->renderer = SDL_CreateRenderer(data->window, -1, 0);
- if (NULL == data->renderer) {
- fprintf(stderr, "SDL: Failed to create renderer\n");
- SDL_DestroyWindow(data->window);
- SDL_Quit();
- status = -1;
- }
- }
-
- if (0 == status) {
- data->background = SDL_CreateRGBSurfaceWithFormat(
- 0, nes_ppu_render_w, nes_ppu_render_h,
- 8, SDL_PIXELFORMAT_INDEX8
- );
-
- if (NULL == data->background) {
- fprintf(stderr, "SDL: Failed to create background\n");
- SDL_DestroyRenderer(data->renderer);
- SDL_DestroyWindow(data->window);
- SDL_Quit();
- status = -1;
- }
- }
-
- if (0 == status) {
- data->background_line = SDL_CreateRGBSurfaceWithFormat(
- 0, nes_ppu_render_w + 8, 8,
- 8, SDL_PIXELFORMAT_INDEX8
- );
-
- if (NULL == data->background_line) {
- fprintf(stderr, "SDL: Failed to create block buffer\n");
- SDL_FreeSurface(data->background);
- SDL_DestroyRenderer(data->renderer);
- SDL_DestroyWindow(data->window);
- SDL_Quit();
- status = -1;
- }
- }
-
- 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);
- SDL_DestroyWindow(data->window);
- SDL_Quit();
- status = -1;
- }
- }
-
- if (0 == status) {
- data->target = SDL_CreateRGBSurfaceWithFormat(
- 0U, nes_ppu_render_w, nes_ppu_render_h,
- 24U, SDL_PIXELFORMAT_RGB888
- );
- 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);
- SDL_DestroyWindow(data->window);
- SDL_Quit();
- status = -1;
- }
- }
-
- if (0 == status) {
- SDL_SetPaletteColors(data->background->format->palette,
- 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);
-
- rend->data = &the_render_data;
- }
-
- return status;
- }
-
- 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);
- SDL_DestroyWindow(data->window);
- 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) {
- uint8_t* sprite = chr_mem(ppu, index * 16U);
- uint8_t* dst_line = (uint8_t*)loc;
-
- for (int y = 8; y > 0; --y) {
- uint8_t lo = sprite[0U];
- uint8_t hi = sprite[8U];
- uint8_t* dst = dst_line;
- for (int x = 8; x > 0; --x) {
- int pal_idx = ( ((hi & 0x80) >> 6) |
- ((lo & 0x80) >> 7));
- *dst++ = (pal_idx ? pal[pal_idx] : 0xFFU);
- hi <<= 1;
- lo <<= 1;
- }
- dst_line += pitch;
- ++sprite;
- }
- }
-
- static void render_background_area(const nes_ppu* ppu, int page,
- void* buffer, int pitch,
- int xs, int ys, int w, int h) {
- int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0;
- const uint8_t* index_line = nes_map_vram_addr(ppu->mapper,
- page << 10);
- const uint8_t* attrs = index_line + 960U;
- index_line += xs + (ys * nes_ppu_blocks_w);
- uint8_t* dst_line = (uint8_t*)buffer;
- for (int y = ys; y < h + ys; ++y) {
- uint8_t* dst = dst_line;
- const uint8_t* index = index_line;
- for (int x = xs; x < w + xs; ++x) {
- int attr_idx = ((y / 4) * 8) + (x / 4);
- int shift = 2 * ((y & 0b10) | ((x & 0b10) >> 1));
- int pal_idx = (attrs[attr_idx] >> shift) & 3;
- const uint8_t* pal = &ppu->palette[pal_idx * 4];
- render_bg_sprite(ppu, bank + *index, pal,
- dst, pitch);
- ++index;
- dst += 8;
- }
- dst_line += pitch * 8;
- 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) {
- 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);
- if (!(ppu->mask & ppu_Mask_Left_Back)) {
- // Handle column 0 flag - need to fill with transparency
- memset(dst, 0xFFU, 8);
- w -= 8;
- x += 8;
- dst += 8;
- }
- render_bg_scanline_area(ppu, page, dst, x, y, w);
- render_bg_scanline_area(ppu, page ^ 1, dst + w, 0, y,
- nes_ppu_render_w - w);
- }
-
- /*
- static void render_background_line(const nes_ppu* ppu, int line,
- void* buffer, int pitch) {
- // TODO: Handle column 0 flag
-
- int page = (ppu->control & ppu_Control_Nametable_Mask);
- int x = ppu->scroll_x / 8;
- line += ppu->scroll_y / 8;
-
- if (line >= nes_ppu_blocks_h) {
- line -= nes_ppu_blocks_h;
- page ^= 0b10;
- }
-
- // Left
- render_background_area(
- ppu, page, buffer, pitch,
- x, line,
- nes_ppu_blocks_w - x, 1
- );
-
- // Right
- buffer += (nes_ppu_blocks_w - x) * 8U;
- render_background_area(
- ppu, page ^ 1, buffer, pitch,
- 0, line,
- 1U + x, 1
- );
- }
-
- static void render_sprite(nes_ppu* ppu, int index,
- const uint8_t* pal, uint8_t attr,
- void* loc, int pitch) {
- uint8_t* sprite = chr_mem(ppu, index * 16U);
- uint8_t* dst_line = (uint8_t*)loc;
- int dx = 1;
- if (attr & oam_Attr_Flip_X) {
- dst_line += 7;
- dx = -dx;
- }
- if (attr & oam_Attr_Flip_Y) {
- dst_line += (7 * pitch);
- pitch = -pitch;
- }
-
- for (int y = 8; y > 0; --y) {
- uint8_t lo = sprite[0U];
- uint8_t hi = sprite[8U];
- uint8_t* dst = dst_line;
- for (int x = 8; x > 0; --x) {
- int pal_idx = ( ((hi & 0x80) >> 6) |
- ((lo & 0x80) >> 7));
- int nes_pal_idx = (pal_idx ? pal[pal_idx] : 0xFFU);
- *dst = nes_pal_idx;
- dst += dx;
- hi <<= 1;
- lo <<= 1;
- }
- dst_line += pitch;
- ++sprite;
- }
- }
- */
-
- static void render_line_sprites(nes_ppu* ppu, uint8_t* dst_line,
- 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;
- }
-
- 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;
- 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;
- 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 + start,
- start, end);
- } else {
- render_sprite_line(ppu, index, y, pal,
- dst_line + sprite->x + start,
- start, end);
- }
- }
- }
-
- /*
- static void render_sprites(nes_ppu* ppu,
- SDL_Surface* buffer,
- SDL_Surface* target,
- int background) {
- int bank = (ppu->control & ppu_Control_Sprite_Bank) ?
- 0x100 : 0;
- const oam_sprite* sprites = (const oam_sprite*)ppu->oam;
- uint8_t* dst_origin = (uint8_t*)buffer->pixels;
- int pitch = buffer->pitch;
- for ( int i_sprite = nes_ppu_oam_sprite_count - 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 = (sprite->y + 1);
- if (y >= nes_ppu_render_h) continue;
- uint8_t* dst = dst_origin;
- int index = sprite->index;
- if (ppu->control & ppu_Control_Sprite_Size) {
- bank = (index & 1) ? 0x100 : 0;
- index &= 0xFEU;
- }
- index += bank;
- int pal_idx = (sprite->attr & oam_Attr_Pal_Mask);
- const uint8_t* pal = &ppu->palette[16 + (pal_idx * 4)];
- if (ppu->control & ppu_Control_Sprite_Size) {
- if (sprite->attr & oam_Attr_Flip_Y) index++;
- render_sprite(ppu, index, pal, sprite->attr,
- dst, pitch);
- dst += pitch * 8;
- if (sprite->attr & oam_Attr_Flip_Y) {
- index--;
- } else {
- index++;
- }
- }
- render_sprite(ppu, index, pal, sprite->attr,
- dst, pitch);
-
- SDL_Rect sprite_rect = {
- .x = 0,
- .y = 0,
- .w = 8,
- .h = (ppu->control & ppu_Control_Sprite_Size) ?
- 16 : 8,
- };
-
- SDL_Rect target_rect = {
- .x = sprite->x,
- .y = y,
- .w = 8,
- .h = (ppu->control & ppu_Control_Sprite_Size) ?
- 16 : 8,
- };
- SDL_BlitSurface(buffer, &sprite_rect,
- 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 y,
- const oam_sprite* sprite,
- const uint8_t* chr,
- const uint8_t* back) {
- int hit_pos = -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;
- 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));
- if (pal_idx && *back != 0xFFU) {
- hit_pos = x;
- break;
- }
- ++back;
- if (sprite->attr & oam_Attr_Flip_X) {
- hi >>= 1;
- lo >>= 1;
- } else {
- hi <<= 1;
- lo <<= 1;
- }
- }
-
- return hit_pos;
- }
-
- #if 0
- static void update_sprite_hit(nes_ppu* ppu, int block_line,
- const void* back_pixels,
- int back_pitch) {
- const oam_sprite* sprite = (oam_sprite*)ppu->oam;
- int x_fine = ppu->scroll_x % 8;
- int y_fine = ppu->scroll_x % 8;
- int index = sprite->index;
- if (ppu->control & ppu_Control_Sprite_Bank) {
- index += 0x100U;
- }
- const uint8_t* chr = chr_mem(ppu, index * 16U);
- int render_line = block_line * 8U;
- int start_y = (sprite->y + 1) + y_fine - render_line;
- int end_y = start_y + 8;
- if (start_y < 8 && end_y > 0) {
- if (start_y < 0) start_y = 0;
- if (end_y > 8) end_y = 8;
- int hit = -1;
- const uint8_t* back = (uint8_t*)back_pixels + x_fine;
- back += (render_line + start_y) * back_pitch;
- for (int y = start_y; y < end_y; ++y) {
- hit = eval_sprite_line(
- ppu, render_line + y - y_fine,
- sprite, chr, back
- );
- if (hit >= 0) {
- ppu->hit_line = y - y_fine + render_line;
- ppu->hit_dot = hit;
- break;
- }
- back += back_pitch;
- }
- }
- }
-
- static void render_block_line(nes_ppu* ppu, int line,
- sdl_render_data* data) {
- // Render single line of blocks
-
- render_background_line(ppu, line,
- data->background_line->pixels,
- data->background_line->pitch);
-
- int x_fine = ppu->scroll_x % 8;
- int y_fine = ppu->scroll_y % 8;
-
- // Check for Sprite 0 Hit
- if ( 0 >= ppu->hit_line &&
- (ppu->mask & ppu_Mask_Sprite)) {
- update_sprite_hit(ppu, line,
- data->background_line->pixels,
- data->background_line->pitch);
- }
-
- // Copy line onto full background
-
- const uint8_t* src = data->background_line->pixels +
- x_fine;
- int start_y = ((line * 8U) - y_fine);
- int end_y = start_y + 8;
- if (start_y < 0) {
- src -= (start_y * data->background_line->pitch);
- start_y = 0;
- }
- uint8_t* dst = data->background->pixels +
- (start_y * data->background->pitch);
-
- for (int y = start_y; y < end_y; ++y) {
- if ((void*)dst >= data->background->pixels) {
- memcpy(dst, src, nes_ppu_render_w);
- }
- src += data->background_line->pitch;
- dst += data->background->pitch;
- }
-
- /*
- SDL_Rect back_rect = {
- .x = x_fine,
- .y = 0,
- .w = nes_ppu_render_w,
- .h = 8U,
- };
-
- SDL_Rect render_rect = {
- .x = 0,
- .y = (line * 8U) - y_fine,
- .w = nes_ppu_render_w,
- .h = 8U,
- };
-
- SDL_BlitSurface(data->background_line, &back_rect,
- 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 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;
- }
-
- SDL_Rect src_rect = {
- .x = 0,
- .y = 0,
- .w = nes_ppu_render_w,
- .h = 1,
- };
-
- 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);
- }
-
- 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 (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);
- }
- */
- }
- }
-
- static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) {
- int status = 0;
- sdl_render_data* data = (sdl_render_data*)rend->data;
-
- if (ppu->scanline < nes_ppu_prerender) {
- REND_LOG("Scanline %3d -> Prerender\n", ppu->scanline);
- /*
- 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);
- }
- */
- /*
- int line = ppu->scanline - (int)nes_ppu_prerender;
- render_scanline(ppu, line, data);
- */
-
- } 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);
-
- // TODO: Only re-render if VRAM/scroll changes?
- if (ppu->mask & ppu_Mask_Back) {
- render_block_line(ppu, line, data);
- }
- */
- 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);
-
- } 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)) {
- 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
- );
- SDL_RenderCopy(data->renderer, texture, NULL, NULL);
- SDL_RenderPresent(data->renderer);
- SDL_DestroyTexture(texture);
-
- status = 1;
- }
-
- return status;
- }
-
-
- nes_Renderer sdl_renderer = {
- .init = sdl_render_init,
- .done = sdl_render_done,
- .render = sdl_render,
- };
|