Fix debug pattern rendering

This commit is contained in:
william 2024-07-21 16:41:38 -04:00
parent a533af7901
commit 8ce002e307
10 changed files with 202 additions and 55 deletions

View File

@ -1,5 +1,5 @@
set(HEADERS canvas.h gui.h window.h main_window.h char_map.h pattern_display.h pattern_window.h nametable_window.h) set(HEADERS canvas.h gui.h window.h main_window.h char_map.h pattern_display.h pattern_window.h nametable_window.h dbg_pattern_table.h)
set(SOURCE canvas.c gui.c window.c main_window.c char_map.c pattern_display.c pattern_window.c nametable_window.c) set(SOURCE canvas.c gui.c window.c main_window.c char_map.c pattern_display.c pattern_window.c nametable_window.c dbg_pattern_table.c)
add_library(nes_gui ${SOURCE} ${HEADERS}) add_library(nes_gui ${SOURCE} ${HEADERS})

96
gui/dbg_pattern_table.c Normal file
View File

@ -0,0 +1,96 @@
//
// Created by william on 7/12/24.
//
#include <assert.h>
#include <stdbool.h>
#include "dbg_pattern_table.h"
#include "../include/ppu.h"
#include "../include/system.h"
DebugPatternTable pattern_table;
void dbg_pattern_table_build_bank(DebugPattern *bank, byte *pattern_memory) {
for (int tile_index = 0; tile_index < PATTERN_TABLE_SIZE; tile_index++) {
DebugPattern *pattern = &bank[tile_index];
address tile_addr = tile_index * PATTERN_BYTES;
memcpy(pattern->data_low, &pattern_memory[tile_addr], PATTERN_SIZE);
memcpy(pattern->data_high, &pattern_memory[tile_addr + PATTERN_SIZE], PATTERN_SIZE);
}
}
void dbg_pattern_table_init() {
byte *pattern_memory = system_get_mapper()->ppu_read(0);
dbg_pattern_table_build_bank(pattern_table.bank_0, pattern_memory);
dbg_pattern_table_build_bank(pattern_table.bank_1, &pattern_memory[PATTERN_BANK_SIZE]);
}
DebugPattern dbg_pattern_get(int x, int y, int bank) {
address pattern_addr = x + y * PATTERN_TABLE_WIDTH;
switch (bank) {
case PATTERN_BANK_0:
return pattern_table.bank_0[pattern_addr];
case PATTERN_BANK_1:
return pattern_table.bank_1[pattern_addr];
default:
assert(false);
}
}
void dbg_pattern_draw_borders(pixel *buffer, int buffer_width) {
for (int by = 0; by < PATTERN_DRAW_SIZE; by++) {
address pixel_addr = (by * buffer_width) + PATTERN_DRAW_SIZE - 1;
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
}
for (int bx = 0; bx < PATTERN_DRAW_SIZE; bx++) {
address pixel_addr = ((PATTERN_DRAW_SIZE - 1) * buffer_width) + bx;
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
}
}
void dbg_pattern_draw(int x, int y, int bank, pixel *buffer, int buffer_width) {
DebugPattern pattern = dbg_pattern_get(x, y, bank);
for (int fine_y = 0; fine_y < PATTERN_SIZE; fine_y++) {
byte data_high = pattern.data_high[fine_y];
byte data_low = pattern.data_low[fine_y];
for (int fine_x = 0; fine_x < PATTERN_SIZE; fine_x++) {
byte bitmask = 1 << (PATTERN_SIZE - fine_x - 1);
byte bit_high = data_high & bitmask;
byte bit_low = data_low & bitmask;
address pixel_addr = fine_x + fine_y * buffer_width;
pixel *pixel = &buffer[pixel_addr];
// TODO: Use palette colors
if (bit_high && bit_low) {
*pixel = 0xffffffff;
} else if (bit_low) {
*pixel = 0xffff0000;
} else if (bit_high) {
*pixel = 0xff00ffff;
} else {
*pixel = 0xff000000;
}
}
}
dbg_pattern_draw_borders(buffer, buffer_width);
}
void dbg_pattern_draw_bank(int bank, pixel *buffer) {
int buffer_width = PATTERN_TABLE_WIDTH * PATTERN_DRAW_SIZE;
for (int x = 0; x < PATTERN_TABLE_WIDTH; x++) {
for (int y = 0; y < PATTERN_TABLE_WIDTH; y++) {
address row_addr = (y * PATTERN_DRAW_SIZE) * buffer_width;
address tile_addr = row_addr + (x * PATTERN_DRAW_SIZE);
dbg_pattern_draw(x, y, bank, &buffer[tile_addr], buffer_width);
}
}
}

43
gui/dbg_pattern_table.h Normal file
View File

@ -0,0 +1,43 @@
//
// Created by william on 7/12/24.
//
#ifndef NES_EMULATOR_DBG_PATTERN_TABLE_H
#define NES_EMULATOR_DBG_PATTERN_TABLE_H
#include <string.h>
#include "../include/types.h"
#define PATTERN_BANK_SIZE 0x1000
#define PATTERN_TABLE_WIDTH 0x10
#define PATTERN_TABLE_SIZE (PATTERN_TABLE_WIDTH * PATTERN_TABLE_WIDTH)
#define PATTERN_SIZE 8
#define PATTERN_BYTES (PATTERN_SIZE * 2)
#define PATTERN_BORDER_WIDTH 1
#define PATTERN_BORDER_COLOR 0xff2223b2
#define PATTERN_DRAW_SIZE (PATTERN_SIZE + PATTERN_BORDER_WIDTH)
#define PATTERN_BANK_0 0
#define PATTERN_BANK_1 1
typedef unsigned int pixel;
typedef struct dbg_pattern {
byte data_low[PATTERN_SIZE];
byte data_high[PATTERN_SIZE];
} DebugPattern;
typedef struct dbg_pattern_table {
DebugPattern bank_0[PATTERN_TABLE_SIZE];
DebugPattern bank_1[PATTERN_TABLE_SIZE];
} DebugPatternTable;
void dbg_pattern_table_init();
DebugPattern dbg_pattern_get(int x, int y, int bank);
void dbg_pattern_draw(int x, int y, int bank, pixel *buffer, int buffer_width);
void dbg_pattern_draw_bank(int bank, pixel *buffer);
#endif //NES_EMULATOR_DBG_PATTERN_TABLE_H

View File

@ -9,6 +9,7 @@
#include "pattern_window.h" #include "pattern_window.h"
#include "../include/system.h" #include "../include/system.h"
#include "nametable_window.h" #include "nametable_window.h"
#include "dbg_pattern_table.h"
typedef struct nes_gui { typedef struct nes_gui {
NesMainWindow main_window; NesMainWindow main_window;
@ -21,6 +22,7 @@ typedef struct nes_gui {
bool debug_enabled; bool debug_enabled;
Uint32 last_frame_tick; Uint32 last_frame_tick;
Uint32 frame_delay; Uint32 frame_delay;
unsigned long tick;
} NesGui; } NesGui;
NesGui gui; NesGui gui;
@ -32,16 +34,14 @@ bool gui_init() {
return false; return false;
} }
gui.debug_enabled = false; gui.debug_enabled = true;
gui.tick = 0;
main_window_init(&gui.main_window, gui.font); main_window_init(&gui.main_window, gui.font);
if (gui.debug_enabled) { if (gui.debug_enabled) {
byte *pattern_memory = system_get_mapper()->ppu_read(0); pattern_window_init(&gui.pattern_window);
pattern_window_init(&gui.pattern_window, pattern_memory); // nametable_window_init(&gui.nametable_window);
PPUMemory *ppu_memory = &ppu_get_state()->memory;
nametable_window_init(&gui.nametable_window, ppu_memory->nametable_0, ppu_memory->nametable_1);
} }
return true; return true;
@ -52,7 +52,7 @@ void gui_uninit() {
if (gui.debug_enabled) { if (gui.debug_enabled) {
pattern_window_uninit(&gui.pattern_window); pattern_window_uninit(&gui.pattern_window);
nametable_window_uninit(&gui.nametable_window); // nametable_window_uninit(&gui.nametable_window);
} }
TTF_CloseFont(gui.font); TTF_CloseFont(gui.font);
@ -60,8 +60,9 @@ void gui_uninit() {
void gui_post_sysinit() { void gui_post_sysinit() {
if (gui.debug_enabled) { if (gui.debug_enabled) {
dbg_pattern_table_init();
pattern_window_build_table(&gui.pattern_window); pattern_window_build_table(&gui.pattern_window);
nametable_window_update(&gui.nametable_window);
} }
} }
@ -82,8 +83,15 @@ void gui_render() {
if (gui.debug_enabled) { if (gui.debug_enabled) {
pattern_window_render(&gui.pattern_window); pattern_window_render(&gui.pattern_window);
nametable_window_render(&gui.nametable_window);
// if (gui.tick % 60 == 0) {
// PPUMemory *ppu_memory = &ppu_get_state()->memory;
// nametable_window_update(&gui.nametable_window, ppu_memory->nametable_0, ppu_memory->nametable_1);
// }
// nametable_window_render(&gui.nametable_window);
} }
gui.tick++;
} }
void gui_present() { void gui_present() {
@ -91,7 +99,7 @@ void gui_present() {
if (gui.debug_enabled) { if (gui.debug_enabled) {
pattern_window_present(&gui.pattern_window); pattern_window_present(&gui.pattern_window);
nametable_window_present(&gui.nametable_window); // nametable_window_present(&gui.nametable_window);
} }
} }

View File

@ -7,14 +7,11 @@
#define NAMETABLE_BANK_SIZE 0x0400 #define NAMETABLE_BANK_SIZE 0x0400
void nametable_window_init(NesNametableWindow *window, byte *nametable_0, byte *nametable_1) { void nametable_window_init(NesNametableWindow *window) {
int win_size = pattern_display_get_size(NW_ROW_TILE_COUNT); int win_size = pattern_display_get_size(NW_ROW_TILE_COUNT);
window->sdl_context = window_init("Nametable", win_size, win_size, NW_SCALE); window->sdl_context = window_init("Nametable", win_size, win_size, NW_SCALE);
window->nametable_0 = nametable_0; pattern_display_init(&window->pattern_display, window->sdl_context.renderer, NW_ROW_TILE_COUNT, NW_ROW_TILE_COUNT - 2,
window->nametable_1 = nametable_1;
pattern_display_init(&window->pattern_display, window->sdl_context.renderer, NW_ROW_TILE_COUNT, NW_ROW_TILE_COUNT,
PATTERN_DISPLAY_DYNAMIC); PATTERN_DISPLAY_DYNAMIC);
} }
@ -27,7 +24,7 @@ static byte *nametable_window_read_byte(address addr, void *data) {
assert(addr < NAMETABLE_BANK_SIZE * 4); assert(addr < NAMETABLE_BANK_SIZE * 4);
assert(data != NULL); assert(data != NULL);
NesNametableWindow *window = (NesNametableWindow *) data; byte **nametables = (byte **) data;
int bank = addr / NAMETABLE_BANK_SIZE; int bank = addr / NAMETABLE_BANK_SIZE;
int bank_addr = addr % NAMETABLE_BANK_SIZE; int bank_addr = addr % NAMETABLE_BANK_SIZE;
@ -35,14 +32,18 @@ static byte *nametable_window_read_byte(address addr, void *data) {
switch (bank) { switch (bank) {
case 0: case 0:
case 1: case 1:
return &window->nametable_0[bank_addr]; return &nametables[0][bank_addr];
default: default:
return &window->nametable_1[bank_addr]; return &nametables[1][bank_addr];
} }
} }
void nametable_window_update(NesNametableWindow *window) { void nametable_window_update(NesNametableWindow *window, byte *nametable_0, byte *nametable_1) {
pattern_display_build(&window->pattern_display, &nametable_window_read_byte, window); byte **nametables[2];
nametables[0] = &nametable_0;
nametables[1] = &nametable_1;
pattern_display_build(&window->pattern_display, &nametable_window_read_byte, nametables);
} }
void nametable_window_render(NesNametableWindow *window) { void nametable_window_render(NesNametableWindow *window) {

View File

@ -15,15 +15,12 @@
typedef struct nes_nametable_window { typedef struct nes_nametable_window {
NesSdlContext sdl_context; NesSdlContext sdl_context;
PatternDisplay pattern_display; PatternDisplay pattern_display;
byte *nametable_0;
byte *nametable_1;
} NesNametableWindow; } NesNametableWindow;
void nametable_window_init(NesNametableWindow *window, byte* nametable_0, byte* nametable_1); void nametable_window_init(NesNametableWindow *window);
void nametable_window_uninit(NesNametableWindow *window); void nametable_window_uninit(NesNametableWindow *window);
void nametable_window_update(NesNametableWindow *window); void nametable_window_update(NesNametableWindow *window, byte* nametable_0, byte* nametable_1);
void nametable_window_render(NesNametableWindow *window); void nametable_window_render(NesNametableWindow *window);
void nametable_window_present(NesNametableWindow *window); void nametable_window_present(NesNametableWindow *window);

View File

@ -2,41 +2,43 @@
// Created by william on 6/14/24. // Created by william on 6/14/24.
// //
#include <assert.h>
#include "pattern_window.h" #include "pattern_window.h"
#include "dbg_pattern_table.h"
#define PW_SCALE 2 #define PW_SCALE 2
#define PW_WIDTH (PW_ROW_TILE_COUNT * PATTERN_DRAW_SIZE)
#define PW_HEIGHT (PW_WIDTH * 2)
#define PW_BUFFER_SIZE (PW_WIDTH * PW_HEIGHT)
void pattern_window_init(NesPatternWindow *window, byte *pattern_memory) { void pattern_window_init(NesPatternWindow *window) {
int win_width = pattern_display_get_size(PW_ROW_TILE_COUNT); int win_width = pattern_display_get_size(PW_ROW_TILE_COUNT);
window->sdl_context = window_init("Pattern Table", win_width, win_width * 2, PW_SCALE); window->sdl_context = window_init("Pattern Table", win_width, win_width * 2, PW_SCALE);
window->pattern_memory = pattern_memory;
pattern_display_init(&window->pattern_display, window->sdl_context.renderer, PW_ROW_TILE_COUNT, window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888,
PW_ROW_TILE_COUNT * 2, PATTERN_DISPLAY_STATIC); SDL_TEXTUREACCESS_STATIC, PW_WIDTH, PW_HEIGHT);
// pattern_display_init(&window->pattern_display, window->sdl_context.renderer, PW_ROW_TILE_COUNT,
// PW_ROW_TILE_COUNT * 2, PATTERN_DISPLAY_STATIC);
} }
void pattern_window_uninit(NesPatternWindow *window) { void pattern_window_uninit(NesPatternWindow *window) {
pattern_display_uninit(&window->pattern_display); SDL_DestroyTexture(window->texture);
// pattern_display_uninit(&window->pattern_display);
window_uninit(window->sdl_context); window_uninit(window->sdl_context);
} }
static byte *pattern_window_read_byte(address addr, void *data) {
assert(data != NULL);
assert(addr < 0x2000);
NesPatternWindow *window = (NesPatternWindow *) data;
return &window->pattern_memory[addr];
}
void pattern_window_build_table(NesPatternWindow *window) { void pattern_window_build_table(NesPatternWindow *window) {
pattern_display_build(&window->pattern_display, &pattern_window_read_byte, window); pixel buffer[PW_BUFFER_SIZE] = {0};
dbg_pattern_draw_bank(PATTERN_BANK_0, buffer);
dbg_pattern_draw_bank(PATTERN_BANK_1, &buffer[PW_WIDTH * (PW_HEIGHT / 2)]);
SDL_UpdateTexture(window->texture, NULL, buffer, PW_WIDTH * sizeof(pixel));
} }
void pattern_window_render(NesPatternWindow *window) { void pattern_window_render(NesPatternWindow *window) {
SDL_RenderClear(window->sdl_context.renderer); SDL_RenderClear(window->sdl_context.renderer);
pattern_display_render(&window->pattern_display, window->sdl_context.renderer); SDL_RenderCopy(window->sdl_context.renderer, window->texture, NULL, NULL);
// pattern_display_render(&window->pattern_display, window->sdl_context.renderer);
} }
void pattern_window_present(NesPatternWindow *window) { void pattern_window_present(NesPatternWindow *window) {

View File

@ -14,10 +14,10 @@
typedef struct nes_pattern_window { typedef struct nes_pattern_window {
NesSdlContext sdl_context; NesSdlContext sdl_context;
PatternDisplay pattern_display; PatternDisplay pattern_display;
byte* pattern_memory; SDL_Texture *texture;
} NesPatternWindow; } NesPatternWindow;
void pattern_window_init(NesPatternWindow *window, byte *pattern_memory); void pattern_window_init(NesPatternWindow *window);
void pattern_window_uninit(NesPatternWindow *window); void pattern_window_uninit(NesPatternWindow *window);
void pattern_window_build_table(NesPatternWindow *window); void pattern_window_build_table(NesPatternWindow *window);

View File

@ -52,14 +52,14 @@
#define PPU_MASK_NONE 0xff #define PPU_MASK_NONE 0xff
#define PATTERN_TABLE_SIZE 0x1000 #define PATTERN_TABLE_BYTES_SIZE 0x1000
#define NAMETABLE_SIZE 0x0400 #define NAMETABLE_BYTES_SIZE 0x0400
#define PALETTE_TABLE_SIZE 0x0020 #define PALETTE_TABLE_BYTES_SIZE 0x0020
typedef struct ppu_memory { typedef struct ppu_memory {
byte nametable_0[NAMETABLE_SIZE]; byte nametable_0[NAMETABLE_BYTES_SIZE];
byte nametable_1[NAMETABLE_SIZE]; byte nametable_1[NAMETABLE_BYTES_SIZE];
byte palette[PALETTE_TABLE_SIZE]; byte palette[PALETTE_TABLE_BYTES_SIZE];
} PPUMemory; } PPUMemory;
typedef struct ppu_tile_fetch { typedef struct ppu_tile_fetch {

View File

@ -252,7 +252,7 @@ void ppu_cycle() {
ppu_post_render(ppu_state.cycle, ppu_state.scanline); ppu_post_render(ppu_state.cycle, ppu_state.scanline);
} else if (ppu_state.scanline == PPU_PRE_RENDER_LINE) { } else if (ppu_state.scanline == PPU_PRE_RENDER_LINE) {
ppu_pre_render(ppu_state.cycle); ppu_pre_render(ppu_state.cycle);
ppu_visible_frame(ppu_state.cycle); // ppu_visible_frame(ppu_state.cycle);
ppu_state.ppu_address = ppu_state.temp_ppu_addr; ppu_state.ppu_address = ppu_state.temp_ppu_addr;
} }
@ -315,7 +315,7 @@ void ppu_write(address addr, byte data) {
relative_addr = addr - 0x2c00; relative_addr = addr - 0x2c00;
ppu_state.memory.nametable_1[relative_addr] = data; ppu_state.memory.nametable_1[relative_addr] = data;
} else if (addr >= 0x3f00) { } else if (addr >= 0x3f00) {
relative_addr = (addr - 0x3f00) % PALETTE_TABLE_SIZE; relative_addr = (addr - 0x3f00) % PALETTE_TABLE_BYTES_SIZE;
ppu_state.memory.palette[relative_addr] = data; ppu_state.memory.palette[relative_addr] = data;
} }
} }
@ -356,7 +356,7 @@ byte ppu_read(address addr) {
relative_addr = addr - 0x2c00; relative_addr = addr - 0x2c00;
return ppu_state.memory.nametable_1[relative_addr]; return ppu_state.memory.nametable_1[relative_addr];
} else if (addr >= 0x3f00) { } else if (addr >= 0x3f00) {
relative_addr = (addr - 0x3f00) % PALETTE_TABLE_SIZE; relative_addr = (addr - 0x3f00) % PALETTE_TABLE_BYTES_SIZE;
return ppu_state.memory.palette[relative_addr]; return ppu_state.memory.palette[relative_addr];
} }