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/cdriso.h"
32 #include "../libpcsxcore/psemu_plugin_defs.h"
33 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
34 #include "../plugins/dfinput/main.h"
37 #define array_size(x) (sizeof(x) / sizeof(x[0]))
48 MA_MAIN_SWAP_CD_MULTI,
77 static int last_psx_w, last_psx_h, last_psx_bpp;
78 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
79 static char rom_fname_reload[MAXPATHLEN];
80 static char last_selected_fname[MAXPATHLEN];
81 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
83 static int memcard1_sel, memcard2_sel;
85 int analog_deadzone; // for Caanoo
87 #ifdef __ARM_ARCH_7A__
88 #define DEFAULT_PSX_CLOCK 57
89 #define DEFAULT_PSX_CLOCK_S "57"
91 #define DEFAULT_PSX_CLOCK 50
92 #define DEFAULT_PSX_CLOCK_S "50"
96 extern int iUseReverb;
97 extern int iUseInterpolation;
99 extern int iSPUIRQWait;
100 extern int iUseTimer;
103 static const char *bioses[24];
104 static const char *gpu_plugins[16];
105 static const char *spu_plugins[16];
106 static const char *memcards[32];
107 static int bios_sel, gpu_plugsel, spu_plugsel;
110 static int min(int x, int y) { return x < y ? x : y; }
111 static int max(int x, int y) { return x > y ? x : y; }
113 void emu_make_path(char *buff, const char *end, int size)
117 end_len = strlen(end);
118 pos = plat_get_root_dir(buff, size);
119 strncpy(buff + pos, end, size - pos);
121 if (pos + end_len > size - 1)
122 printf("Warning: path truncated: %s\n", buff);
125 static int emu_check_save_file(int slot)
127 int ret = emu_check_state(slot);
128 return ret == 0 ? 1 : 0;
131 static int emu_save_load_game(int load, int unused)
136 ret = emu_load_state(state_slot);
138 // reflect hle/bios mode from savestate
141 else if (bios_sel == 0 && bioses[1] != NULL)
142 // XXX: maybe find the right bios instead
146 ret = emu_save_state(state_slot);
151 // propagate menu settings to the emu vars
152 static void menu_sync_config(void)
154 static int allow_abs_only_old;
159 Config.PsxType = region - 1;
161 cycle_multiplier = 10000 / psx_clock;
163 switch (in_type_sel1) {
164 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
165 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
166 default: in_type1 = PSE_PAD_TYPE_STANDARD;
168 switch (in_type_sel2) {
169 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
170 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
171 default: in_type2 = PSE_PAD_TYPE_STANDARD;
173 if (in_evdev_allow_abs_only != allow_abs_only_old) {
174 plat_rescan_inputs();
175 allow_abs_only_old = in_evdev_allow_abs_only;
178 iVolume = 768 + 128 * volume_boost;
179 pl_rearmed_cbs.frameskip = frameskip - 1;
180 pl_timing_prepare(Config.PsxType);
183 static void menu_set_defconfig(void)
185 emu_set_default_config();
191 analog_deadzone = 50;
192 psx_clock = DEFAULT_PSX_CLOCK;
195 in_type_sel1 = in_type_sel2 = 0;
196 in_evdev_allow_abs_only = 0;
201 #define CE_CONFIG_STR(val) \
202 { #val, 0, Config.val }
204 #define CE_CONFIG_VAL(val) \
205 { #val, sizeof(Config.val), &Config.val }
207 #define CE_STR(val) \
210 #define CE_INTVAL(val) \
211 { #val, sizeof(val), &val }
213 #define CE_INTVAL_P(val) \
214 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
216 // 'versioned' var, used when defaults change
217 #define CE_INTVAL_V(val, ver) \
218 { #val #ver, sizeof(val), &val }
220 #define CE_INTVAL_PV(val, ver) \
221 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
223 static const struct {
231 // CE_CONFIG_STR(Cdr),
236 CE_CONFIG_VAL(Debug),
237 CE_CONFIG_VAL(PsxOut),
238 CE_CONFIG_VAL(SpuIrq),
239 CE_CONFIG_VAL(RCntFix),
240 CE_CONFIG_VAL(VSyncWA),
242 CE_CONFIG_VAL(CdrReschedule),
244 CE_INTVAL_V(scaling, 2),
245 CE_INTVAL(g_layer_x),
246 CE_INTVAL(g_layer_y),
247 CE_INTVAL(g_layer_w),
248 CE_INTVAL(g_layer_h),
250 CE_INTVAL(state_slot),
251 CE_INTVAL(cpu_clock),
253 CE_INTVAL(in_type_sel1),
254 CE_INTVAL(in_type_sel2),
255 CE_INTVAL(analog_deadzone),
256 CE_INTVAL_V(frameskip, 2),
257 CE_INTVAL_P(gpu_peops.iUseDither),
258 CE_INTVAL_P(gpu_peops.dwActFixes),
259 CE_INTVAL_P(gpu_unai.abe_hack),
260 CE_INTVAL_P(gpu_unai.no_light),
261 CE_INTVAL_P(gpu_unai.no_blend),
262 CE_INTVAL_V(iUseReverb, 3),
263 CE_INTVAL_V(iXAPitch, 3),
264 CE_INTVAL_V(iUseInterpolation, 3),
265 CE_INTVAL_V(iSPUIRQWait, 3),
266 CE_INTVAL_V(iUseTimer, 3),
267 CE_INTVAL(warned_about_bios),
268 CE_INTVAL(in_evdev_allow_abs_only),
269 CE_INTVAL(volume_boost),
270 CE_INTVAL(psx_clock),
271 CE_INTVAL(new_dynarec_hacks),
274 static char *get_cd_label(void)
276 static char trimlabel[33];
279 strncpy(trimlabel, CdromLabel, 32);
281 for (j = 31; j >= 0; j--)
282 if (trimlabel[j] == ' ')
288 static void make_cfg_fname(char *buf, size_t size, int is_game)
291 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
293 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
296 static void keys_write_all(FILE *f);
298 static int menu_write_config(int is_game)
300 char cfgfile[MAXPATHLEN];
304 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
305 f = fopen(cfgfile, "w");
307 printf("menu_write_config: failed to open: %s\n", cfgfile);
311 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
312 fprintf(f, "%s = ", config_data[i].name);
313 switch (config_data[i].len) {
315 fprintf(f, "%s\n", (char *)config_data[i].val);
318 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
321 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
324 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
327 printf("menu_write_config: unhandled len %d for %s\n",
328 config_data[i].len, config_data[i].name);
334 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
342 static void parse_str_val(char *cval, const char *src)
345 strncpy(cval, src, MAXPATHLEN);
346 cval[MAXPATHLEN - 1] = 0;
347 tmp = strchr(cval, '\n');
349 tmp = strchr(cval, '\r');
354 static void keys_load_all(const char *cfg);
356 static int menu_load_config(int is_game)
358 char cfgfile[MAXPATHLEN];
364 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
365 f = fopen(cfgfile, "r");
367 printf("menu_load_config: failed to open: %s\n", cfgfile);
371 fseek(f, 0, SEEK_END);
374 printf("bad size %ld: %s\n", size, cfgfile);
378 cfg = malloc(size + 1);
382 fseek(f, 0, SEEK_SET);
383 if (fread(cfg, 1, size, f) != size) {
384 printf("failed to read: %s\n", cfgfile);
389 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
393 tmp = strstr(cfg, config_data[i].name);
396 tmp += strlen(config_data[i].name);
397 if (strncmp(tmp, " = ", 3) != 0)
401 if (config_data[i].len == 0) {
402 parse_str_val(config_data[i].val, tmp);
407 val = strtoul(tmp, &tmp2, 16);
408 if (tmp2 == NULL || tmp == tmp2)
409 continue; // parse failed
411 switch (config_data[i].len) {
413 *(u8 *)config_data[i].val = val;
416 *(u16 *)config_data[i].val = val;
419 *(u32 *)config_data[i].val = val;
422 printf("menu_load_config: unhandled len %d for %s\n",
423 config_data[i].len, config_data[i].name);
429 char *tmp = strstr(cfg, "lastcdimg = ");
432 parse_str_val(last_selected_fname, tmp);
447 for (i = bios_sel = 0; bioses[i] != NULL; i++)
448 if (strcmp(Config.Bios, bioses[i]) == 0)
449 { bios_sel = i; break; }
451 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
452 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
453 { gpu_plugsel = i; break; }
455 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
456 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
457 { spu_plugsel = i; break; }
462 // rrrr rggg gggb bbbb
463 static unsigned short fname2color(const char *fname)
465 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
466 ".bz", ".znx", ".pbp", ".cbn" };
467 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
468 ".table", ".index", ".sbi" };
469 const char *ext = strrchr(fname, '.');
474 for (i = 0; i < array_size(cdimg_exts); i++)
475 if (strcasecmp(ext, cdimg_exts[i]) == 0)
477 for (i = 0; i < array_size(other_exts); i++)
478 if (strcasecmp(ext, other_exts[i]) == 0)
483 static void draw_savestate_bg(int slot);
485 static const char *filter_exts[] = {
486 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
489 #define MENU_ALIGN_LEFT
490 #ifdef __ARM_ARCH_7A__ // assume hires device
496 #define menu_init menu_init_common
497 #include "common/menu.c"
500 // a bit of black magic here
501 static void draw_savestate_bg(int slot)
503 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
505 char fname[MAXPATHLEN];
512 ret = get_state_filename(fname, sizeof(fname), slot);
516 f = gzopen(fname, "rb");
520 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
521 fprintf(stderr, "gzseek failed\n");
526 gpu = malloc(sizeof(*gpu));
532 ret = gzread(f, gpu, sizeof(*gpu));
534 if (ret != sizeof(*gpu)) {
535 fprintf(stderr, "gzread failed\n");
539 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
541 if (gpu->ulStatus & 0x800000)
542 goto out; // disabled
544 x = gpu->ulControl[5] & 0x3ff;
545 y = (gpu->ulControl[5] >> 10) & 0x1ff;
546 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
547 w = psx_widths[(gpu->ulStatus >> 16) & 7];
548 tmp = gpu->ulControl[7];
549 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
550 if (gpu->ulStatus & 0x80000) // doubleheight
553 x = max(0, g_menuscreen_w - w) & ~3;
554 y = max(0, g_menuscreen_h / 2 - h / 2);
555 w = min(g_menuscreen_w, w);
556 h = min(g_menuscreen_h, h);
557 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
559 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
560 if (gpu->ulStatus & 0x200000)
561 bgr888_to_rgb565(d, s, w * 3);
563 bgr555_to_rgb565(d, s, w * 2);
564 #ifndef __ARM_ARCH_7A__
565 // better darken this on small screens
566 menu_darken_bg(d, d, w * 2, 0);
574 // ---------- XXX: pandora specific -----------
576 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
577 static char **pnd_filter_list;
579 static void apply_filter(int which)
585 if (pnd_filter_list == NULL || which == old)
588 for (i = 0; i < which; i++)
589 if (pnd_filter_list[i] == NULL)
592 if (pnd_filter_list[i] == NULL)
595 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
600 static void apply_lcdrate(int pal)
608 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
609 pnd_script_base, pal ? 50 : 60);
614 static menu_entry e_menu_gfx_options[];
616 static void pnd_menu_init(void)
624 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
626 dir = opendir("/etc/pandora/conf/dss_fir");
628 perror("filter opendir");
641 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
650 mfilters = calloc(count + 1, sizeof(mfilters[0]));
651 if (mfilters == NULL)
655 for (i = 0; (ent = readdir(dir)); ) {
658 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
661 len = strlen(ent->d_name);
663 // skip pre-HF5 extra files
664 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
666 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
669 // have to cut "_up_h" for pre-HF5
670 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
673 if (len > sizeof(buff) - 1)
676 strncpy(buff, ent->d_name, len);
678 mfilters[i] = strdup(buff);
679 if (mfilters[i] != NULL)
684 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
685 e_menu_gfx_options[i].data = (void *)mfilters;
686 pnd_filter_list = mfilters;
689 void menu_finish(void)
691 plat_cpu_clock_apply(cpu_clock_st);
694 // -------------- key config --------------
696 me_bind_action me_ctrl_actions[] =
698 { "UP ", 1 << DKEY_UP},
699 { "DOWN ", 1 << DKEY_DOWN },
700 { "LEFT ", 1 << DKEY_LEFT },
701 { "RIGHT ", 1 << DKEY_RIGHT },
702 { "TRIANGLE", 1 << DKEY_TRIANGLE },
703 { "CIRCLE ", 1 << DKEY_CIRCLE },
704 { "CROSS ", 1 << DKEY_CROSS },
705 { "SQUARE ", 1 << DKEY_SQUARE },
706 { "L1 ", 1 << DKEY_L1 },
707 { "R1 ", 1 << DKEY_R1 },
708 { "L2 ", 1 << DKEY_L2 },
709 { "R2 ", 1 << DKEY_R2 },
710 { "L3 ", 1 << DKEY_L3 },
711 { "R3 ", 1 << DKEY_R3 },
712 { "START ", 1 << DKEY_START },
713 { "SELECT ", 1 << DKEY_SELECT },
717 me_bind_action emuctrl_actions[] =
719 { "Save State ", 1 << SACTION_SAVE_STATE },
720 { "Load State ", 1 << SACTION_LOAD_STATE },
721 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
722 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
723 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
724 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
725 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
726 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
727 { "Gun A button ", 1 << SACTION_GUN_A },
728 { "Gun B button ", 1 << SACTION_GUN_B },
729 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
730 #ifndef __ARM_ARCH_7A__ /* XXX */
731 { "Volume Up ", 1 << SACTION_VOLUME_UP },
732 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
737 static char *mystrip(char *str)
742 for (i = 0; i < len; i++)
743 if (str[i] != ' ') break;
744 if (i > 0) memmove(str, str + i, len - i + 1);
747 for (i = len - 1; i >= 0; i--)
748 if (str[i] != ' ') break;
754 static void get_line(char *d, size_t size, const char *s)
759 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
770 static void keys_write_all(FILE *f)
774 for (d = 0; d < IN_MAX_DEVS; d++)
776 const int *binds = in_get_dev_binds(d);
777 const char *name = in_get_dev_name(d, 0, 0);
780 if (binds == NULL || name == NULL)
783 fprintf(f, "binddev = %s\n", name);
784 in_get_config(d, IN_CFG_BIND_COUNT, &count);
786 for (k = 0; k < count; k++)
791 act[0] = act[31] = 0;
792 name = in_get_key_name(d, k);
794 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
795 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
796 mask = me_ctrl_actions[i].mask;
798 strncpy(act, me_ctrl_actions[i].name, 31);
799 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
802 mask = me_ctrl_actions[i].mask << 16;
804 strncpy(act, me_ctrl_actions[i].name, 31);
805 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
810 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
811 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
812 mask = emuctrl_actions[i].mask;
814 strncpy(act, emuctrl_actions[i].name, 31);
815 fprintf(f, "bind %s = %s\n", name, mystrip(act));
823 static int parse_bind_val(const char *val, int *type)
827 *type = IN_BINDTYPE_NONE;
831 if (strncasecmp(val, "player", 6) == 0)
833 int player, shift = 0;
834 player = atoi(val + 6) - 1;
836 if ((unsigned int)player > 1)
841 *type = IN_BINDTYPE_PLAYER12;
842 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
843 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
844 return me_ctrl_actions[i].mask << shift;
847 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
848 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
849 *type = IN_BINDTYPE_EMU;
850 return emuctrl_actions[i].mask;
857 static void keys_load_all(const char *cfg)
859 char dev[256], key[128], *act;
865 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
868 get_line(dev, sizeof(dev), p);
869 dev_id = in_config_parse_dev(dev);
871 printf("input: can't handle dev: %s\n", dev);
875 in_unbind_all(dev_id, -1, -1);
876 while ((p = strstr(p, "bind"))) {
877 if (strncmp(p, "binddev = ", 10) == 0)
882 printf("input: parse error: %16s..\n", p);
886 get_line(key, sizeof(key), p);
887 act = strchr(key, '=');
889 printf("parse failed: %16s..\n", p);
897 bind = parse_bind_val(act, &bindtype);
898 if (bind != -1 && bind != 0) {
899 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
900 in_config_bind_key(dev_id, key, bind, bindtype);
903 lprintf("config: unhandled action \"%s\"\n", act);
909 static int key_config_loop_wrap(int id, int keys)
912 case MA_CTRL_PLAYER1:
913 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
915 case MA_CTRL_PLAYER2:
916 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
919 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
927 static const char *mgn_dev_name(int id, int *offs)
929 const char *name = NULL;
932 if (id == MA_CTRL_DEV_FIRST)
935 for (; it < IN_MAX_DEVS; it++) {
936 name = in_get_dev_name(it, 1, 1);
945 static const char *mgn_saveloadcfg(int id, int *offs)
950 static int mh_savecfg(int id, int keys)
952 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
953 me_update_msg("config saved");
955 me_update_msg("failed to write config");
960 static int mh_input_rescan(int id, int keys)
962 //menu_sync_config();
963 plat_rescan_inputs();
964 me_update_msg("rescan complete.");
969 static const char *men_in_type_sel[] = {
970 "Standard (SCPH-1080)",
971 "Analog (SCPH-1150)",
975 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
976 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
978 static menu_entry e_menu_keyconfig[] =
980 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
981 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
982 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
984 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
985 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
986 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
987 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
988 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
989 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
990 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
991 mee_handler ("Rescan devices", mh_input_rescan),
993 mee_label ("Input devices:"),
994 mee_label_mk (MA_CTRL_DEV_FIRST, 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),
999 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1000 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1004 static int menu_loop_keyconfig(int id, int keys)
1008 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1009 me_loop(e_menu_keyconfig, &sel);
1013 // ------------ gfx options menu ------------
1015 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1016 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1017 "using d-pad or move it using R+d-pad";
1018 static const char *men_dummy[] = { NULL };
1020 static int menu_loop_cscaler(int id, int keys)
1024 scaling = SCALE_CUSTOM;
1026 omap_enable_layer(1);
1031 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1032 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1033 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1036 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1037 if (inp & PBTN_UP) g_layer_y--;
1038 if (inp & PBTN_DOWN) g_layer_y++;
1039 if (inp & PBTN_LEFT) g_layer_x--;
1040 if (inp & PBTN_RIGHT) g_layer_x++;
1041 if (!(inp & PBTN_R)) {
1042 if (inp & PBTN_UP) g_layer_h += 2;
1043 if (inp & PBTN_DOWN) g_layer_h -= 2;
1044 if (inp & PBTN_LEFT) g_layer_w += 2;
1045 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1047 if (inp & (PBTN_MOK|PBTN_MBACK))
1050 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1051 if (g_layer_x < 0) g_layer_x = 0;
1052 if (g_layer_x > 640) g_layer_x = 640;
1053 if (g_layer_y < 0) g_layer_y = 0;
1054 if (g_layer_y > 420) g_layer_y = 420;
1055 if (g_layer_w < 160) g_layer_w = 160;
1056 if (g_layer_h < 60) g_layer_h = 60;
1057 if (g_layer_x + g_layer_w > 800)
1058 g_layer_w = 800 - g_layer_x;
1059 if (g_layer_y + g_layer_h > 480)
1060 g_layer_h = 480 - g_layer_y;
1061 omap_enable_layer(1);
1065 omap_enable_layer(0);
1070 static menu_entry e_menu_gfx_options[] =
1072 mee_enum ("Scaler", 0, scaling, men_scaler),
1073 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1074 // mee_onoff ("Vsync", 0, vsync, 1),
1075 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1079 static int menu_loop_gfx_options(int id, int keys)
1083 me_loop(e_menu_gfx_options, &sel);
1088 // ------------ bios/plugins ------------
1090 static menu_entry e_menu_plugin_gpu_unai[] =
1092 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1093 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1094 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1098 static int menu_loop_plugin_gpu_unai(int id, int keys)
1101 me_loop(e_menu_plugin_gpu_unai, &sel);
1105 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1106 static const char h_gpu_0[] = "Needed for Chrono Cross";
1107 static const char h_gpu_1[] = "Capcom fighting games";
1108 static const char h_gpu_2[] = "Black screens in Lunar";
1109 static const char h_gpu_3[] = "Compatibility mode";
1110 static const char h_gpu_6[] = "Pandemonium 2";
1111 static const char h_gpu_7[] = "Skip every second frame";
1112 static const char h_gpu_8[] = "Needed by Dark Forces";
1113 static const char h_gpu_9[] = "better g-colors, worse textures";
1114 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1116 static menu_entry e_menu_plugin_gpu_peops[] =
1118 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1119 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1120 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1121 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1122 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1123 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1124 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1125 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1126 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1127 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1131 static int menu_loop_plugin_gpu_peops(int id, int keys)
1134 me_loop(e_menu_plugin_gpu_peops, &sel);
1138 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1139 static const char h_spu_volboost[] = "Large values cause distortion";
1140 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1141 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1143 static menu_entry e_menu_plugin_spu[] =
1145 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1146 mee_onoff ("Reverb", 0, iUseReverb, 2),
1147 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1148 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1149 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1150 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1154 static int menu_loop_plugin_spu(int id, int keys)
1157 me_loop(e_menu_plugin_spu, &sel);
1161 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1162 "savestates and can't be changed there. Must save\n"
1163 "config and reload the game for change to take effect";
1164 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1165 "for plugin change to take effect";
1166 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1167 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1168 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1170 static menu_entry e_menu_plugin_options[] =
1172 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1173 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1174 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1175 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1176 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1177 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1181 static menu_entry e_menu_main2[];
1183 static int menu_loop_plugin_options(int id, int keys)
1186 me_loop(e_menu_plugin_options, &sel);
1188 // sync BIOS/plugins
1189 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1190 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1191 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1192 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1197 // ------------ adv options menu ------------
1199 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1200 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1201 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1202 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1204 static menu_entry e_menu_speed_hacks[] =
1206 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1207 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1208 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1209 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1213 static int menu_loop_speed_hacks(int id, int keys)
1216 me_loop(e_menu_speed_hacks, &sel);
1220 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1221 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1222 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1223 "(green: normal, red: fmod, blue: noise)";
1224 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1225 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1226 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1227 "(proper .cue/.bin dump is needed otherwise)";
1228 static const char h_cfg_sio[] = "You should not need this, breaks games";
1229 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1230 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1231 "(timing hack, breaks other games)";
1232 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1233 "(timing hack, breaks other games)";
1234 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1235 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1236 "Might be useful to overcome some dynarec bugs";
1237 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1238 "must reload game for any change to take effect";
1240 static menu_entry e_menu_adv_options[] =
1242 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1243 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1244 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1245 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1246 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1247 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1248 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1249 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1250 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1251 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1252 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1253 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1257 static int menu_loop_adv_options(int id, int keys)
1260 me_loop(e_menu_adv_options, &sel);
1264 // ------------ options menu ------------
1266 static int mh_restore_defaults(int id, int keys)
1268 menu_set_defconfig();
1269 me_update_msg("defaults restored");
1273 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1274 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1276 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1277 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1278 "loading state or both";
1280 static const char h_restore_def[] = "Switches back to default / recommended\n"
1282 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1284 static menu_entry e_menu_options[] =
1286 // mee_range ("Save slot", 0, state_slot, 0, 9),
1287 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1288 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1289 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1290 mee_enum ("Region", 0, region, men_region),
1291 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1292 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1293 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1294 mee_handler ("[Advanced]", menu_loop_adv_options),
1295 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1296 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1297 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1301 static int menu_loop_options(int id, int keys)
1306 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1307 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1308 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1310 me_loop(e_menu_options, &sel);
1315 // ------------ debug menu ------------
1317 static void draw_frame_debug(GPUFreeze_t *gpuf)
1319 int w = min(g_menuscreen_w, 1024);
1320 int h = min(g_menuscreen_h, 512);
1321 u16 *d = g_menuscreen_ptr;
1322 u16 *s = (u16 *)gpuf->psxVRam;
1326 gpuf->ulFreezeVersion = 1;
1327 if (GPU_freeze != NULL)
1328 GPU_freeze(1, gpuf);
1330 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1331 bgr555_to_rgb565(d, s, w * 2);
1333 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1334 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1335 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1336 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1337 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1340 static void debug_menu_loop(void)
1345 gpuf = malloc(sizeof(*gpuf));
1352 draw_frame_debug(gpuf);
1355 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1356 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1357 if (inp & PBTN_MBACK)
1364 // --------- memcard manager ---------
1366 static void draw_mc_icon(int dx, int dy, const u16 *s)
1371 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1373 for (y = 0; y < 16; y++, s += 16) {
1374 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1375 for (x = 0; x < 16; x++) {
1377 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1378 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1384 static void draw_mc_bg(void)
1386 McdBlock *blocks1, *blocks2;
1390 blocks1 = malloc(15 * sizeof(blocks1[0]));
1391 blocks2 = malloc(15 * sizeof(blocks1[0]));
1392 if (blocks1 == NULL || blocks2 == NULL)
1395 for (i = 0; i < 15; i++) {
1396 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1397 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1402 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1404 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1408 maxicons = g_menuscreen_h / 32;
1411 row2 = g_menuscreen_w / 2;
1412 for (i = 0; i < maxicons; i++) {
1413 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1414 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1416 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1417 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1420 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1428 static void handle_memcard_sel(void)
1431 if (memcard1_sel != 0)
1432 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1434 if (memcard2_sel != 0)
1435 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1436 LoadMcds(Config.Mcd1, Config.Mcd2);
1440 static menu_entry e_memcard_options[] =
1442 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1443 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1447 static int menu_loop_memcards(int id, int keys)
1453 memcard1_sel = memcard2_sel = 0;
1454 p = strrchr(Config.Mcd1, '/');
1456 for (i = 0; memcards[i] != NULL; i++)
1457 if (strcmp(p + 1, memcards[i]) == 0)
1458 { memcard1_sel = i; break; }
1459 p = strrchr(Config.Mcd2, '/');
1461 for (i = 0; memcards[i] != NULL; i++)
1462 if (strcmp(p + 1, memcards[i]) == 0)
1463 { memcard2_sel = i; break; }
1465 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1467 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1472 // --------- main menu help ----------
1474 static void menu_bios_warn(void)
1477 static const char msg[] =
1478 "You don't seem to have copied any BIOS\n"
1480 #ifdef __ARM_ARCH_7A__ // XXX
1481 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1483 "pcsx_rearmed/bios/\n\n"
1485 "While many games work fine with fake\n"
1486 "(HLE) BIOS, others (like MGS and FF8)\n"
1487 "require BIOS to work.\n"
1488 "After copying the file, you'll also need\n"
1489 "to select it in the emu's menu:\n"
1490 "options->[BIOS/Plugins]\n\n"
1491 "The file is usually named SCPH1001.BIN,\n"
1492 "but other not compressed files can be\n"
1494 "Press (B) or (X) to continue";
1498 draw_menu_message(msg, NULL);
1500 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1501 if (inp & (PBTN_MBACK|PBTN_MOK))
1506 // ------------ main menu ------------
1510 static void draw_frame_main(void)
1517 if (CdromId[0] != 0) {
1518 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1519 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1520 Config.HLE ? "HLE" : "BIOS");
1521 smalltext_out16(4, 1, buff, 0x105f);
1526 tmp = localtime(<ime);
1527 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1528 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1529 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1533 static void draw_frame_credits(void)
1535 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1538 static const char credits_text[] =
1540 "(C) 1999-2003 PCSX Team\n"
1541 "(C) 2005-2009 PCSX-df Team\n"
1542 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1543 "GPU and SPU code by Pete Bernert\n"
1544 " and the P.E.Op.S. team\n"
1545 "ARM recompiler (C) 2009-2011 Ari64\n"
1546 "PCSX4ALL plugins by PCSX4ALL team\n"
1547 " Chui, Franxis, Unai\n\n"
1548 "integration, optimization and\n"
1549 " frontend (C) 2010-2011 notaz\n";
1551 static int reset_game(void)
1554 if (bios_sel == 0 && !Config.HLE)
1560 if (CheckCdrom() != -1) {
1566 static int reload_plugins(const char *cdimg)
1572 set_cd_image(cdimg);
1574 pcnt_hook_plugins();
1576 if (OpenPlugins() == -1) {
1577 me_update_msg("failed to open plugins");
1580 plugin_call_rearmed_cbs();
1582 cdrIsoMultidiskCount = 1;
1584 CdromLabel[0] = '\0';
1589 static int run_bios(void)
1595 if (reload_plugins(NULL) != 0)
1603 static int run_exe(void)
1607 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1612 if (reload_plugins(NULL) != 0)
1616 if (Load(fname) != 0) {
1617 me_update_msg("exe load failed, bad file?");
1626 static int run_cd_image(const char *fname)
1629 reload_plugins(fname);
1631 // always autodetect, menu_sync_config will override as needed
1634 if (CheckCdrom() == -1) {
1635 // Only check the CD if we are starting the console with a CD
1637 me_update_msg("unsupported/invalid CD image");
1643 // Read main executable directly from CDRom and start it
1644 if (LoadCdrom() == -1) {
1646 me_update_msg("failed to load CD image");
1651 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1656 static int romsel_run(void)
1658 int prev_gpu, prev_spu;
1661 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1665 printf("selected file: %s\n", fname);
1667 new_dynarec_clear_full();
1669 if (run_cd_image(fname) != 0)
1672 prev_gpu = gpu_plugsel;
1673 prev_spu = spu_plugsel;
1674 if (menu_load_config(1) != 0)
1675 menu_load_config(0);
1677 // check for plugin changes, have to repeat
1678 // loading if game config changed plugins to reload them
1679 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1680 printf("plugin change detected, reloading plugins..\n");
1681 if (run_cd_image(fname) != 0)
1686 printf("note: running without BIOS, expect compatibility problems\n");
1688 strcpy(last_selected_fname, rom_fname_reload);
1692 static int swap_cd_image(void)
1696 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1700 printf("selected file: %s\n", fname);
1703 CdromLabel[0] = '\0';
1705 set_cd_image(fname);
1706 if (ReloadCdromPlugin() < 0) {
1707 me_update_msg("failed to load cdr plugin");
1710 if (CDR_open() < 0) {
1711 me_update_msg("failed to open cdr plugin");
1715 SetCdOpenCaseTime(time(NULL) + 2);
1718 strcpy(last_selected_fname, rom_fname_reload);
1722 static int swap_cd_multidisk(void)
1724 cdrIsoMultidiskSelect++;
1726 CdromLabel[0] = '\0';
1729 if (CDR_open() < 0) {
1730 me_update_msg("failed to open cdr plugin");
1734 SetCdOpenCaseTime(time(NULL) + 2);
1740 static int main_menu_handler(int id, int keys)
1744 case MA_MAIN_RESUME_GAME:
1748 case MA_MAIN_SAVE_STATE:
1750 return menu_loop_savestate(0);
1752 case MA_MAIN_LOAD_STATE:
1754 return menu_loop_savestate(1);
1756 case MA_MAIN_RESET_GAME:
1757 if (ready_to_go && reset_game() == 0)
1760 case MA_MAIN_LOAD_ROM:
1761 if (romsel_run() == 0)
1764 case MA_MAIN_SWAP_CD:
1765 if (swap_cd_image() == 0)
1768 case MA_MAIN_SWAP_CD_MULTI:
1769 if (swap_cd_multidisk() == 0)
1772 case MA_MAIN_RUN_BIOS:
1773 if (run_bios() == 0)
1776 case MA_MAIN_RUN_EXE:
1780 case MA_MAIN_CREDITS:
1781 draw_menu_message(credits_text, draw_frame_credits);
1782 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1788 lprintf("%s: something unknown selected\n", __FUNCTION__);
1795 static menu_entry e_menu_main2[] =
1797 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1798 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1799 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1800 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1801 mee_handler ("Memcard manager", menu_loop_memcards),
1805 static int main_menu2_handler(int id, int keys)
1809 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1810 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1811 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1813 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1816 static const char h_extra[] = "Change CD, manage memcards..\n";
1818 static menu_entry e_menu_main[] =
1822 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1823 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1824 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1825 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1826 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1827 mee_handler ("Options", menu_loop_options),
1828 mee_handler ("Controls", menu_loop_keyconfig),
1829 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1830 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1831 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1835 // ----------------------------
1837 static void menu_leave_emu(void);
1839 void menu_loop(void)
1845 if (bioses[1] == NULL && !warned_about_bios) {
1847 warned_about_bios = 1;
1850 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1851 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1852 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1853 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1855 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1858 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1859 } while (!ready_to_go);
1861 /* wait until menu, ok, back is released */
1862 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1865 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1870 static int qsort_strcmp(const void *p1, const void *p2)
1872 char * const *s1 = (char * const *)p1;
1873 char * const *s2 = (char * const *)p2;
1874 return strcasecmp(*s1, *s2);
1877 static void scan_bios_plugins(void)
1879 char fname[MAXPATHLEN];
1881 int bios_i, gpu_i, spu_i, mc_i;
1886 gpu_plugins[0] = "builtin_gpu";
1887 spu_plugins[0] = "builtin_spu";
1888 memcards[0] = "(none)";
1889 bios_i = gpu_i = spu_i = mc_i = 1;
1891 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1892 dir = opendir(fname);
1894 perror("scan_bios_plugins bios opendir");
1909 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1912 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1913 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1914 printf("bad BIOS file: %s\n", ent->d_name);
1918 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1919 bioses[bios_i++] = strdup(ent->d_name);
1923 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1929 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1930 dir = opendir(fname);
1932 perror("scan_bios_plugins plugins opendir");
1946 p = strstr(ent->d_name, ".so");
1950 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1951 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1953 fprintf(stderr, "%s\n", dlerror());
1957 // now what do we have here?
1958 tmp = dlsym(h, "GPUinit");
1961 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1962 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1966 tmp = dlsym(h, "SPUinit");
1969 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1970 spu_plugins[spu_i++] = strdup(ent->d_name);
1974 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1981 dir = opendir("." MEMCARD_DIR);
1983 perror("scan_bios_plugins memcards opendir");
1998 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2001 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2002 if (stat(fname, &st) != 0) {
2003 printf("bad memcard file: %s\n", ent->d_name);
2007 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2008 memcards[mc_i++] = strdup(ent->d_name);
2012 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2016 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2021 void menu_init(void)
2023 char buff[MAXPATHLEN];
2025 strcpy(last_selected_fname, "/media");
2027 scan_bios_plugins();
2031 menu_set_defconfig();
2032 menu_load_config(0);
2037 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2038 if (g_menubg_src_ptr == NULL)
2040 emu_make_path(buff, "skin/background.png", sizeof(buff));
2041 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2043 #ifndef __ARM_ARCH_7A__ /* XXX */
2044 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2045 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2047 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2051 void menu_notify_mode_change(int w, int h, int bpp)
2062 g_layer_w = w; g_layer_h = h;
2066 if (h > g_menuscreen_h || (240 < h && h <= 360))
2067 goto fractional_4_3;
2069 // 4:3 that prefers integer scaling
2070 imult = g_menuscreen_h / h;
2071 g_layer_w = w * imult;
2072 g_layer_h = h * imult;
2073 mult = (float)g_layer_w / (float)g_layer_h;
2074 if (mult < 1.25f || mult > 1.666f)
2075 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2076 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2081 mult = 240.0f / (float)h * 4.0f / 3.0f;
2084 g_layer_w = mult * (float)g_menuscreen_h;
2085 g_layer_h = g_menuscreen_h;
2086 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2089 case SCALE_FULLSCREEN:
2090 g_layer_w = g_menuscreen_w;
2091 g_layer_h = g_menuscreen_h;
2098 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2099 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2100 if (g_layer_x < 0) g_layer_x = 0;
2101 if (g_layer_y < 0) g_layer_y = 0;
2102 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2103 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2106 static void menu_leave_emu(void)
2108 if (GPU_close != NULL) {
2109 int ret = GPU_close();
2111 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2114 plat_video_menu_enter(ready_to_go);
2116 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2117 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2118 int x = max(0, g_menuscreen_w - last_psx_w);
2119 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2120 int w = min(g_menuscreen_w, last_psx_w);
2121 int h = min(g_menuscreen_h, last_psx_h);
2122 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2123 u16 *s = pl_vout_buf;
2125 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2126 menu_darken_bg(d, s, w, 0);
2130 cpu_clock = plat_cpu_clock_get();
2133 void menu_prepare_emu(void)
2135 R3000Acpu *prev_cpu = psxCpu;
2137 plat_video_menu_leave();
2139 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2141 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2142 if (psxCpu != prev_cpu)
2143 // note that this does not really reset, just clears drc caches
2146 // core doesn't care about Config.Cdda changes,
2147 // so handle them manually here
2152 apply_lcdrate(Config.PsxType);
2153 apply_filter(filter);
2154 plat_cpu_clock_apply(cpu_clock);
2156 // push config to GPU plugin
2157 plugin_call_rearmed_cbs();
2159 if (GPU_open != NULL) {
2160 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2162 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2168 void me_update_msg(const char *msg)
2170 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2171 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2173 menu_error_time = plat_get_ticks_ms();
2174 lprintf("msg: %s\n", menu_error_msg);