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,
87 static int last_psx_w, last_psx_h, last_psx_bpp;
88 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
89 static char rom_fname_reload[MAXPATHLEN];
90 static char last_selected_fname[MAXPATHLEN];
91 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
93 static int memcard1_sel, memcard2_sel;
95 int soft_scaling, analog_deadzone; // for Caanoo
97 #ifdef __ARM_ARCH_7A__
98 #define DEFAULT_PSX_CLOCK 57
99 #define DEFAULT_PSX_CLOCK_S "57"
101 #define DEFAULT_PSX_CLOCK 50
102 #define DEFAULT_PSX_CLOCK_S "50"
106 extern int iUseReverb;
107 extern int iUseInterpolation;
109 extern int iSPUIRQWait;
110 extern int iUseTimer;
113 static const char *bioses[24];
114 static const char *gpu_plugins[16];
115 static const char *spu_plugins[16];
116 static const char *memcards[32];
117 static int bios_sel, gpu_plugsel, spu_plugsel;
120 static int min(int x, int y) { return x < y ? x : y; }
121 static int max(int x, int y) { return x > y ? x : y; }
123 void emu_make_path(char *buff, const char *end, int size)
127 end_len = strlen(end);
128 pos = plat_get_root_dir(buff, size);
129 strncpy(buff + pos, end, size - pos);
131 if (pos + end_len > size - 1)
132 printf("Warning: path truncated: %s\n", buff);
135 static int emu_check_save_file(int slot, int *time)
137 char fname[MAXPATHLEN];
141 ret = emu_check_state(slot);
142 if (ret != 0 || time == NULL)
143 return ret == 0 ? 1 : 0;
145 ret = get_state_filename(fname, sizeof(fname), slot);
149 ret = stat(fname, &status);
153 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
154 return 1; // probably bad rtc like on some Caanoos
156 *time = status.st_mtime;
161 static int emu_save_load_game(int load, int unused)
166 ret = emu_load_state(state_slot);
168 // reflect hle/bios mode from savestate
171 else if (bios_sel == 0 && bioses[1] != NULL)
172 // XXX: maybe find the right bios instead
176 ret = emu_save_state(state_slot);
181 // propagate menu settings to the emu vars
182 static void menu_sync_config(void)
184 static int allow_abs_only_old;
189 Config.PsxType = region - 1;
191 cycle_multiplier = 10000 / psx_clock;
193 switch (in_type_sel1) {
194 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
195 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
196 default: in_type1 = PSE_PAD_TYPE_STANDARD;
198 switch (in_type_sel2) {
199 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
200 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
201 default: in_type2 = PSE_PAD_TYPE_STANDARD;
203 if (in_evdev_allow_abs_only != allow_abs_only_old) {
205 allow_abs_only_old = in_evdev_allow_abs_only;
208 iVolume = 768 + 128 * volume_boost;
209 pl_rearmed_cbs.frameskip = frameskip - 1;
210 pl_timing_prepare(Config.PsxType);
213 static void menu_set_defconfig(void)
215 emu_set_default_config();
221 analog_deadzone = 50;
223 psx_clock = DEFAULT_PSX_CLOCK;
226 in_type_sel1 = in_type_sel2 = 0;
227 in_evdev_allow_abs_only = 0;
232 #define CE_CONFIG_STR(val) \
233 { #val, 0, Config.val }
235 #define CE_CONFIG_VAL(val) \
236 { #val, sizeof(Config.val), &Config.val }
238 #define CE_STR(val) \
241 #define CE_INTVAL(val) \
242 { #val, sizeof(val), &val }
244 #define CE_INTVAL_P(val) \
245 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
247 // 'versioned' var, used when defaults change
248 #define CE_CONFIG_STR_V(val, ver) \
249 { #val #ver, 0, Config.val }
251 #define CE_INTVAL_V(val, ver) \
252 { #val #ver, sizeof(val), &val }
254 #define CE_INTVAL_PV(val, ver) \
255 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
257 static const struct {
263 CE_CONFIG_STR_V(Gpu, 2),
265 // CE_CONFIG_STR(Cdr),
270 CE_CONFIG_VAL(Debug),
271 CE_CONFIG_VAL(PsxOut),
272 CE_CONFIG_VAL(SpuIrq),
273 CE_CONFIG_VAL(RCntFix),
274 CE_CONFIG_VAL(VSyncWA),
276 CE_CONFIG_VAL(CdrReschedule),
278 CE_INTVAL_V(scaling, 2),
279 CE_INTVAL(g_layer_x),
280 CE_INTVAL(g_layer_y),
281 CE_INTVAL(g_layer_w),
282 CE_INTVAL(g_layer_h),
284 CE_INTVAL(state_slot),
285 CE_INTVAL(cpu_clock),
287 CE_INTVAL(in_type_sel1),
288 CE_INTVAL(in_type_sel2),
289 CE_INTVAL(analog_deadzone),
290 CE_INTVAL_V(frameskip, 3),
291 CE_INTVAL_P(gpu_peops.iUseDither),
292 CE_INTVAL_P(gpu_peops.dwActFixes),
293 CE_INTVAL_P(gpu_unai.lineskip),
294 CE_INTVAL_P(gpu_unai.abe_hack),
295 CE_INTVAL_P(gpu_unai.no_light),
296 CE_INTVAL_P(gpu_unai.no_blend),
297 CE_INTVAL_P(gpu_neon.allow_interlace),
298 CE_INTVAL_V(iUseReverb, 3),
299 CE_INTVAL_V(iXAPitch, 3),
300 CE_INTVAL_V(iUseInterpolation, 3),
301 CE_INTVAL_V(iSPUIRQWait, 3),
302 CE_INTVAL_V(iUseTimer, 3),
303 CE_INTVAL(warned_about_bios),
304 CE_INTVAL(in_evdev_allow_abs_only),
305 CE_INTVAL(volume_boost),
306 CE_INTVAL(psx_clock),
307 CE_INTVAL(new_dynarec_hacks),
308 CE_INTVAL(in_enable_vibration),
311 static char *get_cd_label(void)
313 static char trimlabel[33];
316 strncpy(trimlabel, CdromLabel, 32);
318 for (j = 31; j >= 0; j--)
319 if (trimlabel[j] == ' ')
325 static void make_cfg_fname(char *buf, size_t size, int is_game)
328 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
330 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
333 static void keys_write_all(FILE *f);
335 static int menu_write_config(int is_game)
337 char cfgfile[MAXPATHLEN];
341 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
342 f = fopen(cfgfile, "w");
344 printf("menu_write_config: failed to open: %s\n", cfgfile);
348 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
349 fprintf(f, "%s = ", config_data[i].name);
350 switch (config_data[i].len) {
352 fprintf(f, "%s\n", (char *)config_data[i].val);
355 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
358 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
361 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
364 printf("menu_write_config: unhandled len %d for %s\n",
365 config_data[i].len, config_data[i].name);
371 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
379 static void parse_str_val(char *cval, const char *src)
382 strncpy(cval, src, MAXPATHLEN);
383 cval[MAXPATHLEN - 1] = 0;
384 tmp = strchr(cval, '\n');
386 tmp = strchr(cval, '\r');
391 static void keys_load_all(const char *cfg);
393 static int menu_load_config(int is_game)
395 char cfgfile[MAXPATHLEN];
401 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
402 f = fopen(cfgfile, "r");
404 printf("menu_load_config: failed to open: %s\n", cfgfile);
408 fseek(f, 0, SEEK_END);
411 printf("bad size %ld: %s\n", size, cfgfile);
415 cfg = malloc(size + 1);
419 fseek(f, 0, SEEK_SET);
420 if (fread(cfg, 1, size, f) != size) {
421 printf("failed to read: %s\n", cfgfile);
426 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
430 tmp = strstr(cfg, config_data[i].name);
433 tmp += strlen(config_data[i].name);
434 if (strncmp(tmp, " = ", 3) != 0)
438 if (config_data[i].len == 0) {
439 parse_str_val(config_data[i].val, tmp);
444 val = strtoul(tmp, &tmp2, 16);
445 if (tmp2 == NULL || tmp == tmp2)
446 continue; // parse failed
448 switch (config_data[i].len) {
450 *(u8 *)config_data[i].val = val;
453 *(u16 *)config_data[i].val = val;
456 *(u32 *)config_data[i].val = val;
459 printf("menu_load_config: unhandled len %d for %s\n",
460 config_data[i].len, config_data[i].name);
466 char *tmp = strstr(cfg, "lastcdimg = ");
469 parse_str_val(last_selected_fname, tmp);
484 for (i = bios_sel = 0; bioses[i] != NULL; i++)
485 if (strcmp(Config.Bios, bioses[i]) == 0)
486 { bios_sel = i; break; }
488 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
489 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
490 { gpu_plugsel = i; break; }
492 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
493 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
494 { spu_plugsel = i; break; }
499 // rrrr rggg gggb bbbb
500 static unsigned short fname2color(const char *fname)
502 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
503 ".bz", ".znx", ".pbp", ".cbn" };
504 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
505 ".table", ".index", ".sbi" };
506 const char *ext = strrchr(fname, '.');
511 for (i = 0; i < array_size(cdimg_exts); i++)
512 if (strcasecmp(ext, cdimg_exts[i]) == 0)
514 for (i = 0; i < array_size(other_exts); i++)
515 if (strcasecmp(ext, other_exts[i]) == 0)
520 static void draw_savestate_bg(int slot);
522 static const char *filter_exts[] = {
523 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
526 #define MENU_ALIGN_LEFT
527 #ifdef __ARM_ARCH_7A__ // assume hires device
533 #define menu_init menu_init_common
534 #include "common/menu.c"
537 // a bit of black magic here
538 static void draw_savestate_bg(int slot)
540 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
542 char fname[MAXPATHLEN];
549 ret = get_state_filename(fname, sizeof(fname), slot);
553 f = gzopen(fname, "rb");
557 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
558 fprintf(stderr, "gzseek failed\n");
563 gpu = malloc(sizeof(*gpu));
569 ret = gzread(f, gpu, sizeof(*gpu));
571 if (ret != sizeof(*gpu)) {
572 fprintf(stderr, "gzread failed\n");
576 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
578 if (gpu->ulStatus & 0x800000)
579 goto out; // disabled
581 x = gpu->ulControl[5] & 0x3ff;
582 y = (gpu->ulControl[5] >> 10) & 0x1ff;
583 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
584 w = psx_widths[(gpu->ulStatus >> 16) & 7];
585 tmp = gpu->ulControl[7];
586 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
587 if (gpu->ulStatus & 0x80000) // doubleheight
590 x = max(0, g_menuscreen_w - w) & ~3;
591 y = max(0, g_menuscreen_h / 2 - h / 2);
592 w = min(g_menuscreen_w, w);
593 h = min(g_menuscreen_h, h);
594 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
596 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
597 if (gpu->ulStatus & 0x200000)
598 bgr888_to_rgb565(d, s, w * 3);
600 bgr555_to_rgb565(d, s, w * 2);
601 #ifndef __ARM_ARCH_7A__
602 // better darken this on small screens
603 menu_darken_bg(d, d, w * 2, 0);
611 // ---------- XXX: pandora specific -----------
613 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
614 static char **pnd_filter_list;
616 static void apply_filter(int which)
622 if (pnd_filter_list == NULL || which == old)
625 for (i = 0; i < which; i++)
626 if (pnd_filter_list[i] == NULL)
629 if (pnd_filter_list[i] == NULL)
632 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
637 static void apply_lcdrate(int pal)
645 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
646 pnd_script_base, pal ? 50 : 60);
651 static menu_entry e_menu_gfx_options[];
653 static void pnd_menu_init(void)
661 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
663 dir = opendir("/etc/pandora/conf/dss_fir");
665 perror("filter opendir");
678 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
687 mfilters = calloc(count + 1, sizeof(mfilters[0]));
688 if (mfilters == NULL)
692 for (i = 0; (ent = readdir(dir)); ) {
695 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
698 len = strlen(ent->d_name);
700 // skip pre-HF5 extra files
701 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
703 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
706 // have to cut "_up_h" for pre-HF5
707 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
710 if (len > sizeof(buff) - 1)
713 strncpy(buff, ent->d_name, len);
715 mfilters[i] = strdup(buff);
716 if (mfilters[i] != NULL)
721 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
722 e_menu_gfx_options[i].data = (void *)mfilters;
723 pnd_filter_list = mfilters;
726 void menu_finish(void)
728 plat_cpu_clock_apply(cpu_clock_st);
731 // -------------- key config --------------
733 me_bind_action me_ctrl_actions[] =
735 { "UP ", 1 << DKEY_UP},
736 { "DOWN ", 1 << DKEY_DOWN },
737 { "LEFT ", 1 << DKEY_LEFT },
738 { "RIGHT ", 1 << DKEY_RIGHT },
739 { "TRIANGLE", 1 << DKEY_TRIANGLE },
740 { "CIRCLE ", 1 << DKEY_CIRCLE },
741 { "CROSS ", 1 << DKEY_CROSS },
742 { "SQUARE ", 1 << DKEY_SQUARE },
743 { "L1 ", 1 << DKEY_L1 },
744 { "R1 ", 1 << DKEY_R1 },
745 { "L2 ", 1 << DKEY_L2 },
746 { "R2 ", 1 << DKEY_R2 },
747 { "L3 ", 1 << DKEY_L3 },
748 { "R3 ", 1 << DKEY_R3 },
749 { "START ", 1 << DKEY_START },
750 { "SELECT ", 1 << DKEY_SELECT },
754 me_bind_action emuctrl_actions[] =
756 { "Save State ", 1 << SACTION_SAVE_STATE },
757 { "Load State ", 1 << SACTION_LOAD_STATE },
758 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
759 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
760 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
761 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
762 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
763 #ifdef __ARM_ARCH_7A__ /* XXX */
764 { "Minimize ", 1 << SACTION_MINIMIZE },
766 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
767 { "Gun A button ", 1 << SACTION_GUN_A },
768 { "Gun B button ", 1 << SACTION_GUN_B },
769 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
770 #ifndef __ARM_ARCH_7A__ /* XXX */
771 { "Volume Up ", 1 << SACTION_VOLUME_UP },
772 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
777 static char *mystrip(char *str)
782 for (i = 0; i < len; i++)
783 if (str[i] != ' ') break;
784 if (i > 0) memmove(str, str + i, len - i + 1);
787 for (i = len - 1; i >= 0; i--)
788 if (str[i] != ' ') break;
794 static void get_line(char *d, size_t size, const char *s)
799 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
810 static void keys_write_all(FILE *f)
814 for (d = 0; d < IN_MAX_DEVS; d++)
816 const int *binds = in_get_dev_binds(d);
817 const char *name = in_get_dev_name(d, 0, 0);
820 if (binds == NULL || name == NULL)
823 fprintf(f, "binddev = %s\n", name);
824 in_get_config(d, IN_CFG_BIND_COUNT, &count);
826 for (k = 0; k < count; k++)
831 act[0] = act[31] = 0;
832 name = in_get_key_name(d, k);
834 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
835 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
836 mask = me_ctrl_actions[i].mask;
838 strncpy(act, me_ctrl_actions[i].name, 31);
839 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
842 mask = me_ctrl_actions[i].mask << 16;
844 strncpy(act, me_ctrl_actions[i].name, 31);
845 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
850 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
851 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
852 mask = emuctrl_actions[i].mask;
854 strncpy(act, emuctrl_actions[i].name, 31);
855 fprintf(f, "bind %s = %s\n", name, mystrip(act));
861 for (k = 0; k < array_size(in_adev); k++)
864 fprintf(f, "bind_analog = %d\n", k);
869 static int parse_bind_val(const char *val, int *type)
873 *type = IN_BINDTYPE_NONE;
877 if (strncasecmp(val, "player", 6) == 0)
879 int player, shift = 0;
880 player = atoi(val + 6) - 1;
882 if ((unsigned int)player > 1)
887 *type = IN_BINDTYPE_PLAYER12;
888 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
889 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
890 return me_ctrl_actions[i].mask << shift;
893 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
894 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
895 *type = IN_BINDTYPE_EMU;
896 return emuctrl_actions[i].mask;
903 static void keys_load_all(const char *cfg)
905 char dev[256], key[128], *act;
911 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
914 get_line(dev, sizeof(dev), p);
915 dev_id = in_config_parse_dev(dev);
917 printf("input: can't handle dev: %s\n", dev);
921 in_unbind_all(dev_id, -1, -1);
922 while ((p = strstr(p, "bind"))) {
923 if (strncmp(p, "binddev = ", 10) == 0)
926 if (strncmp(p, "bind_analog", 11) == 0) {
927 ret = sscanf(p, "bind_analog = %d", &bind);
930 printf("input: parse error: %16s..\n", p);
933 if ((unsigned int)bind >= array_size(in_adev)) {
934 printf("input: analog id %d out of range\n", bind);
937 in_adev[bind] = dev_id;
943 printf("input: parse error: %16s..\n", p);
947 get_line(key, sizeof(key), p);
948 act = strchr(key, '=');
950 printf("parse failed: %16s..\n", p);
958 bind = parse_bind_val(act, &bindtype);
959 if (bind != -1 && bind != 0) {
960 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
961 in_config_bind_key(dev_id, key, bind, bindtype);
964 lprintf("config: unhandled action \"%s\"\n", act);
970 static int key_config_loop_wrap(int id, int keys)
973 case MA_CTRL_PLAYER1:
974 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
976 case MA_CTRL_PLAYER2:
977 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
980 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
988 static const char *adevnames[IN_MAX_DEVS + 2];
989 static int stick_sel[2];
991 static menu_entry e_menu_keyconfig_analog[] =
993 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
994 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
995 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
996 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
997 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
998 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
1002 static int key_config_analog(int id, int keys)
1004 int i, d, count, sel = 0;
1005 int sel2dev_map[IN_MAX_DEVS];
1007 memset(adevnames, 0, sizeof(adevnames));
1008 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1009 memset(stick_sel, 0, sizeof(stick_sel));
1011 adevnames[0] = "None";
1013 for (d = 0; d < IN_MAX_DEVS; d++)
1015 const char *name = in_get_dev_name(d, 0, 1);
1020 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1024 if (in_adev[0] == d) stick_sel[0] = i;
1025 if (in_adev[1] == d) stick_sel[1] = i;
1027 adevnames[i++] = name;
1029 adevnames[i] = NULL;
1031 me_loop(e_menu_keyconfig_analog, &sel);
1033 in_adev[0] = sel2dev_map[stick_sel[0]];
1034 in_adev[1] = sel2dev_map[stick_sel[1]];
1039 static const char *mgn_dev_name(int id, int *offs)
1041 const char *name = NULL;
1044 if (id == MA_CTRL_DEV_FIRST)
1047 for (; it < IN_MAX_DEVS; it++) {
1048 name = in_get_dev_name(it, 1, 1);
1057 static const char *mgn_saveloadcfg(int id, int *offs)
1062 static int mh_savecfg(int id, int keys)
1064 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1065 me_update_msg("config saved");
1067 me_update_msg("failed to write config");
1072 static int mh_input_rescan(int id, int keys)
1074 //menu_sync_config();
1076 me_update_msg("rescan complete.");
1081 static const char *men_in_type_sel[] = {
1082 "Standard (SCPH-1080)",
1083 "Analog (SCPH-1150)",
1087 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1088 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1089 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1091 static menu_entry e_menu_keyconfig[] =
1093 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1094 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1095 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1096 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1098 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1099 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1100 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1101 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1102 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1103 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1104 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1105 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1106 mee_handler ("Rescan devices:", mh_input_rescan),
1108 mee_label_mk (MA_CTRL_DEV_FIRST, 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),
1111 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1112 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1113 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1114 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1118 static int menu_loop_keyconfig(int id, int keys)
1122 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1123 me_loop(e_menu_keyconfig, &sel);
1127 // ------------ gfx options menu ------------
1129 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1130 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1131 "using d-pad or move it using R+d-pad";
1132 static const char *men_dummy[] = { NULL };
1134 static int menu_loop_cscaler(int id, int keys)
1138 scaling = SCALE_CUSTOM;
1140 omap_enable_layer(1);
1145 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1146 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1147 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1150 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1151 if (inp & PBTN_UP) g_layer_y--;
1152 if (inp & PBTN_DOWN) g_layer_y++;
1153 if (inp & PBTN_LEFT) g_layer_x--;
1154 if (inp & PBTN_RIGHT) g_layer_x++;
1155 if (!(inp & PBTN_R)) {
1156 if (inp & PBTN_UP) g_layer_h += 2;
1157 if (inp & PBTN_DOWN) g_layer_h -= 2;
1158 if (inp & PBTN_LEFT) g_layer_w += 2;
1159 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1161 if (inp & (PBTN_MOK|PBTN_MBACK))
1164 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1165 if (g_layer_x < 0) g_layer_x = 0;
1166 if (g_layer_x > 640) g_layer_x = 640;
1167 if (g_layer_y < 0) g_layer_y = 0;
1168 if (g_layer_y > 420) g_layer_y = 420;
1169 if (g_layer_w < 160) g_layer_w = 160;
1170 if (g_layer_h < 60) g_layer_h = 60;
1171 if (g_layer_x + g_layer_w > 800)
1172 g_layer_w = 800 - g_layer_x;
1173 if (g_layer_y + g_layer_h > 480)
1174 g_layer_h = 480 - g_layer_y;
1175 omap_enable_layer(1);
1179 omap_enable_layer(0);
1184 static menu_entry e_menu_gfx_options[] =
1186 mee_enum ("Scaler", MA_OPT_SCALER, scaling, men_scaler),
1187 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1188 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1189 // mee_onoff ("Vsync", 0, vsync, 1),
1190 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1194 static int menu_loop_gfx_options(int id, int keys)
1198 me_loop(e_menu_gfx_options, &sel);
1203 // ------------ bios/plugins ------------
1207 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1208 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1210 static menu_entry e_menu_plugin_gpu_neon[] =
1212 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1216 static int menu_loop_plugin_gpu_neon(int id, int keys)
1219 me_loop(e_menu_plugin_gpu_neon, &sel);
1225 static menu_entry e_menu_plugin_gpu_unai[] =
1227 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1228 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1229 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1230 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1234 static int menu_loop_plugin_gpu_unai(int id, int keys)
1237 me_loop(e_menu_plugin_gpu_unai, &sel);
1241 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1242 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1243 static const char h_gpu_1[] = "Capcom fighting games";
1244 static const char h_gpu_2[] = "Black screens in Lunar";
1245 static const char h_gpu_3[] = "Compatibility mode";
1246 static const char h_gpu_6[] = "Pandemonium 2";
1247 //static const char h_gpu_7[] = "Skip every second frame";
1248 static const char h_gpu_8[] = "Needed by Dark Forces";
1249 static const char h_gpu_9[] = "better g-colors, worse textures";
1250 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1252 static menu_entry e_menu_plugin_gpu_peops[] =
1254 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1255 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1256 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1257 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1258 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1259 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1260 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1261 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1262 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1263 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1267 static int menu_loop_plugin_gpu_peops(int id, int keys)
1270 me_loop(e_menu_plugin_gpu_peops, &sel);
1274 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1275 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1276 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1278 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1280 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1281 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1282 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1283 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1284 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1285 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1286 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1287 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1288 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1289 mee_label ("Fixes/hacks:"),
1290 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1291 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1292 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1293 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1294 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1295 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1296 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1297 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1298 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1299 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1300 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1304 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1307 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1311 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1312 static const char h_spu_volboost[] = "Large values cause distortion";
1313 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1314 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1316 static menu_entry e_menu_plugin_spu[] =
1318 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1319 mee_onoff ("Reverb", 0, iUseReverb, 2),
1320 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1321 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1322 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1323 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1327 static int menu_loop_plugin_spu(int id, int keys)
1330 me_loop(e_menu_plugin_spu, &sel);
1334 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1335 "savestates and can't be changed there. Must save\n"
1336 "config and reload the game for change to take effect";
1337 static const char h_plugin_gpu[] =
1339 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1344 "is Pete's soft GPU, slow but accurate\n"
1345 "gpuPCSX4ALL is GPU from PCSX4ALL, fast but glitchy\n"
1346 "gpuGLES Pete's hw GPU, uses 3D chip but is glitchy\n"
1347 "must save config and reload the game if changed";
1348 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1349 "must save config and reload the game if changed";
1350 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1351 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1352 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1353 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1355 static menu_entry e_menu_plugin_options[] =
1357 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1358 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1359 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1361 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1363 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1364 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1365 mee_handler_h ("Configure GLES GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1366 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1370 static menu_entry e_menu_main2[];
1372 static int menu_loop_plugin_options(int id, int keys)
1375 me_loop(e_menu_plugin_options, &sel);
1377 // sync BIOS/plugins
1378 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1379 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1380 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1381 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1386 // ------------ adv options menu ------------
1388 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1389 "(lower value - less work for the emu, may be faster)";
1390 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1391 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1392 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1394 static menu_entry e_menu_speed_hacks[] =
1396 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1397 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1398 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1399 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1403 static int menu_loop_speed_hacks(int id, int keys)
1406 me_loop(e_menu_speed_hacks, &sel);
1410 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1411 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1412 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1413 "(green: normal, red: fmod, blue: noise)";
1414 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1415 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1416 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1417 "(proper .cue/.bin dump is needed otherwise)";
1418 static const char h_cfg_sio[] = "You should not need this, breaks games";
1419 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1420 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1421 "(timing hack, breaks other games)";
1422 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1423 "(timing hack, breaks other games)";
1424 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1425 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1426 "Might be useful to overcome some dynarec bugs";
1427 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1428 "must reload game for any change to take effect";
1430 static menu_entry e_menu_adv_options[] =
1432 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1433 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1434 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1435 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1436 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1437 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1438 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1439 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1440 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1441 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1442 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1443 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1447 static int menu_loop_adv_options(int id, int keys)
1450 me_loop(e_menu_adv_options, &sel);
1454 // ------------ options menu ------------
1456 static int mh_restore_defaults(int id, int keys)
1458 menu_set_defconfig();
1459 me_update_msg("defaults restored");
1463 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1464 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1466 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1467 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1468 "loading state or both";
1470 static const char h_restore_def[] = "Switches back to default / recommended\n"
1472 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1474 static menu_entry e_menu_options[] =
1476 // mee_range ("Save slot", 0, state_slot, 0, 9),
1477 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1478 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1479 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1480 mee_enum ("Region", 0, region, men_region),
1481 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1482 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1483 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1484 mee_handler ("[Advanced]", menu_loop_adv_options),
1485 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1486 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1487 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1491 static int menu_loop_options(int id, int keys)
1496 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1497 e_menu_options[i].enabled = cpu_clock_st != 0 ? 1 : 0;
1498 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1500 me_loop(e_menu_options, &sel);
1505 // ------------ debug menu ------------
1507 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1509 int w = min(g_menuscreen_w, 1024);
1510 int h = min(g_menuscreen_h, 512);
1511 u16 *d = g_menuscreen_ptr;
1512 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1516 gpuf->ulFreezeVersion = 1;
1517 if (GPU_freeze != NULL)
1518 GPU_freeze(1, gpuf);
1520 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1521 bgr555_to_rgb565(d, s, w * 2);
1523 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1524 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1525 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1526 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1527 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1530 static void debug_menu_loop(void)
1532 int inp, df_x = 0, df_y = 0;
1535 gpuf = malloc(sizeof(*gpuf));
1542 draw_frame_debug(gpuf, df_x, df_y);
1545 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1546 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 10);
1547 if (inp & PBTN_MBACK) break;
1548 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1549 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1550 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x--; }
1551 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x++; }
1557 // --------- memcard manager ---------
1559 static void draw_mc_icon(int dx, int dy, const u16 *s)
1564 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1566 for (y = 0; y < 16; y++, s += 16) {
1567 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1568 for (x = 0; x < 16; x++) {
1570 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1571 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1577 static void draw_mc_bg(void)
1579 McdBlock *blocks1, *blocks2;
1583 blocks1 = malloc(15 * sizeof(blocks1[0]));
1584 blocks2 = malloc(15 * sizeof(blocks1[0]));
1585 if (blocks1 == NULL || blocks2 == NULL)
1588 for (i = 0; i < 15; i++) {
1589 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1590 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1595 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1597 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1601 maxicons = g_menuscreen_h / 32;
1604 row2 = g_menuscreen_w / 2;
1605 for (i = 0; i < maxicons; i++) {
1606 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1607 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1609 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1610 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1613 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1621 static void handle_memcard_sel(void)
1624 if (memcard1_sel != 0)
1625 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1627 if (memcard2_sel != 0)
1628 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1629 LoadMcds(Config.Mcd1, Config.Mcd2);
1633 static menu_entry e_memcard_options[] =
1635 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1636 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1640 static int menu_loop_memcards(int id, int keys)
1646 memcard1_sel = memcard2_sel = 0;
1647 p = strrchr(Config.Mcd1, '/');
1649 for (i = 0; memcards[i] != NULL; i++)
1650 if (strcmp(p + 1, memcards[i]) == 0)
1651 { memcard1_sel = i; break; }
1652 p = strrchr(Config.Mcd2, '/');
1654 for (i = 0; memcards[i] != NULL; i++)
1655 if (strcmp(p + 1, memcards[i]) == 0)
1656 { memcard2_sel = i; break; }
1658 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1660 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1665 // --------- main menu help ----------
1667 static void menu_bios_warn(void)
1670 static const char msg[] =
1671 "You don't seem to have copied any BIOS\n"
1673 #ifdef __ARM_ARCH_7A__ // XXX
1674 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1676 "pcsx_rearmed/bios/\n\n"
1678 "While many games work fine with fake\n"
1679 "(HLE) BIOS, others (like MGS and FF8)\n"
1680 "require BIOS to work.\n"
1681 "After copying the file, you'll also need\n"
1682 "to select it in the emu's menu:\n"
1683 "options->[BIOS/Plugins]\n\n"
1684 "The file is usually named SCPH1001.BIN,\n"
1685 "but other not compressed files can be\n"
1687 "Press (B) or (X) to continue";
1691 draw_menu_message(msg, NULL);
1693 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1694 if (inp & (PBTN_MBACK|PBTN_MOK))
1699 // ------------ main menu ------------
1703 static void draw_frame_main(void)
1710 if (CdromId[0] != 0) {
1711 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1712 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1713 Config.HLE ? "HLE" : "BIOS");
1714 smalltext_out16(4, 1, buff, 0x105f);
1719 tmp = localtime(<ime);
1720 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1721 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1722 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1726 static void draw_frame_credits(void)
1728 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1731 static const char credits_text[] =
1733 "(C) 1999-2003 PCSX Team\n"
1734 "(C) 2005-2009 PCSX-df Team\n"
1735 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1736 "ARM recompiler (C) 2009-2011 Ari64\n"
1738 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1740 "PEOpS GPU and SPU by Pete Bernert\n"
1741 " and the P.E.Op.S. team\n"
1742 "PCSX4ALL plugin by PCSX4ALL team\n"
1743 " Chui, Franxis, Unai\n\n"
1744 "integration, optimization and\n"
1745 " frontend (C) 2010-2012 notaz\n";
1747 static int reset_game(void)
1750 if (bios_sel == 0 && !Config.HLE)
1756 if (CheckCdrom() != -1) {
1762 static int reload_plugins(const char *cdimg)
1768 set_cd_image(cdimg);
1770 pcnt_hook_plugins();
1772 if (OpenPlugins() == -1) {
1773 me_update_msg("failed to open plugins");
1776 plugin_call_rearmed_cbs();
1778 cdrIsoMultidiskCount = 1;
1780 CdromLabel[0] = '\0';
1785 static int run_bios(void)
1791 if (reload_plugins(NULL) != 0)
1799 static int run_exe(void)
1803 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1808 if (reload_plugins(NULL) != 0)
1812 if (Load(fname) != 0) {
1813 me_update_msg("exe load failed, bad file?");
1822 static int run_cd_image(const char *fname)
1825 reload_plugins(fname);
1827 // always autodetect, menu_sync_config will override as needed
1830 if (CheckCdrom() == -1) {
1831 // Only check the CD if we are starting the console with a CD
1833 me_update_msg("unsupported/invalid CD image");
1839 // Read main executable directly from CDRom and start it
1840 if (LoadCdrom() == -1) {
1842 me_update_msg("failed to load CD image");
1847 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1852 static int romsel_run(void)
1854 int prev_gpu, prev_spu;
1857 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1861 printf("selected file: %s\n", fname);
1863 new_dynarec_clear_full();
1865 if (run_cd_image(fname) != 0)
1868 prev_gpu = gpu_plugsel;
1869 prev_spu = spu_plugsel;
1870 if (menu_load_config(1) != 0)
1871 menu_load_config(0);
1873 // check for plugin changes, have to repeat
1874 // loading if game config changed plugins to reload them
1875 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1876 printf("plugin change detected, reloading plugins..\n");
1877 if (run_cd_image(fname) != 0)
1882 printf("note: running without BIOS, expect compatibility problems\n");
1884 strcpy(last_selected_fname, rom_fname_reload);
1888 static int swap_cd_image(void)
1892 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1896 printf("selected file: %s\n", fname);
1899 CdromLabel[0] = '\0';
1901 set_cd_image(fname);
1902 if (ReloadCdromPlugin() < 0) {
1903 me_update_msg("failed to load cdr plugin");
1906 if (CDR_open() < 0) {
1907 me_update_msg("failed to open cdr plugin");
1911 SetCdOpenCaseTime(time(NULL) + 2);
1914 strcpy(last_selected_fname, rom_fname_reload);
1918 static int swap_cd_multidisk(void)
1920 cdrIsoMultidiskSelect++;
1922 CdromLabel[0] = '\0';
1925 if (CDR_open() < 0) {
1926 me_update_msg("failed to open cdr plugin");
1930 SetCdOpenCaseTime(time(NULL) + 2);
1936 static int main_menu_handler(int id, int keys)
1940 case MA_MAIN_RESUME_GAME:
1944 case MA_MAIN_SAVE_STATE:
1946 return menu_loop_savestate(0);
1948 case MA_MAIN_LOAD_STATE:
1950 return menu_loop_savestate(1);
1952 case MA_MAIN_RESET_GAME:
1953 if (ready_to_go && reset_game() == 0)
1956 case MA_MAIN_LOAD_ROM:
1957 if (romsel_run() == 0)
1960 case MA_MAIN_SWAP_CD:
1961 if (swap_cd_image() == 0)
1964 case MA_MAIN_SWAP_CD_MULTI:
1965 if (swap_cd_multidisk() == 0)
1968 case MA_MAIN_RUN_BIOS:
1969 if (run_bios() == 0)
1972 case MA_MAIN_RUN_EXE:
1976 case MA_MAIN_CREDITS:
1977 draw_menu_message(credits_text, draw_frame_credits);
1978 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1984 lprintf("%s: something unknown selected\n", __FUNCTION__);
1991 static menu_entry e_menu_main2[] =
1993 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1994 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1995 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1996 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1997 mee_handler ("Memcard manager", menu_loop_memcards),
2001 static int main_menu2_handler(int id, int keys)
2005 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2006 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2007 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2009 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2012 static const char h_extra[] = "Change CD, manage memcards..\n";
2014 static menu_entry e_menu_main[] =
2018 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2019 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2020 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2021 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2022 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2023 mee_handler ("Options", menu_loop_options),
2024 mee_handler ("Controls", menu_loop_keyconfig),
2025 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2026 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2027 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2031 // ----------------------------
2033 static void menu_leave_emu(void);
2035 void menu_loop(void)
2041 if (bioses[1] == NULL && !warned_about_bios) {
2043 warned_about_bios = 1;
2046 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2047 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2048 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2049 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2051 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2054 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2055 } while (!ready_to_go);
2057 /* wait until menu, ok, back is released */
2058 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2061 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2066 static int qsort_strcmp(const void *p1, const void *p2)
2068 char * const *s1 = (char * const *)p1;
2069 char * const *s2 = (char * const *)p2;
2070 return strcasecmp(*s1, *s2);
2073 static void scan_bios_plugins(void)
2075 char fname[MAXPATHLEN];
2077 int bios_i, gpu_i, spu_i, mc_i;
2082 gpu_plugins[0] = "builtin_gpu";
2083 spu_plugins[0] = "builtin_spu";
2084 memcards[0] = "(none)";
2085 bios_i = gpu_i = spu_i = mc_i = 1;
2087 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2088 dir = opendir(fname);
2090 perror("scan_bios_plugins bios opendir");
2105 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2108 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2109 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2110 printf("bad BIOS file: %s\n", ent->d_name);
2114 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2115 bioses[bios_i++] = strdup(ent->d_name);
2119 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2125 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2126 dir = opendir(fname);
2128 perror("scan_bios_plugins plugins opendir");
2142 p = strstr(ent->d_name, ".so");
2146 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2147 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2149 fprintf(stderr, "%s\n", dlerror());
2153 // now what do we have here?
2154 tmp = dlsym(h, "GPUinit");
2157 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2158 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2162 tmp = dlsym(h, "SPUinit");
2165 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2166 spu_plugins[spu_i++] = strdup(ent->d_name);
2170 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2177 dir = opendir("." MEMCARD_DIR);
2179 perror("scan_bios_plugins memcards opendir");
2194 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2197 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2198 if (stat(fname, &st) != 0) {
2199 printf("bad memcard file: %s\n", ent->d_name);
2203 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2204 memcards[mc_i++] = strdup(ent->d_name);
2208 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2212 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2217 void menu_init(void)
2219 char buff[MAXPATHLEN];
2221 strcpy(last_selected_fname, "/media");
2223 scan_bios_plugins();
2227 menu_set_defconfig();
2228 menu_load_config(0);
2233 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2234 if (g_menubg_src_ptr == NULL)
2236 emu_make_path(buff, "skin/background.png", sizeof(buff));
2237 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2239 #ifndef __ARM_ARCH_7A__ /* XXX */
2240 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2241 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2242 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2243 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2245 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2246 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2247 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2251 void menu_notify_mode_change(int w, int h, int bpp)
2262 g_layer_w = w; g_layer_h = h;
2266 if (h > g_menuscreen_h || (240 < h && h <= 360))
2267 goto fractional_4_3;
2269 // 4:3 that prefers integer scaling
2270 imult = g_menuscreen_h / h;
2271 g_layer_w = w * imult;
2272 g_layer_h = h * imult;
2273 mult = (float)g_layer_w / (float)g_layer_h;
2274 if (mult < 1.25f || mult > 1.666f)
2275 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2276 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2281 mult = 240.0f / (float)h * 4.0f / 3.0f;
2284 g_layer_w = mult * (float)g_menuscreen_h;
2285 g_layer_h = g_menuscreen_h;
2286 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2289 case SCALE_FULLSCREEN:
2290 g_layer_w = g_menuscreen_w;
2291 g_layer_h = g_menuscreen_h;
2298 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2299 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2300 if (g_layer_x < 0) g_layer_x = 0;
2301 if (g_layer_y < 0) g_layer_y = 0;
2302 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2303 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2306 static void menu_leave_emu(void)
2308 if (GPU_close != NULL) {
2309 int ret = GPU_close();
2311 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2314 plat_video_menu_enter(ready_to_go);
2316 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2317 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2318 int x = max(0, g_menuscreen_w - last_psx_w);
2319 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2320 int w = min(g_menuscreen_w, last_psx_w);
2321 int h = min(g_menuscreen_h, last_psx_h);
2322 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2323 u16 *s = pl_vout_buf;
2325 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2326 menu_darken_bg(d, s, w, 0);
2330 cpu_clock = plat_cpu_clock_get();
2333 void menu_prepare_emu(void)
2335 R3000Acpu *prev_cpu = psxCpu;
2337 plat_video_menu_leave();
2339 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2341 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2342 if (psxCpu != prev_cpu)
2343 // note that this does not really reset, just clears drc caches
2346 // core doesn't care about Config.Cdda changes,
2347 // so handle them manually here
2352 apply_lcdrate(Config.PsxType);
2353 apply_filter(filter);
2354 plat_cpu_clock_apply(cpu_clock);
2356 // push config to GPU plugin
2357 plugin_call_rearmed_cbs();
2359 if (GPU_open != NULL) {
2360 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2362 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2368 void me_update_msg(const char *msg)
2370 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2371 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2373 menu_error_time = plat_get_ticks_ms();
2374 lprintf("msg: %s\n", menu_error_msg);