|
|
|
@@ -1,4 +1,4 @@ |
|
|
|
#include <SDL/SDL.h> |
|
|
|
#include <SDL2/SDL.h> |
|
|
|
|
|
|
|
#include "render.h" |
|
|
|
#include "ppu.h" |
|
|
|
@@ -10,7 +10,7 @@ typedef struct { |
|
|
|
uint8_t b; |
|
|
|
} __attribute__ (( packed )) sPal; |
|
|
|
|
|
|
|
static struct sPal nes_palette[64] = { |
|
|
|
static sPal 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}, |
|
|
|
@@ -35,42 +35,70 @@ static struct sPal nes_palette[64] = { |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
SDL_Surface* surface; |
|
|
|
uint8_t buffer[3 * nes_ppu_render_w * nes_ppu_render_h]; |
|
|
|
SDL_Window* window; |
|
|
|
SDL_Renderer* renderer; |
|
|
|
SDL_Texture* texture; |
|
|
|
} sdl_render_data; |
|
|
|
|
|
|
|
static sdl_render_data the_render_data = {0}; |
|
|
|
|
|
|
|
|
|
|
|
static int filter(const SDL_Event* event) { |
|
|
|
return event->type == SDL_QUIT; |
|
|
|
static int filter(void*, SDL_Event* event) { |
|
|
|
return (event->type == SDL_QUIT); |
|
|
|
} |
|
|
|
|
|
|
|
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 { |
|
|
|
SDL_WM_SetCaption("NESe", "NESe"); |
|
|
|
data->window = SDL_CreateWindow( |
|
|
|
"NESe", |
|
|
|
SDL_WINDOWPOS_UNDEFINED, |
|
|
|
SDL_WINDOWPOS_UNDEFINED, |
|
|
|
nes_ppu_render_w * 4, |
|
|
|
nes_ppu_render_h * 4, |
|
|
|
0 |
|
|
|
); |
|
|
|
if (NULL == data->window) { |
|
|
|
fprintf(stderr, "SDL: Failed to create window\n"); |
|
|
|
SDL_Quit(); |
|
|
|
status = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (NULL == SDL_SetVideoMode(nes_ppu_render_w, |
|
|
|
nes_ppu_render_h, |
|
|
|
24, SDL_HWSURFACE)) { |
|
|
|
fprintf(stderr, "SDL: Failed to set video mode\n"); |
|
|
|
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) { |
|
|
|
the_render_data.surface = SDL_CreateRGBSurfaceFrom( |
|
|
|
the_render_data.buffer, nes_ppu_render_w, |
|
|
|
nes_ppu_render_h, 24, nes_ppu_render_w * 3, |
|
|
|
0xFFU, 0xFF00U, 0xFF0000U, 0 |
|
|
|
data->texture = SDL_CreateTexture( |
|
|
|
the_render_data.renderer, |
|
|
|
SDL_PIXELFORMAT_RGB24, |
|
|
|
SDL_TEXTUREACCESS_STREAMING, |
|
|
|
nes_ppu_render_w, |
|
|
|
nes_ppu_render_h |
|
|
|
); |
|
|
|
if (NULL == data->texture) { |
|
|
|
fprintf(stderr, "SDL: Failed to create texture\n"); |
|
|
|
SDL_DestroyRenderer(data->renderer); |
|
|
|
SDL_DestroyWindow(data->window); |
|
|
|
SDL_Quit(); |
|
|
|
status = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
SDL_SetEventFilter(filter); |
|
|
|
|
|
|
|
if (0 == status) { |
|
|
|
SDL_SetEventFilter(filter, NULL); |
|
|
|
rend->data = &the_render_data; |
|
|
|
} |
|
|
|
|
|
|
|
@@ -79,22 +107,66 @@ static int sdl_render_init(nes_Renderer* rend) { |
|
|
|
|
|
|
|
static void sdl_render_done(nes_Renderer* rend) { |
|
|
|
sdl_render_data* data = (sdl_render_data*)rend->data; |
|
|
|
if (NULL != data->surface) { |
|
|
|
SDL_FreeSurface(data->surface); |
|
|
|
data->surface = NULL; |
|
|
|
} |
|
|
|
SDL_DestroyTexture(data->texture); |
|
|
|
SDL_DestroyRenderer(data->renderer); |
|
|
|
SDL_DestroyWindow(data->window); |
|
|
|
SDL_Quit(); |
|
|
|
} |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
|
|
} oam_sprite; |
|
|
|
|
|
|
|
static void render_sprite(const nes_ppu* ppu, int index, |
|
|
|
void* loc, int pitch) { |
|
|
|
uint8_t* sprite = &ppu->chr_mem[index * 16U]; |
|
|
|
uint8_t* dst_line = (uint8_t*)loc; |
|
|
|
for (int y = 8; y > 0; --y) { |
|
|
|
uint8_t hi = sprite[0U]; |
|
|
|
uint8_t lo = sprite[8U]; |
|
|
|
sPal* dst = (sPal*)dst_line; |
|
|
|
for (int x = 8; x > 0; --x) { |
|
|
|
int pal_idx = (!!(hi & 0x80) << 1) | !!(lo & 0x80); |
|
|
|
*dst = nes_palette[16 + (pal_idx * 4)]; |
|
|
|
++dst; |
|
|
|
hi <<= 1; |
|
|
|
lo <<= 1; |
|
|
|
} |
|
|
|
dst_line += pitch; |
|
|
|
++sprite; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: Don't re-render background unless VRAM has changed |
|
|
|
|
|
|
|
static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { |
|
|
|
sdl_render_data* data = (sdl_render_data*)rend->data; |
|
|
|
|
|
|
|
// TODO |
|
|
|
|
|
|
|
SDL_Surface* screen = SDL_GetVideoSurface(); |
|
|
|
if (0 == SDL_BlitSurface(data->surface, NULL, screen, NULL)) { |
|
|
|
SDL_UpdateRect(screen, 0, 0, 0, 0); |
|
|
|
void* buffer = NULL; |
|
|
|
int pitch = 0; |
|
|
|
SDL_LockTexture(data->texture, NULL, &buffer, &pitch); |
|
|
|
int bank = (ppu->control & ppu_Control_Back_Bank) ? 0x100 : 0; |
|
|
|
uint8_t* index = &ppu->vram[0]; |
|
|
|
uint8_t* dst_line = |
|
|
|
(uint8_t*)buffer + |
|
|
|
((nes_ppu_render_w - (8U * nes_ppu_blocks_w)) / 2); |
|
|
|
for (int y = 0; y < nes_ppu_blocks_h; ++y) { |
|
|
|
uint8_t* dst = dst_line; |
|
|
|
for (int x = 0; x < nes_ppu_blocks_w; ++x) { |
|
|
|
render_sprite( |
|
|
|
ppu, bank + *index, dst, pitch |
|
|
|
); |
|
|
|
++index; |
|
|
|
dst += 3 * 8; |
|
|
|
} |
|
|
|
dst_line += pitch * 8; |
|
|
|
} |
|
|
|
SDL_UnlockTexture(data->texture); |
|
|
|
|
|
|
|
|
|
|
|
SDL_RenderCopy(data->renderer, data->texture, NULL, NULL); |
|
|
|
SDL_RenderPresent(data->renderer); |
|
|
|
|
|
|
|
SDL_Event event = {0}; |
|
|
|
return (1 == SDL_PollEvent(&event) && event.type == SDL_QUIT) ? |
|
|
|
|