# HG changeset patch # User Michael Pavone # Date 1653408672 25200 # Node ID 2ed402b4c1fbaa2f50e84dd90c74bed2702e5a36 # Parent bdd83b47d78af722e75f89108724e4c6988551cb# Parent 6f58af5bd6fabacb69cf0f10236d4430f9a58a72 Merge diff -r 6f58af5bd6fa -r 2ed402b4c1fb config.c --- a/config.c Thu Apr 07 00:49:58 2022 -0700 +++ b/config.c Tue May 24 09:11:12 2022 -0700 @@ -250,6 +250,88 @@ return ret; } +static tern_node *dupe_tree(tern_node *head) +{ + if (!head) { + return head; + } + tern_node *out = calloc(1, sizeof(tern_node)); + out->left = dupe_tree(head->left); + out->right = dupe_tree(head->right); + out->el = head->el; + out->valtype = head->valtype; + if (out->el) { + out->straight.next = dupe_tree(head->straight.next); + } else if (out->valtype == TVAL_NODE) { + out->straight.value.ptrval = dupe_tree(head->straight.value.ptrval); + } else if (out->valtype == TVAL_PTR) { + out->straight.value.ptrval = strdup(head->straight.value.ptrval); + } else { + out->straight.value = head->straight.value; + } + return out; +} + +static void migrate_pads(char *key, tern_val val, uint8_t valtype, void *data) +{ + tern_node **pads = data; + if (valtype != TVAL_NODE) { + return; + } + tern_node *existing = tern_find_node(*pads, key); + if (existing) { + return; + } + *pads = tern_insert_node(*pads, key, dupe_tree(val.ptrval)); +} + +#define CONFIG_VERSION 1 +static tern_node *migrate_config(tern_node *config, int from_version) +{ + tern_node *def_config = parse_bundled_config("default.cfg"); + switch(from_version) + { + case 0: { + //Add CD image formats to ui.extensions + uint32_t num_exts; + char **ext_list = get_extension_list(config, &num_exts); + char *old = num_exts ? ext_list[0] : NULL; + uint32_t new_size = num_exts + 2; + uint8_t need_cue = 1, need_iso = 1; + for (uint32_t i = 0; i < num_exts; i++) + { + if (!strcmp(ext_list[i], "cue")) { + need_cue = 0; + new_size--; + } else if (!strcmp(ext_list[i], "iso")) { + need_iso = 0; + new_size--; + } + } + if (new_size != num_exts) { + ext_list = realloc(ext_list, sizeof(char*) * new_size); + if (need_cue) { + ext_list[num_exts++] = "cue"; + } + if (need_iso) { + ext_list[num_exts++] = "iso"; + } + } + char *combined = alloc_join(new_size, (char const **)ext_list, ' '); + config = tern_insert_path(config, "ui\0extensions\0", (tern_val){.ptrval = combined}, TVAL_PTR); + //Copy default pad configs if missing + tern_node *pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval; + tern_node *def_pads = tern_find_path(def_config, "bindings\0pads\0", TVAL_NODE).ptrval; + tern_foreach(def_pads, migrate_pads, &pads); + config = tern_insert_path(config, "bindings\0pads\0", (tern_val){.ptrval = pads}, TVAL_NODE); + break; + } + } + char buffer[16]; + sprintf(buffer, "%d", CONFIG_VERSION); + return tern_insert_ptr(config, "version", strdup(buffer)); +} + static uint8_t app_config_in_config_dir; tern_node *load_config() { @@ -262,6 +344,10 @@ fatal_error("Failed to find a config file in the BlastEm executable directory and the config directory path could not be determined\n"); } } + int config_version = atoi(tern_find_ptr_default(ret, "version", "0")); + if (config_version < CONFIG_VERSION) { + migrate_config(ret, config_version); + } return ret; } @@ -315,7 +401,7 @@ char **get_extension_list(tern_node *config, uint32_t *num_exts_out) { - char *ext_filter = strdup(tern_find_path_default(config, "ui\0extensions\0", (tern_val){.ptrval = "bin gen md smd sms gg"}, TVAL_PTR).ptrval); + char *ext_filter = strdup(tern_find_path_default(config, "ui\0extensions\0", (tern_val){.ptrval = "bin gen md smd sms gg cue iso"}, TVAL_PTR).ptrval); uint32_t num_exts = 0, ext_storage = 5; char **ext_list = malloc(sizeof(char *) * ext_storage); char *cur_filter = ext_filter; diff -r 6f58af5bd6fa -r 2ed402b4c1fb default.cfg --- a/default.cfg Thu Apr 07 00:49:58 2022 -0700 +++ b/default.cfg Tue May 24 09:11:12 2022 -0700 @@ -1,4 +1,3 @@ - bindings { keys { up gamepads.1.up @@ -378,7 +377,7 @@ #accepts special variables $HOME, $EXEDIR, $USERDATA, $ROMNAME save_path $USERDATA/blastem/$ROMNAME #space delimited list of file extensions to filter against in menu - extensions bin gen md smd sms gg zip gz + extensions bin gen md smd sms gg zip gz cue iso #specifies the preferred save-state format, set to gst for Genecyst compatible states state_format native } @@ -398,5 +397,5 @@ #Model of the emulated Gen/MD system, see systems.cfg for a list of options model md1va3 } - - +#Don't manually edit `version`, it's used for automatic config migration +version 1 diff -r 6f58af5bd6fa -r 2ed402b4c1fb menu.c --- a/menu.c Thu Apr 07 00:49:58 2022 -0700 +++ b/menu.c Tue May 24 09:11:12 2022 -0700 @@ -150,7 +150,7 @@ for (size_t i = 0; dst && i < num_entries; i++) { if (num_exts && !entries[i].is_dir) { - if (!path_matches_extensions(entries[i].name, ext_list, num_exts)) { + if (!path_matches_extensions(entries[i].name, (const char **)ext_list, num_exts)) { continue; } } diff -r 6f58af5bd6fa -r 2ed402b4c1fb nuklear_ui/blastem_nuklear.c --- a/nuklear_ui/blastem_nuklear.c Thu Apr 07 00:49:58 2022 -0700 +++ b/nuklear_ui/blastem_nuklear.c Tue May 24 09:11:12 2022 -0700 @@ -72,20 +72,24 @@ } +static char *browser_cur_path; +static const char *browser_label; +static const char *browser_setting_path; +static const char **browser_ext_list; +static uint32_t browser_num_exts; void view_file_browser(struct nk_context *context, uint8_t normal_open) { - static char *current_path; static dir_entry *entries; static size_t num_entries; static int32_t selected_entry = -1; - static char **ext_list; + static const char **ext_list; static uint32_t num_exts; static uint8_t got_ext_list; - if (!current_path) { - get_initial_browse_path(¤t_path); + if (!browser_cur_path) { + get_initial_browse_path(&browser_cur_path); } if (!entries) { - entries = get_dir_list(current_path, &num_entries); + entries = get_dir_list(browser_cur_path, &num_entries); if (entries) { sort_dir_list(entries, num_entries); } @@ -99,16 +103,21 @@ num_entries = 1; } } - if (!got_ext_list) { - ext_list = get_extension_list(config, &num_exts); - got_ext_list = 1; + if (!browser_ext_list) { + if (!got_ext_list) { + ext_list = (const char **)get_extension_list(config, &num_exts); + got_ext_list = 1; + } + browser_ext_list = ext_list; + browser_num_exts = num_exts; } uint32_t width = render_width(); uint32_t height = render_height(); if (nk_begin(context, "Load ROM", nk_rect(0, 0, width, height), 0)) { nk_layout_row_static(context, height - context->style.font->height * 3, width - 60, 1); int32_t old_selected = selected_entry; - char *title = alloc_concat("Select ROM: ", current_path); + const char *parts[] = {browser_label, ": ", browser_cur_path}; + char *title = alloc_concat_m(3, parts); if (nk_group_begin(context, title, NK_WINDOW_BORDER | NK_WINDOW_TITLE)) { nk_layout_row_static(context, context->style.font->height - 2, width-100, 1); for (int32_t i = 0; i < num_entries; i++) @@ -116,7 +125,7 @@ if (entries[i].name[0] == '.' && entries[i].name[1] != '.') { continue; } - if (num_exts && !entries[i].is_dir && !path_matches_extensions(entries[i].name, ext_list, num_exts)) { + if (browser_num_exts && !entries[i].is_dir && !path_matches_extensions(entries[i].name, browser_ext_list, browser_num_exts)) { continue; } int selected = i == selected_entry; @@ -132,16 +141,17 @@ free(title); nk_layout_row_static(context, context->style.font->height * 1.75, width > 600 ? 300 : width / 2, 2); if (nk_button_label(context, "Back")) { + browser_ext_list = NULL; pop_view(); } if (nk_button_label(context, "Open") || (old_selected >= 0 && selected_entry < 0)) { if (selected_entry < 0) { selected_entry = old_selected; } - char *full_path = path_append(current_path, entries[selected_entry].name); + char *full_path = path_append(browser_cur_path, entries[selected_entry].name); if (entries[selected_entry].is_dir) { - free(current_path); - current_path = full_path; + free(browser_cur_path); + browser_cur_path = full_path; free_dir_list(entries, num_entries); entries = NULL; } else { @@ -153,12 +163,21 @@ init_system_with_media(full_path, SYSTEM_UNKNOWN); free(full_path); } + + clear_view_stack(); + show_play_view(); + } else if (browser_setting_path) { + config = tern_insert_path(config, browser_setting_path, (tern_val){.ptrval = full_path}, TVAL_PTR); + config_dirty = 1; + browser_ext_list = NULL; + pop_view(); } else { lockon_media(full_path); free(full_path); + + clear_view_stack(); + show_play_view(); } - clear_view_stack(); - show_play_view(); } selected_entry = -1; } @@ -168,11 +187,18 @@ void view_load(struct nk_context *context) { + browser_label = "Select ROM"; view_file_browser(context, 1); } void view_lock_on(struct nk_context *context) { + browser_label = "Select ROM"; + view_file_browser(context, 0); +} + +void view_file_settings(struct nk_context *context) +{ view_file_browser(context, 0); } @@ -1594,6 +1620,36 @@ free(buffer); } +void settings_path(struct nk_context *context, char *label, char *path, char *def, const char **exts, uint32_t num_exts) +{ + nk_label(context, label, NK_TEXT_LEFT); + char *curstr = tern_find_path_default(config, path, (tern_val){.ptrval = def}, TVAL_PTR).ptrval; + uint32_t len = strlen(curstr); + uint32_t buffer_len = len > 100 ? len + 1 : 101; + char *buffer = malloc(buffer_len); + memcpy(buffer, curstr, len); + memset(buffer+len, 0, buffer_len-len); + nk_edit_string(context, NK_EDIT_SIMPLE, buffer, &len, buffer_len-1, nk_filter_default); + buffer[len] = 0; + if (strcmp(buffer, curstr)) { + config_dirty = 1; + config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR); + } + + nk_spacing(context, 1); + if (nk_button_label(context, "Browse")) { + browser_label = label; + browser_setting_path = path; + browser_ext_list = exts; + browser_num_exts = num_exts; + if (is_absolute_path(buffer)) { + browser_cur_path = path_dirname(buffer); + } + push_view(view_file_settings); + } + free(buffer); +} + void settings_int_property(struct nk_context *context, char *label, char *name, char *path, int def, int min, int max) { char *curstr = tern_find_path(config, path, TVAL_PTR).ptrval; @@ -2051,6 +2107,23 @@ } } +void view_bios_settings(struct nk_context *context) +{ + if (nk_begin(context, "Firmware", nk_rect(0, 0, render_width(), render_height()), 0)) { + uint32_t desired_width = context->style.font->height * 10; + nk_layout_row_static(context, context->style.font->height, desired_width, 2); + static const char* exts[] = {"md", "bin", "smd"}; + settings_path(context, "TMSS ROM", "ui\0save_path\0", "tmss.md", exts, 3); + settings_path(context, "US CD BIOS", "system\0scd_bios_us\0", "cdbios.md", exts, 3); + settings_path(context, "JP CD BIOS", "system\0scd_bios_jp\0", "cdbios.md", exts, 3); + settings_path(context, "EU CD BIOS", "system\0scd_bios_eu\0", "cdbios.md", exts, 3); + if (nk_button_label(context, "Back")) { + pop_view(); + } + nk_end(context); + } +} + void view_back(struct nk_context *context) { pop_view(); @@ -2066,6 +2139,7 @@ {"Video", view_video_settings}, {"Audio", view_audio_settings}, {"System", view_system_settings}, + {"Firmware", view_bios_settings}, {"Reset to Defaults", view_confirm_reset}, {"Back", view_back} }; diff -r 6f58af5bd6fa -r 2ed402b4c1fb romdb.c --- a/romdb.c Thu Apr 07 00:49:58 2022 -0700 +++ b/romdb.c Tue May 24 09:11:12 2022 -0700 @@ -62,10 +62,6 @@ } } free(info->map); - free(info->port1_override); - free(info->port2_override); - free(info->ext_override); - free(info->mouse_mode); } void cart_serialize(system_header *sys, serialize_buffer *buf) diff -r 6f58af5bd6fa -r 2ed402b4c1fb util.c --- a/util.c Thu Apr 07 00:49:58 2022 -0700 +++ b/util.c Tue May 24 09:11:12 2022 -0700 @@ -56,6 +56,26 @@ return ret; } +char * alloc_join(int num_parts, char const **parts, char sep) +{ + int total = num_parts ? num_parts - 1 : 0; + for (int i = 0; i < num_parts; i++) { + total += strlen(parts[i]); + } + char * ret = malloc(total + 1); + char *cur = ret; + for (int i = 0; i < num_parts; i++) { + size_t s = strlen(parts[i]); + if (i) { + *(cur++) = sep; + } + memcpy(cur, parts[i], s); + cur += s; + } + *cur = 0; + return ret; +} + typedef struct { uint32_t start; uint32_t end; @@ -353,7 +373,7 @@ return strdup(lastdot+1); } -uint8_t path_matches_extensions(char *path, char **ext_list, uint32_t num_exts) +uint8_t path_matches_extensions(char *path, const char **ext_list, uint32_t num_exts) { char *ext = path_extension(path); if (!ext) { diff -r 6f58af5bd6fa -r 2ed402b4c1fb util.h --- a/util.h Thu Apr 07 00:49:58 2022 -0700 +++ b/util.h Tue May 24 09:11:12 2022 -0700 @@ -22,6 +22,8 @@ char * alloc_concat(char const * first, char const * second); //Allocates a new string containing the concatenation of the strings pointed to by parts char * alloc_concat_m(int num_parts, char const ** parts); +//Allocates a new string containing the concatenation of the strings pointed to by parts separated by sep +char * alloc_join(int num_parts, char const **parts, char sep); //Returns a newly allocated string in which all variables in based are replaced with values from vars or the environment char *replace_vars(char *base, tern_node *vars, uint8_t allow_env); //Byteswaps a ROM image in memory @@ -49,7 +51,7 @@ //Returns the extension from a path or NULL if there is no extension char *path_extension(char const *path); //Returns true if the given path matches one of the extensions in the list -uint8_t path_matches_extensions(char *path, char **ext_list, uint32_t num_exts); +uint8_t path_matches_extensions(char *path, const char **ext_list, uint32_t num_exts); //Returns the directory portion of a path or NULL if there is no directory part char *path_dirname(const char *path); //Gets the smallest power of two that is >= a certain value, won't work for values > 0x80000000