[GTK3] Allow switching the emulated model

This commit is contained in:
Maximilian Mader 2019-10-14 16:01:51 +02:00
parent 10ca7d3508
commit 571c7f2176
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
5 changed files with 120 additions and 48 deletions

View File

@ -38,7 +38,7 @@ static GtkWindow *printer;
static shader_t shader;
static GuiData gui_data = { NULL };
static GuiData gui_data = { { NULL }, NULL };
static GB_gameboy_t gb;
static uint32_t *image_buffers[3];
static unsigned char current_buffer;
@ -92,6 +92,10 @@ static const GActionEntry app_entries[] = {
};
int main(int argc, char *argv[]) {
// initialize GB_model_t to invalid value
gui_data.cli_options.model = -1;
gui_data.prev_model = -1;
// Create our GApplication and tell GTK that we are able to handle files
main_application = gtk_application_new(APP_ID, G_APPLICATION_NON_UNIQUE | G_APPLICATION_HANDLES_OPEN);
@ -99,9 +103,9 @@ int main(int argc, char *argv[]) {
GOptionEntry entries[] = {
{ "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the application version", NULL },
{ "fullscreen", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Start in fullscreen mode", NULL },
{ "bootrom", 'b', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &gui_data.boot_rom_path, "Path to the boot ROM to use", "<file path>" },
{ "bootrom", 'b', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &gui_data.cli_options.boot_rom_path, "Path to the boot ROM to use", "<file path>" },
{ "model", 'm', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, "Override the model type to emulate", "<model type>" },
{ "config", 'c', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &gui_data.config_path, "Override the path of the configuration file", "<file path>" },
{ "config", 'c', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &gui_data.cli_options.config_path, "Override the path of the configuration file", "<file path>" },
{ NULL }
};
// Setup our command line information
@ -134,7 +138,7 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
}
if (g_variant_dict_lookup(options, "fullscreen", "b", &count)) {
gui_data->fullscreen = true;
gui_data->cli_options.fullscreen = true;
}
// Handle model override
@ -145,42 +149,42 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
// TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_str_has_prefix(model_name, "DMG")) {
if (g_str_has_suffix(model_name, "-B") || g_strcmp0(model_name, "DMG") == 0) {
gui_data->model = GB_MODEL_DMG_B;
gui_data->cli_options.model = GB_MODEL_DMG_B;
}
else {
gui_data->model = GB_MODEL_DMG_B;
gui_data->cli_options.model = GB_MODEL_DMG_B;
g_printerr("Unsupported revision: %s\nFalling back to DMG-B", model_name);
}
}
else if (g_str_has_prefix(model_name, "SGB")) {
if (g_str_has_suffix(model_name, "-NTSC") || g_strcmp0(model_name, "SGB") == 0) {
gui_data->model = GB_MODEL_SGB;
gui_data->cli_options.model = GB_MODEL_SGB;
}
else if (g_str_has_suffix(model_name, "-PAL")) {
gui_data->model = GB_MODEL_SGB | GB_MODEL_PAL_BIT;
gui_data->cli_options.model = GB_MODEL_SGB | GB_MODEL_PAL_BIT;
}
else if (g_str_has_suffix(model_name, "2")) {
gui_data->model = GB_MODEL_SGB2;
gui_data->cli_options.model = GB_MODEL_SGB2;
}
else {
gui_data->model = GB_MODEL_SGB2;
gui_data->cli_options.model = GB_MODEL_SGB2;
g_printerr("Unsupported revision: %s\nFalling back to SGB2", model_name);
}
}
else if (g_str_has_prefix(model_name, "CGB")) {
if (g_str_has_suffix(model_name, "-C")) {
gui_data->model = GB_MODEL_CGB_C;
gui_data->cli_options.model = GB_MODEL_CGB_C;
}
else if (g_str_has_suffix(model_name, "-E") || g_strcmp0(model_name, "CGB") == 0) {
gui_data->model = GB_MODEL_CGB_E;
gui_data->cli_options.model = GB_MODEL_CGB_E;
}
else {
gui_data->model = GB_MODEL_CGB_E;
gui_data->cli_options.model = GB_MODEL_CGB_E;
g_printerr("Unsupported revision: %s\nFalling back to CGB-E", model_name);
}
}
else if (g_str_has_prefix(model_name, "AGB")) {
gui_data->model = GB_MODEL_AGB;
gui_data->cli_options.model = GB_MODEL_AGB;
}
else {
g_printerr("Unknown model: %s\n", model_name);
@ -323,6 +327,28 @@ static gboolean init_audio() {
return TRUE;
}
static GB_model_t get_model() {
if (gui_data.cli_options.model != -1) {
return gui_data.cli_options.model;
}
GAction *action = g_action_map_lookup_action(G_ACTION_MAP(main_application), "change_model");
GVariant *value = g_action_get_state(action);
const gchar *family = g_variant_get_string(value, NULL);
if (g_strcmp0(family, "DMG") == 0) {
return get_dmg_model();
}
else if (g_strcmp0(family, "AGB") == 0) {
return GB_MODEL_AGB;
}
else if (g_strcmp0(family, "SGB") == 0) {
return get_sgb_model();
}
return get_cgb_model();
}
static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) {
if (turbo_down) {
static unsigned skip = 0;
@ -620,7 +646,7 @@ static void startup(GApplication *app, gpointer gui_data_gptr) {
preferences = GTK_WINDOW(get_object("preferences"));
g_signal_connect(preferences, "realize", G_CALLBACK(on_preferences_realize), (gpointer) builder);
init_settings(gui_data->config_path, preferences);
init_settings(gui_data->cli_options.config_path, preferences);
vram_viewer = GTK_WINDOW(get_object("vram_viewer"));
memory_viewer = GTK_WINDOW(get_object("memory_viewer"));
@ -745,7 +771,7 @@ static void activate(GApplication *app, gpointer gui_data_gptr) {
gtk_text_buffer_create_tag(text_buf, "underline", "underline", PANGO_UNDERLINE_SINGLE, "underline-set", TRUE, NULL);
gtk_text_buffer_create_tag(text_buf, "dashed_underline", "underline", PANGO_UNDERLINE_DOUBLE, "underline-set", TRUE, NULL);
if (gui_data->fullscreen) {
if (gui_data->cli_options.fullscreen) {
gtk_window_fullscreen(GTK_WINDOW(main_window));
}
@ -953,8 +979,8 @@ static void on_model_changed(GSimpleAction *action, GVariant *value, gpointer us
switch (result) {
case GTK_RESPONSE_YES:
g_print("TODO: RESET!\n");
g_simple_action_set_state(action, value);
reset(&gui_data);
break;
default:
// Action has been canceled
@ -1805,12 +1831,8 @@ static gpointer run_thread(gpointer gui_data_gptr) {
static void init(GuiData *gui_data) {
if (GB_is_inited(&gb)) return;
g_print("init: %p\n", g_thread_self());
GB_model_t prev_model = GB_get_model(&gb);
gui_data->model = gui_data->model? gui_data->model : GB_MODEL_CGB_E; // TODO: Model from config
GB_init(&gb, gui_data->model);
GB_init(&gb, get_model());
update_window_geometry();
GB_set_vblank_callback(&gb, vblank);
@ -1828,22 +1850,23 @@ static void init(GuiData *gui_data) {
}
static void load_boot_rom(GuiData *gui_data) {
GError *error;
char *boot_rom_path;
char *boot_rom_name;
GBytes *boot_rom_f;
GError *error = NULL;
char *boot_rom_path = NULL;
char *boot_rom_name = NULL;
GBytes *boot_rom_f = NULL;
const guchar *boot_rom_data;
gsize boot_rom_size;
if (gui_data->boot_rom_path != NULL) {
g_print("Trying to load boot ROM from %s\n", gui_data->boot_rom_path);
if (GB_load_boot_rom(&gb, gui_data->boot_rom_path)) {
if (gui_data->cli_options.boot_rom_path != NULL) {
g_print("Trying to load boot ROM from %s\n", gui_data->cli_options.boot_rom_path);
if (GB_load_boot_rom(&gb, gui_data->cli_options.boot_rom_path)) {
g_printerr("Falling back to boot ROM from config\n");
goto config_boot_rom;
}
}
else { config_boot_rom:
switch (gui_data->model) {
// TODO: Synchronize with GB_model_t (Core/gb.h)
switch (get_model()) {
case GB_MODEL_DMG_B:
boot_rom_name = "dmg_boot.bin";
break;
@ -1919,7 +1942,17 @@ static void stop(GuiData *gui_data) {
}
static void reset(GuiData *gui_data) {
GB_switch_model_and_reset(&gb, gui_data->model);
g_print("Reset: %d == %d\n", get_model(), gui_data->prev_model);
GB_model_t current_model = get_model();
if (gui_data->prev_model == -1 || gui_data->prev_model == current_model) {
GB_reset(&gb);
}
else {
GB_switch_model_and_reset(&gb, current_model);
}
gui_data->prev_model = get_model();
GtkRequisition minimum_size;
GtkRequisition natural_size;

View File

@ -16,26 +16,19 @@
#include "settings.h"
#include "shader.h"
enum generic_model {
MODEL_NONE,
MODEL_DMG,
MODEL_CGB,
MODEL_AGB,
MODEL_SGB,
};
typedef struct GuiData {
bool fullscreen;
gint sample_rate;
struct CliOptionData {
gchar *config_path;
gchar *boot_rom_path;
gboolean fullscreen;
GB_model_t model;
} cli_options;
GFile *file;
gchar *boot_rom_path;
gchar *config_path;
gint sample_rate;
enum generic_model generic_model;
GB_model_t model;
bool stopped;
GB_model_t prev_model;
} GuiData;
typedef struct{

View File

@ -331,12 +331,12 @@ Maximilian Mader https://github.com/max-m</property>
<row>
<col id="0" translatable="yes">DMG_CPU_B</col>
<col id="1" translatable="yes">DMG-CPU B</col>
<col id="2">False</col>
<col id="2">True</col>
</row>
<row>
<col id="0" translatable="yes">DMG_CPU_C</col>
<col id="1" translatable="yes">DMG-CPU C</col>
<col id="2">True</col>
<col id="2">False</col>
</row>
</data>
</object>

View File

@ -300,3 +300,45 @@ void set_highpass_mode(GB_highpass_mode_t mode) {
break;
}
}
GB_model_t get_dmg_model(void) {
if (config.dmg_revision_name == NULL) goto default_value;
// TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_strcmp0(config.dmg_revision_name, "DMG_CPU_B") == 0) {
return GB_MODEL_DMG_B;
}
default_value: return GB_MODEL_DMG_B;
}
GB_model_t get_sgb_model(void) {
if (config.sgb_revision_name == NULL) goto default_value;
// TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_strcmp0(config.sgb_revision_name, "SGB1_NTSC") == 0) {
return GB_MODEL_SGB_NTSC;
}
else if (g_strcmp0(config.sgb_revision_name, "SGB1_PAL") == 0) {
return GB_MODEL_SGB_PAL;
}
else if (g_strcmp0(config.sgb_revision_name, "SGB2") == 0) {
return GB_MODEL_SGB2;
}
default_value: return GB_MODEL_SGB2;
}
GB_model_t get_cgb_model(void) {
if (config.cgb_revision_name == NULL) goto default_value;
// TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_strcmp0(config.cgb_revision_name, "CPU_CGB_C") == 0) {
return GB_MODEL_CGB_C;
}
else if (g_strcmp0(config.cgb_revision_name, "CPU_CGB_E") == 0) {
return GB_MODEL_CGB_E;
}
default_value: return GB_MODEL_CGB_E;
}

View File

@ -91,4 +91,8 @@ void set_color_correction_mode(GB_color_correction_mode_t);
GB_highpass_mode_t get_highpass_mode(void);
void set_highpass_mode(GB_highpass_mode_t);
GB_model_t get_dmg_model(void);
GB_model_t get_sgb_model(void);
GB_model_t get_cgb_model(void);
#endif /* settings_h */