2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
21 #include "plugin_lib.h"
26 #include "common/plat.h"
27 #include "common/input.h"
28 #include "linux/in_evdev.h"
29 #include "../libpcsxcore/misc.h"
30 #include "../libpcsxcore/cdrom.h"
31 #include "../libpcsxcore/psemu_plugin_defs.h"
32 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
33 #include "../plugins/dfinput/main.h"
36 #define array_size(x) (sizeof(x) / sizeof(x[0]))
75 static int last_psx_w, last_psx_h, last_psx_bpp;
76 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
77 static char rom_fname_reload[MAXPATHLEN];
78 static char last_selected_fname[MAXPATHLEN];
79 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
81 static int memcard1_sel, memcard2_sel;
83 int analog_deadzone; // for Caanoo
85 #ifdef __ARM_ARCH_7A__
86 #define DEFAULT_PSX_CLOCK 57
87 #define DEFAULT_PSX_CLOCK_S "57"
89 #define DEFAULT_PSX_CLOCK 50
90 #define DEFAULT_PSX_CLOCK_S "50"
94 extern int iUseReverb;
95 extern int iUseInterpolation;
97 extern int iSPUIRQWait;
101 static const char *bioses[24];
102 static const char *gpu_plugins[16];
103 static const char *spu_plugins[16];
104 static const char *memcards[32];
105 static int bios_sel, gpu_plugsel, spu_plugsel;
108 static int min(int x, int y) { return x < y ? x : y; }
109 static int max(int x, int y) { return x > y ? x : y; }
111 void emu_make_path(char *buff, const char *end, int size)
115 end_len = strlen(end);
116 pos = plat_get_root_dir(buff, size);
117 strncpy(buff + pos, end, size - pos);
119 if (pos + end_len > size - 1)
120 printf("Warning: path truncated: %s\n", buff);
123 static int emu_check_save_file(int slot)
125 int ret = emu_check_state(slot);
126 return ret == 0 ? 1 : 0;
129 static int emu_save_load_game(int load, int unused)
134 ret = emu_load_state(state_slot);
136 // reflect hle/bios mode from savestate
139 else if (bios_sel == 0 && bioses[1] != NULL)
140 // XXX: maybe find the right bios instead
144 ret = emu_save_state(state_slot);
149 // propagate menu settings to the emu vars
150 static void menu_sync_config(void)
152 static int allow_abs_only_old;
157 Config.PsxType = region - 1;
159 cycle_multiplier = 10000 / psx_clock;
161 switch (in_type_sel1) {
162 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
163 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
164 default: in_type1 = PSE_PAD_TYPE_STANDARD;
166 switch (in_type_sel2) {
167 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
168 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
169 default: in_type2 = PSE_PAD_TYPE_STANDARD;
171 if (in_evdev_allow_abs_only != allow_abs_only_old) {
172 plat_rescan_inputs();
173 allow_abs_only_old = in_evdev_allow_abs_only;
176 iVolume = 768 + 128 * volume_boost;
177 pl_rearmed_cbs.frameskip = frameskip - 1;
178 pl_timing_prepare(Config.PsxType);
181 static void menu_set_defconfig(void)
183 emu_set_default_config();
189 analog_deadzone = 50;
190 psx_clock = DEFAULT_PSX_CLOCK;
193 in_type_sel1 = in_type_sel2 = 0;
194 in_evdev_allow_abs_only = 0;
199 #define CE_CONFIG_STR(val) \
200 { #val, 0, Config.val }
202 #define CE_CONFIG_VAL(val) \
203 { #val, sizeof(Config.val), &Config.val }
205 #define CE_STR(val) \
208 #define CE_INTVAL(val) \
209 { #val, sizeof(val), &val }
211 #define CE_INTVAL_P(val) \
212 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
214 // 'versioned' var, used when defaults change
215 #define CE_INTVAL_V(val, ver) \
216 { #val #ver, sizeof(val), &val }
218 #define CE_INTVAL_PV(val, ver) \
219 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
221 static const struct {
229 // CE_CONFIG_STR(Cdr),
234 CE_CONFIG_VAL(Debug),
235 CE_CONFIG_VAL(PsxOut),
236 CE_CONFIG_VAL(SpuIrq),
237 CE_CONFIG_VAL(RCntFix),
238 CE_CONFIG_VAL(VSyncWA),
240 CE_CONFIG_VAL(CdrReschedule),
242 CE_INTVAL_V(scaling, 2),
243 CE_INTVAL(g_layer_x),
244 CE_INTVAL(g_layer_y),
245 CE_INTVAL(g_layer_w),
246 CE_INTVAL(g_layer_h),
248 CE_INTVAL(state_slot),
249 CE_INTVAL(cpu_clock),
251 CE_INTVAL(in_type_sel1),
252 CE_INTVAL(in_type_sel2),
253 CE_INTVAL(analog_deadzone),
254 CE_INTVAL_V(frameskip, 2),
255 CE_INTVAL_P(gpu_peops.iUseDither),
256 CE_INTVAL_P(gpu_peops.dwActFixes),
257 CE_INTVAL_P(gpu_unai.abe_hack),
258 CE_INTVAL_P(gpu_unai.no_light),
259 CE_INTVAL_P(gpu_unai.no_blend),
260 CE_INTVAL_V(iUseReverb, 3),
261 CE_INTVAL_V(iXAPitch, 3),
262 CE_INTVAL_V(iUseInterpolation, 3),
263 CE_INTVAL_V(iSPUIRQWait, 3),
264 CE_INTVAL_V(iUseTimer, 3),
265 CE_INTVAL(warned_about_bios),
266 CE_INTVAL(in_evdev_allow_abs_only),
267 CE_INTVAL(volume_boost),
268 CE_INTVAL(psx_clock),
269 CE_INTVAL(new_dynarec_hacks),
272 static char *get_cd_label(void)
274 static char trimlabel[33];
277 strncpy(trimlabel, CdromLabel, 32);
279 for (j = 31; j >= 0; j--)
280 if (trimlabel[j] == ' ')
286 static void make_cfg_fname(char *buf, size_t size, int is_game)
289 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
291 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
294 static void keys_write_all(FILE *f);
296 static int menu_write_config(int is_game)
298 char cfgfile[MAXPATHLEN];
302 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
303 f = fopen(cfgfile, "w");
305 printf("menu_write_config: failed to open: %s\n", cfgfile);
309 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
310 fprintf(f, "%s = ", config_data[i].name);
311 switch (config_data[i].len) {
313 fprintf(f, "%s\n", (char *)config_data[i].val);
316 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
319 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
322 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
325 printf("menu_write_config: unhandled len %d for %s\n",
326 config_data[i].len, config_data[i].name);
332 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
340 static void parse_str_val(char *cval, const char *src)
343 strncpy(cval, src, MAXPATHLEN);
344 cval[MAXPATHLEN - 1] = 0;
345 tmp = strchr(cval, '\n');
347 tmp = strchr(cval, '\r');
352 static void keys_load_all(const char *cfg);
354 static int menu_load_config(int is_game)
356 char cfgfile[MAXPATHLEN];
362 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
363 f = fopen(cfgfile, "r");
365 printf("menu_load_config: failed to open: %s\n", cfgfile);
369 fseek(f, 0, SEEK_END);
372 printf("bad size %ld: %s\n", size, cfgfile);
376 cfg = malloc(size + 1);
380 fseek(f, 0, SEEK_SET);
381 if (fread(cfg, 1, size, f) != size) {
382 printf("failed to read: %s\n", cfgfile);
387 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
391 tmp = strstr(cfg, config_data[i].name);
394 tmp += strlen(config_data[i].name);
395 if (strncmp(tmp, " = ", 3) != 0)
399 if (config_data[i].len == 0) {
400 parse_str_val(config_data[i].val, tmp);
405 val = strtoul(tmp, &tmp2, 16);
406 if (tmp2 == NULL || tmp == tmp2)
407 continue; // parse failed
409 switch (config_data[i].len) {
411 *(u8 *)config_data[i].val = val;
414 *(u16 *)config_data[i].val = val;
417 *(u32 *)config_data[i].val = val;
420 printf("menu_load_config: unhandled len %d for %s\n",
421 config_data[i].len, config_data[i].name);
427 char *tmp = strstr(cfg, "lastcdimg = ");
430 parse_str_val(last_selected_fname, tmp);
445 for (i = bios_sel = 0; bioses[i] != NULL; i++)
446 if (strcmp(Config.Bios, bioses[i]) == 0)
447 { bios_sel = i; break; }
449 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
450 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
451 { gpu_plugsel = i; break; }
453 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
454 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
455 { spu_plugsel = i; break; }
460 // rrrr rggg gggb bbbb
461 static unsigned short fname2color(const char *fname)
463 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
464 ".bz", ".znx", ".pbp", ".cbn" };
465 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
466 ".table", ".index", ".sbi" };
467 const char *ext = strrchr(fname, '.');
472 for (i = 0; i < array_size(cdimg_exts); i++)
473 if (strcasecmp(ext, cdimg_exts[i]) == 0)
475 for (i = 0; i < array_size(other_exts); i++)
476 if (strcasecmp(ext, other_exts[i]) == 0)
481 static void draw_savestate_bg(int slot);
483 static const char *filter_exts[] = {
484 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
487 #define MENU_ALIGN_LEFT
488 #ifdef __ARM_ARCH_7A__ // assume hires device
494 #define menu_init menu_init_common
495 #include "common/menu.c"
498 // a bit of black magic here
499 static void draw_savestate_bg(int slot)
501 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
503 char fname[MAXPATHLEN];
510 ret = get_state_filename(fname, sizeof(fname), slot);
514 f = gzopen(fname, "rb");
518 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
519 fprintf(stderr, "gzseek failed\n");
524 gpu = malloc(sizeof(*gpu));
530 ret = gzread(f, gpu, sizeof(*gpu));
532 if (ret != sizeof(*gpu)) {
533 fprintf(stderr, "gzread failed\n");
537 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
539 if (gpu->ulStatus & 0x800000)
540 goto out; // disabled
542 x = gpu->ulControl[5] & 0x3ff;
543 y = (gpu->ulControl[5] >> 10) & 0x1ff;
544 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
545 w = psx_widths[(gpu->ulStatus >> 16) & 7];
546 tmp = gpu->ulControl[7];
547 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
548 if (gpu->ulStatus & 0x80000) // doubleheight
551 x = max(0, g_menuscreen_w - w) & ~3;
552 y = max(0, g_menuscreen_h / 2 - h / 2);
553 w = min(g_menuscreen_w, w);
554 h = min(g_menuscreen_h, h);
555 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
557 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
558 if (gpu->ulStatus & 0x200000)
559 bgr888_to_rgb565(d, s, w * 3);
561 bgr555_to_rgb565(d, s, w * 2);
562 #ifndef __ARM_ARCH_7A__
563 // better darken this on small screens
564 menu_darken_bg(d, d, w * 2, 0);
572 // ---------- XXX: pandora specific -----------
574 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
575 static char **pnd_filter_list;
577 static void apply_filter(int which)
583 if (pnd_filter_list == NULL || which == old)
586 for (i = 0; i < which; i++)
587 if (pnd_filter_list[i] == NULL)
590 if (pnd_filter_list[i] == NULL)
593 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
598 static void apply_lcdrate(int pal)
606 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
607 pnd_script_base, pal ? 50 : 60);
612 static menu_entry e_menu_gfx_options[];
614 static void pnd_menu_init(void)
622 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
624 dir = opendir("/etc/pandora/conf/dss_fir");
626 perror("filter opendir");
639 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
648 mfilters = calloc(count + 1, sizeof(mfilters[0]));
649 if (mfilters == NULL)
653 for (i = 0; (ent = readdir(dir)); ) {
656 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
659 len = strlen(ent->d_name);
661 // skip pre-HF5 extra files
662 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
664 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
667 // have to cut "_up_h" for pre-HF5
668 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
671 if (len > sizeof(buff) - 1)
674 strncpy(buff, ent->d_name, len);
676 mfilters[i] = strdup(buff);
677 if (mfilters[i] != NULL)
682 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
683 e_menu_gfx_options[i].data = (void *)mfilters;
684 pnd_filter_list = mfilters;
687 void menu_finish(void)
689 plat_cpu_clock_apply(cpu_clock_st);
692 // -------------- key config --------------
694 me_bind_action me_ctrl_actions[] =
696 { "UP ", 1 << DKEY_UP},
697 { "DOWN ", 1 << DKEY_DOWN },
698 { "LEFT ", 1 << DKEY_LEFT },
699 { "RIGHT ", 1 << DKEY_RIGHT },
700 { "TRIANGLE", 1 << DKEY_TRIANGLE },
701 { "CIRCLE ", 1 << DKEY_CIRCLE },
702 { "CROSS ", 1 << DKEY_CROSS },
703 { "SQUARE ", 1 << DKEY_SQUARE },
704 { "L1 ", 1 << DKEY_L1 },
705 { "R1 ", 1 << DKEY_R1 },
706 { "L2 ", 1 << DKEY_L2 },
707 { "R2 ", 1 << DKEY_R2 },
708 { "L3 ", 1 << DKEY_L3 },
709 { "R3 ", 1 << DKEY_R3 },
710 { "START ", 1 << DKEY_START },
711 { "SELECT ", 1 << DKEY_SELECT },
715 me_bind_action emuctrl_actions[] =
717 { "Save State ", 1 << SACTION_SAVE_STATE },
718 { "Load State ", 1 << SACTION_LOAD_STATE },
719 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
720 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
721 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
722 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
723 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
724 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
725 { "Gun A button ", 1 << SACTION_GUN_A },
726 { "Gun B button ", 1 << SACTION_GUN_B },
727 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
728 #ifndef __ARM_ARCH_7A__ /* XXX */
729 { "Volume Up ", 1 << SACTION_VOLUME_UP },
730 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
735 static char *mystrip(char *str)
740 for (i = 0; i < len; i++)
741 if (str[i] != ' ') break;
742 if (i > 0) memmove(str, str + i, len - i + 1);
745 for (i = len - 1; i >= 0; i--)
746 if (str[i] != ' ') break;
752 static void get_line(char *d, size_t size, const char *s)
757 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
768 static void keys_write_all(FILE *f)
772 for (d = 0; d < IN_MAX_DEVS; d++)
774 const int *binds = in_get_dev_binds(d);
775 const char *name = in_get_dev_name(d, 0, 0);
778 if (binds == NULL || name == NULL)
781 fprintf(f, "binddev = %s\n", name);
782 in_get_config(d, IN_CFG_BIND_COUNT, &count);
784 for (k = 0; k < count; k++)
789 act[0] = act[31] = 0;
790 name = in_get_key_name(d, k);
792 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
793 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
794 mask = me_ctrl_actions[i].mask;
796 strncpy(act, me_ctrl_actions[i].name, 31);
797 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
800 mask = me_ctrl_actions[i].mask << 16;
802 strncpy(act, me_ctrl_actions[i].name, 31);
803 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
808 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
809 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
810 mask = emuctrl_actions[i].mask;
812 strncpy(act, emuctrl_actions[i].name, 31);
813 fprintf(f, "bind %s = %s\n", name, mystrip(act));
821 static int parse_bind_val(const char *val, int *type)
825 *type = IN_BINDTYPE_NONE;
829 if (strncasecmp(val, "player", 6) == 0)
831 int player, shift = 0;
832 player = atoi(val + 6) - 1;
834 if ((unsigned int)player > 1)
839 *type = IN_BINDTYPE_PLAYER12;
840 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
841 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
842 return me_ctrl_actions[i].mask << shift;
845 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
846 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
847 *type = IN_BINDTYPE_EMU;
848 return emuctrl_actions[i].mask;
855 static void keys_load_all(const char *cfg)
857 char dev[256], key[128], *act;
863 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
866 get_line(dev, sizeof(dev), p);
867 dev_id = in_config_parse_dev(dev);
869 printf("input: can't handle dev: %s\n", dev);
873 in_unbind_all(dev_id, -1, -1);
874 while ((p = strstr(p, "bind"))) {
875 if (strncmp(p, "binddev = ", 10) == 0)
880 printf("input: parse error: %16s..\n", p);
884 get_line(key, sizeof(key), p);
885 act = strchr(key, '=');
887 printf("parse failed: %16s..\n", p);
895 bind = parse_bind_val(act, &bindtype);
896 if (bind != -1 && bind != 0) {
897 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
898 in_config_bind_key(dev_id, key, bind, bindtype);
901 lprintf("config: unhandled action \"%s\"\n", act);
907 static int key_config_loop_wrap(int id, int keys)
910 case MA_CTRL_PLAYER1:
911 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
913 case MA_CTRL_PLAYER2:
914 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
917 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
925 static const char *mgn_dev_name(int id, int *offs)
927 const char *name = NULL;
930 if (id == MA_CTRL_DEV_FIRST)
933 for (; it < IN_MAX_DEVS; it++) {
934 name = in_get_dev_name(it, 1, 1);
943 static const char *mgn_saveloadcfg(int id, int *offs)
948 static int mh_savecfg(int id, int keys)
950 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
951 me_update_msg("config saved");
953 me_update_msg("failed to write config");
958 static int mh_input_rescan(int id, int keys)
960 //menu_sync_config();
961 plat_rescan_inputs();
962 me_update_msg("rescan complete.");
967 static const char *men_in_type_sel[] = {
968 "Standard (SCPH-1080)",
969 "Analog (SCPH-1150)",
973 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
974 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
976 static menu_entry e_menu_keyconfig[] =
978 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
979 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
980 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
982 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
983 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
984 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
985 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
986 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
987 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
988 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
989 mee_handler ("Rescan devices", mh_input_rescan),
991 mee_label ("Input devices:"),
992 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
993 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
994 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
995 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
996 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
997 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
998 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1002 static int menu_loop_keyconfig(int id, int keys)
1006 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1007 me_loop(e_menu_keyconfig, &sel);
1011 // ------------ gfx options menu ------------
1013 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1014 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1015 "using d-pad or move it using R+d-pad";
1016 static const char *men_dummy[] = { NULL };
1018 static int menu_loop_cscaler(int id, int keys)
1022 scaling = SCALE_CUSTOM;
1024 omap_enable_layer(1);
1029 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1030 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1031 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1034 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1035 if (inp & PBTN_UP) g_layer_y--;
1036 if (inp & PBTN_DOWN) g_layer_y++;
1037 if (inp & PBTN_LEFT) g_layer_x--;
1038 if (inp & PBTN_RIGHT) g_layer_x++;
1039 if (!(inp & PBTN_R)) {
1040 if (inp & PBTN_UP) g_layer_h += 2;
1041 if (inp & PBTN_DOWN) g_layer_h -= 2;
1042 if (inp & PBTN_LEFT) g_layer_w += 2;
1043 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1045 if (inp & (PBTN_MOK|PBTN_MBACK))
1048 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1049 if (g_layer_x < 0) g_layer_x = 0;
1050 if (g_layer_x > 640) g_layer_x = 640;
1051 if (g_layer_y < 0) g_layer_y = 0;
1052 if (g_layer_y > 420) g_layer_y = 420;
1053 if (g_layer_w < 160) g_layer_w = 160;
1054 if (g_layer_h < 60) g_layer_h = 60;
1055 if (g_layer_x + g_layer_w > 800)
1056 g_layer_w = 800 - g_layer_x;
1057 if (g_layer_y + g_layer_h > 480)
1058 g_layer_h = 480 - g_layer_y;
1059 omap_enable_layer(1);
1063 omap_enable_layer(0);
1068 static menu_entry e_menu_gfx_options[] =
1070 mee_enum ("Scaler", 0, scaling, men_scaler),
1071 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1072 // mee_onoff ("Vsync", 0, vsync, 1),
1073 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1077 static int menu_loop_gfx_options(int id, int keys)
1081 me_loop(e_menu_gfx_options, &sel);
1086 // ------------ bios/plugins ------------
1088 static menu_entry e_menu_plugin_gpu_unai[] =
1090 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1091 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1092 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1096 static int menu_loop_plugin_gpu_unai(int id, int keys)
1099 me_loop(e_menu_plugin_gpu_unai, &sel);
1103 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1104 static const char h_gpu_0[] = "Needed for Chrono Cross";
1105 static const char h_gpu_1[] = "Capcom fighting games";
1106 static const char h_gpu_2[] = "Black screens in Lunar";
1107 static const char h_gpu_3[] = "Compatibility mode";
1108 static const char h_gpu_6[] = "Pandemonium 2";
1109 static const char h_gpu_7[] = "Skip every second frame";
1110 static const char h_gpu_8[] = "Needed by Dark Forces";
1111 static const char h_gpu_9[] = "better g-colors, worse textures";
1112 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1114 static menu_entry e_menu_plugin_gpu_peops[] =
1116 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1117 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1118 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1119 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1120 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1121 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1122 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1123 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1124 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1125 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1129 static int menu_loop_plugin_gpu_peops(int id, int keys)
1132 me_loop(e_menu_plugin_gpu_peops, &sel);
1136 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1137 static const char h_spu_volboost[] = "Large values cause distortion";
1138 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1139 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1141 static menu_entry e_menu_plugin_spu[] =
1143 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1144 mee_onoff ("Reverb", 0, iUseReverb, 2),
1145 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1146 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1147 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1148 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1152 static int menu_loop_plugin_spu(int id, int keys)
1155 me_loop(e_menu_plugin_spu, &sel);
1159 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1160 "savestates and can't be changed there. Must save\n"
1161 "config and reload the game for change to take effect";
1162 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1163 "for plugin change to take effect";
1164 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1165 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1166 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1168 static menu_entry e_menu_plugin_options[] =
1170 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1171 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1172 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1173 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1174 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1175 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1179 static menu_entry e_menu_main2[];
1181 static int menu_loop_plugin_options(int id, int keys)
1184 me_loop(e_menu_plugin_options, &sel);
1186 // sync BIOS/plugins
1187 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1188 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1189 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1190 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1195 // ------------ adv options menu ------------
1197 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1198 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1199 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1200 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1202 static menu_entry e_menu_speed_hacks[] =
1204 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1205 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1206 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1207 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1211 static int menu_loop_speed_hacks(int id, int keys)
1214 me_loop(e_menu_speed_hacks, &sel);
1218 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1219 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1220 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1221 "(green: normal, red: fmod, blue: noise)";
1222 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1223 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1224 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1225 "(proper .cue/.bin dump is needed otherwise)";
1226 static const char h_cfg_sio[] = "You should not need this, breaks games";
1227 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1228 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1229 "(timing hack, breaks other games)";
1230 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1231 "(timing hack, breaks other games)";
1232 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1233 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1234 "Might be useful to overcome some dynarec bugs";
1235 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1236 "must reload game for any change to take effect";
1238 static menu_entry e_menu_adv_options[] =
1240 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1241 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1242 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1243 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1244 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1245 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1246 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1247 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1248 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1249 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1250 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1251 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1255 static int menu_loop_adv_options(int id, int keys)
1258 me_loop(e_menu_adv_options, &sel);
1262 // ------------ options menu ------------
1264 static int mh_restore_defaults(int id, int keys)
1266 menu_set_defconfig();
1267 me_update_msg("defaults restored");
1271 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1272 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1274 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1275 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1276 "loading state or both";
1278 static const char h_restore_def[] = "Switches back to default / recommended\n"
1280 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1282 static menu_entry e_menu_options[] =
1284 // mee_range ("Save slot", 0, state_slot, 0, 9),
1285 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1286 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1287 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1288 mee_enum ("Region", 0, region, men_region),
1289 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1290 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1291 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1292 mee_handler ("[Advanced]", menu_loop_adv_options),
1293 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1294 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1295 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1299 static int menu_loop_options(int id, int keys)
1304 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1305 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1306 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1308 me_loop(e_menu_options, &sel);
1313 // ------------ debug menu ------------
1315 static void draw_frame_debug(GPUFreeze_t *gpuf)
1317 int w = min(g_menuscreen_w, 1024);
1318 int h = min(g_menuscreen_h, 512);
1319 u16 *d = g_menuscreen_ptr;
1320 u16 *s = (u16 *)gpuf->psxVRam;
1324 gpuf->ulFreezeVersion = 1;
1325 if (GPU_freeze != NULL)
1326 GPU_freeze(1, gpuf);
1328 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1329 bgr555_to_rgb565(d, s, w * 2);
1331 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1332 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1333 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1334 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1335 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1338 static void debug_menu_loop(void)
1343 gpuf = malloc(sizeof(*gpuf));
1350 draw_frame_debug(gpuf);
1353 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1354 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1355 if (inp & PBTN_MBACK)
1362 // --------- memcard manager ---------
1364 static void draw_mc_icon(int dx, int dy, const u16 *s)
1369 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1371 for (y = 0; y < 16; y++, s += 16) {
1372 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1373 for (x = 0; x < 16; x++) {
1375 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1376 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1382 static void draw_mc_bg(void)
1384 McdBlock *blocks1, *blocks2;
1388 blocks1 = malloc(15 * sizeof(blocks1[0]));
1389 blocks2 = malloc(15 * sizeof(blocks1[0]));
1390 if (blocks1 == NULL || blocks2 == NULL)
1393 for (i = 0; i < 15; i++) {
1394 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1395 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1400 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1402 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1406 maxicons = g_menuscreen_h / 32;
1409 row2 = g_menuscreen_w / 2;
1410 for (i = 0; i < maxicons; i++) {
1411 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1412 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1414 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1415 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1418 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1426 static void handle_memcard_sel(void)
1429 if (memcard1_sel != 0)
1430 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1432 if (memcard2_sel != 0)
1433 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1434 LoadMcds(Config.Mcd1, Config.Mcd2);
1438 static menu_entry e_memcard_options[] =
1440 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1441 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1445 static int menu_loop_memcards(int id, int keys)
1451 memcard1_sel = memcard2_sel = 0;
1452 p = strrchr(Config.Mcd1, '/');
1454 for (i = 0; memcards[i] != NULL; i++)
1455 if (strcmp(p + 1, memcards[i]) == 0)
1456 { memcard1_sel = i; break; }
1457 p = strrchr(Config.Mcd2, '/');
1459 for (i = 0; memcards[i] != NULL; i++)
1460 if (strcmp(p + 1, memcards[i]) == 0)
1461 { memcard2_sel = i; break; }
1463 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1465 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1470 // --------- main menu help ----------
1472 static void menu_bios_warn(void)
1475 static const char msg[] =
1476 "You don't seem to have copied any BIOS\n"
1478 #ifdef __ARM_ARCH_7A__ // XXX
1479 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1481 "pcsx_rearmed/bios/\n\n"
1483 "While many games work fine with fake\n"
1484 "(HLE) BIOS, others (like MGS and FF8)\n"
1485 "require BIOS to work.\n"
1486 "After copying the file, you'll also need\n"
1487 "to select it in the emu's menu:\n"
1488 "options->[BIOS/Plugins]\n\n"
1489 "The file is usually named SCPH1001.BIN,\n"
1490 "but other not compressed files can be\n"
1492 "Press (B) or (X) to continue";
1496 draw_menu_message(msg, NULL);
1498 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1499 if (inp & (PBTN_MBACK|PBTN_MOK))
1504 // ------------ main menu ------------
1508 static void draw_frame_main(void)
1515 if (CdromId[0] != 0) {
1516 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1517 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1518 Config.HLE ? "HLE" : "BIOS");
1519 smalltext_out16(4, 1, buff, 0x105f);
1524 tmp = localtime(<ime);
1525 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1526 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1527 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1531 static void draw_frame_credits(void)
1533 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1536 static const char credits_text[] =
1538 "(C) 1999-2003 PCSX Team\n"
1539 "(C) 2005-2009 PCSX-df Team\n"
1540 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1541 "GPU and SPU code by Pete Bernert\n"
1542 " and the P.E.Op.S. team\n"
1543 "ARM recompiler (C) 2009-2011 Ari64\n"
1544 "PCSX4ALL plugins by PCSX4ALL team\n"
1545 " Chui, Franxis, Unai\n\n"
1546 "integration, optimization and\n"
1547 " frontend (C) 2010-2011 notaz\n";
1549 static int reset_game(void)
1552 if (bios_sel == 0 && !Config.HLE)
1558 if (CheckCdrom() != -1) {
1564 static int reload_plugins(const char *cdimg)
1570 set_cd_image(cdimg);
1572 pcnt_hook_plugins();
1574 if (OpenPlugins() == -1) {
1575 me_update_msg("failed to open plugins");
1578 plugin_call_rearmed_cbs();
1581 CdromLabel[0] = '\0';
1586 static int run_bios(void)
1592 if (reload_plugins(NULL) != 0)
1600 static int run_exe(void)
1604 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1609 if (reload_plugins(NULL) != 0)
1613 if (Load(fname) != 0) {
1614 me_update_msg("exe load failed, bad file?");
1623 static int run_cd_image(const char *fname)
1626 reload_plugins(fname);
1628 // always autodetect, menu_sync_config will override as needed
1631 if (CheckCdrom() == -1) {
1632 // Only check the CD if we are starting the console with a CD
1634 me_update_msg("unsupported/invalid CD image");
1640 // Read main executable directly from CDRom and start it
1641 if (LoadCdrom() == -1) {
1643 me_update_msg("failed to load CD image");
1651 static int romsel_run(void)
1653 int prev_gpu, prev_spu;
1656 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1660 printf("selected file: %s\n", fname);
1662 new_dynarec_clear_full();
1664 if (run_cd_image(fname) != 0)
1667 prev_gpu = gpu_plugsel;
1668 prev_spu = spu_plugsel;
1669 if (menu_load_config(1) != 0)
1670 menu_load_config(0);
1672 // check for plugin changes, have to repeat
1673 // loading if game config changed plugins to reload them
1674 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1675 printf("plugin change detected, reloading plugins..\n");
1676 if (run_cd_image(fname) != 0)
1681 printf("note: running without BIOS, expect compatibility problems\n");
1683 strcpy(last_selected_fname, rom_fname_reload);
1687 static int swap_cd_image(void)
1691 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1695 printf("selected file: %s\n", fname);
1698 CdromLabel[0] = '\0';
1700 set_cd_image(fname);
1701 if (ReloadCdromPlugin() < 0) {
1702 me_update_msg("failed to load cdr plugin");
1705 if (CDR_open() < 0) {
1706 me_update_msg("failed to open cdr plugin");
1710 SetCdOpenCaseTime(time(NULL) + 2);
1713 strcpy(last_selected_fname, rom_fname_reload);
1717 static int main_menu_handler(int id, int keys)
1721 case MA_MAIN_RESUME_GAME:
1725 case MA_MAIN_SAVE_STATE:
1727 return menu_loop_savestate(0);
1729 case MA_MAIN_LOAD_STATE:
1731 return menu_loop_savestate(1);
1733 case MA_MAIN_RESET_GAME:
1734 if (ready_to_go && reset_game() == 0)
1737 case MA_MAIN_LOAD_ROM:
1738 if (romsel_run() == 0)
1741 case MA_MAIN_SWAP_CD:
1742 if (swap_cd_image() == 0)
1745 case MA_MAIN_RUN_BIOS:
1746 if (run_bios() == 0)
1749 case MA_MAIN_RUN_EXE:
1753 case MA_MAIN_CREDITS:
1754 draw_menu_message(credits_text, draw_frame_credits);
1755 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1761 lprintf("%s: something unknown selected\n", __FUNCTION__);
1768 static menu_entry e_menu_main2[] =
1770 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1771 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1772 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1773 mee_handler ("Memcard manager", menu_loop_memcards),
1777 static int main_menu2_handler(int id, int keys)
1781 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1782 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1784 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1787 static const char h_extra[] = "Change CD, manage memcards..\n";
1789 static menu_entry e_menu_main[] =
1793 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1794 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1795 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1796 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1797 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1798 mee_handler ("Options", menu_loop_options),
1799 mee_handler ("Controls", menu_loop_keyconfig),
1800 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1801 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1802 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1806 // ----------------------------
1808 static void menu_leave_emu(void);
1810 void menu_loop(void)
1816 if (bioses[1] == NULL && !warned_about_bios) {
1818 warned_about_bios = 1;
1821 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1822 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1823 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1824 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1826 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1829 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1830 } while (!ready_to_go);
1832 /* wait until menu, ok, back is released */
1833 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1836 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1841 static int qsort_strcmp(const void *p1, const void *p2)
1843 char * const *s1 = (char * const *)p1;
1844 char * const *s2 = (char * const *)p2;
1845 return strcasecmp(*s1, *s2);
1848 static void scan_bios_plugins(void)
1850 char fname[MAXPATHLEN];
1852 int bios_i, gpu_i, spu_i, mc_i;
1857 gpu_plugins[0] = "builtin_gpu";
1858 spu_plugins[0] = "builtin_spu";
1859 memcards[0] = "(none)";
1860 bios_i = gpu_i = spu_i = mc_i = 1;
1862 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1863 dir = opendir(fname);
1865 perror("scan_bios_plugins bios opendir");
1880 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1883 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1884 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1885 printf("bad BIOS file: %s\n", ent->d_name);
1889 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1890 bioses[bios_i++] = strdup(ent->d_name);
1894 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1900 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1901 dir = opendir(fname);
1903 perror("scan_bios_plugins plugins opendir");
1917 p = strstr(ent->d_name, ".so");
1921 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1922 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1924 fprintf(stderr, "%s\n", dlerror());
1928 // now what do we have here?
1929 tmp = dlsym(h, "GPUinit");
1932 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1933 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1937 tmp = dlsym(h, "SPUinit");
1940 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1941 spu_plugins[spu_i++] = strdup(ent->d_name);
1945 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1952 dir = opendir("." MEMCARD_DIR);
1954 perror("scan_bios_plugins memcards opendir");
1969 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1972 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1973 if (stat(fname, &st) != 0) {
1974 printf("bad memcard file: %s\n", ent->d_name);
1978 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1979 memcards[mc_i++] = strdup(ent->d_name);
1983 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1987 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1992 void menu_init(void)
1994 char buff[MAXPATHLEN];
1996 strcpy(last_selected_fname, "/media");
1998 scan_bios_plugins();
2002 menu_set_defconfig();
2003 menu_load_config(0);
2008 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2009 if (g_menubg_src_ptr == NULL)
2011 emu_make_path(buff, "skin/background.png", sizeof(buff));
2012 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2014 #ifndef __ARM_ARCH_7A__ /* XXX */
2015 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2016 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2018 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2022 void menu_notify_mode_change(int w, int h, int bpp)
2033 g_layer_w = w; g_layer_h = h;
2037 if (h > g_menuscreen_h || (240 < h && h <= 360))
2038 goto fractional_4_3;
2040 // 4:3 that prefers integer scaling
2041 imult = g_menuscreen_h / h;
2042 g_layer_w = w * imult;
2043 g_layer_h = h * imult;
2044 mult = (float)g_layer_w / (float)g_layer_h;
2045 if (mult < 1.25f || mult > 1.666f)
2046 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2047 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2052 mult = 240.0f / (float)h * 4.0f / 3.0f;
2055 g_layer_w = mult * (float)g_menuscreen_h;
2056 g_layer_h = g_menuscreen_h;
2057 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2060 case SCALE_FULLSCREEN:
2061 g_layer_w = g_menuscreen_w;
2062 g_layer_h = g_menuscreen_h;
2069 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2070 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2071 if (g_layer_x < 0) g_layer_x = 0;
2072 if (g_layer_y < 0) g_layer_y = 0;
2073 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2074 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2077 static void menu_leave_emu(void)
2079 if (GPU_close != NULL) {
2080 int ret = GPU_close();
2082 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2085 plat_video_menu_enter(ready_to_go);
2087 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2088 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2089 int x = max(0, g_menuscreen_w - last_psx_w);
2090 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2091 int w = min(g_menuscreen_w, last_psx_w);
2092 int h = min(g_menuscreen_h, last_psx_h);
2093 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2094 u16 *s = pl_vout_buf;
2096 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2097 menu_darken_bg(d, s, w, 0);
2101 cpu_clock = plat_cpu_clock_get();
2104 void menu_prepare_emu(void)
2106 R3000Acpu *prev_cpu = psxCpu;
2108 plat_video_menu_leave();
2110 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2112 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2113 if (psxCpu != prev_cpu)
2114 // note that this does not really reset, just clears drc caches
2117 // core doesn't care about Config.Cdda changes,
2118 // so handle them manually here
2123 apply_lcdrate(Config.PsxType);
2124 apply_filter(filter);
2125 plat_cpu_clock_apply(cpu_clock);
2127 // push config to GPU plugin
2128 plugin_call_rearmed_cbs();
2130 if (GPU_open != NULL) {
2131 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2133 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2139 void me_update_msg(const char *msg)
2141 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2142 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2144 menu_error_time = plat_get_ticks_ms();
2145 lprintf("msg: %s\n", menu_error_msg);