[GTK3] Allow switching the emulated model
This commit is contained in:
parent
2dd5abfae7
commit
5b60b9654b
95
gtk3/main.c
95
gtk3/main.c
@ -38,7 +38,7 @@ static GtkWindow *printer;
|
|||||||
|
|
||||||
static shader_t shader;
|
static shader_t shader;
|
||||||
|
|
||||||
static GuiData gui_data = { NULL };
|
static GuiData gui_data = { { NULL }, NULL };
|
||||||
static GB_gameboy_t gb;
|
static GB_gameboy_t gb;
|
||||||
static uint32_t *image_buffers[3];
|
static uint32_t *image_buffers[3];
|
||||||
static unsigned char current_buffer;
|
static unsigned char current_buffer;
|
||||||
@ -92,6 +92,10 @@ static const GActionEntry app_entries[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
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
|
// 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);
|
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[] = {
|
GOptionEntry entries[] = {
|
||||||
{ "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the application version", NULL },
|
{ "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 },
|
{ "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>" },
|
{ "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 }
|
{ NULL }
|
||||||
};
|
};
|
||||||
// Setup our command line information
|
// 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)) {
|
if (g_variant_dict_lookup(options, "fullscreen", "b", &count)) {
|
||||||
gui_data->fullscreen = true;
|
gui_data->cli_options.fullscreen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle model override
|
// 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)
|
// TODO: Synchronize with GB_model_t (Core/gb.h)
|
||||||
if (g_str_has_prefix(model_name, "DMG")) {
|
if (g_str_has_prefix(model_name, "DMG")) {
|
||||||
if (g_str_has_suffix(model_name, "-B") || g_strcmp0(model_name, "DMG") == 0) {
|
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 {
|
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);
|
g_printerr("Unsupported revision: %s\nFalling back to DMG-B", model_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (g_str_has_prefix(model_name, "SGB")) {
|
else if (g_str_has_prefix(model_name, "SGB")) {
|
||||||
if (g_str_has_suffix(model_name, "-NTSC") || g_strcmp0(model_name, "SGB") == 0) {
|
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")) {
|
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")) {
|
else if (g_str_has_suffix(model_name, "2")) {
|
||||||
gui_data->model = GB_MODEL_SGB2;
|
gui_data->cli_options.model = GB_MODEL_SGB2;
|
||||||
}
|
}
|
||||||
else {
|
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);
|
g_printerr("Unsupported revision: %s\nFalling back to SGB2", model_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (g_str_has_prefix(model_name, "CGB")) {
|
else if (g_str_has_prefix(model_name, "CGB")) {
|
||||||
if (g_str_has_suffix(model_name, "-C")) {
|
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) {
|
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 {
|
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);
|
g_printerr("Unsupported revision: %s\nFalling back to CGB-E", model_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (g_str_has_prefix(model_name, "AGB")) {
|
else if (g_str_has_prefix(model_name, "AGB")) {
|
||||||
gui_data->model = GB_MODEL_AGB;
|
gui_data->cli_options.model = GB_MODEL_AGB;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g_printerr("Unknown model: %s\n", model_name);
|
g_printerr("Unknown model: %s\n", model_name);
|
||||||
@ -323,6 +327,28 @@ static gboolean init_audio() {
|
|||||||
return TRUE;
|
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) {
|
static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) {
|
||||||
if (turbo_down) {
|
if (turbo_down) {
|
||||||
static unsigned skip = 0;
|
static unsigned skip = 0;
|
||||||
@ -620,7 +646,7 @@ static void startup(GApplication *app, gpointer gui_data_gptr) {
|
|||||||
preferences = GTK_WINDOW(get_object("preferences"));
|
preferences = GTK_WINDOW(get_object("preferences"));
|
||||||
|
|
||||||
g_signal_connect(preferences, "realize", G_CALLBACK(on_preferences_realize), (gpointer) builder);
|
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"));
|
vram_viewer = GTK_WINDOW(get_object("vram_viewer"));
|
||||||
memory_viewer = GTK_WINDOW(get_object("memory_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, "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);
|
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));
|
gtk_window_fullscreen(GTK_WINDOW(main_window));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,8 +979,8 @@ static void on_model_changed(GSimpleAction *action, GVariant *value, gpointer us
|
|||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case GTK_RESPONSE_YES:
|
case GTK_RESPONSE_YES:
|
||||||
g_print("TODO: RESET!\n");
|
|
||||||
g_simple_action_set_state(action, value);
|
g_simple_action_set_state(action, value);
|
||||||
|
reset(&gui_data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Action has been canceled
|
// Action has been canceled
|
||||||
@ -1805,12 +1831,8 @@ static gpointer run_thread(gpointer gui_data_gptr) {
|
|||||||
|
|
||||||
static void init(GuiData *gui_data) {
|
static void init(GuiData *gui_data) {
|
||||||
if (GB_is_inited(&gb)) return;
|
if (GB_is_inited(&gb)) return;
|
||||||
g_print("init: %p\n", g_thread_self());
|
|
||||||
|
|
||||||
GB_model_t prev_model = GB_get_model(&gb);
|
GB_init(&gb, get_model());
|
||||||
gui_data->model = gui_data->model? gui_data->model : GB_MODEL_CGB_E; // TODO: Model from config
|
|
||||||
|
|
||||||
GB_init(&gb, gui_data->model);
|
|
||||||
update_window_geometry();
|
update_window_geometry();
|
||||||
|
|
||||||
GB_set_vblank_callback(&gb, vblank);
|
GB_set_vblank_callback(&gb, vblank);
|
||||||
@ -1828,22 +1850,23 @@ static void init(GuiData *gui_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void load_boot_rom(GuiData *gui_data) {
|
static void load_boot_rom(GuiData *gui_data) {
|
||||||
GError *error;
|
GError *error = NULL;
|
||||||
char *boot_rom_path;
|
char *boot_rom_path = NULL;
|
||||||
char *boot_rom_name;
|
char *boot_rom_name = NULL;
|
||||||
GBytes *boot_rom_f;
|
GBytes *boot_rom_f = NULL;
|
||||||
const guchar *boot_rom_data;
|
const guchar *boot_rom_data;
|
||||||
gsize boot_rom_size;
|
gsize boot_rom_size;
|
||||||
|
|
||||||
if (gui_data->boot_rom_path != NULL) {
|
if (gui_data->cli_options.boot_rom_path != NULL) {
|
||||||
g_print("Trying to load boot ROM from %s\n", gui_data->boot_rom_path);
|
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->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");
|
g_printerr("Falling back to boot ROM from config\n");
|
||||||
goto config_boot_rom;
|
goto config_boot_rom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { 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:
|
case GB_MODEL_DMG_B:
|
||||||
boot_rom_name = "dmg_boot.bin";
|
boot_rom_name = "dmg_boot.bin";
|
||||||
break;
|
break;
|
||||||
@ -1919,7 +1942,17 @@ static void stop(GuiData *gui_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void reset(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 minimum_size;
|
||||||
GtkRequisition natural_size;
|
GtkRequisition natural_size;
|
||||||
|
23
gtk3/main.h
23
gtk3/main.h
@ -16,26 +16,19 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
enum generic_model {
|
|
||||||
MODEL_NONE,
|
|
||||||
MODEL_DMG,
|
|
||||||
MODEL_CGB,
|
|
||||||
MODEL_AGB,
|
|
||||||
MODEL_SGB,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct GuiData {
|
typedef struct GuiData {
|
||||||
bool fullscreen;
|
struct CliOptionData {
|
||||||
gint sample_rate;
|
gchar *config_path;
|
||||||
|
gchar *boot_rom_path;
|
||||||
|
gboolean fullscreen;
|
||||||
|
GB_model_t model;
|
||||||
|
} cli_options;
|
||||||
|
|
||||||
GFile *file;
|
GFile *file;
|
||||||
gchar *boot_rom_path;
|
gint sample_rate;
|
||||||
gchar *config_path;
|
|
||||||
|
|
||||||
enum generic_model generic_model;
|
|
||||||
GB_model_t model;
|
|
||||||
|
|
||||||
bool stopped;
|
bool stopped;
|
||||||
|
GB_model_t prev_model;
|
||||||
} GuiData;
|
} GuiData;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
|
@ -331,12 +331,12 @@ Maximilian Mader https://github.com/max-m</property>
|
|||||||
<row>
|
<row>
|
||||||
<col id="0" translatable="yes">DMG_CPU_B</col>
|
<col id="0" translatable="yes">DMG_CPU_B</col>
|
||||||
<col id="1" 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>
|
||||||
<row>
|
<row>
|
||||||
<col id="0" translatable="yes">DMG_CPU_C</col>
|
<col id="0" translatable="yes">DMG_CPU_C</col>
|
||||||
<col id="1" 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>
|
</row>
|
||||||
</data>
|
</data>
|
||||||
</object>
|
</object>
|
||||||
|
@ -300,3 +300,45 @@ void set_highpass_mode(GB_highpass_mode_t mode) {
|
|||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
@ -91,4 +91,8 @@ void set_color_correction_mode(GB_color_correction_mode_t);
|
|||||||
GB_highpass_mode_t get_highpass_mode(void);
|
GB_highpass_mode_t get_highpass_mode(void);
|
||||||
void set_highpass_mode(GB_highpass_mode_t);
|
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 */
|
#endif /* settings_h */
|
||||||
|
Loading…
Reference in New Issue
Block a user