changeset 2159:2ed402b4c1fb

Merge
author Michael Pavone <pavone@retrodev.com>
date Tue, 24 May 2022 09:11:12 -0700
parents bdd83b47d78a (diff) 6f58af5bd6fa (current diff)
children 3f09312685e3
files romdb.c
diffstat 7 files changed, 204 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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
--- 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;
 					}
 				}
--- 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(&current_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}
 	};
--- 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)
--- 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) {
--- 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