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"
27 #include "common/plat.h"
28 #include "common/input.h"
29 #include "linux/in_evdev.h"
30 #include "../libpcsxcore/misc.h"
31 #include "../libpcsxcore/cdrom.h"
32 #include "../libpcsxcore/cdriso.h"
33 #include "../libpcsxcore/psemu_plugin_defs.h"
34 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
35 #include "../plugins/dfinput/main.h"
36 #include "../plugins/gpulib/cspace.h"
39 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
41 #define array_size(x) (sizeof(x) / sizeof(x[0]))
52 MA_MAIN_SWAP_CD_MULTI,
86 static int last_psx_w, last_psx_h, last_psx_bpp;
87 static int scaling, cpu_clock, cpu_clock_st, volume_boost, frameskip;
88 static char rom_fname_reload[MAXPATHLEN];
89 static char last_selected_fname[MAXPATHLEN];
90 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
92 static int memcard1_sel, memcard2_sel;
94 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;
111 static const char *bioses[24];
112 static const char *gpu_plugins[16];
113 static const char *spu_plugins[16];
114 static const char *memcards[32];
115 static int bios_sel, gpu_plugsel, spu_plugsel;
118 static int min(int x, int y) { return x < y ? x : y; }
119 static int max(int x, int y) { return x > y ? x : y; }
121 void emu_make_path(char *buff, const char *end, int size)
125 end_len = strlen(end);
126 pos = plat_get_root_dir(buff, size);
127 strncpy(buff + pos, end, size - pos);
129 if (pos + end_len > size - 1)
130 printf("Warning: path truncated: %s\n", buff);
133 static int emu_check_save_file(int slot, int *time)
135 char fname[MAXPATHLEN];
139 ret = emu_check_state(slot);
140 if (ret != 0 || time == NULL)
141 return ret == 0 ? 1 : 0;
143 ret = get_state_filename(fname, sizeof(fname), slot);
147 ret = stat(fname, &status);
151 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
152 return 1; // probably bad rtc like on some Caanoos
154 *time = status.st_mtime;
159 static int emu_save_load_game(int load, int unused)
164 ret = emu_load_state(state_slot);
166 // reflect hle/bios mode from savestate
169 else if (bios_sel == 0 && bioses[1] != NULL)
170 // XXX: maybe find the right bios instead
174 ret = emu_save_state(state_slot);
179 // propagate menu settings to the emu vars
180 static void menu_sync_config(void)
182 static int allow_abs_only_old;
187 Config.PsxType = region - 1;
189 cycle_multiplier = 10000 / psx_clock;
191 switch (in_type_sel1) {
192 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
193 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
194 default: in_type1 = PSE_PAD_TYPE_STANDARD;
196 switch (in_type_sel2) {
197 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
198 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
199 default: in_type2 = PSE_PAD_TYPE_STANDARD;
201 if (in_evdev_allow_abs_only != allow_abs_only_old) {
203 allow_abs_only_old = in_evdev_allow_abs_only;
206 iVolume = 768 + 128 * volume_boost;
207 pl_rearmed_cbs.frameskip = frameskip - 1;
208 pl_timing_prepare(Config.PsxType);
211 static void menu_set_defconfig(void)
213 emu_set_default_config();
219 analog_deadzone = 50;
221 psx_clock = DEFAULT_PSX_CLOCK;
224 in_type_sel1 = in_type_sel2 = 0;
225 in_evdev_allow_abs_only = 0;
230 #define CE_CONFIG_STR(val) \
231 { #val, 0, Config.val }
233 #define CE_CONFIG_VAL(val) \
234 { #val, sizeof(Config.val), &Config.val }
236 #define CE_STR(val) \
239 #define CE_INTVAL(val) \
240 { #val, sizeof(val), &val }
242 #define CE_INTVAL_P(val) \
243 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
245 // 'versioned' var, used when defaults change
246 #define CE_CONFIG_STR_V(val, ver) \
247 { #val #ver, 0, Config.val }
249 #define CE_INTVAL_V(val, ver) \
250 { #val #ver, sizeof(val), &val }
252 #define CE_INTVAL_PV(val, ver) \
253 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
255 static const struct {
261 CE_CONFIG_STR_V(Gpu, 2),
263 // CE_CONFIG_STR(Cdr),
268 CE_CONFIG_VAL(Debug),
269 CE_CONFIG_VAL(PsxOut),
270 CE_CONFIG_VAL(SpuIrq),
271 CE_CONFIG_VAL(RCntFix),
272 CE_CONFIG_VAL(VSyncWA),
274 CE_CONFIG_VAL(CdrReschedule),
276 CE_INTVAL_V(scaling, 2),
277 CE_INTVAL(g_layer_x),
278 CE_INTVAL(g_layer_y),
279 CE_INTVAL(g_layer_w),
280 CE_INTVAL(g_layer_h),
282 CE_INTVAL(state_slot),
283 CE_INTVAL(cpu_clock),
285 CE_INTVAL(in_type_sel1),
286 CE_INTVAL(in_type_sel2),
287 CE_INTVAL(analog_deadzone),
288 CE_INTVAL_V(frameskip, 3),
289 CE_INTVAL_P(gpu_peops.iUseDither),
290 CE_INTVAL_P(gpu_peops.dwActFixes),
291 CE_INTVAL_P(gpu_unai.lineskip),
292 CE_INTVAL_P(gpu_unai.abe_hack),
293 CE_INTVAL_P(gpu_unai.no_light),
294 CE_INTVAL_P(gpu_unai.no_blend),
295 CE_INTVAL_P(gpu_neon.allow_interlace),
296 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
297 CE_INTVAL_P(gpu_peopsgl.iFilterType),
298 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
299 CE_INTVAL_P(gpu_peopsgl.iUseMask),
300 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
301 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
302 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
303 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
304 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
305 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
306 CE_INTVAL_V(iUseReverb, 3),
307 CE_INTVAL_V(iXAPitch, 3),
308 CE_INTVAL_V(iUseInterpolation, 3),
309 CE_INTVAL(warned_about_bios),
310 CE_INTVAL(in_evdev_allow_abs_only),
311 CE_INTVAL(volume_boost),
312 CE_INTVAL(psx_clock),
313 CE_INTVAL(new_dynarec_hacks),
314 CE_INTVAL(in_enable_vibration),
317 static char *get_cd_label(void)
319 static char trimlabel[33];
322 strncpy(trimlabel, CdromLabel, 32);
324 for (j = 31; j >= 0; j--)
325 if (trimlabel[j] == ' ')
331 static void make_cfg_fname(char *buf, size_t size, int is_game)
334 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
336 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
339 static void keys_write_all(FILE *f);
341 static int menu_write_config(int is_game)
343 char cfgfile[MAXPATHLEN];
347 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
348 f = fopen(cfgfile, "w");
350 printf("menu_write_config: failed to open: %s\n", cfgfile);
354 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
355 fprintf(f, "%s = ", config_data[i].name);
356 switch (config_data[i].len) {
358 fprintf(f, "%s\n", (char *)config_data[i].val);
361 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
364 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
367 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
370 printf("menu_write_config: unhandled len %d for %s\n",
371 config_data[i].len, config_data[i].name);
377 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
385 static void parse_str_val(char *cval, const char *src)
388 strncpy(cval, src, MAXPATHLEN);
389 cval[MAXPATHLEN - 1] = 0;
390 tmp = strchr(cval, '\n');
392 tmp = strchr(cval, '\r');
397 static void keys_load_all(const char *cfg);
399 static int menu_load_config(int is_game)
401 char cfgfile[MAXPATHLEN];
407 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
408 f = fopen(cfgfile, "r");
410 printf("menu_load_config: failed to open: %s\n", cfgfile);
414 fseek(f, 0, SEEK_END);
417 printf("bad size %ld: %s\n", size, cfgfile);
421 cfg = malloc(size + 1);
425 fseek(f, 0, SEEK_SET);
426 if (fread(cfg, 1, size, f) != size) {
427 printf("failed to read: %s\n", cfgfile);
432 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
436 tmp = strstr(cfg, config_data[i].name);
439 tmp += strlen(config_data[i].name);
440 if (strncmp(tmp, " = ", 3) != 0)
444 if (config_data[i].len == 0) {
445 parse_str_val(config_data[i].val, tmp);
450 val = strtoul(tmp, &tmp2, 16);
451 if (tmp2 == NULL || tmp == tmp2)
452 continue; // parse failed
454 switch (config_data[i].len) {
456 *(u8 *)config_data[i].val = val;
459 *(u16 *)config_data[i].val = val;
462 *(u32 *)config_data[i].val = val;
465 printf("menu_load_config: unhandled len %d for %s\n",
466 config_data[i].len, config_data[i].name);
472 char *tmp = strstr(cfg, "lastcdimg = ");
475 parse_str_val(last_selected_fname, tmp);
489 // caanoo old config compat hack
490 if (strcmp(Config.Gpu, "gpuPCSX4ALL.so") == 0)
491 strcpy(Config.Gpu, "gpu_unai.so");
494 for (i = bios_sel = 0; bioses[i] != NULL; i++)
495 if (strcmp(Config.Bios, bioses[i]) == 0)
496 { bios_sel = i; break; }
498 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
499 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
500 { gpu_plugsel = i; break; }
502 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
503 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
504 { spu_plugsel = i; break; }
509 // rrrr rggg gggb bbbb
510 static unsigned short fname2color(const char *fname)
512 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
513 ".bz", ".znx", ".pbp", ".cbn" };
514 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
515 ".table", ".index", ".sbi" };
516 const char *ext = strrchr(fname, '.');
521 for (i = 0; i < array_size(cdimg_exts); i++)
522 if (strcasecmp(ext, cdimg_exts[i]) == 0)
524 for (i = 0; i < array_size(other_exts); i++)
525 if (strcasecmp(ext, other_exts[i]) == 0)
530 static void draw_savestate_bg(int slot);
532 static const char *filter_exts[] = {
533 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
536 #define MENU_ALIGN_LEFT
537 #ifdef __ARM_ARCH_7A__ // assume hires device
543 #define menu_init menu_init_common
544 #include "common/menu.c"
547 // a bit of black magic here
548 static void draw_savestate_bg(int slot)
550 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
552 char fname[MAXPATHLEN];
559 ret = get_state_filename(fname, sizeof(fname), slot);
563 f = gzopen(fname, "rb");
567 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
568 fprintf(stderr, "gzseek failed\n");
573 gpu = malloc(sizeof(*gpu));
579 ret = gzread(f, gpu, sizeof(*gpu));
581 if (ret != sizeof(*gpu)) {
582 fprintf(stderr, "gzread failed\n");
586 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
588 if (gpu->ulStatus & 0x800000)
589 goto out; // disabled
591 x = gpu->ulControl[5] & 0x3ff;
592 y = (gpu->ulControl[5] >> 10) & 0x1ff;
593 s = (u16 *)gpu->psxVRam + y * 1024 + x;
594 w = psx_widths[(gpu->ulStatus >> 16) & 7];
595 tmp = gpu->ulControl[7];
596 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
597 if (gpu->ulStatus & 0x80000) // doubleheight
600 x = max(0, g_menuscreen_w - w) & ~3;
601 y = max(0, g_menuscreen_h / 2 - h / 2);
602 w = min(g_menuscreen_w, w);
603 h = min(g_menuscreen_h, h);
604 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
606 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
607 if (gpu->ulStatus & 0x200000)
608 bgr888_to_rgb565(d, s, w * 3);
610 bgr555_to_rgb565(d, s, w * 2);
612 // darken this so that menu text is visible
613 if (g_menuscreen_w - w < 320)
614 menu_darken_bg(d, d, w * 2, 0);
621 // -------------- key config --------------
623 me_bind_action me_ctrl_actions[] =
625 { "UP ", 1 << DKEY_UP},
626 { "DOWN ", 1 << DKEY_DOWN },
627 { "LEFT ", 1 << DKEY_LEFT },
628 { "RIGHT ", 1 << DKEY_RIGHT },
629 { "TRIANGLE", 1 << DKEY_TRIANGLE },
630 { "CIRCLE ", 1 << DKEY_CIRCLE },
631 { "CROSS ", 1 << DKEY_CROSS },
632 { "SQUARE ", 1 << DKEY_SQUARE },
633 { "L1 ", 1 << DKEY_L1 },
634 { "R1 ", 1 << DKEY_R1 },
635 { "L2 ", 1 << DKEY_L2 },
636 { "R2 ", 1 << DKEY_R2 },
637 { "L3 ", 1 << DKEY_L3 },
638 { "R3 ", 1 << DKEY_R3 },
639 { "START ", 1 << DKEY_START },
640 { "SELECT ", 1 << DKEY_SELECT },
644 me_bind_action emuctrl_actions[] =
646 { "Save State ", 1 << SACTION_SAVE_STATE },
647 { "Load State ", 1 << SACTION_LOAD_STATE },
648 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
649 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
650 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
651 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
652 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
653 #ifdef __ARM_ARCH_7A__ /* XXX */
654 { "Minimize ", 1 << SACTION_MINIMIZE },
656 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
657 { "Gun A button ", 1 << SACTION_GUN_A },
658 { "Gun B button ", 1 << SACTION_GUN_B },
659 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
660 #ifndef __ARM_ARCH_7A__ /* XXX */
661 { "Volume Up ", 1 << SACTION_VOLUME_UP },
662 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
667 static char *mystrip(char *str)
672 for (i = 0; i < len; i++)
673 if (str[i] != ' ') break;
674 if (i > 0) memmove(str, str + i, len - i + 1);
677 for (i = len - 1; i >= 0; i--)
678 if (str[i] != ' ') break;
684 static void get_line(char *d, size_t size, const char *s)
689 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
700 static void keys_write_all(FILE *f)
704 for (d = 0; d < IN_MAX_DEVS; d++)
706 const int *binds = in_get_dev_binds(d);
707 const char *name = in_get_dev_name(d, 0, 0);
710 if (binds == NULL || name == NULL)
713 fprintf(f, "binddev = %s\n", name);
714 in_get_config(d, IN_CFG_BIND_COUNT, &count);
716 for (k = 0; k < count; k++)
721 act[0] = act[31] = 0;
722 name = in_get_key_name(d, k);
724 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
725 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
726 mask = me_ctrl_actions[i].mask;
728 strncpy(act, me_ctrl_actions[i].name, 31);
729 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
732 mask = me_ctrl_actions[i].mask << 16;
734 strncpy(act, me_ctrl_actions[i].name, 31);
735 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
740 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
741 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
742 mask = emuctrl_actions[i].mask;
744 strncpy(act, emuctrl_actions[i].name, 31);
745 fprintf(f, "bind %s = %s\n", name, mystrip(act));
751 for (k = 0; k < array_size(in_adev); k++)
754 fprintf(f, "bind_analog = %d\n", k);
759 static int parse_bind_val(const char *val, int *type)
763 *type = IN_BINDTYPE_NONE;
767 if (strncasecmp(val, "player", 6) == 0)
769 int player, shift = 0;
770 player = atoi(val + 6) - 1;
772 if ((unsigned int)player > 1)
777 *type = IN_BINDTYPE_PLAYER12;
778 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
779 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
780 return me_ctrl_actions[i].mask << shift;
783 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
784 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
785 *type = IN_BINDTYPE_EMU;
786 return emuctrl_actions[i].mask;
793 static void keys_load_all(const char *cfg)
795 char dev[256], key[128], *act;
801 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
804 get_line(dev, sizeof(dev), p);
805 dev_id = in_config_parse_dev(dev);
807 printf("input: can't handle dev: %s\n", dev);
811 in_unbind_all(dev_id, -1, -1);
812 while ((p = strstr(p, "bind"))) {
813 if (strncmp(p, "binddev = ", 10) == 0)
816 if (strncmp(p, "bind_analog", 11) == 0) {
817 ret = sscanf(p, "bind_analog = %d", &bind);
820 printf("input: parse error: %16s..\n", p);
823 if ((unsigned int)bind >= array_size(in_adev)) {
824 printf("input: analog id %d out of range\n", bind);
827 in_adev[bind] = dev_id;
833 printf("input: parse error: %16s..\n", p);
837 get_line(key, sizeof(key), p);
838 act = strchr(key, '=');
840 printf("parse failed: %16s..\n", p);
848 bind = parse_bind_val(act, &bindtype);
849 if (bind != -1 && bind != 0) {
850 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
851 in_config_bind_key(dev_id, key, bind, bindtype);
854 lprintf("config: unhandled action \"%s\"\n", act);
860 static int key_config_loop_wrap(int id, int keys)
863 case MA_CTRL_PLAYER1:
864 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
866 case MA_CTRL_PLAYER2:
867 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
870 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
878 static const char *adevnames[IN_MAX_DEVS + 2];
879 static int stick_sel[2];
881 static menu_entry e_menu_keyconfig_analog[] =
883 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
884 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
885 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
886 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
887 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
888 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
892 static int key_config_analog(int id, int keys)
894 int i, d, count, sel = 0;
895 int sel2dev_map[IN_MAX_DEVS];
897 memset(adevnames, 0, sizeof(adevnames));
898 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
899 memset(stick_sel, 0, sizeof(stick_sel));
901 adevnames[0] = "None";
903 for (d = 0; d < IN_MAX_DEVS; d++)
905 const char *name = in_get_dev_name(d, 0, 1);
910 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
914 if (in_adev[0] == d) stick_sel[0] = i;
915 if (in_adev[1] == d) stick_sel[1] = i;
917 adevnames[i++] = name;
921 me_loop(e_menu_keyconfig_analog, &sel);
923 in_adev[0] = sel2dev_map[stick_sel[0]];
924 in_adev[1] = sel2dev_map[stick_sel[1]];
929 static const char *mgn_dev_name(int id, int *offs)
931 const char *name = NULL;
934 if (id == MA_CTRL_DEV_FIRST)
937 for (; it < IN_MAX_DEVS; it++) {
938 name = in_get_dev_name(it, 1, 1);
947 static const char *mgn_saveloadcfg(int id, int *offs)
952 static int mh_savecfg(int id, int keys)
954 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
955 me_update_msg("config saved");
957 me_update_msg("failed to write config");
962 static int mh_input_rescan(int id, int keys)
964 //menu_sync_config();
966 me_update_msg("rescan complete.");
971 static const char *men_in_type_sel[] = {
972 "Standard (SCPH-1080)",
973 "Analog (SCPH-1150)",
977 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
978 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
979 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
981 static menu_entry e_menu_keyconfig[] =
983 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
984 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
985 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
986 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
988 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
989 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
990 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
991 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
992 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
993 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
994 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
995 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
996 mee_handler ("Rescan devices:", mh_input_rescan),
998 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
999 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1000 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1001 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1002 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1003 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1004 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1008 static int menu_loop_keyconfig(int id, int keys)
1012 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1013 me_loop(e_menu_keyconfig, &sel);
1017 // ------------ gfx options menu ------------
1019 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1020 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1021 "using d-pad or move it using R+d-pad";
1022 static const char *men_dummy[] = { NULL };
1024 static int menu_loop_cscaler(int id, int keys)
1028 scaling = SCALE_CUSTOM;
1030 plat_gvideo_open(Config.PsxType);
1035 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1036 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1037 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1040 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1041 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1042 if (inp & PBTN_UP) g_layer_y--;
1043 if (inp & PBTN_DOWN) g_layer_y++;
1044 if (inp & PBTN_LEFT) g_layer_x--;
1045 if (inp & PBTN_RIGHT) g_layer_x++;
1046 if (!(inp & PBTN_R)) {
1047 if (inp & PBTN_UP) g_layer_h += 2;
1048 if (inp & PBTN_DOWN) g_layer_h -= 2;
1049 if (inp & PBTN_LEFT) g_layer_w += 2;
1050 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1052 if (inp & (PBTN_MOK|PBTN_MBACK))
1055 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1056 if (g_layer_x < 0) g_layer_x = 0;
1057 if (g_layer_x > 640) g_layer_x = 640;
1058 if (g_layer_y < 0) g_layer_y = 0;
1059 if (g_layer_y > 420) g_layer_y = 420;
1060 if (g_layer_w < 160) g_layer_w = 160;
1061 if (g_layer_h < 60) g_layer_h = 60;
1062 if (g_layer_x + g_layer_w > 800)
1063 g_layer_w = 800 - g_layer_x;
1064 if (g_layer_y + g_layer_h > 480)
1065 g_layer_h = 480 - g_layer_y;
1067 plat_gvideo_open(Config.PsxType);
1071 plat_gvideo_close();
1076 static menu_entry e_menu_gfx_options[] =
1078 mee_enum ("Scaler", MA_OPT_SCALER, scaling, men_scaler),
1079 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1080 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1081 // mee_onoff ("Vsync", 0, vsync, 1),
1082 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1086 static int menu_loop_gfx_options(int id, int keys)
1090 me_loop(e_menu_gfx_options, &sel);
1096 void menu_set_filter_list(void *filters)
1100 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1101 e_menu_gfx_options[i].data = filters;
1102 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1105 // ------------ bios/plugins ------------
1109 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1110 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1112 static menu_entry e_menu_plugin_gpu_neon[] =
1114 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1118 static int menu_loop_plugin_gpu_neon(int id, int keys)
1121 me_loop(e_menu_plugin_gpu_neon, &sel);
1127 static menu_entry e_menu_plugin_gpu_unai[] =
1129 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1130 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1131 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1132 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1136 static int menu_loop_plugin_gpu_unai(int id, int keys)
1139 me_loop(e_menu_plugin_gpu_unai, &sel);
1143 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1144 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1145 static const char h_gpu_1[] = "Capcom fighting games";
1146 static const char h_gpu_2[] = "Black screens in Lunar";
1147 static const char h_gpu_3[] = "Compatibility mode";
1148 static const char h_gpu_6[] = "Pandemonium 2";
1149 //static const char h_gpu_7[] = "Skip every second frame";
1150 static const char h_gpu_8[] = "Needed by Dark Forces";
1151 static const char h_gpu_9[] = "better g-colors, worse textures";
1152 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1154 static menu_entry e_menu_plugin_gpu_peops[] =
1156 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1157 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1158 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1159 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1160 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1161 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1162 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1163 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1164 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1165 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1169 static int menu_loop_plugin_gpu_peops(int id, int keys)
1172 me_loop(e_menu_plugin_gpu_peops, &sel);
1176 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1177 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1178 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1180 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1182 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1183 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1184 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1185 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1186 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1187 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1188 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1189 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1190 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1191 mee_label ("Fixes/hacks:"),
1192 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1193 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1194 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1195 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1196 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1197 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1198 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1199 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1200 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1201 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1202 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1206 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1209 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1213 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1214 static const char h_spu_volboost[] = "Large values cause distortion";
1216 static menu_entry e_menu_plugin_spu[] =
1218 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1219 mee_onoff ("Reverb", 0, iUseReverb, 2),
1220 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1221 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1225 static int menu_loop_plugin_spu(int id, int keys)
1228 me_loop(e_menu_plugin_spu, &sel);
1232 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1233 "savestates and can't be changed there. Must save\n"
1234 "config and reload the game for change to take effect";
1235 static const char h_plugin_gpu[] =
1237 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1242 "is Pete's soft GPU, slow but accurate\n"
1243 "gpuPCSX4ALL is GPU from PCSX4ALL, fast but glitchy\n"
1244 "gpuGLES Pete's hw GPU, uses 3D chip but is glitchy\n"
1245 "must save config and reload the game if changed";
1246 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1247 "must save config and reload the game if changed";
1248 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1249 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1250 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1251 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1253 static menu_entry e_menu_plugin_options[] =
1255 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1256 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1257 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1259 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1261 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1262 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1263 mee_handler_h ("Configure GLES GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1264 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1268 static menu_entry e_menu_main2[];
1270 static int menu_loop_plugin_options(int id, int keys)
1273 me_loop(e_menu_plugin_options, &sel);
1275 // sync BIOS/plugins
1276 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1277 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1278 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1279 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1284 // ------------ adv options menu ------------
1286 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1287 "(lower value - less work for the emu, may be faster)";
1288 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1289 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1290 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1292 static menu_entry e_menu_speed_hacks[] =
1294 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1295 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1296 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1297 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1301 static int menu_loop_speed_hacks(int id, int keys)
1304 me_loop(e_menu_speed_hacks, &sel);
1308 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1309 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1310 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1311 "(green: normal, red: fmod, blue: noise)";
1312 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1313 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1314 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1315 "(proper .cue/.bin dump is needed otherwise)";
1316 static const char h_cfg_sio[] = "You should not need this, breaks games";
1317 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1318 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1319 "(timing hack, breaks other games)";
1320 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1321 "(timing hack, breaks other games)";
1322 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1323 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1324 "Might be useful to overcome some dynarec bugs";
1325 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1326 "must reload game for any change to take effect";
1328 static menu_entry e_menu_adv_options[] =
1330 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1331 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1332 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1333 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1334 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1335 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1336 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1337 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1338 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1339 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1340 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1341 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1345 static int menu_loop_adv_options(int id, int keys)
1348 me_loop(e_menu_adv_options, &sel);
1352 // ------------ options menu ------------
1354 static int mh_restore_defaults(int id, int keys)
1356 menu_set_defconfig();
1357 me_update_msg("defaults restored");
1361 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1362 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1364 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1365 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1366 "loading state or both";
1368 static const char h_restore_def[] = "Switches back to default / recommended\n"
1370 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1372 static menu_entry e_menu_options[] =
1374 // mee_range ("Save slot", 0, state_slot, 0, 9),
1375 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1376 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1377 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1378 mee_enum ("Region", 0, region, men_region),
1379 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1380 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1381 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1382 mee_handler ("[Advanced]", menu_loop_adv_options),
1383 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1384 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1385 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1389 static int menu_loop_options(int id, int keys)
1394 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1395 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1396 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1398 me_loop(e_menu_options, &sel);
1403 // ------------ debug menu ------------
1405 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1407 int w = min(g_menuscreen_w, 1024);
1408 int h = min(g_menuscreen_h, 512);
1409 u16 *d = g_menuscreen_ptr;
1410 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1414 gpuf->ulFreezeVersion = 1;
1415 if (GPU_freeze != NULL)
1416 GPU_freeze(1, gpuf);
1418 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1419 bgr555_to_rgb565(d, s, w * 2);
1421 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1422 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1423 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1424 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1425 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1428 static void debug_menu_loop(void)
1430 int inp, df_x = 0, df_y = 0;
1433 gpuf = malloc(sizeof(*gpuf));
1440 draw_frame_debug(gpuf, df_x, df_y);
1443 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1444 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1445 if (inp & PBTN_MBACK) break;
1446 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1447 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1448 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1449 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1455 // --------- memcard manager ---------
1457 static void draw_mc_icon(int dx, int dy, const u16 *s)
1462 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1464 for (y = 0; y < 16; y++, s += 16) {
1465 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1466 for (x = 0; x < 16; x++) {
1468 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1469 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1475 static void draw_mc_bg(void)
1477 McdBlock *blocks1, *blocks2;
1481 blocks1 = malloc(15 * sizeof(blocks1[0]));
1482 blocks2 = malloc(15 * sizeof(blocks1[0]));
1483 if (blocks1 == NULL || blocks2 == NULL)
1486 for (i = 0; i < 15; i++) {
1487 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1488 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1493 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1495 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1499 maxicons = g_menuscreen_h / 32;
1502 row2 = g_menuscreen_w / 2;
1503 for (i = 0; i < maxicons; i++) {
1504 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1505 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1507 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1508 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1511 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1519 static void handle_memcard_sel(void)
1522 if (memcard1_sel != 0)
1523 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1525 if (memcard2_sel != 0)
1526 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1527 LoadMcds(Config.Mcd1, Config.Mcd2);
1531 static menu_entry e_memcard_options[] =
1533 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1534 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1538 static int menu_loop_memcards(int id, int keys)
1544 memcard1_sel = memcard2_sel = 0;
1545 p = strrchr(Config.Mcd1, '/');
1547 for (i = 0; memcards[i] != NULL; i++)
1548 if (strcmp(p + 1, memcards[i]) == 0)
1549 { memcard1_sel = i; break; }
1550 p = strrchr(Config.Mcd2, '/');
1552 for (i = 0; memcards[i] != NULL; i++)
1553 if (strcmp(p + 1, memcards[i]) == 0)
1554 { memcard2_sel = i; break; }
1556 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1558 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1563 // --------- main menu help ----------
1565 static void menu_bios_warn(void)
1568 static const char msg[] =
1569 "You don't seem to have copied any BIOS\n"
1571 #ifdef __ARM_ARCH_7A__ // XXX
1572 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1574 "pcsx_rearmed/bios/\n\n"
1576 "While many games work fine with fake\n"
1577 "(HLE) BIOS, others (like MGS and FF8)\n"
1578 "require BIOS to work.\n"
1579 "After copying the file, you'll also need\n"
1580 "to select it in the emu's menu:\n"
1581 "options->[BIOS/Plugins]\n\n"
1582 "The file is usually named SCPH1001.BIN,\n"
1583 "but other not compressed files can be\n"
1585 "Press %s or %s to continue";
1586 char tmp_msg[sizeof(msg) + 64];
1588 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1589 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1592 draw_menu_message(tmp_msg, NULL);
1594 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1595 if (inp & (PBTN_MBACK|PBTN_MOK))
1600 // ------------ main menu ------------
1604 static void draw_frame_main(void)
1613 if (CdromId[0] != 0) {
1614 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1615 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1616 Config.HLE ? "HLE" : "BIOS");
1617 smalltext_out16(4, 1, buff, 0x105f);
1621 capacity = plat_get_bat_capacity();
1623 tmp = localtime(<ime);
1624 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1625 if (capacity >= 0) {
1626 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1631 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1635 static void draw_frame_credits(void)
1637 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1640 static const char credits_text[] =
1642 "(C) 1999-2003 PCSX Team\n"
1643 "(C) 2005-2009 PCSX-df Team\n"
1644 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1645 "ARM recompiler (C) 2009-2011 Ari64\n"
1647 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1649 "PEOpS GPU and SPU by Pete Bernert\n"
1650 " and the P.E.Op.S. team\n"
1651 "PCSX4ALL plugin by PCSX4ALL team\n"
1652 " Chui, Franxis, Unai\n\n"
1653 "integration, optimization and\n"
1654 " frontend (C) 2010-2012 notaz\n";
1656 static int reset_game(void)
1659 if (bios_sel == 0 && !Config.HLE)
1665 if (CheckCdrom() != -1) {
1671 static int reload_plugins(const char *cdimg)
1677 set_cd_image(cdimg);
1679 pcnt_hook_plugins();
1681 if (OpenPlugins() == -1) {
1682 me_update_msg("failed to open plugins");
1685 plugin_call_rearmed_cbs();
1687 cdrIsoMultidiskCount = 1;
1689 CdromLabel[0] = '\0';
1694 static int run_bios(void)
1700 if (reload_plugins(NULL) != 0)
1708 static int run_exe(void)
1712 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1717 if (reload_plugins(NULL) != 0)
1721 if (Load(fname) != 0) {
1722 me_update_msg("exe load failed, bad file?");
1731 static int run_cd_image(const char *fname)
1734 reload_plugins(fname);
1736 // always autodetect, menu_sync_config will override as needed
1739 if (CheckCdrom() == -1) {
1740 // Only check the CD if we are starting the console with a CD
1742 me_update_msg("unsupported/invalid CD image");
1748 // Read main executable directly from CDRom and start it
1749 if (LoadCdrom() == -1) {
1751 me_update_msg("failed to load CD image");
1756 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1761 static int romsel_run(void)
1763 int prev_gpu, prev_spu;
1766 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1770 printf("selected file: %s\n", fname);
1772 new_dynarec_clear_full();
1774 if (run_cd_image(fname) != 0)
1777 prev_gpu = gpu_plugsel;
1778 prev_spu = spu_plugsel;
1779 if (menu_load_config(1) != 0)
1780 menu_load_config(0);
1782 // check for plugin changes, have to repeat
1783 // loading if game config changed plugins to reload them
1784 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1785 printf("plugin change detected, reloading plugins..\n");
1786 if (run_cd_image(fname) != 0)
1791 printf("note: running without BIOS, expect compatibility problems\n");
1793 strcpy(last_selected_fname, rom_fname_reload);
1797 static int swap_cd_image(void)
1801 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1805 printf("selected file: %s\n", fname);
1808 CdromLabel[0] = '\0';
1810 set_cd_image(fname);
1811 if (ReloadCdromPlugin() < 0) {
1812 me_update_msg("failed to load cdr plugin");
1815 if (CDR_open() < 0) {
1816 me_update_msg("failed to open cdr plugin");
1820 SetCdOpenCaseTime(time(NULL) + 2);
1823 strcpy(last_selected_fname, rom_fname_reload);
1827 static int swap_cd_multidisk(void)
1829 cdrIsoMultidiskSelect++;
1831 CdromLabel[0] = '\0';
1834 if (CDR_open() < 0) {
1835 me_update_msg("failed to open cdr plugin");
1839 SetCdOpenCaseTime(time(NULL) + 2);
1845 static int main_menu_handler(int id, int keys)
1849 case MA_MAIN_RESUME_GAME:
1853 case MA_MAIN_SAVE_STATE:
1855 return menu_loop_savestate(0);
1857 case MA_MAIN_LOAD_STATE:
1859 return menu_loop_savestate(1);
1861 case MA_MAIN_RESET_GAME:
1862 if (ready_to_go && reset_game() == 0)
1865 case MA_MAIN_LOAD_ROM:
1866 if (romsel_run() == 0)
1869 case MA_MAIN_SWAP_CD:
1870 if (swap_cd_image() == 0)
1873 case MA_MAIN_SWAP_CD_MULTI:
1874 if (swap_cd_multidisk() == 0)
1877 case MA_MAIN_RUN_BIOS:
1878 if (run_bios() == 0)
1881 case MA_MAIN_RUN_EXE:
1885 case MA_MAIN_CREDITS:
1886 draw_menu_message(credits_text, draw_frame_credits);
1887 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1893 lprintf("%s: something unknown selected\n", __FUNCTION__);
1900 static menu_entry e_menu_main2[] =
1902 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1903 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1904 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1905 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1906 mee_handler ("Memcard manager", menu_loop_memcards),
1910 static int main_menu2_handler(int id, int keys)
1914 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1915 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1916 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1918 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1921 static const char h_extra[] = "Change CD, manage memcards..\n";
1923 static menu_entry e_menu_main[] =
1927 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1928 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1929 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1930 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1931 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1932 mee_handler ("Options", menu_loop_options),
1933 mee_handler ("Controls", menu_loop_keyconfig),
1934 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1935 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1936 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1940 // ----------------------------
1942 static void menu_leave_emu(void);
1944 void menu_loop(void)
1950 if (bioses[1] == NULL && !warned_about_bios) {
1952 warned_about_bios = 1;
1955 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1956 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1957 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1958 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1960 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1963 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1964 } while (!ready_to_go);
1966 /* wait until menu, ok, back is released */
1967 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1970 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1975 static int qsort_strcmp(const void *p1, const void *p2)
1977 char * const *s1 = (char * const *)p1;
1978 char * const *s2 = (char * const *)p2;
1979 return strcasecmp(*s1, *s2);
1982 static void scan_bios_plugins(void)
1984 char fname[MAXPATHLEN];
1986 int bios_i, gpu_i, spu_i, mc_i;
1991 gpu_plugins[0] = "builtin_gpu";
1992 spu_plugins[0] = "builtin_spu";
1993 memcards[0] = "(none)";
1994 bios_i = gpu_i = spu_i = mc_i = 1;
1996 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1997 dir = opendir(fname);
1999 perror("scan_bios_plugins bios opendir");
2014 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2017 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2018 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2019 printf("bad BIOS file: %s\n", ent->d_name);
2023 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2024 bioses[bios_i++] = strdup(ent->d_name);
2028 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2034 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2035 dir = opendir(fname);
2037 perror("scan_bios_plugins plugins opendir");
2051 p = strstr(ent->d_name, ".so");
2055 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2056 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2058 fprintf(stderr, "%s\n", dlerror());
2062 // now what do we have here?
2063 tmp = dlsym(h, "GPUinit");
2066 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2067 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2071 tmp = dlsym(h, "SPUinit");
2074 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2075 spu_plugins[spu_i++] = strdup(ent->d_name);
2079 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2086 dir = opendir("." MEMCARD_DIR);
2088 perror("scan_bios_plugins memcards opendir");
2103 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2106 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2107 if (stat(fname, &st) != 0) {
2108 printf("bad memcard file: %s\n", ent->d_name);
2112 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2113 memcards[mc_i++] = strdup(ent->d_name);
2117 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2121 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2126 void menu_init(void)
2128 char buff[MAXPATHLEN];
2130 strcpy(last_selected_fname, "/media");
2132 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2134 scan_bios_plugins();
2137 menu_set_defconfig();
2138 menu_load_config(0);
2143 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2144 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2145 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2146 fprintf(stderr, "OOM\n");
2150 emu_make_path(buff, "skin/background.png", sizeof(buff));
2151 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2153 #ifndef __ARM_ARCH_7A__ /* XXX */
2154 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2155 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2156 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2157 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2159 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2160 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2161 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2165 void menu_notify_mode_change(int w, int h, int bpp)
2174 // XXX: should really menu code cotrol the layer size?
2177 g_layer_w = w; g_layer_h = h;
2181 if (h > g_menuscreen_h || (240 < h && h <= 360))
2182 goto fractional_4_3;
2184 // 4:3 that prefers integer scaling
2185 imult = g_menuscreen_h / h;
2186 g_layer_w = w * imult;
2187 g_layer_h = h * imult;
2188 mult = (float)g_layer_w / (float)g_layer_h;
2189 if (mult < 1.25f || mult > 1.666f)
2190 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2191 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2196 mult = 240.0f / (float)h * 4.0f / 3.0f;
2199 g_layer_w = mult * (float)g_menuscreen_h;
2200 g_layer_h = g_menuscreen_h;
2201 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2204 case SCALE_FULLSCREEN:
2205 g_layer_w = g_menuscreen_w;
2206 g_layer_h = g_menuscreen_h;
2213 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2214 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2215 if (g_layer_x < 0) g_layer_x = 0;
2216 if (g_layer_y < 0) g_layer_y = 0;
2217 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2218 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2221 static void menu_leave_emu(void)
2223 if (GPU_close != NULL) {
2224 int ret = GPU_close();
2226 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2229 plat_video_menu_enter(ready_to_go);
2231 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2232 if (pl_vout_buf != NULL && ready_to_go) {
2233 int x = max(0, g_menuscreen_w - last_psx_w);
2234 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2235 int w = min(g_menuscreen_w, last_psx_w);
2236 int h = min(g_menuscreen_h, last_psx_h);
2237 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2238 char *s = pl_vout_buf;
2240 if (last_psx_bpp == 16) {
2241 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 2)
2242 menu_darken_bg(d, s, w, 0);
2245 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 3) {
2246 rgb888_to_rgb565(d, s, w * 3);
2247 menu_darken_bg(d, d, w, 0);
2253 cpu_clock = plat_cpu_clock_get();
2256 void menu_prepare_emu(void)
2258 R3000Acpu *prev_cpu = psxCpu;
2260 plat_video_menu_leave();
2262 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2264 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2265 if (psxCpu != prev_cpu)
2266 // note that this does not really reset, just clears drc caches
2269 // core doesn't care about Config.Cdda changes,
2270 // so handle them manually here
2276 plat_cpu_clock_apply(cpu_clock);
2278 // push config to GPU plugin
2279 plugin_call_rearmed_cbs();
2281 if (GPU_open != NULL) {
2282 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2284 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2290 void me_update_msg(const char *msg)
2292 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2293 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2295 menu_error_time = plat_get_ticks_ms();
2296 lprintf("msg: %s\n", menu_error_msg);
2299 void menu_finish(void)
2301 plat_cpu_clock_apply(cpu_clock_st);