[GTK3] Restructure config_t by using sub structs

This commit is contained in:
Maximilian Mader 2020-05-12 20:55:29 +02:00
parent 116ea7d0d7
commit 2887110e99
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
3 changed files with 214 additions and 202 deletions

View File

@ -1220,7 +1220,7 @@ static void vblank(GB_gameboy_t *gb) {
//gui_data.clock_mutliplier = clamp_double(0.5, 1.0, gui_data.clock_mutliplier + 1.0 / 16); //gui_data.clock_mutliplier = clamp_double(0.5, 1.0, gui_data.clock_mutliplier + 1.0 / 16);
GB_set_clock_multiplier(gb, gui_data.clock_mutliplier); GB_set_clock_multiplier(gb, gui_data.clock_mutliplier);
} }
else if (config.analog_speed_controls && gui_data.analog_clock_multiplier_valid) { else if (config.controls.analog_speed_controls && gui_data.analog_clock_multiplier_valid) {
GB_set_clock_multiplier(gb, gui_data.analog_clock_multiplier); GB_set_clock_multiplier(gb, gui_data.analog_clock_multiplier);
if (gui_data.analog_clock_multiplier == 1.0) { if (gui_data.analog_clock_multiplier == 1.0) {
@ -1296,7 +1296,7 @@ static void handle_events(GB_gameboy_t *gb) {
SDL_GameControllerUpdate(); SDL_GameControllerUpdate();
uint8_t controller_state = 0; uint8_t controller_state = 0;
double analog_clock_multiplier = 1.0; gui_data.analog_clock_multiplier = 1.0;
for (unsigned i = 0; i < gui_data.controller_count; i++) { for (unsigned i = 0; i < gui_data.controller_count; i++) {
struct Controller_t *s = &gui_data.controllers[i]; struct Controller_t *s = &gui_data.controllers[i];
@ -1307,16 +1307,16 @@ static void handle_events(GB_gameboy_t *gb) {
int16_t right_x_axis = SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_RIGHTX); int16_t right_x_axis = SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_RIGHTX);
int16_t right_y_axis = SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_RIGHTY); int16_t right_y_axis = SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_RIGHTY);
if (config.analog_speed_controls) { if (config.controls.analog_speed_controls) {
double left_trigger = (double) SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / (double) 32767; double left_trigger = (double) SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / (double) 32767;
double right_trigger = (double) SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / (double) 32767; double right_trigger = (double) SDL_GameControllerGetAxis(s->controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / (double) 32767;
if (left_trigger > 0.0) { if (left_trigger > 0.0) {
analog_clock_multiplier = min_double(analog_clock_multiplier, clamp_double(1.0 / 3, 1.0, 1 - left_trigger + 0.2)); gui_data.analog_clock_multiplier = min_double(gui_data.analog_clock_multiplier, clamp_double(1.0 / 3, 1.0, 1 - left_trigger + 0.2));
gui_data.analog_clock_multiplier_valid = true; gui_data.analog_clock_multiplier_valid = true;
} }
else if (right_trigger > 0.0) { else if (right_trigger > 0.0) {
analog_clock_multiplier = max_double(analog_clock_multiplier, clamp_double(1.0, 3.0, right_trigger * 3 + 0.8)); gui_data.analog_clock_multiplier = max_double(gui_data.analog_clock_multiplier, clamp_double(1.0, 3.0, right_trigger * 3 + 0.8));
gui_data.analog_clock_multiplier_valid = true; gui_data.analog_clock_multiplier_valid = true;
} }
} }
@ -1380,8 +1380,6 @@ static void handle_events(GB_gameboy_t *gb) {
} }
} }
gui_data.analog_clock_multiplier = analog_clock_multiplier;
GB_set_key_state(gb, GB_KEY_RIGHT, (gui_data.pressed_buttons & BUTTON_MASK_RIGHT) | (controller_state & BUTTON_MASK_RIGHT)); GB_set_key_state(gb, GB_KEY_RIGHT, (gui_data.pressed_buttons & BUTTON_MASK_RIGHT) | (controller_state & BUTTON_MASK_RIGHT));
GB_set_key_state(gb, GB_KEY_LEFT, (gui_data.pressed_buttons & BUTTON_MASK_LEFT) | (controller_state & BUTTON_MASK_LEFT)); GB_set_key_state(gb, GB_KEY_LEFT, (gui_data.pressed_buttons & BUTTON_MASK_LEFT) | (controller_state & BUTTON_MASK_LEFT));
GB_set_key_state(gb, GB_KEY_UP, (gui_data.pressed_buttons & BUTTON_MASK_UP) | (controller_state & BUTTON_MASK_UP)); GB_set_key_state(gb, GB_KEY_UP, (gui_data.pressed_buttons & BUTTON_MASK_UP) | (controller_state & BUTTON_MASK_UP));
@ -1420,8 +1418,8 @@ static void load_boot_rom(GB_gameboy_t *gb, GB_boot_rom_t type) {
} }
} }
else { config_boot_rom: else { config_boot_rom:
if (config.boot_rom_path != NULL && g_strcmp0(config.boot_rom_path, "other") != 0 && g_strcmp0(config.boot_rom_path, "auto") != 0) { if (config.emulation.boot_rom_path != NULL && g_strcmp0(config.emulation.boot_rom_path, "other") != 0 && g_strcmp0(config.emulation.boot_rom_path, "auto") != 0) {
boot_rom_path = g_build_filename(config.boot_rom_path, boot_rom_name, NULL); boot_rom_path = g_build_filename(config.emulation.boot_rom_path, boot_rom_name, NULL);
g_message("Trying to load boot ROM from %s", boot_rom_path); g_message("Trying to load boot ROM from %s", boot_rom_path);
if (GB_load_boot_rom(gb, boot_rom_path)) { if (GB_load_boot_rom(gb, boot_rom_path)) {
@ -1464,7 +1462,7 @@ static void init(void) {
GB_set_sample_rate(&gb, GB_audio_get_sample_rate()); GB_set_sample_rate(&gb, GB_audio_get_sample_rate());
GB_set_color_correction_mode(&gb, get_color_correction_mode()); GB_set_color_correction_mode(&gb, get_color_correction_mode());
GB_set_highpass_filter_mode(&gb, get_highpass_mode()); GB_set_highpass_filter_mode(&gb, get_highpass_mode());
GB_set_rewind_length(&gb, config.rewind_duration); GB_set_rewind_length(&gb, config.emulation.rewind_duration);
GB_set_update_input_hint_callback(&gb, handle_events); GB_set_update_input_hint_callback(&gb, handle_events);
GB_apu_set_sample_callback(&gb, gb_audio_callback); GB_apu_set_sample_callback(&gb, gb_audio_callback);
GB_set_input_callback(&gb, sync_console_input); GB_set_input_callback(&gb, sync_console_input);
@ -1604,11 +1602,14 @@ static gpointer run_thread(gpointer null_ptr) {
gui_data.battery_save_path = battery_save_path; gui_data.battery_save_path = battery_save_path;
gui_data.cheats_save_path = cheats_save_path; gui_data.cheats_save_path = cheats_save_path;
if (!GB_is_inited(&gb)) {
init();
}
if (gui_data.stopped) { if (gui_data.stopped) {
start(); start();
} }
else { else {
init();
reset(); reset();
start(); start();
} }
@ -2015,11 +2016,11 @@ static void startup(GApplication *app, gpointer null_ptr) {
gui_data.console = GTK_WINDOW(get_object("console")); gui_data.console = GTK_WINDOW(get_object("console"));
gui_data.printer = GTK_WINDOW(get_object("printer")); gui_data.printer = GTK_WINDOW(get_object("printer"));
if (config.sample_rate == -1) { if (config.audio.sample_rate == -1) {
gui_data.sample_rate = GB_audio_default_sample_rate(); gui_data.sample_rate = GB_audio_default_sample_rate();
} }
else { else {
gui_data.sample_rate = config.sample_rate; gui_data.sample_rate = config.audio.sample_rate;
} }
// setup main window // setup main window
@ -2107,12 +2108,12 @@ static void update_viewport(void) {
double x_factor = win_width / (double) GB_get_screen_width(&gb); double x_factor = win_width / (double) GB_get_screen_width(&gb);
double y_factor = win_height / (double) GB_get_screen_height(&gb); double y_factor = win_height / (double) GB_get_screen_height(&gb);
if (config.use_integer_scaling) { if (config.video.use_integer_scaling) {
x_factor = (int)(x_factor); x_factor = (int)(x_factor);
y_factor = (int)(y_factor); y_factor = (int)(y_factor);
} }
if (config.keep_aspect_ratio) { if (config.video.keep_aspect_ratio) {
if (x_factor > y_factor) { if (x_factor > y_factor) {
x_factor = y_factor; x_factor = y_factor;
} }
@ -2231,7 +2232,7 @@ static void gl_init(GtkWidget *w) {
renderer = (char *)glGetString(GL_RENDERER); renderer = (char *)glGetString(GL_RENDERER);
g_debug("GtkGLArea on %s", renderer ? renderer : "Unknown"); g_debug("GtkGLArea on %s", renderer ? renderer : "Unknown");
if (config.shader == NULL || (!init_shader_with_name(&gui_data.shader, config.shader) && !init_shader_with_name(&gui_data.shader, "NearestNeighbor"))) { if (config.video.shader == NULL || (!init_shader_with_name(&gui_data.shader, config.video.shader) && !init_shader_with_name(&gui_data.shader, "NearestNeighbor"))) {
GError *error = g_error_new_literal(g_quark_from_string("sameboy-gl-error"), 1, "Failed to initialize shaders"); GError *error = g_error_new_literal(g_quark_from_string("sameboy-gl-error"), 1, "Failed to initialize shaders");
gtk_gl_area_set_error(gl_area, error); gtk_gl_area_set_error(gl_area, error);
} }
@ -2300,9 +2301,6 @@ static void setup_console(void) {
// This function gets called when the GApplication gets activated, i.e. it is ready to show widgets. // This function gets called when the GApplication gets activated, i.e. it is ready to show widgets.
static void activate(GApplication *app, gpointer null_ptr) { static void activate(GApplication *app, gpointer null_ptr) {
// initialize SameBoy core
init();
init_audio(); init_audio();
init_controllers(); init_controllers();
@ -2535,25 +2533,25 @@ G_MODULE_EXPORT void on_boot_rom_location_changed(GtkWidget *w, gpointer user_da
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native)); gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
if (res == GTK_RESPONSE_ACCEPT) { if (res == GTK_RESPONSE_ACCEPT) {
config.boot_rom_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native)); config.emulation.boot_rom_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native));
update_boot_rom_selector(gui_data.builder); update_boot_rom_selector(gui_data.builder);
} }
g_object_unref(native); g_object_unref(native);
} }
else { else {
config.boot_rom_path = (gchar *)id; config.emulation.boot_rom_path = (gchar *)id;
} }
} }
G_MODULE_EXPORT void on_cgb_model_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_cgb_model_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.cgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box); config.emulation.cgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
} }
G_MODULE_EXPORT void on_color_correction_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_color_correction_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.color_correction_id = (gchar *)gtk_combo_box_get_active_id(box); config.video.color_correction_id = (gchar *)gtk_combo_box_get_active_id(box);
if (GB_is_inited(&gb)) { if (GB_is_inited(&gb)) {
GB_set_color_correction_mode(&gb, get_color_correction_mode()); GB_set_color_correction_mode(&gb, get_color_correction_mode());
@ -2562,42 +2560,42 @@ G_MODULE_EXPORT void on_color_correction_changed(GtkWidget *w, gpointer user_dat
G_MODULE_EXPORT void on_frame_blending_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_frame_blending_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.frame_blending_mode = (gchar *)gtk_combo_box_get_active_id(box); config.video.frame_blending_mode = (gchar *)gtk_combo_box_get_active_id(box);
} }
G_MODULE_EXPORT void on_display_border_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_display_border_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.display_border_mode = (gchar *)gtk_combo_box_get_active_id(box); config.video.display_border_mode = (gchar *)gtk_combo_box_get_active_id(box);
gui_data.border_mode_changed = true; gui_data.border_mode_changed = true;
} }
G_MODULE_EXPORT void on_monochrome_palette_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_monochrome_palette_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.monochrome_palette_id = (gchar *)gtk_combo_box_get_active_id(box); config.video.monochrome_palette_id = (gchar *)gtk_combo_box_get_active_id(box);
GB_set_palette(&gb, get_monochrome_palette()); GB_set_palette(&gb, get_monochrome_palette());
} }
G_MODULE_EXPORT void on_color_menubar_override_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_color_menubar_override_changed(GtkWidget *w, gpointer user_data_ptr) {
config.menubar_override = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w)); config.video.menubar_override = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w));
} }
G_MODULE_EXPORT void on_dmg_model_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_dmg_model_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.dmg_revision_name = (gchar *)gtk_combo_box_get_active_id(box); config.emulation.dmg_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
} }
G_MODULE_EXPORT void on_graphic_filter_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_graphic_filter_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.shader = (gchar *)gtk_combo_box_get_active_id(box); config.video.shader = (gchar *)gtk_combo_box_get_active_id(box);
free_shader(&gui_data.shader); free_shader(&gui_data.shader);
init_shader_with_name(&gui_data.shader, config.shader); init_shader_with_name(&gui_data.shader, config.video.shader);
} }
G_MODULE_EXPORT void on_highpass_filter_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_highpass_filter_changed(GtkWidget *w, gpointer user_data_ptr) {
config.high_pass_filter_id = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w)); config.audio.high_pass_filter_id = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w));
if (GB_is_inited(&gb)) { if (GB_is_inited(&gb)) {
GB_set_highpass_filter_mode(&gb, get_highpass_mode()); GB_set_highpass_filter_mode(&gb, get_highpass_mode());
@ -2607,25 +2605,25 @@ G_MODULE_EXPORT void on_highpass_filter_changed(GtkWidget *w, gpointer user_data
G_MODULE_EXPORT void on_keep_aspect_ratio_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_keep_aspect_ratio_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w); GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.keep_aspect_ratio = value; config.video.keep_aspect_ratio = value;
update_viewport(); update_viewport();
} }
G_MODULE_EXPORT void on_rewind_duration_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_rewind_duration_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.rewind_duration = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10); config.emulation.rewind_duration = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10);
GB_set_rewind_length(&gb, config.rewind_duration); GB_set_rewind_length(&gb, config.emulation.rewind_duration);
} }
G_MODULE_EXPORT void on_sample_rate_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_sample_rate_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.sample_rate = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10); config.audio.sample_rate = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10);
if (config.sample_rate == -1) { if (config.audio.sample_rate == -1) {
gui_data.sample_rate = GB_audio_default_sample_rate(); gui_data.sample_rate = GB_audio_default_sample_rate();
} }
else { else {
gui_data.sample_rate = config.sample_rate; gui_data.sample_rate = config.audio.sample_rate;
} }
init_audio(); init_audio();
@ -2633,13 +2631,13 @@ G_MODULE_EXPORT void on_sample_rate_changed(GtkWidget *w, gpointer user_data_ptr
G_MODULE_EXPORT void on_sgb_model_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_sgb_model_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.sgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box); config.emulation.sgb_revision_name = (gchar *)gtk_combo_box_get_active_id(box);
} }
G_MODULE_EXPORT void on_use_integer_scaling_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_use_integer_scaling_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w); GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.use_integer_scaling = value; config.video.use_integer_scaling = value;
update_viewport(); update_viewport();
} }
@ -2674,7 +2672,7 @@ G_MODULE_EXPORT void console_on_enter(GtkWidget *w, gpointer user_data_ptr) {
G_MODULE_EXPORT void on_rumble_mode_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_rumble_mode_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkComboBox *box = GTK_COMBO_BOX(w); GtkComboBox *box = GTK_COMBO_BOX(w);
config.rumble_mode = (gchar *)gtk_combo_box_get_active_id(box); config.controls.rumble_mode = (gchar *)gtk_combo_box_get_active_id(box);
GB_set_rumble_mode(&gb, get_rumble_mode()); GB_set_rumble_mode(&gb, get_rumble_mode());
} }
@ -2682,7 +2680,7 @@ G_MODULE_EXPORT void on_rumble_mode_changed(GtkWidget *w, gpointer user_data_ptr
G_MODULE_EXPORT void on_analog_speed_controls_changed(GtkWidget *w, gpointer user_data_ptr) { G_MODULE_EXPORT void on_analog_speed_controls_changed(GtkWidget *w, gpointer user_data_ptr) {
GtkCheckButton *button = GTK_CHECK_BUTTON(w); GtkCheckButton *button = GTK_CHECK_BUTTON(w);
gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
config.analog_speed_controls = value; config.controls.analog_speed_controls = value;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

View File

@ -12,39 +12,49 @@ static void print_config_error(GError *error) {
} }
void _print_config(config_t *config, GLogLevelFlags log_level) { void _print_config(config_t *config, GLogLevelFlags log_level) {
#define EXPAND_GROUP(group_name, members) \ #define EXPAND_GROUP(name, members) { \
g_log(G_LOG_DOMAIN, log_level, "[%s]", #group_name); \ g_log(G_LOG_DOMAIN, log_level, "[%s]", #name); \
members struct config_ ## name ## _t *group = &config->name; \
members \
}
#define EXPAND_GROUP_MEMBER(member, key_type, default_value) \ #define EXPAND_GROUP_MEMBER(member, key_type, default_value) \
g_log(G_LOG_DOMAIN, log_level, "%s="FORMAT_FOR_KEY_TYPE(key_type)"", #member, config->member); g_log(G_LOG_DOMAIN, log_level, "%s="FORMAT_FOR_KEY_TYPE(key_type)"", #member, group->member);
EXPAND_CONFIG EXPAND_CONFIG
#undef EXPAND_GROUP #undef EXPAND_GROUP
#undef EXPAND_GROUP_MEMBER #undef EXPAND_GROUP_MEMBER
} }
// Duplicates the input and converts the first character to uppercase
gchar* ascii_ucfirst(gchar *str) {
gchar *out = g_strdup(str);
out[0] = g_ascii_toupper(str[0]);
return out;
}
void load_config_from_key_file(config_t *config, GKeyFile *key_file) { void load_config_from_key_file(config_t *config, GKeyFile *key_file) {
g_message("Loading config from key file"); g_message("Loading config from key file");
GError *error = NULL; GError *error = NULL;
gchar *group_name;
#define EXPAND_GROUP(name, members) \ #define EXPAND_GROUP(name_arg, members) { \
group_name = #name; \ struct config_ ## name_arg ## _t *group = &config->name_arg; \
members g_autofree gchar *group_name = ascii_ucfirst(#name_arg); \
members \
}
#define EXPAND_GROUP_MEMBER(member, key_type, default_value) \ #define EXPAND_GROUP_MEMBER(member, key_type, default_value) \
config->member = g_key_file_get_##key_type(key_file, group_name, #member, &error); \ group->member = g_key_file_get_##key_type(key_file, group_name, #member, &error); \
if (error != NULL) { \ if (error != NULL) { \
config->member = default_value; \ group->member = default_value; \
print_config_error(error); \ print_config_error(error); \
g_clear_error(&error); \ g_clear_error(&error); \
} }
EXPAND_CONFIG EXPAND_CONFIG
if (config->rewind_duration > 600) { if (config->emulation.rewind_duration > 600) {
g_warning("Setting Emulation.rewind_duration too high might affect performance."); g_warning("Setting Emulation.rewind_duration too high might affect performance.");
} }
@ -61,16 +71,18 @@ void save_config_to_key_file(config_t *config, GKeyFile *key_file) {
GError *error = NULL; GError *error = NULL;
gchar *group_name; gchar *group_name;
#define EXPAND_GROUP(name, members) \ #define EXPAND_GROUP(name_arg, members) { \
group_name = #name; \ struct config_ ## name_arg ## _t *group = &config->name_arg; \
members g_autofree gchar *group_name = ascii_ucfirst(#name_arg); \
members \
}
#define EXPAND_GROUP_MEMBER_IF_0(member, key_type, default_value) \ #define EXPAND_GROUP_MEMBER_IF_0(member, key_type, default_value) \
g_key_file_set_##key_type(key_file, group_name, #member, config->member); g_key_file_set_##key_type(key_file, group_name, #member, group->member);
#define EXPAND_GROUP_MEMBER_IF_1(member, key_type, default_value) \ #define EXPAND_GROUP_MEMBER_IF_1(member, key_type, default_value) \
if (config->member != NULL) { \ if (group->member != NULL) { \
g_key_file_set_##key_type(key_file, group_name, #member, config->member); \ g_key_file_set_##key_type(key_file, group_name, #member, group->member); \
} \ } \
else if (g_key_file_has_key(key_file, group_name, #member, &error)) { \ else if (g_key_file_has_key(key_file, group_name, #member, &error)) { \
if (error != NULL) { \ if (error != NULL) { \
@ -105,24 +117,24 @@ void on_preferences_realize(GtkWidget *w, gpointer builder_ptr) {
update_boot_rom_selector(builder); update_boot_rom_selector(builder);
// Hook up the static preferences // Hook up the static preferences
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rewind_duration_selector"), g_strdup_printf("%i", config.rewind_duration)); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rewind_duration_selector"), g_strdup_printf("%i", config.emulation.rewind_duration));
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "dmg_revision_selector"), config.dmg_revision_name); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "dmg_revision_selector"), config.emulation.dmg_revision_name);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "sgb_revision_selector"), config.sgb_revision_name); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "sgb_revision_selector"), config.emulation.sgb_revision_name);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "cgb_revision_selector"), config.cgb_revision_name); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "cgb_revision_selector"), config.emulation.cgb_revision_name);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "shader_selector"), config.shader); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "shader_selector"), config.video.shader);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "color_correction_selector"), config.color_correction_id); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "color_correction_selector"), config.video.color_correction_id);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "frame_blending_selector"), config.frame_blending_mode); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "frame_blending_selector"), config.video.frame_blending_mode);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "display_border_selector"), config.display_border_mode); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "display_border_selector"), config.video.display_border_mode);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "monochrome_palette_selector"), config.monochrome_palette_id); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "monochrome_palette_selector"), config.video.monochrome_palette_id);
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "integer_scaling_toggle"), config.use_integer_scaling); gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "integer_scaling_toggle"), config.video.use_integer_scaling);
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "aspect_ratio_toggle"), config.keep_aspect_ratio); gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "aspect_ratio_toggle"), config.video.keep_aspect_ratio);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "highpass_filter_selector"), config.high_pass_filter_id); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "highpass_filter_selector"), config.audio.high_pass_filter_id);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "sample_rate_selector"), g_strdup_printf("%i", config.sample_rate)); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "sample_rate_selector"), g_strdup_printf("%i", config.audio.sample_rate));
gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "analog_speed_controls_toggle"), config.analog_speed_controls); gtk_toggle_button_set_active(builder_get(GTK_TOGGLE_BUTTON, "analog_speed_controls_toggle"), config.controls.analog_speed_controls);
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rumble_mode_selector"), config.rumble_mode); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "rumble_mode_selector"), config.controls.rumble_mode);
#if ! NDEBUG #if ! NDEBUG
gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "menubar_override_selector"), config.menubar_override); gtk_combo_box_set_active_id(builder_get(GTK_COMBO_BOX, "menubar_override_selector"), config.video.menubar_override);
#else #else
if (builder_get(GTK_COMBO_BOX, "menubar_override_selector") != NULL) { if (builder_get(GTK_COMBO_BOX, "menubar_override_selector") != NULL) {
gtk_widget_destroy(GTK_WIDGET(builder_get(GTK_COMBO_BOX, "menubar_override_selector"))); gtk_widget_destroy(GTK_WIDGET(builder_get(GTK_COMBO_BOX, "menubar_override_selector")));
@ -192,9 +204,9 @@ void update_boot_rom_selector(GtkBuilder *builder) {
GtkComboBoxText *combo_box = builder_get(GTK_COMBO_BOX_TEXT, "boot_rom_selector"); GtkComboBoxText *combo_box = builder_get(GTK_COMBO_BOX_TEXT, "boot_rom_selector");
gtk_combo_box_text_remove_all(combo_box); gtk_combo_box_text_remove_all(combo_box);
gtk_combo_box_text_append(combo_box, "auto", "Use Built-in Boot ROMs"); gtk_combo_box_text_append(combo_box, "auto", "Use Built-in Boot ROMs");
if (config.boot_rom_path != NULL && !g_str_equal(config.boot_rom_path, "auto") && !g_str_equal(config.boot_rom_path, "other")) { if (config.emulation.boot_rom_path != NULL && !g_str_equal(config.emulation.boot_rom_path, "auto") && !g_str_equal(config.emulation.boot_rom_path, "other")) {
gtk_combo_box_text_append(combo_box, config.boot_rom_path, config.boot_rom_path); gtk_combo_box_text_append(combo_box, config.emulation.boot_rom_path, config.emulation.boot_rom_path);
gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), config.boot_rom_path); gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), config.emulation.boot_rom_path);
} }
else { else {
gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), "auto"); gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), "auto");
@ -204,170 +216,170 @@ void update_boot_rom_selector(GtkBuilder *builder) {
} }
enum menubar_type_t get_show_menubar(void) { enum menubar_type_t get_show_menubar(void) {
if (config.menubar_override == NULL) goto default_value; if (config.video.menubar_override == NULL) goto default_value;
if (g_strcmp0(config.menubar_override, "auto") == 0) { if (g_strcmp0(config.video.menubar_override, "auto") == 0) {
return MENUBAR_AUTO; return MENUBAR_AUTO;
} }
else if (g_strcmp0(config.menubar_override, "show_in_shell") == 0) { else if (g_strcmp0(config.video.menubar_override, "show_in_shell") == 0) {
return MENUBAR_SHOW_IN_SHELL; return MENUBAR_SHOW_IN_SHELL;
} }
else if (g_strcmp0(config.menubar_override, "show_in_window") == 0) { else if (g_strcmp0(config.video.menubar_override, "show_in_window") == 0) {
return MENUBAR_SHOW_IN_WINDOW; return MENUBAR_SHOW_IN_WINDOW;
} }
else if (g_strcmp0(config.menubar_override, "show_hamburger") == 0) { else if (g_strcmp0(config.video.menubar_override, "show_hamburger") == 0) {
return MENUBAR_SHOW_HAMBURGER; return MENUBAR_SHOW_HAMBURGER;
} }
// This should not happen // This should not happen
g_warning("Unknown menubar setting: %s\nFalling back to “Auto”", config.menubar_override); g_warning("Unknown menubar setting: %s\nFalling back to “Auto”", config.video.menubar_override);
default_value: return MENUBAR_AUTO; default_value: return MENUBAR_AUTO;
} }
void set_show_menubar(enum menubar_type_t value) { void set_show_menubar(enum menubar_type_t value) {
switch (value) { switch (value) {
case MENUBAR_AUTO: case MENUBAR_AUTO:
config.menubar_override = "auto"; config.video.menubar_override = "auto";
break; break;
case MENUBAR_SHOW_IN_SHELL: case MENUBAR_SHOW_IN_SHELL:
config.menubar_override = "show_in_shell"; config.video.menubar_override = "show_in_shell";
break; break;
case MENUBAR_SHOW_IN_WINDOW: case MENUBAR_SHOW_IN_WINDOW:
config.menubar_override = "show_in_window"; config.video.menubar_override = "show_in_window";
break; break;
case MENUBAR_SHOW_HAMBURGER: case MENUBAR_SHOW_HAMBURGER:
config.menubar_override = "show_hamburger"; config.video.menubar_override = "show_hamburger";
break; break;
} }
} }
GB_color_correction_mode_t get_color_correction_mode(void) { GB_color_correction_mode_t get_color_correction_mode(void) {
if (config.color_correction_id == NULL) goto default_value; if (config.video.color_correction_id == NULL) goto default_value;
if (g_strcmp0(config.color_correction_id, "disabled") == 0) { if (g_strcmp0(config.video.color_correction_id, "disabled") == 0) {
return GB_COLOR_CORRECTION_DISABLED; return GB_COLOR_CORRECTION_DISABLED;
} }
else if (g_strcmp0(config.color_correction_id, "correct_color_curves") == 0) { else if (g_strcmp0(config.video.color_correction_id, "correct_color_curves") == 0) {
return GB_COLOR_CORRECTION_CORRECT_CURVES; return GB_COLOR_CORRECTION_CORRECT_CURVES;
} }
else if (g_strcmp0(config.color_correction_id, "emulate_hardware") == 0) { else if (g_strcmp0(config.video.color_correction_id, "emulate_hardware") == 0) {
return GB_COLOR_CORRECTION_EMULATE_HARDWARE; return GB_COLOR_CORRECTION_EMULATE_HARDWARE;
} }
else if (g_strcmp0(config.color_correction_id, "preserve_brightness") == 0) { else if (g_strcmp0(config.video.color_correction_id, "preserve_brightness") == 0) {
return GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS; return GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS;
} }
else if (g_strcmp0(config.color_correction_id, "reduce_contrast") == 0) { else if (g_strcmp0(config.video.color_correction_id, "reduce_contrast") == 0) {
return GB_COLOR_CORRECTION_REDUCE_CONTRAST; return GB_COLOR_CORRECTION_REDUCE_CONTRAST;
} }
// This should not happen // This should not happen
g_warning("Unknown color correction mode: %s\nFalling back to “Emulate Hardware”", config.color_correction_id); g_warning("Unknown color correction mode: %s\nFalling back to “Emulate Hardware”", config.video.color_correction_id);
default_value: return GB_COLOR_CORRECTION_EMULATE_HARDWARE; default_value: return GB_COLOR_CORRECTION_EMULATE_HARDWARE;
} }
void set_color_correction_mode(GB_color_correction_mode_t mode) { void set_color_correction_mode(GB_color_correction_mode_t mode) {
switch (mode) { switch (mode) {
case GB_COLOR_CORRECTION_DISABLED: case GB_COLOR_CORRECTION_DISABLED:
config.color_correction_id = "disabled"; config.video.color_correction_id = "disabled";
break; break;
case GB_COLOR_CORRECTION_CORRECT_CURVES: case GB_COLOR_CORRECTION_CORRECT_CURVES:
config.color_correction_id = "correct_color_curves"; config.video.color_correction_id = "correct_color_curves";
break; break;
case GB_COLOR_CORRECTION_EMULATE_HARDWARE: case GB_COLOR_CORRECTION_EMULATE_HARDWARE:
config.color_correction_id = "emulate_hardware"; config.video.color_correction_id = "emulate_hardware";
break; break;
case GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS: case GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS:
config.color_correction_id = "preserve_brightness"; config.video.color_correction_id = "preserve_brightness";
break; break;
case GB_COLOR_CORRECTION_REDUCE_CONTRAST: case GB_COLOR_CORRECTION_REDUCE_CONTRAST:
config.color_correction_id = "reduce_contrast"; config.video.color_correction_id = "reduce_contrast";
break; break;
} }
} }
GB_frame_blending_mode_t get_frame_blending_mode(void) { GB_frame_blending_mode_t get_frame_blending_mode(void) {
if (config.frame_blending_mode == NULL) goto default_value; if (config.video.frame_blending_mode == NULL) goto default_value;
if (g_strcmp0(config.frame_blending_mode, "disabled") == 0) { if (g_strcmp0(config.video.frame_blending_mode, "disabled") == 0) {
return GB_FRAME_BLENDING_MODE_DISABLED; return GB_FRAME_BLENDING_MODE_DISABLED;
} }
else if (g_strcmp0(config.frame_blending_mode, "simple") == 0) { else if (g_strcmp0(config.video.frame_blending_mode, "simple") == 0) {
return GB_FRAME_BLENDING_MODE_SIMPLE; return GB_FRAME_BLENDING_MODE_SIMPLE;
} }
else if (g_strcmp0(config.frame_blending_mode, "accurate") == 0) { else if (g_strcmp0(config.video.frame_blending_mode, "accurate") == 0) {
return GB_FRAME_BLENDING_MODE_ACCURATE; return GB_FRAME_BLENDING_MODE_ACCURATE;
} }
// This should not happen // This should not happen
g_warning("Unknown frame blending mode: %s\nFalling back to “Disabled”", config.frame_blending_mode); g_warning("Unknown frame blending mode: %s\nFalling back to “Disabled”", config.video.frame_blending_mode);
default_value: return GB_FRAME_BLENDING_MODE_DISABLED; default_value: return GB_FRAME_BLENDING_MODE_DISABLED;
} }
void set_frame_blending_mode(GB_frame_blending_mode_t mode) { void set_frame_blending_mode(GB_frame_blending_mode_t mode) {
switch (mode) { switch (mode) {
case GB_FRAME_BLENDING_MODE_DISABLED: case GB_FRAME_BLENDING_MODE_DISABLED:
config.frame_blending_mode = "disabled"; config.video.frame_blending_mode = "disabled";
break; break;
case GB_FRAME_BLENDING_MODE_SIMPLE: case GB_FRAME_BLENDING_MODE_SIMPLE:
config.frame_blending_mode = "simple"; config.video.frame_blending_mode = "simple";
break; break;
case GB_FRAME_BLENDING_MODE_ACCURATE: case GB_FRAME_BLENDING_MODE_ACCURATE:
case GB_FRAME_BLENDING_MODE_ACCURATE_ODD: case GB_FRAME_BLENDING_MODE_ACCURATE_ODD:
config.frame_blending_mode = "accurate"; config.video.frame_blending_mode = "accurate";
break; break;
} }
} }
GB_border_mode_t get_display_border_mode(void) { GB_border_mode_t get_display_border_mode(void) {
if (config.display_border_mode == NULL) goto default_value; if (config.video.display_border_mode == NULL) goto default_value;
if (g_strcmp0(config.display_border_mode, "never") == 0) { if (g_strcmp0(config.video.display_border_mode, "never") == 0) {
return GB_BORDER_NEVER; return GB_BORDER_NEVER;
} }
else if (g_strcmp0(config.display_border_mode, "sgb_only") == 0) { else if (g_strcmp0(config.video.display_border_mode, "sgb_only") == 0) {
return GB_BORDER_SGB; return GB_BORDER_SGB;
} }
else if (g_strcmp0(config.display_border_mode, "always") == 0) { else if (g_strcmp0(config.video.display_border_mode, "always") == 0) {
return GB_BORDER_ALWAYS; return GB_BORDER_ALWAYS;
} }
// This should not happen // This should not happen
g_warning("Unknown SGB border mode: %s\nFalling back to “Never”", config.display_border_mode); g_warning("Unknown SGB border mode: %s\nFalling back to “Never”", config.video.display_border_mode);
default_value: return GB_BORDER_NEVER; default_value: return GB_BORDER_NEVER;
} }
void set_display_border_mode(GB_border_mode_t mode) { void set_display_border_mode(GB_border_mode_t mode) {
switch (mode) { switch (mode) {
case GB_BORDER_NEVER: case GB_BORDER_NEVER:
config.display_border_mode = "never"; config.video.display_border_mode = "never";
break; break;
case GB_BORDER_SGB: case GB_BORDER_SGB:
config.display_border_mode = "sgb_only"; config.video.display_border_mode = "sgb_only";
break; break;
case GB_BORDER_ALWAYS: case GB_BORDER_ALWAYS:
config.display_border_mode = "always"; config.video.display_border_mode = "always";
break; break;
} }
} }
const GB_palette_t* get_monochrome_palette(void) { const GB_palette_t* get_monochrome_palette(void) {
if (config.monochrome_palette_id == NULL) goto default_value; if (config.video.monochrome_palette_id == NULL) goto default_value;
if (g_strcmp0(config.monochrome_palette_id, "greyscale") == 0) { if (g_strcmp0(config.video.monochrome_palette_id, "greyscale") == 0) {
return &GB_PALETTE_GREY; return &GB_PALETTE_GREY;
} }
else if (g_strcmp0(config.monochrome_palette_id, "lime") == 0) { else if (g_strcmp0(config.video.monochrome_palette_id, "lime") == 0) {
return &GB_PALETTE_DMG; return &GB_PALETTE_DMG;
} }
else if (g_strcmp0(config.monochrome_palette_id, "olive") == 0) { else if (g_strcmp0(config.video.monochrome_palette_id, "olive") == 0) {
return &GB_PALETTE_MGB; return &GB_PALETTE_MGB;
} }
else if (g_strcmp0(config.monochrome_palette_id, "teal") == 0) { else if (g_strcmp0(config.video.monochrome_palette_id, "teal") == 0) {
return &GB_PALETTE_GBL; return &GB_PALETTE_GBL;
} }
// This should not happen // This should not happen
g_warning("Unknown monochrome palette: %s\nFalling back to “Greyscale”", config.monochrome_palette_id); g_warning("Unknown monochrome palette: %s\nFalling back to “Greyscale”", config.video.monochrome_palette_id);
default_value: return &GB_PALETTE_GREY; default_value: return &GB_PALETTE_GREY;
} }
@ -375,90 +387,90 @@ void set_monochrome_palette(const GB_palette_t *mode) {
g_message("%p | %p | %p | %p | %p", mode, &GB_PALETTE_GREY, &GB_PALETTE_DMG, &GB_PALETTE_MGB, &GB_PALETTE_GBL); g_message("%p | %p | %p | %p | %p", mode, &GB_PALETTE_GREY, &GB_PALETTE_DMG, &GB_PALETTE_MGB, &GB_PALETTE_GBL);
if (mode == &GB_PALETTE_GREY) { if (mode == &GB_PALETTE_GREY) {
config.monochrome_palette_id = "greyscale"; config.video.monochrome_palette_id = "greyscale";
} }
else if (mode == &GB_PALETTE_DMG) { else if (mode == &GB_PALETTE_DMG) {
config.monochrome_palette_id = "lime"; config.video.monochrome_palette_id = "lime";
} }
else if (mode == &GB_PALETTE_MGB) { else if (mode == &GB_PALETTE_MGB) {
config.monochrome_palette_id = "olive"; config.video.monochrome_palette_id = "olive";
} }
else if (mode == &GB_PALETTE_GBL) { else if (mode == &GB_PALETTE_GBL) {
config.monochrome_palette_id = "teal"; config.video.monochrome_palette_id = "teal";
} }
} }
GB_highpass_mode_t get_highpass_mode(void) { GB_highpass_mode_t get_highpass_mode(void) {
if (config.high_pass_filter_id == NULL) goto default_value; if (config.audio.high_pass_filter_id == NULL) goto default_value;
if (g_strcmp0(config.high_pass_filter_id, "disabled") == 0) { if (g_strcmp0(config.audio.high_pass_filter_id, "disabled") == 0) {
return GB_HIGHPASS_OFF; return GB_HIGHPASS_OFF;
} }
else if (g_strcmp0(config.high_pass_filter_id, "emulate_hardware") == 0) { else if (g_strcmp0(config.audio.high_pass_filter_id, "emulate_hardware") == 0) {
return GB_HIGHPASS_ACCURATE; return GB_HIGHPASS_ACCURATE;
} }
else if (g_strcmp0(config.high_pass_filter_id, "preserve_waveform") == 0) { else if (g_strcmp0(config.audio.high_pass_filter_id, "preserve_waveform") == 0) {
return GB_HIGHPASS_REMOVE_DC_OFFSET; return GB_HIGHPASS_REMOVE_DC_OFFSET;
} }
// This should not happen // This should not happen
g_warning("Unknown highpass mode: %s\nFalling back to “Accurate”", config.high_pass_filter_id); g_warning("Unknown highpass mode: %s\nFalling back to “Accurate”", config.audio.high_pass_filter_id);
default_value: return GB_HIGHPASS_ACCURATE; default_value: return GB_HIGHPASS_ACCURATE;
} }
void set_highpass_mode(GB_highpass_mode_t mode) { void set_highpass_mode(GB_highpass_mode_t mode) {
switch (mode) { switch (mode) {
case GB_HIGHPASS_OFF: case GB_HIGHPASS_OFF:
config.high_pass_filter_id = "disabled"; config.audio.high_pass_filter_id = "disabled";
break; break;
case GB_HIGHPASS_MAX: case GB_HIGHPASS_MAX:
g_warning("GB_HIGHPASS_MAX is not a valid highpass mode, falling back to “Accurate”."); g_warning("GB_HIGHPASS_MAX is not a valid highpass mode, falling back to “Accurate”.");
case GB_HIGHPASS_ACCURATE: case GB_HIGHPASS_ACCURATE:
config.high_pass_filter_id = "emulate_hardware"; config.audio.high_pass_filter_id = "emulate_hardware";
break; break;
case GB_HIGHPASS_REMOVE_DC_OFFSET: case GB_HIGHPASS_REMOVE_DC_OFFSET:
config.high_pass_filter_id = "preserve_waveform"; config.audio.high_pass_filter_id = "preserve_waveform";
break; break;
} }
} }
const GB_rumble_mode_t get_rumble_mode(void) { const GB_rumble_mode_t get_rumble_mode(void) {
if (config.rumble_mode == NULL) goto default_value; if (config.controls.rumble_mode == NULL) goto default_value;
if (g_strcmp0(config.rumble_mode, "never") == 0) { if (g_strcmp0(config.controls.rumble_mode, "never") == 0) {
return GB_RUMBLE_DISABLED; return GB_RUMBLE_DISABLED;
} }
else if (g_strcmp0(config.rumble_mode, "rumble_cartridges") == 0) { else if (g_strcmp0(config.controls.rumble_mode, "rumble_cartridges") == 0) {
return GB_RUMBLE_CARTRIDGE_ONLY; return GB_RUMBLE_CARTRIDGE_ONLY;
} }
else if (g_strcmp0(config.rumble_mode, "always") == 0) { else if (g_strcmp0(config.controls.rumble_mode, "always") == 0) {
return GB_RUMBLE_ALL_GAMES; return GB_RUMBLE_ALL_GAMES;
} }
// This should not happen // This should not happen
g_warning("Unknown highpass mode: %s\nFalling back to “Never”", config.rumble_mode); g_warning("Unknown highpass mode: %s\nFalling back to “Never”", config.controls.rumble_mode);
default_value: return GB_RUMBLE_DISABLED; default_value: return GB_RUMBLE_DISABLED;
} }
void set_rumble_mode(GB_rumble_mode_t mode) { void set_rumble_mode(GB_rumble_mode_t mode) {
switch (mode) { switch (mode) {
case GB_RUMBLE_DISABLED: case GB_RUMBLE_DISABLED:
config.rumble_mode = "never"; config.controls.rumble_mode = "never";
break; break;
case GB_RUMBLE_CARTRIDGE_ONLY: case GB_RUMBLE_CARTRIDGE_ONLY:
config.rumble_mode = "rumble_cartridges"; config.controls.rumble_mode = "rumble_cartridges";
break; break;
case GB_RUMBLE_ALL_GAMES: case GB_RUMBLE_ALL_GAMES:
config.rumble_mode = "always"; config.controls.rumble_mode = "always";
break; break;
} }
} }
GB_model_t get_dmg_model(void) { GB_model_t get_dmg_model(void) {
if (config.dmg_revision_name == NULL) goto default_value; if (config.emulation.dmg_revision_name == NULL) goto default_value;
// TODO: Synchronize with GB_model_t (Core/gb.h) // TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_strcmp0(config.dmg_revision_name, "DMG_CPU_B") == 0) { if (g_strcmp0(config.emulation.dmg_revision_name, "DMG_CPU_B") == 0) {
return GB_MODEL_DMG_B; return GB_MODEL_DMG_B;
} }
@ -466,16 +478,16 @@ GB_model_t get_dmg_model(void) {
} }
GB_model_t get_sgb_model(void) { GB_model_t get_sgb_model(void) {
if (config.sgb_revision_name == NULL) goto default_value; if (config.emulation.sgb_revision_name == NULL) goto default_value;
// TODO: Synchronize with GB_model_t (Core/gb.h) // TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_strcmp0(config.sgb_revision_name, "SGB1_NTSC") == 0) { if (g_strcmp0(config.emulation.sgb_revision_name, "SGB1_NTSC") == 0) {
return GB_MODEL_SGB_NTSC; return GB_MODEL_SGB_NTSC;
} }
else if (g_strcmp0(config.sgb_revision_name, "SGB1_PAL") == 0) { else if (g_strcmp0(config.emulation.sgb_revision_name, "SGB1_PAL") == 0) {
return GB_MODEL_SGB_PAL; return GB_MODEL_SGB_PAL;
} }
else if (g_strcmp0(config.sgb_revision_name, "SGB2") == 0) { else if (g_strcmp0(config.emulation.sgb_revision_name, "SGB2") == 0) {
return GB_MODEL_SGB2; return GB_MODEL_SGB2;
} }
@ -483,13 +495,13 @@ GB_model_t get_sgb_model(void) {
} }
GB_model_t get_cgb_model(void) { GB_model_t get_cgb_model(void) {
if (config.cgb_revision_name == NULL) goto default_value; if (config.emulation.cgb_revision_name == NULL) goto default_value;
// TODO: Synchronize with GB_model_t (Core/gb.h) // TODO: Synchronize with GB_model_t (Core/gb.h)
if (g_strcmp0(config.cgb_revision_name, "CPU_CGB_C") == 0) { if (g_strcmp0(config.emulation.cgb_revision_name, "CPU_CGB_C") == 0) {
return GB_MODEL_CGB_C; return GB_MODEL_CGB_C;
} }
else if (g_strcmp0(config.cgb_revision_name, "CPU_CGB_E") == 0) { else if (g_strcmp0(config.emulation.cgb_revision_name, "CPU_CGB_E") == 0) {
return GB_MODEL_CGB_E; return GB_MODEL_CGB_E;
} }

View File

@ -22,21 +22,19 @@
#define GTYPE_IS_POINTER_integer 0 #define GTYPE_IS_POINTER_integer 0
#define GTYPE_IS_POINTER_boolean 0 #define GTYPE_IS_POINTER_boolean 0
// Note: Make sure to use a member name only once for the whole config struct
//
// Macro usage: // Macro usage:
// EXPAND_CONFIG(EXPAND_GROUP(…) EXPAND_GROUP(…) …) // EXPAND_CONFIG(EXPAND_GROUP(…) EXPAND_GROUP(…) …)
// EXPAND_GROUP(group_name, group_members) // EXPAND_GROUP(group_name, group_members)
// EXPAND_GROUP_MEMBER(member_name, key_type, default_value) // EXPAND_GROUP_MEMBER(member_name, key_type, default_value)
#define EXPAND_CONFIG \ #define EXPAND_CONFIG \
EXPAND_GROUP(Emulation, \ EXPAND_GROUP(emulation, \
EXPAND_GROUP_MEMBER(boot_rom_path, string, "auto") /* overrides search location for boot ROMs by name */ \ EXPAND_GROUP_MEMBER(boot_rom_path, string, "auto") /* overrides search location for boot ROMs by name */ \
EXPAND_GROUP_MEMBER(rewind_duration, integer, 10) \ EXPAND_GROUP_MEMBER(rewind_duration, integer, 10) \
EXPAND_GROUP_MEMBER(dmg_revision_name, string, "DMG_CPU_C") \ EXPAND_GROUP_MEMBER(dmg_revision_name, string, "DMG_CPU_C") \
EXPAND_GROUP_MEMBER(sgb_revision_name, string, "SGB2") \ EXPAND_GROUP_MEMBER(sgb_revision_name, string, "SGB2") \
EXPAND_GROUP_MEMBER(cgb_revision_name, string, "CPU_CGB_E") \ EXPAND_GROUP_MEMBER(cgb_revision_name, string, "CPU_CGB_E") \
) \ ) \
EXPAND_GROUP(Video, \ EXPAND_GROUP(video, \
EXPAND_GROUP_MEMBER(shader, string, "NearestNeighbor") \ EXPAND_GROUP_MEMBER(shader, string, "NearestNeighbor") \
EXPAND_GROUP_MEMBER(color_correction_id, string, "emulate_hardware") \ EXPAND_GROUP_MEMBER(color_correction_id, string, "emulate_hardware") \
EXPAND_GROUP_MEMBER(frame_blending_mode, string, "disabled") \ EXPAND_GROUP_MEMBER(frame_blending_mode, string, "disabled") \
@ -46,19 +44,23 @@
EXPAND_GROUP_MEMBER(use_integer_scaling, boolean, true) \ EXPAND_GROUP_MEMBER(use_integer_scaling, boolean, true) \
EXPAND_GROUP_MEMBER(menubar_override, string, "auto") \ EXPAND_GROUP_MEMBER(menubar_override, string, "auto") \
) \ ) \
EXPAND_GROUP(Audio, \ EXPAND_GROUP(audio, \
EXPAND_GROUP_MEMBER(high_pass_filter_id, string, "emulate_hardware") \ EXPAND_GROUP_MEMBER(high_pass_filter_id, string, "emulate_hardware") \
EXPAND_GROUP_MEMBER(sample_rate, integer, -1) \ EXPAND_GROUP_MEMBER(sample_rate, integer, -1) \
) \ ) \
EXPAND_GROUP(Controls, \ EXPAND_GROUP(controls, \
EXPAND_GROUP_MEMBER(analog_speed_controls, boolean, false) \ EXPAND_GROUP_MEMBER(analog_speed_controls, boolean, false) \
EXPAND_GROUP_MEMBER(rumble_mode, string, "Never") \ EXPAND_GROUP_MEMBER(rumble_mode, string, "Never") \
) )
typedef struct config_t { typedef struct config_t {
#define EXPAND_GROUP(group_name, members) members #define EXPAND_GROUP(group_name, members) struct config_ ## group_name ## _t { \
members \
} group_name;
#define EXPAND_GROUP_MEMBER(member, key_type, default_value) GTYPE_OF_KEY_TYPE(key_type) member; #define EXPAND_GROUP_MEMBER(member, key_type, default_value) GTYPE_OF_KEY_TYPE(key_type) member;
EXPAND_CONFIG EXPAND_CONFIG
#undef EXPAND_GROUP #undef EXPAND_GROUP
#undef EXPAND_GROUP_MEMBER #undef EXPAND_GROUP_MEMBER
} config_t; } config_t;