Fix debug pattern rendering
This commit is contained in:
parent
a533af7901
commit
8ce002e307
|
@ -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(SOURCE canvas.c gui.c window.c main_window.c char_map.c pattern_display.c pattern_window.c nametable_window.c)
|
||||
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 dbg_pattern_table.c)
|
||||
|
||||
add_library(nes_gui ${SOURCE} ${HEADERS})
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
28
gui/gui.c
28
gui/gui.c
|
@ -9,6 +9,7 @@
|
|||
#include "pattern_window.h"
|
||||
#include "../include/system.h"
|
||||
#include "nametable_window.h"
|
||||
#include "dbg_pattern_table.h"
|
||||
|
||||
typedef struct nes_gui {
|
||||
NesMainWindow main_window;
|
||||
|
@ -21,6 +22,7 @@ typedef struct nes_gui {
|
|||
bool debug_enabled;
|
||||
Uint32 last_frame_tick;
|
||||
Uint32 frame_delay;
|
||||
unsigned long tick;
|
||||
} NesGui;
|
||||
NesGui gui;
|
||||
|
||||
|
@ -32,16 +34,14 @@ bool gui_init() {
|
|||
return false;
|
||||
}
|
||||
|
||||
gui.debug_enabled = false;
|
||||
gui.debug_enabled = true;
|
||||
gui.tick = 0;
|
||||
|
||||
main_window_init(&gui.main_window, gui.font);
|
||||
|
||||
if (gui.debug_enabled) {
|
||||
byte *pattern_memory = system_get_mapper()->ppu_read(0);
|
||||
pattern_window_init(&gui.pattern_window, pattern_memory);
|
||||
|
||||
PPUMemory *ppu_memory = &ppu_get_state()->memory;
|
||||
nametable_window_init(&gui.nametable_window, ppu_memory->nametable_0, ppu_memory->nametable_1);
|
||||
pattern_window_init(&gui.pattern_window);
|
||||
// nametable_window_init(&gui.nametable_window);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -52,7 +52,7 @@ void gui_uninit() {
|
|||
|
||||
if (gui.debug_enabled) {
|
||||
pattern_window_uninit(&gui.pattern_window);
|
||||
nametable_window_uninit(&gui.nametable_window);
|
||||
// nametable_window_uninit(&gui.nametable_window);
|
||||
}
|
||||
|
||||
TTF_CloseFont(gui.font);
|
||||
|
@ -60,8 +60,9 @@ void gui_uninit() {
|
|||
|
||||
void gui_post_sysinit() {
|
||||
if (gui.debug_enabled) {
|
||||
dbg_pattern_table_init();
|
||||
|
||||
pattern_window_build_table(&gui.pattern_window);
|
||||
nametable_window_update(&gui.nametable_window);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,8 +83,15 @@ void gui_render() {
|
|||
|
||||
if (gui.debug_enabled) {
|
||||
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() {
|
||||
|
@ -91,7 +99,7 @@ void gui_present() {
|
|||
|
||||
if (gui.debug_enabled) {
|
||||
pattern_window_present(&gui.pattern_window);
|
||||
nametable_window_present(&gui.nametable_window);
|
||||
// nametable_window_present(&gui.nametable_window);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,14 +7,11 @@
|
|||
|
||||
#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);
|
||||
window->sdl_context = window_init("Nametable", win_size, win_size, NW_SCALE);
|
||||
|
||||
window->nametable_0 = nametable_0;
|
||||
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_init(&window->pattern_display, window->sdl_context.renderer, NW_ROW_TILE_COUNT, NW_ROW_TILE_COUNT - 2,
|
||||
PATTERN_DISPLAY_DYNAMIC);
|
||||
}
|
||||
|
||||
|
@ -27,7 +24,7 @@ static byte *nametable_window_read_byte(address addr, void *data) {
|
|||
assert(addr < NAMETABLE_BANK_SIZE * 4);
|
||||
assert(data != NULL);
|
||||
|
||||
NesNametableWindow *window = (NesNametableWindow *) data;
|
||||
byte **nametables = (byte **) data;
|
||||
|
||||
int bank = 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) {
|
||||
case 0:
|
||||
case 1:
|
||||
return &window->nametable_0[bank_addr];
|
||||
return &nametables[0][bank_addr];
|
||||
default:
|
||||
return &window->nametable_1[bank_addr];
|
||||
return &nametables[1][bank_addr];
|
||||
}
|
||||
}
|
||||
|
||||
void nametable_window_update(NesNametableWindow *window) {
|
||||
pattern_display_build(&window->pattern_display, &nametable_window_read_byte, window);
|
||||
void nametable_window_update(NesNametableWindow *window, byte *nametable_0, byte *nametable_1) {
|
||||
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) {
|
||||
|
|
|
@ -15,15 +15,12 @@
|
|||
typedef struct nes_nametable_window {
|
||||
NesSdlContext sdl_context;
|
||||
PatternDisplay pattern_display;
|
||||
|
||||
byte *nametable_0;
|
||||
byte *nametable_1;
|
||||
} 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_update(NesNametableWindow *window);
|
||||
void nametable_window_update(NesNametableWindow *window, byte* nametable_0, byte* nametable_1);
|
||||
|
||||
void nametable_window_render(NesNametableWindow *window);
|
||||
void nametable_window_present(NesNametableWindow *window);
|
||||
|
|
|
@ -2,41 +2,43 @@
|
|||
// Created by william on 6/14/24.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include "pattern_window.h"
|
||||
#include "dbg_pattern_table.h"
|
||||
|
||||
#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);
|
||||
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,
|
||||
PW_ROW_TILE_COUNT * 2, PATTERN_DISPLAY_STATIC);
|
||||
window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888,
|
||||
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) {
|
||||
pattern_display_uninit(&window->pattern_display);
|
||||
SDL_DestroyTexture(window->texture);
|
||||
// pattern_display_uninit(&window->pattern_display);
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
typedef struct nes_pattern_window {
|
||||
NesSdlContext sdl_context;
|
||||
PatternDisplay pattern_display;
|
||||
byte* pattern_memory;
|
||||
SDL_Texture *texture;
|
||||
} 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_build_table(NesPatternWindow *window);
|
||||
|
|
|
@ -52,14 +52,14 @@
|
|||
|
||||
#define PPU_MASK_NONE 0xff
|
||||
|
||||
#define PATTERN_TABLE_SIZE 0x1000
|
||||
#define NAMETABLE_SIZE 0x0400
|
||||
#define PALETTE_TABLE_SIZE 0x0020
|
||||
#define PATTERN_TABLE_BYTES_SIZE 0x1000
|
||||
#define NAMETABLE_BYTES_SIZE 0x0400
|
||||
#define PALETTE_TABLE_BYTES_SIZE 0x0020
|
||||
|
||||
typedef struct ppu_memory {
|
||||
byte nametable_0[NAMETABLE_SIZE];
|
||||
byte nametable_1[NAMETABLE_SIZE];
|
||||
byte palette[PALETTE_TABLE_SIZE];
|
||||
byte nametable_0[NAMETABLE_BYTES_SIZE];
|
||||
byte nametable_1[NAMETABLE_BYTES_SIZE];
|
||||
byte palette[PALETTE_TABLE_BYTES_SIZE];
|
||||
} PPUMemory;
|
||||
|
||||
typedef struct ppu_tile_fetch {
|
||||
|
|
|
@ -252,7 +252,7 @@ void ppu_cycle() {
|
|||
ppu_post_render(ppu_state.cycle, ppu_state.scanline);
|
||||
} else if (ppu_state.scanline == PPU_PRE_RENDER_LINE) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -315,7 +315,7 @@ void ppu_write(address addr, byte data) {
|
|||
relative_addr = addr - 0x2c00;
|
||||
ppu_state.memory.nametable_1[relative_addr] = data;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ byte ppu_read(address addr) {
|
|||
relative_addr = addr - 0x2c00;
|
||||
return ppu_state.memory.nametable_1[relative_addr];
|
||||
} 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];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue