Browse Source

Baby's first background

master
Nathaniel Walizer 1 year ago
parent
commit
0078a19a9e
5 changed files with 106 additions and 31 deletions
  1. +1
    -1
      Makefile
  2. +2
    -2
      src/nese.c
  3. +1
    -1
      src/ppu.c
  4. +6
    -3
      src/ppu.h
  5. +96
    -24
      src/sdl_render.c

+ 1
- 1
Makefile View File

@@ -11,7 +11,7 @@ BINDIR = bin
# nese

TARGET_1 = nese
LDLIBS_1 = -lSDL
LDLIBS_1 = -lSDL2

SRC_SRCS_1 = nese.c ines.c nes.c ppu.c sdl_render.c



+ 2
- 2
src/nese.c View File

@@ -54,7 +54,7 @@ int main(int argc, char* argv[]) {
nes_init(&sys);
nes_reset(&sys);

int total_cycles = 0;
uint64_t total_cycles = 0;
int last_frame_rendered = -1;
for (int i = 0; i < n_loops && status == 0; ++i) {
int run = 0;
@@ -78,7 +78,7 @@ int main(int argc, char* argv[]) {
float ms_run = ( total_cycles * 1000. *
nes_clock_master_den) /
nes_clock_master_num;
fprintf(stdout, "Ran %f ms, %d master cycles (%s)\n",
fprintf(stdout, "Ran %f ms, %lu master cycles (%s)\n",
ms_run, total_cycles,
status == 0 ? "OK" : "Halted");



+ 1
- 1
src/ppu.c View File

@@ -156,7 +156,7 @@ int nes_ppu_run(nes_ppu* ppu, int cycles) {
ppu->status &= ~ppu_Status_VBlank;
ppu->scanline = 0;
ppu->frame++;
// TODO: Render callback?
// TODO: Render callback if vblank was previously set
} else if (ppu->scanline >= nes_ppu_prerender +
nes_ppu_height +
nes_ppu_postrender) {


+ 6
- 3
src/ppu.h View File

@@ -10,9 +10,12 @@
#define nes_ppu_postrender (1U)
#define nes_ppu_vblank (20U)

#define nes_ppu_render_w (320U)
#define nes_ppu_render_w (320U) // Includes full overscan
#define nes_ppu_render_h nes_ppu_height

#define nes_ppu_blocks_w (32U)
#define nes_ppu_blocks_h (30U)

#define nes_ppu_mem_size (0x4000U)
#define nes_ppu_mem_pal_start (0x3F00U)
#define nes_ppu_mem_pal_size (0x0020U)
@@ -24,8 +27,8 @@
typedef enum {
ppu_Control_Nametable_Mask = 0b00000011,
ppu_Control_VRAM_Inc = 0b00000100,
ppu_Control_Sprite_Addr = 0b00001000,
ppu_Control_Back_Addr = 0b00010000,
ppu_Control_Sprite_Bank = 0b00001000,
ppu_Control_Back_Bank = 0b00010000,
ppu_Control_Sprite_Size = 0b00100000,
ppu_Control_Master = 0b01000000,
ppu_Control_VBlank = 0b10000000,


+ 96
- 24
src/sdl_render.c View File

@@ -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) ?


Loading…
Cancel
Save