diff --git a/Makefile b/Makefile index c5cd20c..1a08b05 100644 --- a/Makefile +++ b/Makefile @@ -439,6 +439,10 @@ gtk3/resources/Shaders/%.fsh: Shaders/%.fsh -@$(MKDIR) -p gtk3/resources/gtk3/resources/Shaders/ cp -rf $< gtk3/resources/$@ +gtk3/resources/Misc/%: Misc/% + -@$(MKDIR) -p gtk3/resources/gtk3/resources/Misc/ + cp -rf $< gtk3/resources/$@ + # Boot ROMs $(OBJ)/%.2bpp: %.png diff --git a/gtk3/main.c b/gtk3/main.c index 3d1df2e..5e0d139 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -6,6 +6,9 @@ #include #include #include + +// TODO: right now we need access to GB_debugger_add_symbol +#define GB_INTERNAL #include #include "settings.h" @@ -53,6 +56,9 @@ typedef struct GuiData { GFile *file; gint sample_rate; + char *battery_save_path; + char *cheats_save_path; + GB_model_t prev_model; const GThread *main_thread; @@ -202,6 +208,23 @@ static const GActionEntry app_entries[] = { { "change_model", NULL, "s", "@s 'CGB'", on_model_changed }, }; +static void replace_extension(const char *src, size_t length, char *dest, const char *ext) { + memcpy(dest, src, length); + dest[length] = 0; + + /* Remove extension */ + for (size_t i = length; i--;) { + if (dest[i] == '/') break; + if (dest[i] == '.') { + dest[i] = 0; + break; + } + } + + /* Add new extension */ + strcat(dest, ext); +} + static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) { return 0xFF000000 | (r << 16) | (g << 8) | b; } @@ -1266,6 +1289,45 @@ static void reset(void) { g_warning("Failed to load ROM: %s", path); } + GB_load_battery(&gb, gui_data.battery_save_path); + GB_load_cheats(&gb, gui_data.cheats_save_path); + + // TODO: Implement without GB_INTERNAL + /* GB_debugger_load_symbol_file */ { + GError *error = NULL; + GInputStream *stream = g_resources_open_stream(RESOURCE_PREFIX "Misc/registers.sym", G_RESOURCE_LOOKUP_FLAGS_NONE, &error); + GDataInputStream *input_stream = g_data_input_stream_new(stream); + + char *line = NULL; + gsize length = 0; + + while ((line = g_data_input_stream_read_line_utf8(input_stream, &length, NULL, &error))) { + // skip comments + for (unsigned i = 0; i < length; i++) { + if (line[i] == ';') { + line[i] = 0; + length = i; + break; + } + } + if (length == 0) continue; + + unsigned bank, address; + char symbol[length]; + + if (sscanf(line, "%x:%x %s", &bank, &address, symbol) == 3) { + GB_debugger_add_symbol(&gb, bank, address, symbol); + } + } + + g_object_unref(stream); + } + + size_t path_length = strlen(path); + char sym_file_path[path_length + 5]; + replace_extension(path, path_length, sym_file_path, ".sym"); + GB_debugger_load_symbol_file(&gb, sym_file_path); + g_free(path); } @@ -1301,6 +1363,11 @@ static void start(void) { } } + if (gui_data.file) { + GB_save_battery(&gb, gui_data.battery_save_path); + GB_save_cheats(&gb, gui_data.cheats_save_path); + } + gui_data.stopping = false; } @@ -1322,6 +1389,19 @@ static void activate_reset(GSimpleAction *action, GVariant *parameter, gpointer static gpointer run_thread(gpointer null_ptr) { if (!gui_data.file) return NULL; + char *path = g_file_get_path(gui_data.file); + size_t path_length = strlen(path); + + /* At the worst case, size is strlen(path) + 4 bytes for .sav + NULL */ + char battery_save_path[path_length + 5]; + char cheats_save_path[path_length + 5]; + + replace_extension(path, path_length, battery_save_path, ".sav"); + replace_extension(path, path_length, cheats_save_path, ".cht"); + + gui_data.battery_save_path = battery_save_path; + gui_data.cheats_save_path = cheats_save_path; + if (gui_data.stopped) { start(); } diff --git a/gtk3/sameboy.gresource.xml b/gtk3/sameboy.gresource.xml index d170ce3..9d2360c 100644 --- a/gtk3/sameboy.gresource.xml +++ b/gtk3/sameboy.gresource.xml @@ -42,6 +42,8 @@ gtk3/resources/Shaders/Scale4x.fsh gtk3/resources/Shaders/SmoothBilinear.fsh + gtk3/resources/Misc/registers.sym + pixmaps/CPU.png pixmaps/Display.png pixmaps/Joypad.png