aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorneonloop2021-08-27 00:30:47 +0000
committerneonloop2021-08-27 00:30:47 +0000
commit3f527c7426cbbdbd04962545b801c944434a0377 (patch)
treef9ba8499e54dcafb2fea259522fd4ff1b9f66f2b
parent0060a16ad707c1d6f2013947821ff55e377ceb92 (diff)
downloadpicoarch-3f527c7426cbbdbd04962545b801c944434a0377.tar.gz
picoarch-3f527c7426cbbdbd04962545b801c944434a0377.tar.bz2
picoarch-3f527c7426cbbdbd04962545b801c944434a0377.zip
Adds a standalone multi-emulator mode
When starting without arguments, can select a core in the current directory and some content (a game). Allows loading a different game from the in-game menu.
-rw-r--r--Makefile43
-rw-r--r--core.c86
-rw-r--r--core.h8
-rw-r--r--main.c74
-rw-r--r--main.h2
-rw-r--r--menu.c253
-rw-r--r--menu.h2
-rw-r--r--plat.h1
-rw-r--r--plat_sdl.c8
-rw-r--r--util.c53
-rw-r--r--util.h8
11 files changed, 440 insertions, 98 deletions
diff --git a/Makefile b/Makefile
index bc09903..e1db308 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,7 @@ pcsx_rearmed_MAKEFILE = Makefile.libretro
ifeq ($(platform), trimui)
OBJS += plat_trimui.o
- CFLAGS += -mcpu=arm926ej-s -mtune=arm926ej-s -fno-PIC
+ CFLAGS += -mcpu=arm926ej-s -mtune=arm926ej-s -fno-PIC -DCONTENT_DIR='"/mnt/SDCARD/Roms"'
LDFLAGS += -fno-PIC
else ifeq ($(platform), unix)
@@ -66,7 +66,7 @@ else ifeq ($(PROFILE), GENERATE)
CFLAGS += -fprofile-generate=./profile/picoarch
LDFLAGS += -lgcov
else ifeq ($(PROFILE), APPLY)
- CFLAGS += -fprofile-use -fprofile-dir=./profile/picoarch -fbranch-probabilities
+ CFLAGS += -fprofile-use -fprofile-dir=./profile/picoarch -fbranch-probabilities # -Wno-error=coverage-mismatch
endif
ifeq ($(MINUI), 1)
@@ -192,9 +192,14 @@ snes9x2005_PAK_NAME = Super Nintendo (2005)
dist-gmenu-section:
mkdir -p pkg/gmenunx/Apps/picoarch
+ mkdir -p pkg/gmenunx/Apps/gmenunx/sections/emulators
mkdir -p pkg/gmenunx/Apps/gmenunx/sections/libretro
touch pkg/gmenunx/Apps/gmenunx/sections/libretro/.section
+dist-gmenu-picoarch: $(BIN) dist-gmenu-section
+ cp $(BIN) pkg/gmenunx/Apps/picoarch
+ $(file >pkg/gmenunx/Apps/gmenunx/sections/emulators/picoarch,$(picoarch_SHORTCUT))
+
define CORE_gmenushortcut =
$1_NAME ?= $1
@@ -207,15 +212,20 @@ selectordir=/mnt/SDCARD/Roms/$($1_ROM_DIR)
selectorfilter=$($1_TYPES)
endef
-dist-gmenu-$(1): $(BIN) $(1)_libretro.so dist-gmenu-section
- cp $(BIN) $1_libretro.so pkg/gmenunx/Apps/picoarch
+dist-gmenu-$(1): $(BIN) $(1)_libretro.so dist-gmenu-picoarch dist-gmenu-section
+ cp $1_libretro.so pkg/gmenunx/Apps/picoarch
$$(file >pkg/gmenunx/Apps/gmenunx/sections/libretro/$(1),$$($(1)_SHORTCUT))
endef
$(foreach core, $(CORES),$(eval $(call CORE_gmenushortcut,$(core))))
-dist-gmenu: $(foreach core, $(CORES), dist-gmenu-$(core))
+define picoarch_SHORTCUT
+title=$(BIN)
+exec=/mnt/SDCARD/Apps/picoarch/picoarch
+endef
+
+dist-gmenu: $(foreach core, $(CORES), dist-gmenu-$(core)) dist-gmenu-picoarch
# -- MinUI
@@ -246,9 +256,30 @@ dist-minui-$(1): $(BIN) $(1)_libretro.so
endef
+define picoarch_LAUNCH_SH
+#!/bin/sh
+# picoarch.pak/launch.sh
+
+EMU_EXE=picoarch
+EMU_DIR=$$(dirname "$$0")
+EMU_NAME=$$EMU_EXE
+
+needs-swap
+
+HOME="/mnt/SDCARD/Games/picoarch.pak/"
+cd "$$EMU_DIR"
+"$$EMU_DIR/$$EMU_EXE" &> "/mnt/SDCARD/.minui/logs/$$EMU_NAME.txt"
+endef
+
+dist-minui-picoarch: $(BIN) cores
+ mkdir -p "pkg/MinUI/Games/picoarch.pak"
+ $(file >picoarch_launch.sh,$(picoarch_LAUNCH_SH))
+ mv picoarch_launch.sh "pkg/MinUI/Games/picoarch.pak/launch.sh"
+ cp $(BIN) $(SOFILES) "pkg/MinUI/Games/picoarch.pak"
+
$(foreach core, $(CORES),$(eval $(call CORE_pak_template,$(core))))
-dist-minui: $(foreach core, $(CORES), dist-minui-$(core))
+dist-minui: $(foreach core, $(CORES), dist-minui-$(core)) dist-minui-picoarch
endif # MINUI=1
diff --git a/core.c b/core.c
index da5c6a9..a7e45d4 100644
--- a/core.c
+++ b/core.c
@@ -15,15 +15,17 @@
#include "unzip.h"
#include "util.h"
-#define PATH_SEPARATOR_CHAR '/'
-
struct core_cbs current_core;
+char core_path[MAX_PATH];
+char content_path[MAX_PATH];
+static struct string_list *extensions;
double sample_rate;
double frame_rate;
double aspect_ratio;
unsigned audio_buffer_size_override;
int state_slot;
+int resume_slot = -1;
static char config_dir[MAX_PATH];
static char save_dir[MAX_PATH];
@@ -33,29 +35,22 @@ static struct retro_disk_control_ext_callback disk_control_ext;
static uint32_t buttons = 0;
-#define MAX_EXTENSIONS 24
-
-static void core_handle_zip(const char *path, struct retro_system_info *info, struct retro_game_info *game_info, FILE** file) {
- const char *extensions[MAX_EXTENSIONS] = {0};
- char *extensionstr = strdup(info->valid_extensions);
- char *ext = NULL;
- char *saveptr = NULL;
+static void core_handle_zip(const char *path, struct retro_game_info *game_info, FILE** file) {
+ const char *ext = NULL;
int index = 0;
bool haszip = false;
FILE *dest = NULL;
- if (info->valid_extensions && has_suffix_i(path, ".zip")) {
- while((ext = strtok_r(index == 0 ? extensionstr : NULL, "|", &saveptr))) {
+ if (extensions && has_suffix_i(path, ".zip")) {
+ while((ext = extensions->list[index++])) {
if (!strcmp(ext, "zip")) {
haszip = true;
break;
}
- extensions[index++] = ext;
- if (index > MAX_EXTENSIONS - 1) break;
}
if (!haszip) {
- if (!unzip_tmp(*file, extensions, temp_rom, MAX_PATH)) {
+ if (!unzip_tmp(*file, extensions->list, temp_rom, MAX_PATH)) {
game_info->path = temp_rom;
dest = fopen(temp_rom, "r");
if (dest) {
@@ -65,7 +60,6 @@ static void core_handle_zip(const char *path, struct retro_system_info *info, st
}
}
}
- free(extensionstr);
}
static int core_load_game_info(const char *path, struct retro_game_info *game_info) {
@@ -83,7 +77,7 @@ static int core_load_game_info(const char *path, struct retro_game_info *game_in
current_core.retro_get_system_info(&info);
- core_handle_zip(path, &info, game_info, &file);
+ core_handle_zip(path, game_info, &file);
fseek(file, 0, SEEK_END);
game_info->size = ftell(file);
@@ -138,7 +132,7 @@ static void gamepak_related_name(char *buf, size_t len, const char *new_extensio
void config_file_name(char *buf, size_t len, int is_game)
{
- if (is_game && content_path) {
+ if (is_game && content_path[0]) {
gamepak_related_name(buf, len, ".cfg");
} else {
snprintf(buf, len, "%s%s", config_dir, "picoarch.cfg");
@@ -307,6 +301,16 @@ error:
return ret;
}
+int state_resume(void) {
+ int ret = 0;
+ if (resume_slot != -1) {
+ state_slot = resume_slot;
+ ret = state_read();
+ resume_slot = -1;
+ }
+ return ret;
+}
+
unsigned disc_get_count(void) {
if (disk_control_ext.get_num_images)
return disk_control_ext.get_num_images();
@@ -585,7 +589,25 @@ static int16_t pa_input_state(unsigned port, unsigned device, unsigned index, un
return 0;
}
+void core_extract_name(const char* core_file, char *buf, size_t len) {
+ char *suffix = NULL;
+
+ strncpy(buf, basename(core_file), MAX_PATH);
+ buf[len - 1] = 0;
+
+ suffix = strrchr(buf, '_');
+ if (suffix && !strcmp(suffix, "_libretro.so"))
+ *suffix = 0;
+ else {
+ suffix = strrchr(buf, '.');
+ if (suffix && !strcmp(suffix, ".so"))
+ *suffix = 0;
+ }
+}
+
int core_load(const char *corefile) {
+ struct retro_system_info info = {0};
+
void (*set_environment)(retro_environment_t) = NULL;
void (*set_video_refresh)(retro_video_refresh_t) = NULL;
void (*set_audio_sample)(retro_audio_sample_t) = NULL;
@@ -640,6 +662,11 @@ int core_load(const char *corefile) {
set_input_state(pa_input_state);
current_core.retro_init();
+
+ current_core.retro_get_system_info(&info);
+ if (info.valid_extensions)
+ extensions = string_split(info.valid_extensions, '|');
+
current_core.initialized = true;
PA_INFO("Finished loading core\n");
return 0;
@@ -682,18 +709,35 @@ finish:
return ret;
}
+void core_unload_content(void) {
+ if (temp_rom[0]) {
+ remove(temp_rom);
+ temp_rom[0] = '\0';
+ }
+ content_path[0] = '\0';
+}
+
+const char **core_extensions(void) {
+ if (extensions)
+ return extensions->list;
+
+ return NULL;
+}
+
void core_unload(void) {
PA_INFO("Unloading core...\n");
+ core_unload_content();
+
+ string_list_free(extensions);
+ extensions = NULL;
+
if (current_core.initialized) {
+ sram_write();
current_core.retro_deinit();
current_core.initialized = false;
}
- if (temp_rom[0]) {
- remove(temp_rom);
- temp_rom[0] = '\0';
- }
options_free();
if (current_core.handle) {
diff --git a/core.h b/core.h
index 1c39d87..34143ef 100644
--- a/core.h
+++ b/core.h
@@ -2,6 +2,7 @@
#define _CORE_H__
#include "libretro.h"
+#include "main.h"
struct core_cbs {
bool initialized;
@@ -29,12 +30,15 @@ struct core_cbs {
};
extern struct core_cbs current_core;
+extern char core_path[MAX_PATH];
+extern char content_path[MAX_PATH];
extern double sample_rate;
extern double frame_rate;
extern double aspect_ratio;
extern unsigned audio_buffer_size_override;
extern int state_slot;
+extern int resume_slot;
void config_file_name(char *buf, size_t len, int is_game);
void save_relative_path(char *buf, size_t len, const char *basename);
@@ -46,14 +50,18 @@ bool state_allowed(void);
void state_file_name(char *name, size_t size, int slot);
int state_read(void);
int state_write(void);
+int state_resume(void);
unsigned disc_get_count(void);
unsigned disc_get_index(void);
bool disc_switch_index(unsigned index);
bool disc_replace_index(unsigned index, const char *content_path);
+void core_extract_name(const char* core_file, char *buf, size_t len);
int core_load(const char *corefile);
int core_load_content(const char *path);
+void core_unload_content(void);
+const char **core_extensions(void);
void core_unload(void);
#endif
diff --git a/main.c b/main.c
index 036b093..d5091a6 100644
--- a/main.c
+++ b/main.c
@@ -17,36 +17,18 @@
#include <mmenu.h>
#include <SDL/SDL.h>
void* mmenu = NULL;
-static int resume_slot = -1;
char save_template_path[MAX_PATH];
#endif
bool should_quit = false;
unsigned current_audio_buffer_size;
char core_name[MAX_PATH];
-char* content_path;
int config_override = 0;
static int last_screenshot = 0;
static uint32_t vsyncs;
static uint32_t renders;
-static void extract_core_name(const char* core_file) {
- char *suffix = NULL;
-
- strncpy(core_name, basename(core_file), MAX_PATH);
- core_name[sizeof(core_name) - 1] = 0;
-
- suffix = strrchr(core_name, '_');
- if (suffix && !strcmp(suffix, "_libretro.so"))
- *suffix = 0;
- else {
- suffix = strrchr(core_name, '.');
- if (suffix && !strcmp(suffix, ".so"))
- *suffix = 0;
- }
-}
-
static void toggle_fast_forward(int force_off)
{
static int frameskip_style_was;
@@ -294,7 +276,7 @@ void load_config(void)
}
}
-static void load_config_keys(void)
+void load_config_keys(void)
{
char *config = NULL;
int kcount = 0;
@@ -518,35 +500,50 @@ static void adjust_audio(void) {
}
int main(int argc, char **argv) {
- if (argc != 3) {
- printf("Usage: picoarch LIBRETRO_CORE CONTENT");
- return -1;
+ if (argc > 1) {
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ printf("Usage: picoarch [libretro_core [content]]\n");
+ return 0;
+ }
}
- extract_core_name(argv[1]);
- content_path = argv[2];
-
- set_defaults();
-
- if (core_load(argv[1])) {
+ if (plat_init()) {
quit(-1);
}
- if (core_load_content(argv[2])) {
+ if (menu_init()) {
quit(-1);
}
- if (plat_init()) {
+ if (argc > 1 && argv[1]) {
+ strncpy(core_path, argv[1], sizeof(core_path) - 1);
+ } else {
+ if (menu_select_core())
+ quit(-1);
+ }
+
+ core_extract_name(core_path, core_name, sizeof(core_name));
+
+ set_defaults();
+
+ if (core_load(core_path)) {
quit(-1);
}
- /* Must happen after initializing plat_input */
- load_config_keys();
+ if (argc > 2 && argv[2]) {
+ strncpy(content_path, argv[2], sizeof(content_path) - 1);
+ } else {
+ if (menu_select_content())
+ quit(-1);
+ }
- if (menu_init()) {
+ if (core_load_content(content_path)) {
quit(-1);
}
+ load_config_keys();
+ plat_reinit();
+
#ifdef MMENU
mmenu = dlopen("libmmenu.so", RTLD_LAZY);
@@ -554,14 +551,10 @@ int main(int argc, char **argv) {
ResumeSlot_t ResumeSlot = (ResumeSlot_t)dlsym(mmenu, "ResumeSlot");
if (ResumeSlot) resume_slot = ResumeSlot();
}
-
- if (state_allowed() && resume_slot!=-1) {
- state_slot = resume_slot;
- state_read();
- resume_slot = -1;
- }
#endif
+ state_resume();
+
show_startup_message();
do {
count_fps();
@@ -575,9 +568,6 @@ int main(int argc, char **argv) {
}
int quit(int code) {
- if (current_core.initialized)
- sram_write();
-
menu_finish();
core_unload();
plat_finish();
diff --git a/main.h b/main.h
index 87864c8..b46ab2c 100644
--- a/main.h
+++ b/main.h
@@ -21,7 +21,6 @@ typedef enum {
extern bool should_quit;
extern unsigned current_audio_buffer_size;
extern char core_name[MAX_PATH];
-extern char* content_path;
extern int config_override;
#ifdef MMENU
@@ -45,6 +44,7 @@ int screenshot(void);
void set_defaults(void);
int save_config(int is_game);
void load_config(void);
+void load_config_keys(void);
int remove_config(int is_game);
void handle_emu_action(emu_action action);
diff --git a/menu.c b/menu.c
index 0ffbfe2..77b1664 100644
--- a/menu.c
+++ b/menu.c
@@ -10,10 +10,14 @@
static int drew_alt_bg = 0;
+static char cores_path[MAX_PATH];
+static struct dirent **corelist = NULL;
+static int corelist_len = 0;
+
#define MENU_ALIGN_LEFT 0
#define MENU_X2 0
-#define CORE_OPTIONS_PER_PAGE 11
+#define MENU_ITEMS_PER_PAGE 11
typedef enum
{
@@ -22,7 +26,9 @@ typedef enum
MA_MAIN_SAVE_STATE,
MA_MAIN_LOAD_STATE,
MA_MAIN_DISC_CTRL,
+ MA_MAIN_CORE_SEL,
MA_MAIN_CORE_OPTS,
+ MA_MAIN_CONTENT_SEL,
MA_MAIN_RESET_GAME,
MA_MAIN_CREDITS,
MA_MAIN_EXIT,
@@ -100,11 +106,6 @@ static unsigned short fname2color(const char *fname)
#include "libpicofe/menu.c"
-static const char *menu_loop_romsel(char *curr_path, int len,
- const char **filter_exts,
- int (*extra_filter)(struct dirent **namelist, int count,
- const char *basedir)) __attribute__((unused));
-
static void draw_menu_message(const char *msg, void (*draw_more)(void)) __attribute__((unused));
static const char *mgn_saveloadcfg(int id, int *offs)
@@ -144,6 +145,202 @@ static void draw_src_bg(void) {
menu_darken_bg(g_menubg_ptr, g_menubg_src_ptr, g_menubg_src_h * g_menubg_src_pp, 0);
}
+static int mh_set_core(int id, int keys) {
+ if (corelist && id < corelist_len)
+ snprintf(core_path, sizeof(core_path), "%s/%s", cores_path, corelist[id]->d_name);
+
+ return 1;
+}
+
+static int core_selector(const struct dirent *ent) {
+ return has_suffix_i(ent->d_name, "_libretro.so");
+}
+
+static int menu_loop_core_page(int offset, int keys) {
+ static int sel = 0;
+ menu_entry e_menu_cores[MENU_ITEMS_PER_PAGE + 2] = {0}; /* +2 for Next, NULL */
+ size_t menu_idx = 0;
+ int i;
+ char names[MENU_ITEMS_PER_PAGE][MAX_PATH];
+
+ for (i = offset, menu_idx = 0; i < corelist_len && menu_idx < MENU_ITEMS_PER_PAGE; i++) {
+ menu_entry *option;
+ struct dirent *ent = corelist[i];
+ option = &e_menu_cores[menu_idx];
+ core_extract_name(ent->d_name, names[menu_idx], sizeof(names[menu_idx]));
+
+ option->name = names[menu_idx];
+ option->beh = MB_OPT_CUSTOM;
+ option->id = i;
+ option->enabled = 1;
+ option->selectable = 1;
+ option->handler = mh_set_core;
+ menu_idx++;
+ }
+
+ if (i < corelist_len) {
+ menu_entry *option;
+ option = &e_menu_cores[menu_idx];
+ option->name = "Next page";
+ option->beh = MB_OPT_CUSTOM;
+ option->id = i;
+ option->enabled = 1;
+ option->selectable = 1;
+ option->handler = menu_loop_core_page;
+ }
+
+ return me_loop(e_menu_cores, &sel);
+}
+
+int menu_select_core(void) {
+ int ret = -1;
+ getcwd(cores_path, MAX_PATH);
+
+ corelist_len = scandir(cores_path, &corelist, core_selector, alphasort);
+ if (!corelist_len) return -1;
+
+ plat_video_menu_enter(1);
+
+ if (menu_loop_core_page(0, 0) < 0)
+ goto finish;
+
+ if (core_path[0] == '\0')
+ goto finish;
+
+ ret = 0;
+finish:
+ /* wait until menu, ok, back is released */
+ while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
+ ;
+
+ plat_video_menu_leave();
+
+ if (corelist_len > 0) {
+ while (corelist_len--)
+ free(corelist[corelist_len]);
+ free(corelist);
+ corelist = NULL;
+ }
+ return ret;
+}
+
+int hidden_file_filter(struct dirent **namelist, int count, const char *basedir) {
+ int newcount = 0;
+
+ for (int i = 0; i < count; i++) {
+ if (namelist[i]->d_name[0] == '.' && namelist[i]->d_name[1] != '.') {
+ free(namelist[i]);
+ namelist[i] = NULL;
+ }
+ }
+
+ for (int i = 0; i < count; i++) {
+ if (namelist[i] != NULL)
+ namelist[newcount++] = namelist[i];
+ }
+
+ return newcount;
+}
+
+const char *select_content(void) {
+ const char *fname = NULL;
+ const char **extensions = core_extensions();
+ const char **exts_with_zip = NULL;
+ int i = 0, size = 0;
+
+ if (content_path[0] == '\0') {
+ if (getenv("CONTENT_DIR")) {
+ strncpy(content_path, getenv("CONTENT_DIR"), sizeof(content_path) - 1);
+#ifdef CONTENT_DIR
+ } else {
+ strncpy(content_path, CONTENT_DIR, sizeof(content_path) - 1);
+#else
+ } else if (getenv("HOME")) {
+ strncpy(content_path, getenv("HOME"), sizeof(content_path) - 1);
+#endif
+ }
+ }
+
+ if (extensions) {
+ for (size = 0; extensions[size]; size++)
+ ;
+ }
+
+ exts_with_zip = calloc(size + 2, sizeof (char *)); /* add 2 for "zip", NULL */
+
+ if (exts_with_zip) {
+ for (i = 0; extensions[i]; i++) {
+ exts_with_zip[i] = extensions[i];
+ }
+ exts_with_zip[i] = "zip";
+ } else {
+ exts_with_zip = extensions;
+ }
+
+ fname = menu_loop_romsel(content_path, sizeof(content_path), exts_with_zip, hidden_file_filter);
+
+ if (exts_with_zip != extensions)
+ free(exts_with_zip);
+
+ return fname;
+}
+
+int menu_select_content(void) {
+ const char *fname = NULL;
+ int ret = -1;
+
+ plat_video_menu_enter(1);
+ fname = select_content();
+ if (!fname)
+ goto finish;
+
+ strncpy(content_path, fname, sizeof(content_path) - 1);
+ set_defaults();
+ load_config();
+ if (g_autostateld_opt)
+ resume_slot = 0;
+ ret = 0;
+
+finish:
+ /* wait until menu, ok, back is released */
+ while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
+ ;
+
+ plat_video_menu_leave();
+ return ret;
+}
+
+static int menu_loop_select_content(int id, int keys) {
+ const char *fname = select_content();
+
+ if (fname == NULL)
+ return -1;
+
+ core_unload_content();
+ strncpy(content_path, fname, sizeof(content_path) - 1);
+
+ set_defaults();
+
+ if (core_load_content(fname)) {
+ quit(-1);
+ }
+
+ load_config();
+
+ if (plat_reinit()) {
+ quit(-1);
+ }
+
+ load_config_keys();
+
+ if (g_autostateld_opt) {
+ resume_slot = 0;
+ state_resume();
+ }
+
+ return 1;
+}
+
static int menu_loop_disc(int id, int keys)
{
static int sel = 0;
@@ -181,7 +378,7 @@ static int menu_loop_core_options_page(int offset, int keys) {
return 0;
}
- for (i = offset, menu_idx = 0; i < core_options.len && menu_idx < CORE_OPTIONS_PER_PAGE; i++) {
+ for (i = offset, menu_idx = 0; i < core_options.len && menu_idx < MENU_ITEMS_PER_PAGE; i++) {
struct core_option_entry *entry = &core_options.entries[i];
menu_entry *option;
const char *key = entry->key;
@@ -294,22 +491,6 @@ static int key_config_loop_wrap(int id, int keys)
return 0;
}
-static menu_entry e_menu_keyconfig[] =
-{
- mee_handler_id ("Player controls", MA_CTRL_PLAYER1, key_config_loop_wrap),
- mee_handler_id ("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
- mee_cust_nosave ("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
- mee_cust_nosave ("Save game config", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
- mee_end,
-};
-
-static int menu_loop_keyconfig(int id, int keys)
-{
- static int sel = 0;
- me_loop(e_menu_keyconfig, &sel);
- return 0;
-}
-
const char *config_label(int id, int *offs) {
return config_override ? "Loaded: game config" : "Loaded: global config";
}
@@ -335,6 +516,24 @@ static int menu_loop_config_options(int id, int keys)
return 0;
}
+static menu_entry e_menu_options[] =
+{
+ mee_handler ("Audio and video", menu_loop_video_options),
+ mee_handler_id("Emulator options", MA_MAIN_CORE_OPTS, menu_loop_core_options),
+ mee_handler_id("Player controls", MA_CTRL_PLAYER1, key_config_loop_wrap),
+ mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
+ mee_handler ("Save config", menu_loop_config_options),
+ mee_end,
+};
+
+static int menu_loop_options(int id, int keys)
+{
+ static int sel = 0;
+ me_loop(e_menu_options, &sel);
+
+ return 0;
+}
+
static int main_menu_handler(int id, int keys)
{
switch (id)
@@ -365,12 +564,10 @@ static menu_entry e_menu_main[] =
mee_handler_id("Save state", MA_MAIN_SAVE_STATE, main_menu_handler),
mee_handler_id("Load state", MA_MAIN_LOAD_STATE, main_menu_handler),
mee_handler_id("Disc control", MA_MAIN_DISC_CTRL, menu_loop_disc),
- mee_handler_id("Emulator options", MA_MAIN_CORE_OPTS, menu_loop_core_options),
- mee_handler ("Audio and video", menu_loop_video_options),
- mee_handler ("Controls", menu_loop_keyconfig),
/* mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler), */
- mee_handler ("Save config", menu_loop_config_options),
+ mee_handler ("Options", menu_loop_options),
mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
+ mee_handler_id("Load new game", MA_MAIN_CONTENT_SEL, menu_loop_select_content),
mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
mee_end,
};
@@ -431,7 +628,7 @@ void menu_loop(void)
me_enable(e_menu_main, MA_MAIN_LOAD_STATE, mmenu == NULL);
}
#endif
- me_loop_d(e_menu_main, &sel, NULL, NULL);
+ me_loop(e_menu_main, &sel);
/* wait until menu, ok, back is released */
while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
diff --git a/menu.h b/menu.h
index b9117ce..33950cc 100644
--- a/menu.h
+++ b/menu.h
@@ -6,6 +6,8 @@
int menu_init(void);
void menu_loop(void);
+int menu_select_core(void);
+int menu_select_content(void);
void menu_begin(void);
void menu_end(void);
void menu_finish(void);
diff --git a/plat.h b/plat.h
index dbbaa7f..9a0d969 100644
--- a/plat.h
+++ b/plat.h
@@ -11,6 +11,7 @@ struct audio_frame {
#define HUD_LEN 41
int plat_init(void);
+int plat_reinit(void);
void plat_finish(void);
void plat_minimize(void);
diff --git a/plat_sdl.c b/plat_sdl.c
index 010d1b6..d04c8c2 100644
--- a/plat_sdl.c
+++ b/plat_sdl.c
@@ -413,6 +413,14 @@ int plat_init(void)
return 0;
}
+int plat_reinit(void)
+{
+ audio.in_sample_rate = sample_rate;
+ plat_sound_resize_buffer();
+ scale_update_scaler();
+ return 0;
+}
+
void plat_finish(void)
{
plat_sound_finish();
diff --git a/util.c b/util.c
index ccc8c19..d07899f 100644
--- a/util.c
+++ b/util.c
@@ -1,5 +1,58 @@
+#include <stdlib.h>
+#include <string.h>
#include "util.h"
+struct string_list *string_split(const char *string, char delim) {
+ const char *loc = string;
+ int size = 2; /* rest of string, NULL terminator */
+ int index = 0;
+ char delims[2] = {0};
+ char *saveptr = NULL;
+ struct string_list *list = calloc(1, sizeof(struct string_list));
+
+ if (!list)
+ goto finish;
+
+ list->source = strdup(string);
+ if (!list->source)
+ goto finish;
+
+ while((loc = strchr(loc, delim))) {
+ size++;
+ while (*loc && *loc == delim) loc++;
+ }
+
+ list->list = calloc(size, sizeof(char *));
+ if (!list->list)
+ goto finish;
+
+ delims[0] = delim;
+
+ while((loc = strtok_r(index == 0 ? list->source : NULL, delims, &saveptr))) {
+ list->list[index++] = loc;
+ if (index >= size)
+ break;
+ }
+
+finish:
+ return list;
+}
+
+void string_list_free(struct string_list *list) {
+ if (list) {
+ if (list->list) {
+ free(list->list);
+ list->list = NULL;
+ }
+ if (list->source) {
+ free(list->source);
+ list->source = NULL;
+ }
+
+ free(list);
+ }
+}
+
void string_truncate(char *string, size_t max_len) {
size_t len = strlen(string) + 1;
if (len <= max_len) return;
diff --git a/util.h b/util.h
index 641165b..95c73cf 100644
--- a/util.h
+++ b/util.h
@@ -9,12 +9,20 @@
#define array_size(x) (sizeof(x) / sizeof(x[0]))
+struct string_list {
+ const char **list;
+ char *source;
+};
+
static inline bool has_suffix_i(const char *str, const char *suffix) {
const char *p = strrchr(str, suffix[0]);
if (!p) p = str;
return !strcasecmp(p, suffix);
}
+struct string_list *string_split(const char *string, char delim);
+void string_list_free(struct string_list *list);
+
void string_truncate(char *string, size_t max_len);
void string_wrap(char *string, size_t max_len, size_t max_lines);