aboutsummaryrefslogtreecommitdiff
path: root/menu.c
diff options
context:
space:
mode:
authorneonloop2021-08-04 15:09:12 +0000
committerneonloop2021-08-04 15:09:12 +0000
commit99632f66e74fc57c463072be312d634aeb67bc61 (patch)
treee4ccaf52b93d04c69865d82556e2ce4cd3a6c599 /menu.c
downloadpicoarch-99632f66e74fc57c463072be312d634aeb67bc61.tar.gz
picoarch-99632f66e74fc57c463072be312d634aeb67bc61.tar.bz2
picoarch-99632f66e74fc57c463072be312d634aeb67bc61.zip
Initial commit
Diffstat (limited to 'menu.c')
-rw-r--r--menu.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/menu.c b/menu.c
new file mode 100644
index 0000000..352e57f
--- /dev/null
+++ b/menu.c
@@ -0,0 +1,409 @@
+#include <sys/stat.h>
+#include "core.h"
+#include "main.h"
+#include "menu.h"
+#include "options.h"
+#include "plat.h"
+#include "scale.h"
+
+#define MENU_ALIGN_LEFT 0
+#define MENU_X2 0
+
+typedef enum
+{
+ MA_NONE = 1,
+ MA_MAIN_RESUME_GAME,
+ MA_MAIN_SAVE_STATE,
+ MA_MAIN_LOAD_STATE,
+ MA_MAIN_CORE_OPTS,
+ MA_MAIN_RESET_GAME,
+ MA_MAIN_CREDITS,
+ MA_MAIN_EXIT,
+ MA_OPT_SAVECFG,
+ MA_OPT_SAVECFG_GAME,
+ MA_CTRL_PLAYER1,
+ MA_CTRL_EMU,
+} menu_id;
+
+me_bind_action me_ctrl_actions[] =
+{
+ { "UP ", 1 << RETRO_DEVICE_ID_JOYPAD_UP},
+ { "DOWN ", 1 << RETRO_DEVICE_ID_JOYPAD_DOWN },
+ { "LEFT ", 1 << RETRO_DEVICE_ID_JOYPAD_LEFT },
+ { "RIGHT ", 1 << RETRO_DEVICE_ID_JOYPAD_RIGHT },
+ { "A BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_A },
+ { "B BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_B },
+ { "X BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_X },
+ { "Y BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_Y },
+ { "START ", 1 << RETRO_DEVICE_ID_JOYPAD_START },
+ { "SELECT ", 1 << RETRO_DEVICE_ID_JOYPAD_SELECT },
+ { "L BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_L },
+ { "R BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_R },
+ { "L2 BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_L2 },
+ { "R2 BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_R2 },
+ { NULL, 0 }
+};
+
+me_bind_action gba_ctrl_actions[] =
+{
+ { "UP ", 1 << RETRO_DEVICE_ID_JOYPAD_UP},
+ { "DOWN ", 1 << RETRO_DEVICE_ID_JOYPAD_DOWN },
+ { "LEFT ", 1 << RETRO_DEVICE_ID_JOYPAD_LEFT },
+ { "RIGHT ", 1 << RETRO_DEVICE_ID_JOYPAD_RIGHT },
+ { "A BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_A },
+ { "B BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_B },
+ { "A TURBO ", 1 << RETRO_DEVICE_ID_JOYPAD_X },
+ { "B TURBO ", 1 << RETRO_DEVICE_ID_JOYPAD_Y },
+ { "START ", 1 << RETRO_DEVICE_ID_JOYPAD_START },
+ { "SELECT ", 1 << RETRO_DEVICE_ID_JOYPAD_SELECT },
+ { "L BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_L },
+ { "R BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_R },
+ /* { "FAST FWD ", 1 << RETRO_DEVICE_ID_JOYPAD_R2 }, */
+ { NULL, 0 }
+};
+
+me_bind_action snes_ctrl_actions[] =
+{
+ { "UP ", 1 << RETRO_DEVICE_ID_JOYPAD_UP},
+ { "DOWN ", 1 << RETRO_DEVICE_ID_JOYPAD_DOWN },
+ { "LEFT ", 1 << RETRO_DEVICE_ID_JOYPAD_LEFT },
+ { "RIGHT ", 1 << RETRO_DEVICE_ID_JOYPAD_RIGHT },
+ { "A BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_A },
+ { "B BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_B },
+ { "X BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_X },
+ { "Y BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_Y },
+ { "START ", 1 << RETRO_DEVICE_ID_JOYPAD_START },
+ { "SELECT ", 1 << RETRO_DEVICE_ID_JOYPAD_SELECT },
+ { "L BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_L },
+ { "R BUTTON ", 1 << RETRO_DEVICE_ID_JOYPAD_R },
+ { NULL, 0 }
+};
+
+/* Must be a superset of all possible actions. This is used when
+ * saving config, and if an entry isn't here, the saver won't see
+ * it. */
+me_bind_action emuctrl_actions[] =
+{
+ { "Save State ", 1 << EACTION_SAVE_STATE },
+ { "Load State ", 1 << EACTION_LOAD_STATE },
+ { "Show/Hide FPS ", 1 << EACTION_TOGGLE_FPS },
+ { "Toggle FF ", 1 << EACTION_TOGGLE_FF },
+ { NULL, 0 }
+};
+
+static int emu_check_save_file(int slot, int *time)
+{
+ char fname[MAX_PATH];
+ struct stat status;
+ int ret;
+
+ state_file_name(fname, sizeof(fname), slot);
+
+ ret = stat(fname, &status);
+ if (ret != 0)
+ return 0;
+
+ return 1;
+}
+
+static int emu_save_load_game(int load, int unused)
+{
+ int ret;
+
+ if (load)
+ ret = state_read();
+ else
+ ret = state_write();
+
+ return ret;
+}
+
+// RGB565
+static unsigned short fname2color(const char *fname)
+{
+ return 0xFFFF;
+}
+
+#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)
+{
+ return "";
+}
+
+static int mh_restore_defaults(int id, int keys)
+{
+ set_defaults();
+ menu_update_msg("defaults restored");
+ return 1;
+}
+
+static int mh_savecfg(int id, int keys)
+{
+ if (save_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
+ menu_update_msg("config saved");
+ else
+ menu_update_msg("failed to write config");
+
+ return 1;
+}
+
+static int menu_loop_core_options(int id, int keys)
+{
+ static int sel = 0;
+ menu_entry *e_menu_core_options;
+
+ e_menu_core_options = (menu_entry *)calloc(core_options.visible_len + 1, sizeof(menu_entry));
+
+ if (!e_menu_core_options) {
+ PA_ERROR("Error allocating core options\n");
+ return 0;
+ }
+
+ for(int i = 0, menu_idx = 0; i < core_options.len; i++) {
+ const char *key;
+ struct core_option_entry *entry;
+ menu_entry *option;
+ key = core_options.defs ? core_options.defs[i].key : core_options.vars[i].key;
+ if (options_is_blocked(key))
+ continue;
+
+ entry = options_get_entry(key);
+ option = &e_menu_core_options[menu_idx];
+
+ option->name = entry->desc;
+ option->beh = MB_OPT_ENUM;
+ option->var = options_get_value_ptr(key);
+ option->enabled = 1;
+ option->need_to_save = 1;
+ option->selectable = 1;
+ option->data = options_get_options(key);
+ option->help = entry->info;
+ menu_idx++;
+ }
+
+ me_loop(e_menu_core_options, &sel);
+
+ options_update_changed();
+
+ free(e_menu_core_options);
+ return 0;
+}
+
+static const char h_restore_def[] = "Switches back to default / recommended\n"
+ "configuration";
+
+static const char h_show_fps[] = "Shows frames and vsyncs per second";
+
+static const char h_audio_buffer_size[] =
+ "The size of the audio buffer, in frames. Higher\n"
+ "values reduce the risk of audio crackling at the\n"
+ "cost of delayed sound.";
+
+static const char h_scale_size[] =
+ "How much to stretch the screen when scaling. Native\n"
+ "does no stretching. Aspect uses the correct aspect\n"
+ "ratio. Full uses the whole screen.";
+
+static const char h_scale_filter[] =
+ "When stretching, how missing pixels are filled.\n"
+ "Nearest copies the last pixel. Sharp keeps pixels\n"
+ "aligned where possible. Smooth adds a blur effect.";
+
+
+static const char *men_scale_size[] = { "Native", "Aspect", "Full", NULL};
+static const char *men_scale_filter[] = { "Nearest", "Sharp", "Smooth", NULL};
+
+static menu_entry e_menu_video_options[] =
+{
+ mee_onoff_h ("Show FPS", 0, show_fps, 1, h_show_fps),
+ mee_enum_h ("Screen size", 0, scale_size, men_scale_size, h_scale_size),
+ mee_enum_h ("Filter", 0, scale_filter, men_scale_filter, h_scale_filter),
+ mee_range_h ("Audio buffer", 0, audio_buffer_size, 1, 15, h_audio_buffer_size),
+ mee_end,
+};
+
+static int menu_loop_video_options(int id, int keys)
+{
+ static int sel = 0;
+
+ me_loop(e_menu_video_options, &sel);
+ scale_update_scaler();
+
+ return 0;
+}
+
+static int key_config_loop_wrap(int id, int keys)
+{
+ me_bind_action *actions = me_ctrl_actions;
+ size_t action_size = array_size(me_ctrl_actions);
+ me_bind_action *emu_actions = emuctrl_actions;
+ size_t emu_action_size = array_size(emuctrl_actions);
+
+ if (!strcmp(core_name, "gpsp")) {
+ actions = gba_ctrl_actions;
+ action_size = array_size(gba_ctrl_actions);
+ } else if (strstr(core_name, "snes")) {
+ actions = snes_ctrl_actions;
+ action_size = array_size(snes_ctrl_actions);
+ }
+
+ switch (id) {
+ case MA_CTRL_PLAYER1:
+ key_config_loop(actions, action_size - 1, 0);
+ break;
+ case MA_CTRL_EMU:
+ key_config_loop(emu_actions, emu_action_size - 1, -1);
+ break;
+ default:
+ break;
+ }
+ 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;
+}
+
+static menu_entry e_menu_config_options[] =
+{
+ 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_handler_h ("Restore defaults", mh_restore_defaults, h_restore_def),
+ mee_end,
+};
+
+static int menu_loop_config_options(int id, int keys)
+{
+ static int sel = 0;
+
+ me_loop(e_menu_config_options, &sel);
+
+ return 0;
+}
+
+static int main_menu_handler(int id, int keys)
+{
+ switch (id)
+ {
+ case MA_MAIN_RESUME_GAME:
+ return 1;
+ case MA_MAIN_SAVE_STATE:
+ return menu_loop_savestate(0);
+ case MA_MAIN_LOAD_STATE:
+ return menu_loop_savestate(1);
+ case MA_MAIN_RESET_GAME:
+ current_core.retro_reset();
+ return 1;
+ case MA_MAIN_EXIT:
+ should_quit = 1;
+ return 1;
+ default:
+ lprintf("%s: something unknown selected\n", __FUNCTION__);
+ break;
+ }
+
+ return 0;
+}
+
+static menu_entry e_menu_main[] =
+{
+ mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
+ 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("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_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
+ mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
+ mee_end,
+};
+
+static void draw_savestate_bg(int slot)
+{
+}
+
+void menu_loop(void)
+{
+ static int sel = 0;
+ plat_video_menu_enter(1);
+
+ me_enable(e_menu_main, MA_MAIN_CORE_OPTS, core_options.visible_len > 0);
+
+#ifdef MMENU
+ me_enable(e_menu_main, MA_MAIN_SAVE_STATE, mmenu == NULL);
+ me_enable(e_menu_main, MA_MAIN_LOAD_STATE, mmenu == NULL);
+#endif
+
+ memcpy(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_h * g_menuscreen_pp * sizeof(uint16_t));
+
+ menu_darken_bg(g_menubg_ptr, g_menubg_ptr, g_menuscreen_h * g_menuscreen_pp, 0);
+ me_loop_d(e_menu_main, &sel, NULL, NULL);
+
+ /* wait until menu, ok, back is released */
+ while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
+ ;
+ memset(g_menubg_ptr, 0, g_menuscreen_h * g_menuscreen_pp * sizeof(uint16_t));
+
+ /* Force the hud to clear */
+ plat_video_set_msg(" ");
+ plat_video_menu_leave();
+}
+
+int menu_init(void)
+{
+ menu_init_base();
+
+ g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
+ g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
+ if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
+ fprintf(stderr, "OOM\n");
+ return -1;
+ }
+ return 0;
+}
+
+void menu_finish(void)
+{
+ if (g_menubg_src_ptr) {
+ free(g_menubg_src_ptr);
+ }
+
+ if (g_menubg_ptr) {
+ free(g_menubg_ptr);
+ }
+}
+
+static void debug_menu_loop(void)
+{
+}
+
+void menu_update_msg(const char *msg)
+{
+ strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
+ menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
+
+ menu_error_time = plat_get_ticks_ms();
+ PA_INFO("%s\n", menu_error_msg);
+}