Преглед изворни кода

Clean up PPU and SDL render modules

master
Nathaniel Walizer пре 11 месеци
родитељ
комит
07486046c2
2 измењених фајлова са 31 додато и 385 уклоњено
  1. +10
    -27
      src/ppu.c
  2. +21
    -358
      src/sdl_render.c

+ 10
- 27
src/ppu.c Прегледај датотеку

@@ -32,7 +32,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) {

} else if (ppu_reg_data == addr) {
if (ppu->addr >= nes_ppu_mem_pal_start) {
// printf("PPU: PAL READ %04x > %02x\n", ppu->addr, val);
PPU_LOG("PPU: PAL READ %04x > %02x\n", ppu->addr, val);
uint8_t pal_addr =
(ppu->addr - nes_ppu_mem_pal_start) &
(nes_ppu_mem_pal_size - 1);
@@ -42,7 +42,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) {
val = ppu->data;

if (ppu->addr < nes_ppu_mem_vram_start) {
// printf("PPU: CHR MEM READ %04x > %02x\n", ppu->addr, val);
PPU_LOG("PPU: CHR MEM READ %04x > %02x\n", ppu->addr, val);
ppu->data = nes_chr_read(ppu->mapper, ppu->addr);
} else if (ppu->addr < nes_ppu_mem_vram_start +
nes_ppu_mem_vram_size) {
@@ -52,7 +52,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) {
ppu->addr - nes_ppu_mem_vram_start
);
} else if (ppu->addr < nes_ppu_mem_pal_start) {
printf("PPU: BLANK READ %04x > %02x\n", ppu->addr, val);
PPU_LOG("PPU: BLANK READ %04x > %02x\n", ppu->addr, val);
/*
ppu->data = *(nes_map_chr_addr(ppu->mapper,
ppu->addr));
@@ -69,6 +69,7 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) {
return val;
}

// Copy t to v (decoded into scroll_x, control)
static inline void nes_ppu_internal_copy_x(nes_ppu* ppu) {
ppu->control &= ~(1U);
ppu->control |= ((ppu->t >> 10) & 1U);
@@ -77,9 +78,8 @@ static inline void nes_ppu_internal_copy_x(nes_ppu* ppu) {
(ppu->x & 0b111U);
}

// Copy t to v (decoded into scroll_y, control)
static inline void nes_ppu_internal_copy_y(nes_ppu* ppu) {
// Copy t to v (decoded into scroll_x, scroll_y, ctrl)

ppu->control &= ~(0b10U);
ppu->control |= ((ppu->t >> 10) & 0b10U);

@@ -112,18 +112,17 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) {
} else if (ppu_reg_scroll == addr) {
if (ppu->latch) {
PPU_LOG("PPU: Scroll Y %02x\n", val);
// ppu->scroll_y = val;
ppu->t &= 0b0000110000011111U;
ppu->t |= (uint16_t)(val & 0b00000111U) << 12;
ppu->t |= (uint16_t)(val & 0b11111000U) << 2;

} else {
PPU_LOG("PPU: Scroll X %02x\n", val);
// ppu->scroll_x = val;
ppu->t &= ~(0b11111U);
ppu->t |= (val & 0b11111000U) >> 3;
ppu->x = (val & 0b111U);
}

ppu->latch = !ppu->latch;

} else if (ppu_reg_addr == addr) {
@@ -132,13 +131,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) {
if (ppu->latch) {
ppu->t &= 0xFF00U;
ppu->t |= val;
/*
// Take advantage of the quick split quirk
ppu->scroll_x &= 0b00000111;
ppu->scroll_x |= (val & 0b00011111);
ppu->scroll_y &= 0b11000111;
ppu->scroll_y |= (val & 0b11100000) >> 2;
*/

ppu->addr = (ppu->t & 0x3FFFU);
VRAM_LOG("PPU: VRAM ADDR %04x\n", ppu->addr);

@@ -152,18 +145,8 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) {
} else {
ppu->t &= 0x00FFU;
ppu->t |= (uint16_t)(0x3FU & val) << 8;
/*
// Take advantage of the quick split quirk
ppu->control &= ~ppu_Control_Nametable_Mask;
ppu->control |= (val & 0b1100) >> 2;
ppu->scroll_y &= 0b00111000;
ppu->scroll_y |= (val & 0b11) << 6;
ppu->scroll_y |= (val & 0b110000) >> 4;

PPU_LOG("PPU: Scroll X, Y = %d, %d\n",
ppu->scroll_x, ppu->scroll_y);
*/
}

ppu->latch = !ppu->latch;

} else if (ppu_reg_data == addr) {
@@ -174,7 +157,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) {
uint8_t pal_addr =
(ppu->addr - nes_ppu_mem_pal_start) &
(nes_ppu_mem_pal_size - 1);
// printf("PPU: PAL %02x < %02x\n", pal_addr, val);
PPU_LOG("PPU: PAL %02x < %02x\n", pal_addr, val);
ppu->palette[pal_addr] = val;
if ((pal_addr & 0b11) == 0) {
ppu->palette[pal_addr & 0xF] = val;
@@ -206,7 +189,7 @@ void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) {
nes_vram_write(ppu->mapper, vram_addr, val);

} else {
// printf("PPU: CHR MEM WRITE %04x > %02x\n", ppu->addr, val);
// PPU_LOG("PPU: CHR MEM WRITE %04x > %02x\n", ppu->addr, val);
nes_chr_write(ppu->mapper, ppu->addr, val);
}



+ 21
- 358
src/sdl_render.c Прегледај датотеку

@@ -248,57 +248,6 @@ static inline void render_bg_sprite_line(
}
}

/*
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) {
@@ -338,13 +287,7 @@ 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 y = ppu->scroll_y;
int w = (nes_ppu_render_w - x);
if (!(ppu->mask & ppu_Mask_Left_Back)) {
// Handle column 0 flag - need to fill with transparency
@@ -358,70 +301,6 @@ static void render_bg_scanline(const nes_ppu* ppu,/* int scanline,*/
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, const uint8_t* back,
const oam_sprite* sprites,
@@ -478,72 +357,6 @@ static void render_line_sprites(nes_ppu* ppu, uint8_t* dst_line,
}
}

/*
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.
@@ -555,6 +368,8 @@ static int eval_sprite_line(const nes_ppu* ppu, int y,
const uint8_t* back) {
int hit_pos = -1;

// TODO: Handle Column 0 mask

if (sprite->attr & oam_Attr_Flip_Y) y = 7 - y;
uint8_t lo = chr[0U + y];
uint8_t hi = chr[8U + y];
@@ -583,103 +398,6 @@ static int eval_sprite_line(const nes_ppu* ppu, int y,
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];
@@ -758,7 +476,6 @@ static void dump_line_sprites(const nes_ppu* ppu, int line,

static void render_scanline(nes_ppu* ppu, int line,
sdl_render_data* data) {

SDL_Rect dst_rect = {
.x = 0,
.y = line,
@@ -788,7 +505,6 @@ static void render_scanline(nes_ppu* ppu, int line,
.h = 1,
};

uint8_t* foreground = data->foreground->pixels;
uint8_t* background = data->background->pixels;

// We check for hits if EITHER layer is enabled.
@@ -797,25 +513,26 @@ static void render_scanline(nes_ppu* ppu, int line,
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);
oam_sprite line_sprites[8] = {0};
int n_sprites = select_line_sprites(ppu, line,
line_sprites, 8);

dump_line_sprites(ppu, line, line_sprites, n_sprites);
dump_line_sprites(ppu, line, line_sprites, n_sprites);

if (ppu->mask & ppu_Mask_Back) {
SDL_BlitSurface(data->background, &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, background,
line_sprites, n_sprites);
SDL_BlitSurface(data->foreground, &src_rect,
data->target, &dst_rect);
}
if (ppu->mask & ppu_Mask_Sprite) {
uint8_t* foreground = data->foreground->pixels;
memset(foreground, 0xFFU, nes_ppu_render_w);

render_line_sprites(ppu, foreground, line, background,
line_sprites, n_sprites);

SDL_BlitSurface(data->foreground, &src_rect,
data->target, &dst_rect);
}
}

@@ -825,34 +542,10 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) {

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);
*/
// TODO: Perform evaluations here?

} 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,
@@ -862,37 +555,7 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) {

} 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
);


Loading…
Откажи
Сачувај