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.
16 #include <sys/types.h>
24 #include "plugin_lib.h"
28 #include "common/plat.h"
29 #include "common/input.h"
30 #include "linux/in_evdev.h"
31 #include "../libpcsxcore/misc.h"
32 #include "../libpcsxcore/cdrom.h"
33 #include "../libpcsxcore/cdriso.h"
34 #include "../libpcsxcore/psemu_plugin_defs.h"
35 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
36 #include "../plugins/dfinput/main.h"
37 #include "../plugins/gpulib/cspace.h"
40 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
42 #define array_size(x) (sizeof(x) / sizeof(x[0]))
53 MA_MAIN_SWAP_CD_MULTI,
84 static int last_psx_w, last_psx_h, last_psx_bpp;
85 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
86 static char rom_fname_reload[MAXPATHLEN];
87 static char last_selected_fname[MAXPATHLEN];
88 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
90 static int memcard1_sel, memcard2_sel;
92 int analog_deadzone; // for Caanoo
94 #ifdef __ARM_ARCH_7A__
95 #define DEFAULT_PSX_CLOCK 57
96 #define DEFAULT_PSX_CLOCK_S "57"
98 #define DEFAULT_PSX_CLOCK 50
99 #define DEFAULT_PSX_CLOCK_S "50"
103 extern int iUseReverb;
104 extern int iUseInterpolation;
106 extern int iSPUIRQWait;
107 extern int iUseTimer;
110 static const char *bioses[24];
111 static const char *gpu_plugins[16];
112 static const char *spu_plugins[16];
113 static const char *memcards[32];
114 static int bios_sel, gpu_plugsel, spu_plugsel;
117 static int min(int x, int y) { return x < y ? x : y; }
118 static int max(int x, int y) { return x > y ? x : y; }
120 void emu_make_path(char *buff, const char *end, int size)
124 end_len = strlen(end);
125 pos = plat_get_root_dir(buff, size);
126 strncpy(buff + pos, end, size - pos);
128 if (pos + end_len > size - 1)
129 printf("Warning: path truncated: %s\n", buff);
132 static int emu_check_save_file(int slot, int *time)
134 char fname[MAXPATHLEN];
138 ret = emu_check_state(slot);
139 if (ret != 0 || time == NULL)
140 return ret == 0 ? 1 : 0;
142 ret = get_state_filename(fname, sizeof(fname), slot);
146 ret = stat(fname, &status);
150 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
151 return 1; // probably bad rtc like on some Caanoos
153 *time = status.st_mtime;
158 static int emu_save_load_game(int load, int unused)
163 ret = emu_load_state(state_slot);
165 // reflect hle/bios mode from savestate
168 else if (bios_sel == 0 && bioses[1] != NULL)
169 // XXX: maybe find the right bios instead
173 ret = emu_save_state(state_slot);
178 // propagate menu settings to the emu vars
179 static void menu_sync_config(void)
181 static int allow_abs_only_old;
186 Config.PsxType = region - 1;
188 cycle_multiplier = 10000 / psx_clock;
190 switch (in_type_sel1) {
191 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
192 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
193 default: in_type1 = PSE_PAD_TYPE_STANDARD;
195 switch (in_type_sel2) {
196 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
197 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
198 default: in_type2 = PSE_PAD_TYPE_STANDARD;
200 if (in_evdev_allow_abs_only != allow_abs_only_old) {
202 allow_abs_only_old = in_evdev_allow_abs_only;
205 iVolume = 768 + 128 * volume_boost;
206 pl_rearmed_cbs.frameskip = frameskip - 1;
207 pl_timing_prepare(Config.PsxType);
210 static void menu_set_defconfig(void)
212 emu_set_default_config();
218 analog_deadzone = 50;
219 psx_clock = DEFAULT_PSX_CLOCK;
222 in_type_sel1 = in_type_sel2 = 0;
223 in_evdev_allow_abs_only = 0;
228 #define CE_CONFIG_STR(val) \
229 { #val, 0, Config.val }
231 #define CE_CONFIG_VAL(val) \
232 { #val, sizeof(Config.val), &Config.val }
234 #define CE_STR(val) \
237 #define CE_INTVAL(val) \
238 { #val, sizeof(val), &val }
240 #define CE_INTVAL_P(val) \
241 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
243 // 'versioned' var, used when defaults change
244 #define CE_CONFIG_STR_V(val, ver) \
245 { #val #ver, 0, Config.val }
247 #define CE_INTVAL_V(val, ver) \
248 { #val #ver, sizeof(val), &val }
250 #define CE_INTVAL_PV(val, ver) \
251 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
253 static const struct {
259 CE_CONFIG_STR_V(Gpu, 2),
261 // CE_CONFIG_STR(Cdr),
266 CE_CONFIG_VAL(Debug),
267 CE_CONFIG_VAL(PsxOut),
268 CE_CONFIG_VAL(SpuIrq),
269 CE_CONFIG_VAL(RCntFix),
270 CE_CONFIG_VAL(VSyncWA),
272 CE_CONFIG_VAL(CdrReschedule),
274 CE_INTVAL_V(scaling, 2),
275 CE_INTVAL(g_layer_x),
276 CE_INTVAL(g_layer_y),
277 CE_INTVAL(g_layer_w),
278 CE_INTVAL(g_layer_h),
280 CE_INTVAL(state_slot),
281 CE_INTVAL(cpu_clock),
283 CE_INTVAL(in_type_sel1),
284 CE_INTVAL(in_type_sel2),
285 CE_INTVAL(analog_deadzone),
286 CE_INTVAL_V(frameskip, 3),
287 CE_INTVAL_P(gpu_peops.iUseDither),
288 CE_INTVAL_P(gpu_peops.dwActFixes),
289 CE_INTVAL_P(gpu_unai.lineskip),
290 CE_INTVAL_P(gpu_unai.abe_hack),
291 CE_INTVAL_P(gpu_unai.no_light),
292 CE_INTVAL_P(gpu_unai.no_blend),
293 CE_INTVAL_P(gpu_neon.allow_interlace),
294 CE_INTVAL_V(iUseReverb, 3),
295 CE_INTVAL_V(iXAPitch, 3),
296 CE_INTVAL_V(iUseInterpolation, 3),
297 CE_INTVAL_V(iSPUIRQWait, 3),
298 CE_INTVAL_V(iUseTimer, 3),
299 CE_INTVAL(warned_about_bios),
300 CE_INTVAL(in_evdev_allow_abs_only),
301 CE_INTVAL(volume_boost),
302 CE_INTVAL(psx_clock),
303 CE_INTVAL(new_dynarec_hacks),
304 CE_INTVAL(in_enable_vibration),
307 static char *get_cd_label(void)
309 static char trimlabel[33];
312 strncpy(trimlabel, CdromLabel, 32);
314 for (j = 31; j >= 0; j--)
315 if (trimlabel[j] == ' ')
321 static void make_cfg_fname(char *buf, size_t size, int is_game)
324 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
326 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
329 static void keys_write_all(FILE *f);
331 static int menu_write_config(int is_game)
333 char cfgfile[MAXPATHLEN];
337 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
338 f = fopen(cfgfile, "w");
340 printf("menu_write_config: failed to open: %s\n", cfgfile);
344 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
345 fprintf(f, "%s = ", config_data[i].name);
346 switch (config_data[i].len) {
348 fprintf(f, "%s\n", (char *)config_data[i].val);
351 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
354 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
357 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
360 printf("menu_write_config: unhandled len %d for %s\n",
361 config_data[i].len, config_data[i].name);
367 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
375 static void parse_str_val(char *cval, const char *src)
378 strncpy(cval, src, MAXPATHLEN);
379 cval[MAXPATHLEN - 1] = 0;
380 tmp = strchr(cval, '\n');
382 tmp = strchr(cval, '\r');
387 static void keys_load_all(const char *cfg);
389 static int menu_load_config(int is_game)
391 char cfgfile[MAXPATHLEN];
397 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
398 f = fopen(cfgfile, "r");
400 printf("menu_load_config: failed to open: %s\n", cfgfile);
404 fseek(f, 0, SEEK_END);
407 printf("bad size %ld: %s\n", size, cfgfile);
411 cfg = malloc(size + 1);
415 fseek(f, 0, SEEK_SET);
416 if (fread(cfg, 1, size, f) != size) {
417 printf("failed to read: %s\n", cfgfile);
422 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
426 tmp = strstr(cfg, config_data[i].name);
429 tmp += strlen(config_data[i].name);
430 if (strncmp(tmp, " = ", 3) != 0)
434 if (config_data[i].len == 0) {
435 parse_str_val(config_data[i].val, tmp);
440 val = strtoul(tmp, &tmp2, 16);
441 if (tmp2 == NULL || tmp == tmp2)
442 continue; // parse failed
444 switch (config_data[i].len) {
446 *(u8 *)config_data[i].val = val;
449 *(u16 *)config_data[i].val = val;
452 *(u32 *)config_data[i].val = val;
455 printf("menu_load_config: unhandled len %d for %s\n",
456 config_data[i].len, config_data[i].name);
462 char *tmp = strstr(cfg, "lastcdimg = ");
465 parse_str_val(last_selected_fname, tmp);
480 for (i = bios_sel = 0; bioses[i] != NULL; i++)
481 if (strcmp(Config.Bios, bioses[i]) == 0)
482 { bios_sel = i; break; }
484 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
485 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
486 { gpu_plugsel = i; break; }
488 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
489 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
490 { spu_plugsel = i; break; }
495 // rrrr rggg gggb bbbb
496 static unsigned short fname2color(const char *fname)
498 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
499 ".bz", ".znx", ".pbp", ".cbn" };
500 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
501 ".table", ".index", ".sbi" };
502 const char *ext = strrchr(fname, '.');
507 for (i = 0; i < array_size(cdimg_exts); i++)
508 if (strcasecmp(ext, cdimg_exts[i]) == 0)
510 for (i = 0; i < array_size(other_exts); i++)
511 if (strcasecmp(ext, other_exts[i]) == 0)
516 static void draw_savestate_bg(int slot);
518 static const char *filter_exts[] = {
519 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
522 #define MENU_ALIGN_LEFT
523 #ifdef __ARM_ARCH_7A__ // assume hires device
529 #define menu_init menu_init_common
530 #include "common/menu.c"
533 // a bit of black magic here
534 static void draw_savestate_bg(int slot)
536 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
538 char fname[MAXPATHLEN];
545 ret = get_state_filename(fname, sizeof(fname), slot);
549 f = gzopen(fname, "rb");
553 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
554 fprintf(stderr, "gzseek failed\n");
559 gpu = malloc(sizeof(*gpu));
565 ret = gzread(f, gpu, sizeof(*gpu));
567 if (ret != sizeof(*gpu)) {
568 fprintf(stderr, "gzread failed\n");
572 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
574 if (gpu->ulStatus & 0x800000)
575 goto out; // disabled
577 x = gpu->ulControl[5] & 0x3ff;
578 y = (gpu->ulControl[5] >> 10) & 0x1ff;
579 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
580 w = psx_widths[(gpu->ulStatus >> 16) & 7];
581 tmp = gpu->ulControl[7];
582 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
583 if (gpu->ulStatus & 0x80000) // doubleheight
586 x = max(0, g_menuscreen_w - w) & ~3;
587 y = max(0, g_menuscreen_h / 2 - h / 2);
588 w = min(g_menuscreen_w, w);
589 h = min(g_menuscreen_h, h);
590 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
592 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
593 if (gpu->ulStatus & 0x200000)
594 bgr888_to_rgb565(d, s, w * 3);
596 bgr555_to_rgb565(d, s, w * 2);
597 #ifndef __ARM_ARCH_7A__
598 // better darken this on small screens
599 menu_darken_bg(d, d, w * 2, 0);
607 // ---------- XXX: pandora specific -----------
609 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
610 static char **pnd_filter_list;
612 static void apply_filter(int which)
618 if (pnd_filter_list == NULL || which == old)
621 for (i = 0; i < which; i++)
622 if (pnd_filter_list[i] == NULL)
625 if (pnd_filter_list[i] == NULL)
628 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
633 static void apply_lcdrate(int pal)
641 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
642 pnd_script_base, pal ? 50 : 60);
647 static menu_entry e_menu_gfx_options[];
649 static void pnd_menu_init(void)
657 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
659 dir = opendir("/etc/pandora/conf/dss_fir");
661 perror("filter opendir");
674 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
683 mfilters = calloc(count + 1, sizeof(mfilters[0]));
684 if (mfilters == NULL)
688 for (i = 0; (ent = readdir(dir)); ) {
691 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
694 len = strlen(ent->d_name);
696 // skip pre-HF5 extra files
697 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
699 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
702 // have to cut "_up_h" for pre-HF5
703 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
706 if (len > sizeof(buff) - 1)
709 strncpy(buff, ent->d_name, len);
711 mfilters[i] = strdup(buff);
712 if (mfilters[i] != NULL)
717 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
718 e_menu_gfx_options[i].data = (void *)mfilters;
719 pnd_filter_list = mfilters;
722 void menu_finish(void)
724 plat_cpu_clock_apply(cpu_clock_st);
727 // -------------- key config --------------
729 me_bind_action me_ctrl_actions[] =
731 { "UP ", 1 << DKEY_UP},
732 { "DOWN ", 1 << DKEY_DOWN },
733 { "LEFT ", 1 << DKEY_LEFT },
734 { "RIGHT ", 1 << DKEY_RIGHT },
735 { "TRIANGLE", 1 << DKEY_TRIANGLE },
736 { "CIRCLE ", 1 << DKEY_CIRCLE },
737 { "CROSS ", 1 << DKEY_CROSS },
738 { "SQUARE ", 1 << DKEY_SQUARE },
739 { "L1 ", 1 << DKEY_L1 },
740 { "R1 ", 1 << DKEY_R1 },
741 { "L2 ", 1 << DKEY_L2 },
742 { "R2 ", 1 << DKEY_R2 },
743 { "L3 ", 1 << DKEY_L3 },
744 { "R3 ", 1 << DKEY_R3 },
745 { "START ", 1 << DKEY_START },
746 { "SELECT ", 1 << DKEY_SELECT },
750 me_bind_action emuctrl_actions[] =
752 { "Save State ", 1 << SACTION_SAVE_STATE },
753 { "Load State ", 1 << SACTION_LOAD_STATE },
754 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
755 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
756 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
757 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
758 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
759 #ifdef __ARM_ARCH_7A__ /* XXX */
760 { "Minimize ", 1 << SACTION_MINIMIZE },
762 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
763 { "Gun A button ", 1 << SACTION_GUN_A },
764 { "Gun B button ", 1 << SACTION_GUN_B },
765 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
766 #ifndef __ARM_ARCH_7A__ /* XXX */
767 { "Volume Up ", 1 << SACTION_VOLUME_UP },
768 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
773 static char *mystrip(char *str)
778 for (i = 0; i < len; i++)
779 if (str[i] != ' ') break;
780 if (i > 0) memmove(str, str + i, len - i + 1);
783 for (i = len - 1; i >= 0; i--)
784 if (str[i] != ' ') break;
790 static void get_line(char *d, size_t size, const char *s)
795 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
806 static void keys_write_all(FILE *f)
810 for (d = 0; d < IN_MAX_DEVS; d++)
812 const int *binds = in_get_dev_binds(d);
813 const char *name = in_get_dev_name(d, 0, 0);
816 if (binds == NULL || name == NULL)
819 fprintf(f, "binddev = %s\n", name);
820 in_get_config(d, IN_CFG_BIND_COUNT, &count);
822 for (k = 0; k < count; k++)
827 act[0] = act[31] = 0;
828 name = in_get_key_name(d, k);
830 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
831 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
832 mask = me_ctrl_actions[i].mask;
834 strncpy(act, me_ctrl_actions[i].name, 31);
835 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
838 mask = me_ctrl_actions[i].mask << 16;
840 strncpy(act, me_ctrl_actions[i].name, 31);
841 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
846 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
847 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
848 mask = emuctrl_actions[i].mask;
850 strncpy(act, emuctrl_actions[i].name, 31);
851 fprintf(f, "bind %s = %s\n", name, mystrip(act));
857 for (k = 0; k < array_size(in_adev); k++)
860 fprintf(f, "bind_analog = %d\n", k);
865 static int parse_bind_val(const char *val, int *type)
869 *type = IN_BINDTYPE_NONE;
873 if (strncasecmp(val, "player", 6) == 0)
875 int player, shift = 0;
876 player = atoi(val + 6) - 1;
878 if ((unsigned int)player > 1)
883 *type = IN_BINDTYPE_PLAYER12;
884 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
885 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
886 return me_ctrl_actions[i].mask << shift;
889 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
890 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
891 *type = IN_BINDTYPE_EMU;
892 return emuctrl_actions[i].mask;
899 static void keys_load_all(const char *cfg)
901 char dev[256], key[128], *act;
907 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
910 get_line(dev, sizeof(dev), p);
911 dev_id = in_config_parse_dev(dev);
913 printf("input: can't handle dev: %s\n", dev);
917 in_unbind_all(dev_id, -1, -1);
918 while ((p = strstr(p, "bind"))) {
919 if (strncmp(p, "binddev = ", 10) == 0)
922 if (strncmp(p, "bind_analog", 11) == 0) {
923 ret = sscanf(p, "bind_analog = %d", &bind);
926 printf("input: parse error: %16s..\n", p);
929 if ((unsigned int)bind >= array_size(in_adev)) {
930 printf("input: analog id %d out of range\n", bind);
933 in_adev[bind] = dev_id;
939 printf("input: parse error: %16s..\n", p);
943 get_line(key, sizeof(key), p);
944 act = strchr(key, '=');
946 printf("parse failed: %16s..\n", p);
954 bind = parse_bind_val(act, &bindtype);
955 if (bind != -1 && bind != 0) {
956 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
957 in_config_bind_key(dev_id, key, bind, bindtype);
960 lprintf("config: unhandled action \"%s\"\n", act);
966 static int key_config_loop_wrap(int id, int keys)
969 case MA_CTRL_PLAYER1:
970 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
972 case MA_CTRL_PLAYER2:
973 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
976 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
984 static const char *adevnames[IN_MAX_DEVS + 2];
985 static int stick_sel[2];
987 static menu_entry e_menu_keyconfig_analog[] =
989 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
990 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
991 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
992 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
993 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
994 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
998 static int key_config_analog(int id, int keys)
1000 int i, d, count, sel = 0;
1001 int sel2dev_map[IN_MAX_DEVS];
1003 memset(adevnames, 0, sizeof(adevnames));
1004 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1005 memset(stick_sel, 0, sizeof(stick_sel));
1007 adevnames[0] = "None";
1009 for (d = 0; d < IN_MAX_DEVS; d++)
1011 const char *name = in_get_dev_name(d, 0, 1);
1016 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1020 if (in_adev[0] == d) stick_sel[0] = i;
1021 if (in_adev[1] == d) stick_sel[1] = i;
1023 adevnames[i++] = name;
1025 adevnames[i] = NULL;
1027 me_loop(e_menu_keyconfig_analog, &sel);
1029 in_adev[0] = sel2dev_map[stick_sel[0]];
1030 in_adev[1] = sel2dev_map[stick_sel[1]];
1035 static const char *mgn_dev_name(int id, int *offs)
1037 const char *name = NULL;
1040 if (id == MA_CTRL_DEV_FIRST)
1043 for (; it < IN_MAX_DEVS; it++) {
1044 name = in_get_dev_name(it, 1, 1);
1053 static const char *mgn_saveloadcfg(int id, int *offs)
1058 static int mh_savecfg(int id, int keys)
1060 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1061 me_update_msg("config saved");
1063 me_update_msg("failed to write config");
1068 static int mh_input_rescan(int id, int keys)
1070 //menu_sync_config();
1072 me_update_msg("rescan complete.");
1077 static const char *men_in_type_sel[] = {
1078 "Standard (SCPH-1080)",
1079 "Analog (SCPH-1150)",
1083 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1084 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1085 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1087 static menu_entry e_menu_keyconfig[] =
1089 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1090 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1091 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1092 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1094 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1095 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1096 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1097 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1098 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1099 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1100 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1101 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1102 mee_handler ("Rescan devices:", mh_input_rescan),
1104 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1105 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1106 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1107 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1108 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1109 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1110 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1114 static int menu_loop_keyconfig(int id, int keys)
1118 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1119 me_loop(e_menu_keyconfig, &sel);
1123 // ------------ gfx options menu ------------
1125 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1126 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1127 "using d-pad or move it using R+d-pad";
1128 static const char *men_dummy[] = { NULL };
1130 static int menu_loop_cscaler(int id, int keys)
1134 scaling = SCALE_CUSTOM;
1136 omap_enable_layer(1);
1141 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1142 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1143 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1146 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1147 if (inp & PBTN_UP) g_layer_y--;
1148 if (inp & PBTN_DOWN) g_layer_y++;
1149 if (inp & PBTN_LEFT) g_layer_x--;
1150 if (inp & PBTN_RIGHT) g_layer_x++;
1151 if (!(inp & PBTN_R)) {
1152 if (inp & PBTN_UP) g_layer_h += 2;
1153 if (inp & PBTN_DOWN) g_layer_h -= 2;
1154 if (inp & PBTN_LEFT) g_layer_w += 2;
1155 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1157 if (inp & (PBTN_MOK|PBTN_MBACK))
1160 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1161 if (g_layer_x < 0) g_layer_x = 0;
1162 if (g_layer_x > 640) g_layer_x = 640;
1163 if (g_layer_y < 0) g_layer_y = 0;
1164 if (g_layer_y > 420) g_layer_y = 420;
1165 if (g_layer_w < 160) g_layer_w = 160;
1166 if (g_layer_h < 60) g_layer_h = 60;
1167 if (g_layer_x + g_layer_w > 800)
1168 g_layer_w = 800 - g_layer_x;
1169 if (g_layer_y + g_layer_h > 480)
1170 g_layer_h = 480 - g_layer_y;
1171 omap_enable_layer(1);
1175 omap_enable_layer(0);
1180 static menu_entry e_menu_gfx_options[] =
1182 mee_enum ("Scaler", 0, scaling, men_scaler),
1183 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1184 // mee_onoff ("Vsync", 0, vsync, 1),
1185 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1189 static int menu_loop_gfx_options(int id, int keys)
1193 me_loop(e_menu_gfx_options, &sel);
1198 // ------------ bios/plugins ------------
1202 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1203 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1205 static menu_entry e_menu_plugin_gpu_neon[] =
1207 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1211 static int menu_loop_plugin_gpu_neon(int id, int keys)
1214 me_loop(e_menu_plugin_gpu_neon, &sel);
1220 static menu_entry e_menu_plugin_gpu_unai[] =
1222 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1223 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1224 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1225 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1229 static int menu_loop_plugin_gpu_unai(int id, int keys)
1232 me_loop(e_menu_plugin_gpu_unai, &sel);
1236 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1237 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1238 static const char h_gpu_1[] = "Capcom fighting games";
1239 static const char h_gpu_2[] = "Black screens in Lunar";
1240 static const char h_gpu_3[] = "Compatibility mode";
1241 static const char h_gpu_6[] = "Pandemonium 2";
1242 //static const char h_gpu_7[] = "Skip every second frame";
1243 static const char h_gpu_8[] = "Needed by Dark Forces";
1244 static const char h_gpu_9[] = "better g-colors, worse textures";
1245 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1247 static menu_entry e_menu_plugin_gpu_peops[] =
1249 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1250 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1251 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1252 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1253 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1254 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1255 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1256 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1257 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1258 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1262 static int menu_loop_plugin_gpu_peops(int id, int keys)
1265 me_loop(e_menu_plugin_gpu_peops, &sel);
1269 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1270 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1271 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1273 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1275 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1276 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1277 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1278 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1279 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1280 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1281 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1282 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1283 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1284 mee_label ("Fixes/hacks:"),
1285 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1286 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1287 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1288 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1289 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1290 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1291 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1292 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1293 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1294 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1295 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1299 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1302 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1306 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1307 static const char h_spu_volboost[] = "Large values cause distortion";
1308 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1309 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1311 static menu_entry e_menu_plugin_spu[] =
1313 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1314 mee_onoff ("Reverb", 0, iUseReverb, 2),
1315 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1316 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1317 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1318 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1322 static int menu_loop_plugin_spu(int id, int keys)
1325 me_loop(e_menu_plugin_spu, &sel);
1329 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1330 "savestates and can't be changed there. Must save\n"
1331 "config and reload the game for change to take effect";
1332 static const char h_plugin_gpu[] =
1334 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1339 "is Pete's soft GPU, slow but accurate\n"
1340 "gpuPCSX4ALL is GPU from PCSX4ALL, fast but glitchy\n"
1341 "gpuGLES Pete's hw GPU, uses 3D chip but is glitchy\n"
1342 "must save config and reload the game if changed";
1343 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1344 "must save config and reload the game if changed";
1345 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1346 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1347 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1348 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1350 static menu_entry e_menu_plugin_options[] =
1352 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1353 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1354 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1356 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1358 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1359 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1360 mee_handler_h ("Configure GLES GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1361 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1365 static menu_entry e_menu_main2[];
1367 static int menu_loop_plugin_options(int id, int keys)
1370 me_loop(e_menu_plugin_options, &sel);
1372 // sync BIOS/plugins
1373 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1374 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1375 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1376 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1381 // ------------ adv options menu ------------
1383 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1384 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1385 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1386 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1388 static menu_entry e_menu_speed_hacks[] =
1390 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1391 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1392 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1393 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1397 static int menu_loop_speed_hacks(int id, int keys)
1400 me_loop(e_menu_speed_hacks, &sel);
1404 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1405 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1406 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1407 "(green: normal, red: fmod, blue: noise)";
1408 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1409 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1410 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1411 "(proper .cue/.bin dump is needed otherwise)";
1412 static const char h_cfg_sio[] = "You should not need this, breaks games";
1413 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1414 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1415 "(timing hack, breaks other games)";
1416 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1417 "(timing hack, breaks other games)";
1418 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1419 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1420 "Might be useful to overcome some dynarec bugs";
1421 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1422 "must reload game for any change to take effect";
1424 static menu_entry e_menu_adv_options[] =
1426 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1427 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1428 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1429 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1430 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1431 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1432 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1433 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1434 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1435 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1436 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1437 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1441 static int menu_loop_adv_options(int id, int keys)
1444 me_loop(e_menu_adv_options, &sel);
1448 // ------------ options menu ------------
1450 static int mh_restore_defaults(int id, int keys)
1452 menu_set_defconfig();
1453 me_update_msg("defaults restored");
1457 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1458 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1460 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1461 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1462 "loading state or both";
1464 static const char h_restore_def[] = "Switches back to default / recommended\n"
1466 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1468 static menu_entry e_menu_options[] =
1470 // mee_range ("Save slot", 0, state_slot, 0, 9),
1471 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1472 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1473 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1474 mee_enum ("Region", 0, region, men_region),
1475 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1476 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1477 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1478 mee_handler ("[Advanced]", menu_loop_adv_options),
1479 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1480 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1481 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1485 static int menu_loop_options(int id, int keys)
1490 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1491 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1492 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1494 me_loop(e_menu_options, &sel);
1499 // ------------ debug menu ------------
1501 static void draw_frame_debug(GPUFreeze_t *gpuf)
1503 int w = min(g_menuscreen_w, 1024);
1504 int h = min(g_menuscreen_h, 512);
1505 u16 *d = g_menuscreen_ptr;
1506 u16 *s = (u16 *)gpuf->psxVRam;
1510 gpuf->ulFreezeVersion = 1;
1511 if (GPU_freeze != NULL)
1512 GPU_freeze(1, gpuf);
1514 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1515 bgr555_to_rgb565(d, s, w * 2);
1517 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1518 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1519 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1520 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1521 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1524 static void debug_menu_loop(void)
1529 gpuf = malloc(sizeof(*gpuf));
1536 draw_frame_debug(gpuf);
1539 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1540 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1541 if (inp & PBTN_MBACK)
1548 // --------- memcard manager ---------
1550 static void draw_mc_icon(int dx, int dy, const u16 *s)
1555 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1557 for (y = 0; y < 16; y++, s += 16) {
1558 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1559 for (x = 0; x < 16; x++) {
1561 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1562 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1568 static void draw_mc_bg(void)
1570 McdBlock *blocks1, *blocks2;
1574 blocks1 = malloc(15 * sizeof(blocks1[0]));
1575 blocks2 = malloc(15 * sizeof(blocks1[0]));
1576 if (blocks1 == NULL || blocks2 == NULL)
1579 for (i = 0; i < 15; i++) {
1580 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1581 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1586 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1588 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1592 maxicons = g_menuscreen_h / 32;
1595 row2 = g_menuscreen_w / 2;
1596 for (i = 0; i < maxicons; i++) {
1597 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1598 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1600 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1601 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1604 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1612 static void handle_memcard_sel(void)
1615 if (memcard1_sel != 0)
1616 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1618 if (memcard2_sel != 0)
1619 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1620 LoadMcds(Config.Mcd1, Config.Mcd2);
1624 static menu_entry e_memcard_options[] =
1626 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1627 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1631 static int menu_loop_memcards(int id, int keys)
1637 memcard1_sel = memcard2_sel = 0;
1638 p = strrchr(Config.Mcd1, '/');
1640 for (i = 0; memcards[i] != NULL; i++)
1641 if (strcmp(p + 1, memcards[i]) == 0)
1642 { memcard1_sel = i; break; }
1643 p = strrchr(Config.Mcd2, '/');
1645 for (i = 0; memcards[i] != NULL; i++)
1646 if (strcmp(p + 1, memcards[i]) == 0)
1647 { memcard2_sel = i; break; }
1649 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1651 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1656 // --------- main menu help ----------
1658 static void menu_bios_warn(void)
1661 static const char msg[] =
1662 "You don't seem to have copied any BIOS\n"
1664 #ifdef __ARM_ARCH_7A__ // XXX
1665 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1667 "pcsx_rearmed/bios/\n\n"
1669 "While many games work fine with fake\n"
1670 "(HLE) BIOS, others (like MGS and FF8)\n"
1671 "require BIOS to work.\n"
1672 "After copying the file, you'll also need\n"
1673 "to select it in the emu's menu:\n"
1674 "options->[BIOS/Plugins]\n\n"
1675 "The file is usually named SCPH1001.BIN,\n"
1676 "but other not compressed files can be\n"
1678 "Press (B) or (X) to continue";
1682 draw_menu_message(msg, NULL);
1684 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1685 if (inp & (PBTN_MBACK|PBTN_MOK))
1690 // ------------ main menu ------------
1694 static void draw_frame_main(void)
1701 if (CdromId[0] != 0) {
1702 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1703 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1704 Config.HLE ? "HLE" : "BIOS");
1705 smalltext_out16(4, 1, buff, 0x105f);
1710 tmp = localtime(<ime);
1711 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1712 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1713 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1717 static void draw_frame_credits(void)
1719 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1722 static const char credits_text[] =
1724 "(C) 1999-2003 PCSX Team\n"
1725 "(C) 2005-2009 PCSX-df Team\n"
1726 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1727 "ARM recompiler (C) 2009-2011 Ari64\n"
1729 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1731 "PEOpS GPU and SPU by Pete Bernert\n"
1732 " and the P.E.Op.S. team\n"
1733 "PCSX4ALL plugin by PCSX4ALL team\n"
1734 " Chui, Franxis, Unai\n\n"
1735 "integration, optimization and\n"
1736 " frontend (C) 2010-2012 notaz\n";
1738 static int reset_game(void)
1741 if (bios_sel == 0 && !Config.HLE)
1747 if (CheckCdrom() != -1) {
1753 static int reload_plugins(const char *cdimg)
1759 set_cd_image(cdimg);
1761 pcnt_hook_plugins();
1763 if (OpenPlugins() == -1) {
1764 me_update_msg("failed to open plugins");
1767 plugin_call_rearmed_cbs();
1769 cdrIsoMultidiskCount = 1;
1771 CdromLabel[0] = '\0';
1776 static int run_bios(void)
1782 if (reload_plugins(NULL) != 0)
1790 static int run_exe(void)
1794 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1799 if (reload_plugins(NULL) != 0)
1803 if (Load(fname) != 0) {
1804 me_update_msg("exe load failed, bad file?");
1813 static int run_cd_image(const char *fname)
1816 reload_plugins(fname);
1818 // always autodetect, menu_sync_config will override as needed
1821 if (CheckCdrom() == -1) {
1822 // Only check the CD if we are starting the console with a CD
1824 me_update_msg("unsupported/invalid CD image");
1830 // Read main executable directly from CDRom and start it
1831 if (LoadCdrom() == -1) {
1833 me_update_msg("failed to load CD image");
1838 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1843 static int romsel_run(void)
1845 int prev_gpu, prev_spu;
1848 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1852 printf("selected file: %s\n", fname);
1854 new_dynarec_clear_full();
1856 if (run_cd_image(fname) != 0)
1859 prev_gpu = gpu_plugsel;
1860 prev_spu = spu_plugsel;
1861 if (menu_load_config(1) != 0)
1862 menu_load_config(0);
1864 // check for plugin changes, have to repeat
1865 // loading if game config changed plugins to reload them
1866 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1867 printf("plugin change detected, reloading plugins..\n");
1868 if (run_cd_image(fname) != 0)
1873 printf("note: running without BIOS, expect compatibility problems\n");
1875 strcpy(last_selected_fname, rom_fname_reload);
1879 static int swap_cd_image(void)
1883 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1887 printf("selected file: %s\n", fname);
1890 CdromLabel[0] = '\0';
1892 set_cd_image(fname);
1893 if (ReloadCdromPlugin() < 0) {
1894 me_update_msg("failed to load cdr plugin");
1897 if (CDR_open() < 0) {
1898 me_update_msg("failed to open cdr plugin");
1902 SetCdOpenCaseTime(time(NULL) + 2);
1905 strcpy(last_selected_fname, rom_fname_reload);
1909 static int swap_cd_multidisk(void)
1911 cdrIsoMultidiskSelect++;
1913 CdromLabel[0] = '\0';
1916 if (CDR_open() < 0) {
1917 me_update_msg("failed to open cdr plugin");
1921 SetCdOpenCaseTime(time(NULL) + 2);
1927 static int main_menu_handler(int id, int keys)
1931 case MA_MAIN_RESUME_GAME:
1935 case MA_MAIN_SAVE_STATE:
1937 return menu_loop_savestate(0);
1939 case MA_MAIN_LOAD_STATE:
1941 return menu_loop_savestate(1);
1943 case MA_MAIN_RESET_GAME:
1944 if (ready_to_go && reset_game() == 0)
1947 case MA_MAIN_LOAD_ROM:
1948 if (romsel_run() == 0)
1951 case MA_MAIN_SWAP_CD:
1952 if (swap_cd_image() == 0)
1955 case MA_MAIN_SWAP_CD_MULTI:
1956 if (swap_cd_multidisk() == 0)
1959 case MA_MAIN_RUN_BIOS:
1960 if (run_bios() == 0)
1963 case MA_MAIN_RUN_EXE:
1967 case MA_MAIN_CREDITS:
1968 draw_menu_message(credits_text, draw_frame_credits);
1969 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1975 lprintf("%s: something unknown selected\n", __FUNCTION__);
1982 static menu_entry e_menu_main2[] =
1984 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1985 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1986 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1987 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1988 mee_handler ("Memcard manager", menu_loop_memcards),
1992 static int main_menu2_handler(int id, int keys)
1996 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1997 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1998 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2000 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2003 static const char h_extra[] = "Change CD, manage memcards..\n";
2005 static menu_entry e_menu_main[] =
2009 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2010 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2011 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2012 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2013 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2014 mee_handler ("Options", menu_loop_options),
2015 mee_handler ("Controls", menu_loop_keyconfig),
2016 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2017 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2018 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2022 // ----------------------------
2024 static void menu_leave_emu(void);
2026 void menu_loop(void)
2032 if (bioses[1] == NULL && !warned_about_bios) {
2034 warned_about_bios = 1;
2037 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2038 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2039 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2040 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2042 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2045 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2046 } while (!ready_to_go);
2048 /* wait until menu, ok, back is released */
2049 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2052 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2057 static int qsort_strcmp(const void *p1, const void *p2)
2059 char * const *s1 = (char * const *)p1;
2060 char * const *s2 = (char * const *)p2;
2061 return strcasecmp(*s1, *s2);
2064 static void scan_bios_plugins(void)
2066 char fname[MAXPATHLEN];
2068 int bios_i, gpu_i, spu_i, mc_i;
2073 gpu_plugins[0] = "builtin_gpu";
2074 spu_plugins[0] = "builtin_spu";
2075 memcards[0] = "(none)";
2076 bios_i = gpu_i = spu_i = mc_i = 1;
2078 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2079 dir = opendir(fname);
2081 perror("scan_bios_plugins bios opendir");
2096 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2099 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2100 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2101 printf("bad BIOS file: %s\n", ent->d_name);
2105 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2106 bioses[bios_i++] = strdup(ent->d_name);
2110 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2116 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2117 dir = opendir(fname);
2119 perror("scan_bios_plugins plugins opendir");
2133 p = strstr(ent->d_name, ".so");
2137 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2138 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2140 fprintf(stderr, "%s\n", dlerror());
2144 // now what do we have here?
2145 tmp = dlsym(h, "GPUinit");
2148 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2149 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2153 tmp = dlsym(h, "SPUinit");
2156 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2157 spu_plugins[spu_i++] = strdup(ent->d_name);
2161 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2168 dir = opendir("." MEMCARD_DIR);
2170 perror("scan_bios_plugins memcards opendir");
2185 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2188 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2189 if (stat(fname, &st) != 0) {
2190 printf("bad memcard file: %s\n", ent->d_name);
2194 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2195 memcards[mc_i++] = strdup(ent->d_name);
2199 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2203 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2208 void menu_init(void)
2210 char buff[MAXPATHLEN];
2212 strcpy(last_selected_fname, "/media");
2214 scan_bios_plugins();
2218 menu_set_defconfig();
2219 menu_load_config(0);
2224 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2225 if (g_menubg_src_ptr == NULL)
2227 emu_make_path(buff, "skin/background.png", sizeof(buff));
2228 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2230 #ifndef __ARM_ARCH_7A__ /* XXX */
2231 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2232 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2234 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2235 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2239 void menu_notify_mode_change(int w, int h, int bpp)
2250 g_layer_w = w; g_layer_h = h;
2254 if (h > g_menuscreen_h || (240 < h && h <= 360))
2255 goto fractional_4_3;
2257 // 4:3 that prefers integer scaling
2258 imult = g_menuscreen_h / h;
2259 g_layer_w = w * imult;
2260 g_layer_h = h * imult;
2261 mult = (float)g_layer_w / (float)g_layer_h;
2262 if (mult < 1.25f || mult > 1.666f)
2263 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2264 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2269 mult = 240.0f / (float)h * 4.0f / 3.0f;
2272 g_layer_w = mult * (float)g_menuscreen_h;
2273 g_layer_h = g_menuscreen_h;
2274 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2277 case SCALE_FULLSCREEN:
2278 g_layer_w = g_menuscreen_w;
2279 g_layer_h = g_menuscreen_h;
2286 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2287 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2288 if (g_layer_x < 0) g_layer_x = 0;
2289 if (g_layer_y < 0) g_layer_y = 0;
2290 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2291 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2294 static void menu_leave_emu(void)
2296 if (GPU_close != NULL) {
2297 int ret = GPU_close();
2299 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2302 plat_video_menu_enter(ready_to_go);
2304 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2305 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2306 int x = max(0, g_menuscreen_w - last_psx_w);
2307 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2308 int w = min(g_menuscreen_w, last_psx_w);
2309 int h = min(g_menuscreen_h, last_psx_h);
2310 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2311 u16 *s = pl_vout_buf;
2313 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2314 menu_darken_bg(d, s, w, 0);
2318 cpu_clock = plat_cpu_clock_get();
2321 void menu_prepare_emu(void)
2323 R3000Acpu *prev_cpu = psxCpu;
2325 plat_video_menu_leave();
2327 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2329 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2330 if (psxCpu != prev_cpu)
2331 // note that this does not really reset, just clears drc caches
2334 // core doesn't care about Config.Cdda changes,
2335 // so handle them manually here
2340 apply_lcdrate(Config.PsxType);
2341 apply_filter(filter);
2342 plat_cpu_clock_apply(cpu_clock);
2344 // push config to GPU plugin
2345 plugin_call_rearmed_cbs();
2347 if (GPU_open != NULL) {
2348 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2350 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2356 void me_update_msg(const char *msg)
2358 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2359 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2361 menu_error_time = plat_get_ticks_ms();
2362 lprintf("msg: %s\n", menu_error_msg);