From 99632f66e74fc57c463072be312d634aeb67bc61 Mon Sep 17 00:00:00 2001 From: neonloop Date: Wed, 4 Aug 2021 15:09:12 +0000 Subject: Initial commit --- menu.c | 409 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 menu.c (limited to 'menu.c') 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 +#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); +} -- cgit v1.2.3