Start nametable debugger
This commit is contained in:
parent
78160ed311
commit
97d46b4583
|
@ -1,5 +1,5 @@
|
|||
set(HEADERS canvas.h gui.h window.h main_window.h char_map.h pattern_window.h)
|
||||
set(SOURCE canvas.c gui.c window.c main_window.c char_map.c pattern_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)
|
||||
set(SOURCE canvas.c gui.c window.c main_window.c char_map.c pattern_display.c pattern_window.c nametable_window.c)
|
||||
|
||||
add_library(nes_gui ${SOURCE} ${HEADERS})
|
||||
|
||||
|
|
14
gui/gui.c
14
gui/gui.c
|
@ -8,10 +8,12 @@
|
|||
#include "main_window.h"
|
||||
#include "pattern_window.h"
|
||||
#include "../include/system.h"
|
||||
#include "nametable_window.h"
|
||||
|
||||
typedef struct nes_gui {
|
||||
NesMainWindow main_window;
|
||||
NesPatternWindow pattern_window;
|
||||
NesNametableWindow nametable_window;
|
||||
|
||||
TTF_Font *font;
|
||||
|
||||
|
@ -30,12 +32,13 @@ bool gui_init() {
|
|||
return false;
|
||||
}
|
||||
|
||||
gui.debug_enabled = false;
|
||||
gui.debug_enabled = true;
|
||||
|
||||
main_window_init(&gui.main_window, gui.font);
|
||||
|
||||
if (gui.debug_enabled) {
|
||||
pattern_window_init(&gui.pattern_window);
|
||||
nametable_window_init(&gui.nametable_window);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -46,6 +49,7 @@ void gui_uninit() {
|
|||
|
||||
if (gui.debug_enabled) {
|
||||
pattern_window_uninit(&gui.pattern_window);
|
||||
nametable_window_uninit(&gui.nametable_window);
|
||||
}
|
||||
|
||||
TTF_CloseFont(gui.font);
|
||||
|
@ -53,7 +57,15 @@ void gui_uninit() {
|
|||
|
||||
void gui_post_sysinit() {
|
||||
byte *pattern_memory = system_get_mapper()->ppu_read(0);
|
||||
byte nametable_memory[0x0400 * 4];
|
||||
|
||||
memcpy(&nametable_memory, ppu_get_state()->memory.nametable_0, 0x0400);
|
||||
memcpy(&nametable_memory[0x0400], ppu_get_state()->memory.nametable_0, 0x0400);
|
||||
memcpy(&nametable_memory[0x0800], ppu_get_state()->memory.nametable_1, 0x0400);
|
||||
memcpy(&nametable_memory[0x0c00], ppu_get_state()->memory.nametable_1, 0x0400);
|
||||
|
||||
pattern_window_build_table(&gui.pattern_window, pattern_memory);
|
||||
nametable_window_build_table(&gui.nametable_window, &nametable_memory[0]);
|
||||
}
|
||||
|
||||
int gui_input() {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by william on 12/07/24.
|
||||
//
|
||||
|
||||
#include "nametable_window.h"
|
||||
|
||||
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);
|
||||
|
||||
pattern_display_init(&window->pattern_display, window->sdl_context.renderer, NW_ROW_TILE_COUNT, NW_ROW_TILE_COUNT);
|
||||
}
|
||||
|
||||
void nametable_window_uninit(NesNametableWindow *window) {
|
||||
pattern_display_uninit(&window->pattern_display);
|
||||
window_uninit(window->sdl_context);
|
||||
}
|
||||
|
||||
void nametable_window_build_table(NesNametableWindow *window, byte *nametable_memory) {
|
||||
pattern_display_build(&window->pattern_display, nametable_memory);
|
||||
}
|
||||
|
||||
void nametable_window_render(NesNametableWindow *window) {
|
||||
SDL_RenderClear(window->sdl_context.renderer);
|
||||
pattern_display_render(&window->pattern_display, window->sdl_context.renderer);
|
||||
}
|
||||
|
||||
void nametable_window_present(NesNametableWindow *window) {
|
||||
SDL_RenderPresent(window->sdl_context.renderer);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Created by william on 12/07/24.
|
||||
//
|
||||
|
||||
#ifndef NES_EMULATOR_NAMETABLE_WINDOW_H
|
||||
#define NES_EMULATOR_NAMETABLE_WINDOW_H
|
||||
|
||||
#include "window.h"
|
||||
#include "../include/types.h"
|
||||
#include "pattern_display.h"
|
||||
|
||||
#define NW_SCALE 2
|
||||
#define NW_ROW_TILE_COUNT 32
|
||||
|
||||
typedef struct nes_nametable_window {
|
||||
NesSdlContext sdl_context;
|
||||
PatternDisplay pattern_display;
|
||||
} NesNametableWindow;
|
||||
|
||||
void nametable_window_init(NesNametableWindow *window);
|
||||
void nametable_window_uninit(NesNametableWindow *window);
|
||||
|
||||
void nametable_window_build_table(NesNametableWindow *window, byte* nametable_memory);
|
||||
|
||||
void nametable_window_render(NesNametableWindow *window);
|
||||
void nametable_window_present(NesNametableWindow *window);
|
||||
|
||||
#endif //NES_EMULATOR_NAMETABLE_WINDOW_H
|
|
@ -0,0 +1,122 @@
|
|||
//
|
||||
// Created by william on 12/07/24.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include "pattern_display.h"
|
||||
|
||||
#define PATTERN_BYTES (PATTERN_SIZE * 2)
|
||||
|
||||
void pattern_display_init(PatternDisplay *display, SDL_Renderer *renderer, int tiles_x, int tiles_y) {
|
||||
assert(tiles_x > 0);
|
||||
assert(tiles_y > 0);
|
||||
|
||||
display->width = tiles_x;
|
||||
display->height = tiles_y;
|
||||
|
||||
display->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC,
|
||||
pattern_display_get_size(tiles_x),
|
||||
pattern_display_get_size(tiles_y));
|
||||
}
|
||||
|
||||
void pattern_display_uninit(PatternDisplay *display) {
|
||||
SDL_DestroyTexture(display->texture);
|
||||
}
|
||||
|
||||
void pattern_display_draw_borders(unsigned int *buffer, int win_width, int win_height) {
|
||||
assert(buffer != NULL);
|
||||
|
||||
for (int x = 0; x < win_width; x++) {
|
||||
buffer[x] = PATTERN_BORDER_COLOR;
|
||||
}
|
||||
|
||||
for (int y = 1; y < win_height; y++) {
|
||||
buffer[y * win_width] = PATTERN_BORDER_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_display_build_table(PatternTile *tile_table, byte *memory, int tile_count) {
|
||||
for (int tile_index = 0; tile_index < tile_count; tile_index++) {
|
||||
PatternTile *tile = &tile_table[tile_index];
|
||||
|
||||
address tile_addr = tile_index * PATTERN_BYTES;
|
||||
memcpy(tile->data_low, &memory[tile_addr], 8);
|
||||
memcpy(tile->data_high, &memory[tile_addr + 8], 8);
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_display_draw_tile_borders(int tile_addr, pixel *buffer, int win_width) {
|
||||
assert(buffer != NULL);
|
||||
|
||||
for (int by = 0; by < PATTERN_DRAW_SIZE; by++) {
|
||||
address pixel_addr = tile_addr + (by * win_width) + PATTERN_DRAW_SIZE - 1;
|
||||
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
|
||||
}
|
||||
|
||||
for (int bx = 0; bx < PATTERN_DRAW_SIZE; bx++) {
|
||||
address pixel_addr = tile_addr + ((PATTERN_DRAW_SIZE - 1) * win_width) + bx;
|
||||
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_display_draw_tile(PatternTile *tile, pixel *buffer, int tile_addr, int win_width) {
|
||||
assert(buffer != NULL);
|
||||
|
||||
for (int fine_y = 0; fine_y < PATTERN_SIZE; fine_y++) {
|
||||
byte data_high = tile->data_high[fine_y];
|
||||
byte data_low = tile->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;
|
||||
|
||||
int pixel_addr = tile_addr + fine_x + fine_y * win_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pattern_display_draw_tile_borders(tile_addr, buffer, win_width);
|
||||
}
|
||||
|
||||
void pattern_display_build(PatternDisplay *display, byte *memory) {
|
||||
int tile_count = display->width * display->height;
|
||||
PatternTile *tile_table = malloc(tile_count * sizeof(PatternTile));
|
||||
pattern_display_build_table(tile_table, memory, tile_count);
|
||||
|
||||
int win_width = pattern_display_get_size(display->width);
|
||||
int win_height = pattern_display_get_size(display->height);
|
||||
pixel *buffer = malloc(win_width * win_height * sizeof(pixel));
|
||||
|
||||
pattern_display_draw_borders(buffer, win_width, win_height);
|
||||
|
||||
for (int x = 0; x < display->width; x++) {
|
||||
for (int y = 0; y < display->height; y++) {
|
||||
PatternTile *tile = &tile_table[x + y * display->width];
|
||||
address row_addr = (y * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH) * win_width;
|
||||
address tile_addr = row_addr + (x * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH);
|
||||
|
||||
pattern_display_draw_tile(tile, buffer, tile_addr, win_width);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(display->texture, NULL, buffer, win_width * sizeof(pixel));
|
||||
|
||||
free(tile_table);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void pattern_display_render(PatternDisplay *display, SDL_Renderer *renderer) {
|
||||
SDL_RenderCopy(renderer, display->texture, NULL, NULL);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by william on 12/07/24.
|
||||
//
|
||||
|
||||
#ifndef NES_EMULATOR_PATTERN_DISPLAY_H
|
||||
#define NES_EMULATOR_PATTERN_DISPLAY_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include "../include/types.h"
|
||||
|
||||
#define PATTERN_SIZE 8
|
||||
#define PATTERN_BORDER_WIDTH 1
|
||||
#define PATTERN_BORDER_COLOR 0xff2223b2
|
||||
#define PATTERN_DRAW_SIZE (PATTERN_SIZE + PATTERN_BORDER_WIDTH)
|
||||
|
||||
typedef unsigned int pixel;
|
||||
|
||||
typedef struct pattern_tile {
|
||||
byte data_low[8];
|
||||
byte data_high[8];
|
||||
} PatternTile;
|
||||
|
||||
typedef struct pattern_display {
|
||||
SDL_Texture *texture;
|
||||
PatternTile *tiles;
|
||||
int width;
|
||||
int height;
|
||||
} PatternDisplay;
|
||||
|
||||
static inline int pattern_display_get_size(int tile_count) {
|
||||
return tile_count * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH;
|
||||
}
|
||||
|
||||
void pattern_display_init(PatternDisplay *display, SDL_Renderer *renderer, int tiles_x, int tiles_y);
|
||||
|
||||
void pattern_display_uninit(PatternDisplay *display);
|
||||
|
||||
void pattern_display_build(PatternDisplay *display, byte *memory);
|
||||
|
||||
void pattern_display_render(PatternDisplay *display, SDL_Renderer *renderer);
|
||||
|
||||
#endif //NES_EMULATOR_PATTERN_DISPLAY_H
|
|
@ -4,150 +4,28 @@
|
|||
|
||||
#include "pattern_window.h"
|
||||
|
||||
#define PW_TILE_SIZE 8
|
||||
#define PW_TILE_BYTES (PW_TILE_SIZE * 2)
|
||||
#define PW_BANK_SIZE 0x1000
|
||||
#define PW_BANK_TILE_COUNT (PW_ROW_TILE_COUNT * PW_ROW_TILE_COUNT)
|
||||
|
||||
#define PW_TILE_BORDER_WIDTH 1
|
||||
#define PW_TILE_BORDER_COLOR 0xff2223b2
|
||||
#define PW_TILE_DRAW_SIZE (PW_TILE_SIZE + PW_TILE_BORDER_WIDTH)
|
||||
|
||||
#define PW_WIDTH (PW_ROW_TILE_COUNT * PW_TILE_DRAW_SIZE + PW_TILE_BORDER_WIDTH)
|
||||
#define PW_HEIGHT (PW_ROW_TILE_COUNT * PW_TILE_DRAW_SIZE * 2 + PW_TILE_BORDER_WIDTH)
|
||||
#define PW_SCALE 2
|
||||
|
||||
void pattern_window_init(NesPatternWindow *window) {
|
||||
window->sdl_context = window_init("Pattern Table", PW_WIDTH, PW_HEIGHT, PW_SCALE);
|
||||
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->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);
|
||||
}
|
||||
|
||||
void pattern_window_uninit(NesPatternWindow *window) {
|
||||
pattern_display_uninit(&window->pattern_display);
|
||||
window_uninit(window->sdl_context);
|
||||
}
|
||||
|
||||
/*
|
||||
* d888888b d888888b db d88888b .d8888.
|
||||
* `~~88~~' `88' 88 88' 88' YP
|
||||
* 88 88 88 88ooooo `8bo.
|
||||
* 88 88 88 88~~~~~ `Y8b.
|
||||
* 88 .88. 88booo. 88. db 8D
|
||||
* YP Y888888P Y88888P Y88888P `8888Y'
|
||||
*/
|
||||
static PatternTile pattern_window_build_tile(int x, int y, byte *pattern_memory) {
|
||||
PatternTile tile;
|
||||
tile.x = x;
|
||||
tile.y = y;
|
||||
|
||||
address tile_addr = (x + y * PW_ROW_TILE_COUNT) * PW_TILE_BYTES;
|
||||
memcpy(tile.data_low, &pattern_memory[tile_addr], 8);
|
||||
memcpy(tile.data_high, &pattern_memory[tile_addr + 8], 8);
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
static void pattern_window_build_bank(byte *pattern_memory, PatternTile *bank) {
|
||||
for (int y = 0; y < PW_ROW_TILE_COUNT; y++) {
|
||||
for (int x = 0; x < PW_ROW_TILE_COUNT; x++) {
|
||||
int tile_index = y * PW_ROW_TILE_COUNT + x;
|
||||
PatternTile *tile = &bank[tile_index];
|
||||
*tile = pattern_window_build_tile(x, y, pattern_memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_window_build_tiles(NesPatternWindow *window, byte *pattern_memory) {
|
||||
pattern_window_build_bank(pattern_memory, window->tiles_bank_0);
|
||||
pattern_window_build_bank(&pattern_memory[PW_BANK_SIZE], window->tiles_bank_1);
|
||||
}
|
||||
|
||||
/*
|
||||
* d8888b. d88888b d8b db d8888b. d88888b d8888b. d888888b d8b db d888b
|
||||
* 88 `8D 88' 888o 88 88 `8D 88' 88 `8D `88' 888o 88 88' Y8b
|
||||
* 88oobY' 88ooooo 88V8o 88 88 88 88ooooo 88oobY' 88 88V8o 88 88
|
||||
* 88`8b 88~~~~~ 88 V8o88 88 88 88~~~~~ 88`8b 88 88 V8o88 88 ooo
|
||||
* 88 `88. 88. 88 V888 88 .8D 88. 88 `88. .88. 88 V888 88. ~8~
|
||||
* 88 YD Y88888P VP V8P Y8888D' Y88888P 88 YD Y888888P VP V8P Y888P
|
||||
*/
|
||||
static void pattern_window_draw_borders(unsigned int *buffer) {
|
||||
for (int x = 0; x < PW_WIDTH; x++) {
|
||||
buffer[x] = PW_TILE_BORDER_COLOR;
|
||||
}
|
||||
|
||||
for (int y = 1; y < PW_HEIGHT; y++) {
|
||||
buffer[y * PW_WIDTH] = PW_TILE_BORDER_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
static void pattern_window_draw_tile_borders(int tile_addr, unsigned int *buffer) {
|
||||
for (int by = 0; by < PW_TILE_DRAW_SIZE; by++) {
|
||||
int pixel_addr = tile_addr + (by * PW_WIDTH) + PW_TILE_DRAW_SIZE - 1;
|
||||
buffer[pixel_addr] = PW_TILE_BORDER_COLOR;
|
||||
}
|
||||
|
||||
for (int bx = 0; bx < PW_TILE_DRAW_SIZE; bx++) {
|
||||
int pixel_addr = tile_addr + ((PW_TILE_DRAW_SIZE - 1) * PW_WIDTH) + bx;
|
||||
buffer[pixel_addr] = PW_TILE_BORDER_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
static void pattern_window_draw_tile(PatternTile *tile, unsigned int *buffer) {
|
||||
int row_addr = (tile->y * PW_TILE_DRAW_SIZE + 1) * PW_WIDTH;
|
||||
int tile_buffer_addr = row_addr + (tile->x * PW_TILE_DRAW_SIZE + 1);
|
||||
|
||||
for (int fine_y = 0; fine_y < PW_TILE_SIZE; fine_y++) {
|
||||
byte data_high = tile->data_high[fine_y];
|
||||
byte data_low = tile->data_low[fine_y];
|
||||
|
||||
for (int fine_x = 0; fine_x < PW_TILE_SIZE; fine_x++) {
|
||||
byte bitmask = 1 << (PW_TILE_SIZE - fine_x - 1);
|
||||
byte bit_high = data_high & bitmask;
|
||||
byte bit_low = data_low & bitmask;
|
||||
|
||||
int pixel_addr = tile_buffer_addr + fine_x + fine_y * PW_WIDTH;
|
||||
unsigned int *pixel_data = &buffer[pixel_addr];
|
||||
|
||||
if (bit_high && bit_low) {
|
||||
*pixel_data = 0xffffffff;
|
||||
} else if (bit_low) {
|
||||
*pixel_data = 0xffff0000;
|
||||
} else if (bit_high) {
|
||||
*pixel_data = 0xff00ffff;
|
||||
} else {
|
||||
*pixel_data = 0xff000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pattern_window_draw_tile_borders(tile_buffer_addr, buffer);
|
||||
}
|
||||
|
||||
void pattern_window_draw_bank(PatternTile *tiles, unsigned int *buffer) {
|
||||
for (int i = 0; i < PW_BANK_TILE_COUNT; i++) {
|
||||
PatternTile *tile = &tiles[i];
|
||||
pattern_window_draw_tile(tile, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_window_draw_table(NesPatternWindow *window) {
|
||||
unsigned int tex_buffer[PW_WIDTH * PW_HEIGHT] = {0};
|
||||
pattern_window_draw_borders(tex_buffer);
|
||||
pattern_window_draw_bank(window->tiles_bank_0, tex_buffer);
|
||||
pattern_window_draw_bank(window->tiles_bank_1, &tex_buffer[PW_WIDTH * (PW_HEIGHT / 2)]);
|
||||
|
||||
SDL_UpdateTexture(window->texture, NULL, tex_buffer, PW_WIDTH * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
void pattern_window_build_table(NesPatternWindow *window, byte *pattern_memory) {
|
||||
pattern_window_build_tiles(window, pattern_memory);
|
||||
pattern_window_draw_table(window);
|
||||
pattern_display_build(&window->pattern_display, pattern_memory);
|
||||
}
|
||||
|
||||
void pattern_window_render(NesPatternWindow *window) {
|
||||
SDL_RenderClear(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) {
|
||||
|
|
|
@ -5,25 +5,15 @@
|
|||
#ifndef NES_EMULATOR_PATTERN_WINDOW_H
|
||||
#define NES_EMULATOR_PATTERN_WINDOW_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include "window.h"
|
||||
#include "../include/types.h"
|
||||
#include "window.h"
|
||||
#include "pattern_display.h"
|
||||
|
||||
#define PW_ROW_TILE_COUNT 16
|
||||
|
||||
typedef struct pattern_tile {
|
||||
byte x;
|
||||
byte y;
|
||||
byte data_low[8];
|
||||
byte data_high[8];
|
||||
} PatternTile;
|
||||
|
||||
typedef struct nes_pattern_window {
|
||||
NesSdlContext sdl_context;
|
||||
|
||||
PatternTile tiles_bank_0[PW_ROW_TILE_COUNT * PW_ROW_TILE_COUNT];
|
||||
PatternTile tiles_bank_1[PW_ROW_TILE_COUNT * PW_ROW_TILE_COUNT];
|
||||
SDL_Texture *texture;
|
||||
PatternDisplay pattern_display;
|
||||
} NesPatternWindow;
|
||||
|
||||
void pattern_window_init(NesPatternWindow *window);
|
||||
|
|
Loading…
Reference in New Issue