diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 6b2308f..4d25092 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -1,9 +1,9 @@ -set(HEADERS gui.h window.h main_window.h) +set(HEADERS gui.h window.h main_window.h colors.h) set(SOURCE gui.c window.c main_window.c) if (NES_DEBUG) - list(APPEND HEADERS char_map.h pattern_window.h nametable_window.h dbg_pattern_table.h dbg_nametable.h) - list(APPEND SOURCE char_map.c pattern_window.c nametable_window.c dbg_pattern_table.c dbg_nametable.c) + list(APPEND HEADERS char_map.h pattern_window.h nametable_window.h dbg_pattern_table.h dbg_nametable.h dbg_palette.h) + list(APPEND SOURCE char_map.c pattern_window.c nametable_window.c dbg_pattern_table.c dbg_nametable.c dbg_palette.c) endif (NES_DEBUG) add_library(nes_gui ${SOURCE} ${HEADERS}) diff --git a/gui/colors.h b/gui/colors.h new file mode 100644 index 0000000..35c2f2d --- /dev/null +++ b/gui/colors.h @@ -0,0 +1,99 @@ +// +// Created by william on 7/29/24. +// + +#ifndef NES_EMULATOR_COLORS_H +#define NES_EMULATOR_COLORS_H + +// Generated from http://drag.wootest.net/misc/palgen.html +#define COLOR_00 0x555555 +#define COLOR_01 0x001773 +#define COLOR_02 0x000786 +#define COLOR_03 0x2e0578 +#define COLOR_04 0x59024d +#define COLOR_05 0x720011 +#define COLOR_06 0x6e0000 +#define COLOR_07 0x4c0800 +#define COLOR_08 0x171b00 +#define COLOR_09 0x002a00 +#define COLOR_0A 0x003100 +#define COLOR_0B 0x002e00 +#define COLOR_0C 0x002645 +#define COLOR_0D 0x000000 +#define COLOR_0E 0x000000 +#define COLOR_0F 0x000000 +#define COLOR_10 0xa5a5a5 +#define COLOR_11 0x0057c6 +#define COLOR_12 0x223fe5 +#define COLOR_13 0x6e28d9 +#define COLOR_14 0xae1aa6 +#define COLOR_15 0xd21759 +#define COLOR_16 0xd12107 +#define COLOR_17 0xa73700 +#define COLOR_18 0x635100 +#define COLOR_19 0x186700 +#define COLOR_1A 0x007200 +#define COLOR_1B 0x007331 +#define COLOR_1C 0x006a84 +#define COLOR_1D 0x000000 +#define COLOR_1E 0x000000 +#define COLOR_1F 0x000000 +#define COLOR_20 0xfefeff +#define COLOR_21 0x2aa3ff +#define COLOR_22 0x587cff +#define COLOR_23 0x976bff +#define COLOR_24 0xf36eff +#define COLOR_25 0xff5ea4 +#define COLOR_26 0xff635a +#define COLOR_27 0xfe8122 +#define COLOR_28 0xcda000 +#define COLOR_29 0x81b802 +#define COLOR_2A 0x3dc830 +#define COLOR_2B 0x12cd7b +#define COLOR_2C 0x0dc5d0 +#define COLOR_2D 0x3c3c3c +#define COLOR_2E 0x000000 +#define COLOR_2F 0x000000 +#define COLOR_30 0xfefeff +#define COLOR_31 0xa2dcff +#define COLOR_32 0xadc4ff +#define COLOR_33 0xc9baff +#define COLOR_34 0xf1bfff +#define COLOR_35 0xffb8dd +#define COLOR_36 0xffb7b9 +#define COLOR_37 0xffc5a3 +#define COLOR_38 0xffd696 +#define COLOR_39 0xd0e095 +#define COLOR_3A 0xb3e7a5 +#define COLOR_3B 0x9feac3 +#define COLOR_3C 0x9ae8e6 +#define COLOR_3D 0xafafaf +#define COLOR_3E 0x000000 +#define COLOR_3F 0x000000 + +#define COLOR_LIST_(row) \ + COLOR_ ## row ## 0, \ + COLOR_ ## row ## 1, \ + COLOR_ ## row ## 2, \ + COLOR_ ## row ## 3, \ + COLOR_ ## row ## 4, \ + COLOR_ ## row ## 5, \ + COLOR_ ## row ## 6, \ + COLOR_ ## row ## 7, \ + COLOR_ ## row ## 8, \ + COLOR_ ## row ## 9, \ + COLOR_ ## row ## A, \ + COLOR_ ## row ## B, \ + COLOR_ ## row ## C, \ + COLOR_ ## row ## D, \ + COLOR_ ## row ## E, \ + COLOR_ ## row ## F + +#define COLOR_LIST {\ + COLOR_LIST_(0), \ + COLOR_LIST_(1), \ + COLOR_LIST_(2), \ + COLOR_LIST_(3) \ +} + +#endif //NES_EMULATOR_COLORS_H diff --git a/gui/dbg_nametable.c b/gui/dbg_nametable.c index cb56ff4..6fe3c70 100644 --- a/gui/dbg_nametable.c +++ b/gui/dbg_nametable.c @@ -7,8 +7,6 @@ #include "../include/system.h" #include "../include/rom.h" -// TODO: Add support for palettes - #define NAMETABLE_ROW_DRAW_WIDTH (NAMETABLE_ROW_WIDTH * PATTERN_DRAW_SIZE) DebugNameTable dbg_nametable; @@ -22,6 +20,9 @@ void dbg_nametable_build_bank(byte *nametable, DebugTile *bank) { DebugTile *tile = &bank[i]; tile->tile_id = nametable[i]; + + address attr_addr = 0x3c0 | (i & 0xc00) | ((i >> 4) & 0x38) | ((i >> 2) & 0x7); + tile->attribute = nametable[attr_addr]; } } @@ -62,6 +63,21 @@ void dbg_nametable_render_bank(int bank, pixel *buffer) { (row * PATTERN_DRAW_SIZE * PATTERN_DRAW_SIZE * NAMETABLE_ROW_WIDTH) + (col * PATTERN_DRAW_SIZE); pixel *tile_buffer = &buffer[tile_pixel_addr]; - dbg_pattern_draw(pattern_id, pattern_bank, tile_buffer, NAMETABLE_ROW_DRAW_WIDTH); + // Attribute Data: + // 7654 3210 + // |||| ||++- Color bits 3-2 for top left quadrant of this byte + // |||| ++--- Color bits 3-2 for top right quadrant of this byte + // ||++------ Color bits 3-2 for bottom left quadrant of this byte + // ++-------- Color bits 3-2 for bottom right quadrant of this byte + byte palette = table[i].attribute; + if (row % 4 >= 2) { + palette >>= 4; + } + if (col % 4 >= 2) { + palette >>= 2; + } + palette &= 0b11; + + dbg_pattern_draw(pattern_id, pattern_bank, tile_buffer, NAMETABLE_ROW_DRAW_WIDTH, palette); } } \ No newline at end of file diff --git a/gui/dbg_nametable.h b/gui/dbg_nametable.h index c27cbf6..78bd475 100644 --- a/gui/dbg_nametable.h +++ b/gui/dbg_nametable.h @@ -13,8 +13,9 @@ #define NAMETABLE_ROW_WIDTH 32 #define NAMETABLE_COL_HEIGHT 30 -typedef struct db_tile { +typedef struct dbg_tile { int tile_id; + int attribute; } DebugTile; typedef struct dbg_nametable { diff --git a/gui/dbg_palette.c b/gui/dbg_palette.c new file mode 100644 index 0000000..9b6f932 --- /dev/null +++ b/gui/dbg_palette.c @@ -0,0 +1,38 @@ +// +// Created by william on 7/28/24. +// + +#include +#include +#include "dbg_palette.h" +#include "../include/ppu.h" +#include "colors.h" + +DebugPaletteMemory palette_memory; +pixel color_list[0x40] = COLOR_LIST; + +#define COPY_PALETTE(memory, dest) memcpy(&(dest), &(memory), sizeof(DebugPalette)) +#define COPY_PALETTES(memory, base_addr, dest) \ + COPY_PALETTE((memory)[(base_addr) + 0x1], (dest)[0]); \ + COPY_PALETTE((memory)[(base_addr) + 0x5], (dest)[1]); \ + COPY_PALETTE((memory)[(base_addr) + 0x9], (dest)[2]); \ + COPY_PALETTE((memory)[(base_addr) + 0xd], (dest)[3]) \ + + +void dbg_palette_init() { + byte *memory = ppu_get_state()->memory.palette; + + palette_memory.universal_background_color = memory[0]; + + COPY_PALETTES(memory, 0, palette_memory.background_palettes); + COPY_PALETTES(memory, 0x10, palette_memory.sprite_palettes); +} + +pixel dbg_get_background_color(byte palette, byte data) { + if (data == 0) { + return palette_memory.universal_background_color; + } + + int color = palette_memory.background_palettes[palette][data - 1]; + return color_list[color]; +} \ No newline at end of file diff --git a/gui/dbg_palette.h b/gui/dbg_palette.h new file mode 100644 index 0000000..38566e2 --- /dev/null +++ b/gui/dbg_palette.h @@ -0,0 +1,26 @@ +// +// Created by william on 7/28/24. +// + +#ifndef NES_EMULATOR_DBG_PALETTE_H +#define NES_EMULATOR_DBG_PALETTE_H + +#include "../include/types.h" +#include "dbg_pattern_table.h" + +#define PALETTE_SIZE 3 +#define PALETTE_COUNT 4 + +typedef byte DebugPalette[PALETTE_SIZE]; + +typedef struct dbg_palette_memory { + byte universal_background_color; + DebugPalette background_palettes[PALETTE_COUNT]; + DebugPalette sprite_palettes[PALETTE_COUNT]; +} DebugPaletteMemory; + +void dbg_palette_init(); + +pixel dbg_get_background_color(byte palette, byte data); + +#endif //NES_EMULATOR_DBG_PALETTE_H diff --git a/gui/dbg_pattern_table.c b/gui/dbg_pattern_table.c index 0fdc1ff..9ad34f5 100644 --- a/gui/dbg_pattern_table.c +++ b/gui/dbg_pattern_table.c @@ -8,6 +8,7 @@ #include "dbg_pattern_table.h" #include "../include/ppu.h" #include "../include/system.h" +#include "dbg_palette.h" DebugPatternTable pattern_table; @@ -29,6 +30,7 @@ void dbg_pattern_table_init() { } DebugPattern dbg_pattern_get(int pattern_id, int bank) { + // TODO Should not use same bank switch (bank) { case PATTERN_BANK_0: return pattern_table.bank_1[pattern_id]; @@ -61,43 +63,34 @@ void dbg_pattern_draw_borders(pixel *buffer, int buffer_width) { } } -void dbg_pattern_draw_pattern(DebugPattern pattern, pixel *buffer, int buffer_width) { +void dbg_pattern_draw_pattern(DebugPattern pattern, pixel *buffer, int buffer_width, byte palette) { 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; + byte offset = PATTERN_SIZE - fine_x - 1; + byte bit_high = (data_high >> offset) & 1; + byte bit_low = (data_low >> offset) & 1; 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; - } + byte palette_data = (bit_high << 1) | bit_low; + buffer[pixel_addr] = dbg_get_background_color(palette, palette_data); } } dbg_pattern_draw_borders(buffer, buffer_width); } -void dbg_pattern_draw(int pattern_id, int bank, pixel *buffer, int buffer_width) { +void dbg_pattern_draw(int pattern_id, int bank, pixel *buffer, int buffer_width, int palette) { DebugPattern pattern = dbg_pattern_get(pattern_id, bank); - dbg_pattern_draw_pattern(pattern, buffer, buffer_width); + dbg_pattern_draw_pattern(pattern, buffer, buffer_width, palette); } -void dbg_pattern_draw_pos(int x, int y, int bank, pixel *buffer, int buffer_width) { +void dbg_pattern_draw_pos(int x, int y, int bank, pixel *buffer, int buffer_width, int palette) { DebugPattern pattern = dbg_pattern_get_pos(x, y, bank); - dbg_pattern_draw_pattern(pattern, buffer, buffer_width); + dbg_pattern_draw_pattern(pattern, buffer, buffer_width, palette); } void dbg_pattern_draw_bank(int bank, pixel *buffer) { @@ -108,7 +101,7 @@ void dbg_pattern_draw_bank(int bank, pixel *buffer) { address row_addr = (y * PATTERN_DRAW_SIZE) * buffer_width; address tile_addr = row_addr + (x * PATTERN_DRAW_SIZE); - dbg_pattern_draw_pos(x, y, bank, &buffer[tile_addr], buffer_width); + dbg_pattern_draw_pos(x, y, bank, &buffer[tile_addr], buffer_width, 01); } } } \ No newline at end of file diff --git a/gui/dbg_pattern_table.h b/gui/dbg_pattern_table.h index 7058685..e0916f3 100644 --- a/gui/dbg_pattern_table.h +++ b/gui/dbg_pattern_table.h @@ -59,8 +59,9 @@ DebugPattern dbg_pattern_get_pos(int x, int y, int bank); * @param bank The bank of the pattern * @param buffer The buffer to write the pattern data to * @param buffer_width The width of a pixel row in the buffer + * @param palette The background palette to use */ -void dbg_pattern_draw(int pattern_id, int bank, pixel *buffer, int buffer_width); +void dbg_pattern_draw(int pattern_id, int bank, pixel *buffer, int buffer_width, int palette); /** * Draws a pattern to a buffer. The pattern is determined by its position. @@ -69,11 +70,12 @@ void dbg_pattern_draw(int pattern_id, int bank, pixel *buffer, int buffer_width) * @param bank The bank of the pattern * @param buffer The buffer to write the pattern data to * @param buffer_width The width of a pixel row in the buffer + * @param palette The background palette to use */ -void dbg_pattern_draw_pos(int x, int y, int bank, pixel *buffer, int buffer_width); +void dbg_pattern_draw_pos(int x, int y, int bank, pixel *buffer, int buffer_width, int palette); /** - * Draws a pattern bank to a buffer. + * Draws a pattern bank to a buffer. Uses the palette #0. * @param bank The bank to draw (0 -> 0x0000, 1 -> 0x1000) * @param buffer The buffer to write the patterns data to. */ diff --git a/gui/gui.c b/gui/gui.c index b377ab9..ce274c1 100644 --- a/gui/gui.c +++ b/gui/gui.c @@ -12,6 +12,7 @@ #include "dbg_pattern_table.h" #include "dbg_nametable.h" #include "char_map.h" +#include "dbg_palette.h" typedef struct nes_gui { NesMainWindow main_window; @@ -65,6 +66,7 @@ void gui_uninit() { void gui_post_sysinit() { #if DEBUG + dbg_palette_init(); dbg_pattern_table_init(); dbg_nametable_init(); @@ -80,6 +82,10 @@ int gui_input() { if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE) { return -1; } + + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_p) { + system_toggle_pause(); + } } return 1; @@ -87,6 +93,7 @@ int gui_input() { void gui_render() { #if DEBUG + dbg_palette_init(); pattern_window_render(&gui.pattern_window); nametable_window_update(&gui.nametable_window); diff --git a/gui/nametable_window.h b/gui/nametable_window.h index 3063c89..5acc932 100644 --- a/gui/nametable_window.h +++ b/gui/nametable_window.h @@ -8,7 +8,7 @@ #include "window.h" #include "../include/types.h" -#define NW_SCALE 1 +#define NW_SCALE 2 #define NW_ROW_COUNT 60 #define NW_ROW_TILE_COUNT 64 diff --git a/include/system.h b/include/system.h index 4fa0351..160ae17 100644 --- a/include/system.h +++ b/include/system.h @@ -24,8 +24,8 @@ typedef struct system { void *rom_header; Mapper mapper; - byte apu_registers[APU_REGISTERS_COUNT]; unsigned long cycle_count; + bool paused; } System; /** @@ -38,9 +38,9 @@ void system_start(); void system_next_frame(); /** - * Starts the main loop of a system. + * Toggle pause for the system. If not paused, CPU and PPU cycles will be stopped until this method is called again. */ -void system_loop(); +void system_toggle_pause(); /** * De-initialize the components of a system. @@ -49,8 +49,6 @@ void system_uninit(); unsigned int system_get_cycles(); -void system_add_cycles(unsigned int cycles); - Mapper *system_get_mapper(); #endif //NESEMULATOR_SYSTEM_H diff --git a/main.c b/main.c index 70075cf..6d62693 100644 --- a/main.c +++ b/main.c @@ -23,8 +23,8 @@ #include "gui.h" int main() { - char *rom_path = "./test_roms/dk_jp.nes"; -// char *rom_path = "./test_roms/nes-test-roms/other/BLOCKS.NES"; +// char *rom_path = "./test_roms/dk_japan.nes"; + char *rom_path = "./test_roms/smb.nes"; log_set_level(LOG_INFO); if (!gui_init()) { diff --git a/system.c b/system.c index 61bfcdb..5de8e0e 100644 --- a/system.c +++ b/system.c @@ -23,6 +23,10 @@ void system_start() { } void system_next_frame() { + if (current_sys.paused) { + return; + } + for (int cpu_c = 0; cpu_c < CPU_CYCLE_PER_FRAME; cpu_c++) { cpu_cycle(); @@ -32,6 +36,10 @@ void system_next_frame() { } } +void system_toggle_pause() { + current_sys.paused = !current_sys.paused; +} + void system_uninit() { }