2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
21 #include "plugin_lib.h"
26 #include "common/plat.h"
27 #include "common/input.h"
28 #include "linux/in_evdev.h"
29 #include "../libpcsxcore/misc.h"
30 #include "../libpcsxcore/cdrom.h"
31 #include "../libpcsxcore/cdriso.h"
32 #include "../libpcsxcore/psemu_plugin_defs.h"
33 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
34 #include "../plugins/dfinput/main.h"
37 #define array_size(x) (sizeof(x) / sizeof(x[0]))
48 MA_MAIN_SWAP_CD_MULTI,
79 static int last_psx_w, last_psx_h, last_psx_bpp;
80 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
81 static char rom_fname_reload[MAXPATHLEN];
82 static char last_selected_fname[MAXPATHLEN];
83 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
85 static int memcard1_sel, memcard2_sel;
87 int analog_deadzone; // for Caanoo
89 #ifdef __ARM_ARCH_7A__
90 #define DEFAULT_PSX_CLOCK 57
91 #define DEFAULT_PSX_CLOCK_S "57"
93 #define DEFAULT_PSX_CLOCK 50
94 #define DEFAULT_PSX_CLOCK_S "50"
98 extern int iUseReverb;
99 extern int iUseInterpolation;
101 extern int iSPUIRQWait;
102 extern int iUseTimer;
105 static const char *bioses[24];
106 static const char *gpu_plugins[16];
107 static const char *spu_plugins[16];
108 static const char *memcards[32];
109 static int bios_sel, gpu_plugsel, spu_plugsel;
112 static int min(int x, int y) { return x < y ? x : y; }
113 static int max(int x, int y) { return x > y ? x : y; }
115 void emu_make_path(char *buff, const char *end, int size)
119 end_len = strlen(end);
120 pos = plat_get_root_dir(buff, size);
121 strncpy(buff + pos, end, size - pos);
123 if (pos + end_len > size - 1)
124 printf("Warning: path truncated: %s\n", buff);
127 static int emu_check_save_file(int slot)
129 int ret = emu_check_state(slot);
130 return ret == 0 ? 1 : 0;
133 static int emu_save_load_game(int load, int unused)
138 ret = emu_load_state(state_slot);
140 // reflect hle/bios mode from savestate
143 else if (bios_sel == 0 && bioses[1] != NULL)
144 // XXX: maybe find the right bios instead
148 ret = emu_save_state(state_slot);
153 // propagate menu settings to the emu vars
154 static void menu_sync_config(void)
156 static int allow_abs_only_old;
161 Config.PsxType = region - 1;
163 cycle_multiplier = 10000 / psx_clock;
165 switch (in_type_sel1) {
166 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
167 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
168 default: in_type1 = PSE_PAD_TYPE_STANDARD;
170 switch (in_type_sel2) {
171 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
172 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
173 default: in_type2 = PSE_PAD_TYPE_STANDARD;
175 if (in_evdev_allow_abs_only != allow_abs_only_old) {
177 allow_abs_only_old = in_evdev_allow_abs_only;
180 iVolume = 768 + 128 * volume_boost;
181 pl_rearmed_cbs.frameskip = frameskip - 1;
182 pl_timing_prepare(Config.PsxType);
185 static void menu_set_defconfig(void)
187 emu_set_default_config();
193 analog_deadzone = 50;
194 psx_clock = DEFAULT_PSX_CLOCK;
197 in_type_sel1 = in_type_sel2 = 0;
198 in_evdev_allow_abs_only = 0;
203 #define CE_CONFIG_STR(val) \
204 { #val, 0, Config.val }
206 #define CE_CONFIG_VAL(val) \
207 { #val, sizeof(Config.val), &Config.val }
209 #define CE_STR(val) \
212 #define CE_INTVAL(val) \
213 { #val, sizeof(val), &val }
215 #define CE_INTVAL_P(val) \
216 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
218 // 'versioned' var, used when defaults change
219 #define CE_INTVAL_V(val, ver) \
220 { #val #ver, sizeof(val), &val }
222 #define CE_INTVAL_PV(val, ver) \
223 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
225 static const struct {
233 // CE_CONFIG_STR(Cdr),
238 CE_CONFIG_VAL(Debug),
239 CE_CONFIG_VAL(PsxOut),
240 CE_CONFIG_VAL(SpuIrq),
241 CE_CONFIG_VAL(RCntFix),
242 CE_CONFIG_VAL(VSyncWA),
244 CE_CONFIG_VAL(CdrReschedule),
246 CE_INTVAL_V(scaling, 2),
247 CE_INTVAL(g_layer_x),
248 CE_INTVAL(g_layer_y),
249 CE_INTVAL(g_layer_w),
250 CE_INTVAL(g_layer_h),
252 CE_INTVAL(state_slot),
253 CE_INTVAL(cpu_clock),
255 CE_INTVAL(in_type_sel1),
256 CE_INTVAL(in_type_sel2),
257 CE_INTVAL(analog_deadzone),
258 CE_INTVAL_V(frameskip, 2),
259 CE_INTVAL_P(gpu_peops.iUseDither),
260 CE_INTVAL_P(gpu_peops.dwActFixes),
261 CE_INTVAL_P(gpu_unai.abe_hack),
262 CE_INTVAL_P(gpu_unai.no_light),
263 CE_INTVAL_P(gpu_unai.no_blend),
264 CE_INTVAL_V(iUseReverb, 3),
265 CE_INTVAL_V(iXAPitch, 3),
266 CE_INTVAL_V(iUseInterpolation, 3),
267 CE_INTVAL_V(iSPUIRQWait, 3),
268 CE_INTVAL_V(iUseTimer, 3),
269 CE_INTVAL(warned_about_bios),
270 CE_INTVAL(in_evdev_allow_abs_only),
271 CE_INTVAL(volume_boost),
272 CE_INTVAL(psx_clock),
273 CE_INTVAL(new_dynarec_hacks),
274 CE_INTVAL(in_enable_vibration),
277 static char *get_cd_label(void)
279 static char trimlabel[33];
282 strncpy(trimlabel, CdromLabel, 32);
284 for (j = 31; j >= 0; j--)
285 if (trimlabel[j] == ' ')
291 static void make_cfg_fname(char *buf, size_t size, int is_game)
294 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
296 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
299 static void keys_write_all(FILE *f);
301 static int menu_write_config(int is_game)
303 char cfgfile[MAXPATHLEN];
307 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
308 f = fopen(cfgfile, "w");
310 printf("menu_write_config: failed to open: %s\n", cfgfile);
314 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
315 fprintf(f, "%s = ", config_data[i].name);
316 switch (config_data[i].len) {
318 fprintf(f, "%s\n", (char *)config_data[i].val);
321 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
324 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
327 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
330 printf("menu_write_config: unhandled len %d for %s\n",
331 config_data[i].len, config_data[i].name);
337 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
345 static void parse_str_val(char *cval, const char *src)
348 strncpy(cval, src, MAXPATHLEN);
349 cval[MAXPATHLEN - 1] = 0;
350 tmp = strchr(cval, '\n');
352 tmp = strchr(cval, '\r');
357 static void keys_load_all(const char *cfg);
359 static int menu_load_config(int is_game)
361 char cfgfile[MAXPATHLEN];
367 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
368 f = fopen(cfgfile, "r");
370 printf("menu_load_config: failed to open: %s\n", cfgfile);
374 fseek(f, 0, SEEK_END);
377 printf("bad size %ld: %s\n", size, cfgfile);
381 cfg = malloc(size + 1);
385 fseek(f, 0, SEEK_SET);
386 if (fread(cfg, 1, size, f) != size) {
387 printf("failed to read: %s\n", cfgfile);
392 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
396 tmp = strstr(cfg, config_data[i].name);
399 tmp += strlen(config_data[i].name);
400 if (strncmp(tmp, " = ", 3) != 0)
404 if (config_data[i].len == 0) {
405 parse_str_val(config_data[i].val, tmp);
410 val = strtoul(tmp, &tmp2, 16);
411 if (tmp2 == NULL || tmp == tmp2)
412 continue; // parse failed
414 switch (config_data[i].len) {
416 *(u8 *)config_data[i].val = val;
419 *(u16 *)config_data[i].val = val;
422 *(u32 *)config_data[i].val = val;
425 printf("menu_load_config: unhandled len %d for %s\n",
426 config_data[i].len, config_data[i].name);
432 char *tmp = strstr(cfg, "lastcdimg = ");
435 parse_str_val(last_selected_fname, tmp);
450 for (i = bios_sel = 0; bioses[i] != NULL; i++)
451 if (strcmp(Config.Bios, bioses[i]) == 0)
452 { bios_sel = i; break; }
454 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
455 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
456 { gpu_plugsel = i; break; }
458 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
459 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
460 { spu_plugsel = i; break; }
465 // rrrr rggg gggb bbbb
466 static unsigned short fname2color(const char *fname)
468 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
469 ".bz", ".znx", ".pbp", ".cbn" };
470 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
471 ".table", ".index", ".sbi" };
472 const char *ext = strrchr(fname, '.');
477 for (i = 0; i < array_size(cdimg_exts); i++)
478 if (strcasecmp(ext, cdimg_exts[i]) == 0)
480 for (i = 0; i < array_size(other_exts); i++)
481 if (strcasecmp(ext, other_exts[i]) == 0)
486 static void draw_savestate_bg(int slot);
488 static const char *filter_exts[] = {
489 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
492 #define MENU_ALIGN_LEFT
493 #ifdef __ARM_ARCH_7A__ // assume hires device
499 #define menu_init menu_init_common
500 #include "common/menu.c"
503 // a bit of black magic here
504 static void draw_savestate_bg(int slot)
506 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
508 char fname[MAXPATHLEN];
515 ret = get_state_filename(fname, sizeof(fname), slot);
519 f = gzopen(fname, "rb");
523 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
524 fprintf(stderr, "gzseek failed\n");
529 gpu = malloc(sizeof(*gpu));
535 ret = gzread(f, gpu, sizeof(*gpu));
537 if (ret != sizeof(*gpu)) {
538 fprintf(stderr, "gzread failed\n");
542 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
544 if (gpu->ulStatus & 0x800000)
545 goto out; // disabled
547 x = gpu->ulControl[5] & 0x3ff;
548 y = (gpu->ulControl[5] >> 10) & 0x1ff;
549 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
550 w = psx_widths[(gpu->ulStatus >> 16) & 7];
551 tmp = gpu->ulControl[7];
552 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
553 if (gpu->ulStatus & 0x80000) // doubleheight
556 x = max(0, g_menuscreen_w - w) & ~3;
557 y = max(0, g_menuscreen_h / 2 - h / 2);
558 w = min(g_menuscreen_w, w);
559 h = min(g_menuscreen_h, h);
560 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
562 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
563 if (gpu->ulStatus & 0x200000)
564 bgr888_to_rgb565(d, s, w * 3);
566 bgr555_to_rgb565(d, s, w * 2);
567 #ifndef __ARM_ARCH_7A__
568 // better darken this on small screens
569 menu_darken_bg(d, d, w * 2, 0);
577 // ---------- XXX: pandora specific -----------
579 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
580 static char **pnd_filter_list;
582 static void apply_filter(int which)
588 if (pnd_filter_list == NULL || which == old)
591 for (i = 0; i < which; i++)
592 if (pnd_filter_list[i] == NULL)
595 if (pnd_filter_list[i] == NULL)
598 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
603 static void apply_lcdrate(int pal)
611 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
612 pnd_script_base, pal ? 50 : 60);
617 static menu_entry e_menu_gfx_options[];
619 static void pnd_menu_init(void)
627 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
629 dir = opendir("/etc/pandora/conf/dss_fir");
631 perror("filter opendir");
644 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
653 mfilters = calloc(count + 1, sizeof(mfilters[0]));
654 if (mfilters == NULL)
658 for (i = 0; (ent = readdir(dir)); ) {
661 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
664 len = strlen(ent->d_name);
666 // skip pre-HF5 extra files
667 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
669 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
672 // have to cut "_up_h" for pre-HF5
673 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
676 if (len > sizeof(buff) - 1)
679 strncpy(buff, ent->d_name, len);
681 mfilters[i] = strdup(buff);
682 if (mfilters[i] != NULL)
687 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
688 e_menu_gfx_options[i].data = (void *)mfilters;
689 pnd_filter_list = mfilters;
692 void menu_finish(void)
694 plat_cpu_clock_apply(cpu_clock_st);
697 // -------------- key config --------------
699 me_bind_action me_ctrl_actions[] =
701 { "UP ", 1 << DKEY_UP},
702 { "DOWN ", 1 << DKEY_DOWN },
703 { "LEFT ", 1 << DKEY_LEFT },
704 { "RIGHT ", 1 << DKEY_RIGHT },
705 { "TRIANGLE", 1 << DKEY_TRIANGLE },
706 { "CIRCLE ", 1 << DKEY_CIRCLE },
707 { "CROSS ", 1 << DKEY_CROSS },
708 { "SQUARE ", 1 << DKEY_SQUARE },
709 { "L1 ", 1 << DKEY_L1 },
710 { "R1 ", 1 << DKEY_R1 },
711 { "L2 ", 1 << DKEY_L2 },
712 { "R2 ", 1 << DKEY_R2 },
713 { "L3 ", 1 << DKEY_L3 },
714 { "R3 ", 1 << DKEY_R3 },
715 { "START ", 1 << DKEY_START },
716 { "SELECT ", 1 << DKEY_SELECT },
720 me_bind_action emuctrl_actions[] =
722 { "Save State ", 1 << SACTION_SAVE_STATE },
723 { "Load State ", 1 << SACTION_LOAD_STATE },
724 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
725 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
726 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
727 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
728 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
729 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
730 { "Gun A button ", 1 << SACTION_GUN_A },
731 { "Gun B button ", 1 << SACTION_GUN_B },
732 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
733 #ifndef __ARM_ARCH_7A__ /* XXX */
734 { "Volume Up ", 1 << SACTION_VOLUME_UP },
735 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
740 static char *mystrip(char *str)
745 for (i = 0; i < len; i++)
746 if (str[i] != ' ') break;
747 if (i > 0) memmove(str, str + i, len - i + 1);
750 for (i = len - 1; i >= 0; i--)
751 if (str[i] != ' ') break;
757 static void get_line(char *d, size_t size, const char *s)
762 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
773 static void keys_write_all(FILE *f)
777 for (d = 0; d < IN_MAX_DEVS; d++)
779 const int *binds = in_get_dev_binds(d);
780 const char *name = in_get_dev_name(d, 0, 0);
783 if (binds == NULL || name == NULL)
786 fprintf(f, "binddev = %s\n", name);
787 in_get_config(d, IN_CFG_BIND_COUNT, &count);
789 for (k = 0; k < count; k++)
794 act[0] = act[31] = 0;
795 name = in_get_key_name(d, k);
797 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
798 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
799 mask = me_ctrl_actions[i].mask;
801 strncpy(act, me_ctrl_actions[i].name, 31);
802 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
805 mask = me_ctrl_actions[i].mask << 16;
807 strncpy(act, me_ctrl_actions[i].name, 31);
808 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
813 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
814 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
815 mask = emuctrl_actions[i].mask;
817 strncpy(act, emuctrl_actions[i].name, 31);
818 fprintf(f, "bind %s = %s\n", name, mystrip(act));
824 for (k = 0; k < array_size(in_adev); k++)
827 fprintf(f, "bind_analog = %d\n", k);
832 static int parse_bind_val(const char *val, int *type)
836 *type = IN_BINDTYPE_NONE;
840 if (strncasecmp(val, "player", 6) == 0)
842 int player, shift = 0;
843 player = atoi(val + 6) - 1;
845 if ((unsigned int)player > 1)
850 *type = IN_BINDTYPE_PLAYER12;
851 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
852 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
853 return me_ctrl_actions[i].mask << shift;
856 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
857 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
858 *type = IN_BINDTYPE_EMU;
859 return emuctrl_actions[i].mask;
866 static void keys_load_all(const char *cfg)
868 char dev[256], key[128], *act;
874 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
877 get_line(dev, sizeof(dev), p);
878 dev_id = in_config_parse_dev(dev);
880 printf("input: can't handle dev: %s\n", dev);
884 in_unbind_all(dev_id, -1, -1);
885 while ((p = strstr(p, "bind"))) {
886 if (strncmp(p, "binddev = ", 10) == 0)
889 if (strncmp(p, "bind_analog", 11) == 0) {
890 ret = sscanf(p, "bind_analog = %d", &bind);
893 printf("input: parse error: %16s..\n", p);
896 if ((unsigned int)bind >= array_size(in_adev)) {
897 printf("input: analog id %d out of range\n", bind);
900 in_adev[bind] = dev_id;
906 printf("input: parse error: %16s..\n", p);
910 get_line(key, sizeof(key), p);
911 act = strchr(key, '=');
913 printf("parse failed: %16s..\n", p);
921 bind = parse_bind_val(act, &bindtype);
922 if (bind != -1 && bind != 0) {
923 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
924 in_config_bind_key(dev_id, key, bind, bindtype);
927 lprintf("config: unhandled action \"%s\"\n", act);
933 static int key_config_loop_wrap(int id, int keys)
936 case MA_CTRL_PLAYER1:
937 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
939 case MA_CTRL_PLAYER2:
940 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
943 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
951 static const char *adevnames[IN_MAX_DEVS + 2];
952 static int stick_sel[2];
954 static menu_entry e_menu_keyconfig_analog[] =
956 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
957 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
958 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
959 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
960 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
961 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
965 static int key_config_analog(int id, int keys)
967 int i, d, count, sel = 0;
968 int sel2dev_map[IN_MAX_DEVS];
970 memset(adevnames, 0, sizeof(adevnames));
971 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
972 memset(stick_sel, 0, sizeof(stick_sel));
974 adevnames[0] = "None";
976 for (d = 0; d < IN_MAX_DEVS; d++)
978 const char *name = in_get_dev_name(d, 0, 1);
983 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
987 if (in_adev[0] == d) stick_sel[0] = i;
988 if (in_adev[1] == d) stick_sel[1] = i;
990 adevnames[i++] = name;
994 me_loop(e_menu_keyconfig_analog, &sel);
996 in_adev[0] = sel2dev_map[stick_sel[0]];
997 in_adev[1] = sel2dev_map[stick_sel[1]];
1002 static const char *mgn_dev_name(int id, int *offs)
1004 const char *name = NULL;
1007 if (id == MA_CTRL_DEV_FIRST)
1010 for (; it < IN_MAX_DEVS; it++) {
1011 name = in_get_dev_name(it, 1, 1);
1020 static const char *mgn_saveloadcfg(int id, int *offs)
1025 static int mh_savecfg(int id, int keys)
1027 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1028 me_update_msg("config saved");
1030 me_update_msg("failed to write config");
1035 static int mh_input_rescan(int id, int keys)
1037 //menu_sync_config();
1039 me_update_msg("rescan complete.");
1044 static const char *men_in_type_sel[] = {
1045 "Standard (SCPH-1080)",
1046 "Analog (SCPH-1150)",
1050 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1051 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1052 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1054 static menu_entry e_menu_keyconfig[] =
1056 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1057 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1058 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1059 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1061 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1062 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1063 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1064 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1065 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1066 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1067 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1068 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1069 mee_handler ("Rescan devices:", mh_input_rescan),
1071 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1072 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1073 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1074 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1075 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1076 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1077 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1081 static int menu_loop_keyconfig(int id, int keys)
1085 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1086 me_loop(e_menu_keyconfig, &sel);
1090 // ------------ gfx options menu ------------
1092 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1093 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1094 "using d-pad or move it using R+d-pad";
1095 static const char *men_dummy[] = { NULL };
1097 static int menu_loop_cscaler(int id, int keys)
1101 scaling = SCALE_CUSTOM;
1103 omap_enable_layer(1);
1108 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1109 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1110 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1113 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1114 if (inp & PBTN_UP) g_layer_y--;
1115 if (inp & PBTN_DOWN) g_layer_y++;
1116 if (inp & PBTN_LEFT) g_layer_x--;
1117 if (inp & PBTN_RIGHT) g_layer_x++;
1118 if (!(inp & PBTN_R)) {
1119 if (inp & PBTN_UP) g_layer_h += 2;
1120 if (inp & PBTN_DOWN) g_layer_h -= 2;
1121 if (inp & PBTN_LEFT) g_layer_w += 2;
1122 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1124 if (inp & (PBTN_MOK|PBTN_MBACK))
1127 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1128 if (g_layer_x < 0) g_layer_x = 0;
1129 if (g_layer_x > 640) g_layer_x = 640;
1130 if (g_layer_y < 0) g_layer_y = 0;
1131 if (g_layer_y > 420) g_layer_y = 420;
1132 if (g_layer_w < 160) g_layer_w = 160;
1133 if (g_layer_h < 60) g_layer_h = 60;
1134 if (g_layer_x + g_layer_w > 800)
1135 g_layer_w = 800 - g_layer_x;
1136 if (g_layer_y + g_layer_h > 480)
1137 g_layer_h = 480 - g_layer_y;
1138 omap_enable_layer(1);
1142 omap_enable_layer(0);
1147 static menu_entry e_menu_gfx_options[] =
1149 mee_enum ("Scaler", 0, scaling, men_scaler),
1150 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1151 // mee_onoff ("Vsync", 0, vsync, 1),
1152 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1156 static int menu_loop_gfx_options(int id, int keys)
1160 me_loop(e_menu_gfx_options, &sel);
1165 // ------------ bios/plugins ------------
1167 static menu_entry e_menu_plugin_gpu_unai[] =
1169 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1170 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1171 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1175 static int menu_loop_plugin_gpu_unai(int id, int keys)
1178 me_loop(e_menu_plugin_gpu_unai, &sel);
1182 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1183 static const char h_gpu_0[] = "Needed for Chrono Cross";
1184 static const char h_gpu_1[] = "Capcom fighting games";
1185 static const char h_gpu_2[] = "Black screens in Lunar";
1186 static const char h_gpu_3[] = "Compatibility mode";
1187 static const char h_gpu_6[] = "Pandemonium 2";
1188 static const char h_gpu_7[] = "Skip every second frame";
1189 static const char h_gpu_8[] = "Needed by Dark Forces";
1190 static const char h_gpu_9[] = "better g-colors, worse textures";
1191 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1193 static menu_entry e_menu_plugin_gpu_peops[] =
1195 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1196 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1197 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1198 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1199 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1200 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1201 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1202 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1203 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1204 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1208 static int menu_loop_plugin_gpu_peops(int id, int keys)
1211 me_loop(e_menu_plugin_gpu_peops, &sel);
1215 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1216 static const char h_spu_volboost[] = "Large values cause distortion";
1217 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1218 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1220 static menu_entry e_menu_plugin_spu[] =
1222 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1223 mee_onoff ("Reverb", 0, iUseReverb, 2),
1224 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1225 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1226 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1227 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1231 static int menu_loop_plugin_spu(int id, int keys)
1234 me_loop(e_menu_plugin_spu, &sel);
1238 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1239 "savestates and can't be changed there. Must save\n"
1240 "config and reload the game for change to take effect";
1241 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1242 "for plugin change to take effect";
1243 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1244 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1245 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1247 static menu_entry e_menu_plugin_options[] =
1249 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1250 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1251 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1252 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1253 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1254 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1258 static menu_entry e_menu_main2[];
1260 static int menu_loop_plugin_options(int id, int keys)
1263 me_loop(e_menu_plugin_options, &sel);
1265 // sync BIOS/plugins
1266 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1267 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1268 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1269 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1274 // ------------ adv options menu ------------
1276 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1277 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1278 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1279 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1281 static menu_entry e_menu_speed_hacks[] =
1283 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1284 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1285 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1286 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1290 static int menu_loop_speed_hacks(int id, int keys)
1293 me_loop(e_menu_speed_hacks, &sel);
1297 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1298 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1299 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1300 "(green: normal, red: fmod, blue: noise)";
1301 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1302 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1303 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1304 "(proper .cue/.bin dump is needed otherwise)";
1305 static const char h_cfg_sio[] = "You should not need this, breaks games";
1306 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1307 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1308 "(timing hack, breaks other games)";
1309 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1310 "(timing hack, breaks other games)";
1311 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1312 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1313 "Might be useful to overcome some dynarec bugs";
1314 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1315 "must reload game for any change to take effect";
1317 static menu_entry e_menu_adv_options[] =
1319 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1320 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1321 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1322 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1323 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1324 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1325 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1326 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1327 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1328 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1329 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1330 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1334 static int menu_loop_adv_options(int id, int keys)
1337 me_loop(e_menu_adv_options, &sel);
1341 // ------------ options menu ------------
1343 static int mh_restore_defaults(int id, int keys)
1345 menu_set_defconfig();
1346 me_update_msg("defaults restored");
1350 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1351 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1353 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1354 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1355 "loading state or both";
1357 static const char h_restore_def[] = "Switches back to default / recommended\n"
1359 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1361 static menu_entry e_menu_options[] =
1363 // mee_range ("Save slot", 0, state_slot, 0, 9),
1364 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1365 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1366 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1367 mee_enum ("Region", 0, region, men_region),
1368 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1369 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1370 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1371 mee_handler ("[Advanced]", menu_loop_adv_options),
1372 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1373 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1374 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1378 static int menu_loop_options(int id, int keys)
1383 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1384 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1385 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1387 me_loop(e_menu_options, &sel);
1392 // ------------ debug menu ------------
1394 static void draw_frame_debug(GPUFreeze_t *gpuf)
1396 int w = min(g_menuscreen_w, 1024);
1397 int h = min(g_menuscreen_h, 512);
1398 u16 *d = g_menuscreen_ptr;
1399 u16 *s = (u16 *)gpuf->psxVRam;
1403 gpuf->ulFreezeVersion = 1;
1404 if (GPU_freeze != NULL)
1405 GPU_freeze(1, gpuf);
1407 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1408 bgr555_to_rgb565(d, s, w * 2);
1410 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1411 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1412 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1413 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1414 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1417 static void debug_menu_loop(void)
1422 gpuf = malloc(sizeof(*gpuf));
1429 draw_frame_debug(gpuf);
1432 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1433 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1434 if (inp & PBTN_MBACK)
1441 // --------- memcard manager ---------
1443 static void draw_mc_icon(int dx, int dy, const u16 *s)
1448 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1450 for (y = 0; y < 16; y++, s += 16) {
1451 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1452 for (x = 0; x < 16; x++) {
1454 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1455 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1461 static void draw_mc_bg(void)
1463 McdBlock *blocks1, *blocks2;
1467 blocks1 = malloc(15 * sizeof(blocks1[0]));
1468 blocks2 = malloc(15 * sizeof(blocks1[0]));
1469 if (blocks1 == NULL || blocks2 == NULL)
1472 for (i = 0; i < 15; i++) {
1473 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1474 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1479 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1481 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1485 maxicons = g_menuscreen_h / 32;
1488 row2 = g_menuscreen_w / 2;
1489 for (i = 0; i < maxicons; i++) {
1490 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1491 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1493 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1494 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1497 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1505 static void handle_memcard_sel(void)
1508 if (memcard1_sel != 0)
1509 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1511 if (memcard2_sel != 0)
1512 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1513 LoadMcds(Config.Mcd1, Config.Mcd2);
1517 static menu_entry e_memcard_options[] =
1519 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1520 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1524 static int menu_loop_memcards(int id, int keys)
1530 memcard1_sel = memcard2_sel = 0;
1531 p = strrchr(Config.Mcd1, '/');
1533 for (i = 0; memcards[i] != NULL; i++)
1534 if (strcmp(p + 1, memcards[i]) == 0)
1535 { memcard1_sel = i; break; }
1536 p = strrchr(Config.Mcd2, '/');
1538 for (i = 0; memcards[i] != NULL; i++)
1539 if (strcmp(p + 1, memcards[i]) == 0)
1540 { memcard2_sel = i; break; }
1542 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1544 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1549 // --------- main menu help ----------
1551 static void menu_bios_warn(void)
1554 static const char msg[] =
1555 "You don't seem to have copied any BIOS\n"
1557 #ifdef __ARM_ARCH_7A__ // XXX
1558 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1560 "pcsx_rearmed/bios/\n\n"
1562 "While many games work fine with fake\n"
1563 "(HLE) BIOS, others (like MGS and FF8)\n"
1564 "require BIOS to work.\n"
1565 "After copying the file, you'll also need\n"
1566 "to select it in the emu's menu:\n"
1567 "options->[BIOS/Plugins]\n\n"
1568 "The file is usually named SCPH1001.BIN,\n"
1569 "but other not compressed files can be\n"
1571 "Press (B) or (X) to continue";
1575 draw_menu_message(msg, NULL);
1577 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1578 if (inp & (PBTN_MBACK|PBTN_MOK))
1583 // ------------ main menu ------------
1587 static void draw_frame_main(void)
1594 if (CdromId[0] != 0) {
1595 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1596 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1597 Config.HLE ? "HLE" : "BIOS");
1598 smalltext_out16(4, 1, buff, 0x105f);
1603 tmp = localtime(<ime);
1604 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1605 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1606 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1610 static void draw_frame_credits(void)
1612 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1615 static const char credits_text[] =
1617 "(C) 1999-2003 PCSX Team\n"
1618 "(C) 2005-2009 PCSX-df Team\n"
1619 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1620 "GPU and SPU code by Pete Bernert\n"
1621 " and the P.E.Op.S. team\n"
1622 "ARM recompiler (C) 2009-2011 Ari64\n"
1623 "PCSX4ALL plugins by PCSX4ALL team\n"
1624 " Chui, Franxis, Unai\n\n"
1625 "integration, optimization and\n"
1626 " frontend (C) 2010-2011 notaz\n";
1628 static int reset_game(void)
1631 if (bios_sel == 0 && !Config.HLE)
1637 if (CheckCdrom() != -1) {
1643 static int reload_plugins(const char *cdimg)
1649 set_cd_image(cdimg);
1651 pcnt_hook_plugins();
1653 if (OpenPlugins() == -1) {
1654 me_update_msg("failed to open plugins");
1657 plugin_call_rearmed_cbs();
1659 cdrIsoMultidiskCount = 1;
1661 CdromLabel[0] = '\0';
1666 static int run_bios(void)
1672 if (reload_plugins(NULL) != 0)
1680 static int run_exe(void)
1684 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1689 if (reload_plugins(NULL) != 0)
1693 if (Load(fname) != 0) {
1694 me_update_msg("exe load failed, bad file?");
1703 static int run_cd_image(const char *fname)
1706 reload_plugins(fname);
1708 // always autodetect, menu_sync_config will override as needed
1711 if (CheckCdrom() == -1) {
1712 // Only check the CD if we are starting the console with a CD
1714 me_update_msg("unsupported/invalid CD image");
1720 // Read main executable directly from CDRom and start it
1721 if (LoadCdrom() == -1) {
1723 me_update_msg("failed to load CD image");
1728 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1733 static int romsel_run(void)
1735 int prev_gpu, prev_spu;
1738 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1742 printf("selected file: %s\n", fname);
1744 new_dynarec_clear_full();
1746 if (run_cd_image(fname) != 0)
1749 prev_gpu = gpu_plugsel;
1750 prev_spu = spu_plugsel;
1751 if (menu_load_config(1) != 0)
1752 menu_load_config(0);
1754 // check for plugin changes, have to repeat
1755 // loading if game config changed plugins to reload them
1756 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1757 printf("plugin change detected, reloading plugins..\n");
1758 if (run_cd_image(fname) != 0)
1763 printf("note: running without BIOS, expect compatibility problems\n");
1765 strcpy(last_selected_fname, rom_fname_reload);
1769 static int swap_cd_image(void)
1773 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1777 printf("selected file: %s\n", fname);
1780 CdromLabel[0] = '\0';
1782 set_cd_image(fname);
1783 if (ReloadCdromPlugin() < 0) {
1784 me_update_msg("failed to load cdr plugin");
1787 if (CDR_open() < 0) {
1788 me_update_msg("failed to open cdr plugin");
1792 SetCdOpenCaseTime(time(NULL) + 2);
1795 strcpy(last_selected_fname, rom_fname_reload);
1799 static int swap_cd_multidisk(void)
1801 cdrIsoMultidiskSelect++;
1803 CdromLabel[0] = '\0';
1806 if (CDR_open() < 0) {
1807 me_update_msg("failed to open cdr plugin");
1811 SetCdOpenCaseTime(time(NULL) + 2);
1817 static int main_menu_handler(int id, int keys)
1821 case MA_MAIN_RESUME_GAME:
1825 case MA_MAIN_SAVE_STATE:
1827 return menu_loop_savestate(0);
1829 case MA_MAIN_LOAD_STATE:
1831 return menu_loop_savestate(1);
1833 case MA_MAIN_RESET_GAME:
1834 if (ready_to_go && reset_game() == 0)
1837 case MA_MAIN_LOAD_ROM:
1838 if (romsel_run() == 0)
1841 case MA_MAIN_SWAP_CD:
1842 if (swap_cd_image() == 0)
1845 case MA_MAIN_SWAP_CD_MULTI:
1846 if (swap_cd_multidisk() == 0)
1849 case MA_MAIN_RUN_BIOS:
1850 if (run_bios() == 0)
1853 case MA_MAIN_RUN_EXE:
1857 case MA_MAIN_CREDITS:
1858 draw_menu_message(credits_text, draw_frame_credits);
1859 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1865 lprintf("%s: something unknown selected\n", __FUNCTION__);
1872 static menu_entry e_menu_main2[] =
1874 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1875 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1876 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1877 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1878 mee_handler ("Memcard manager", menu_loop_memcards),
1882 static int main_menu2_handler(int id, int keys)
1886 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1887 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1888 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1890 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1893 static const char h_extra[] = "Change CD, manage memcards..\n";
1895 static menu_entry e_menu_main[] =
1899 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1900 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1901 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1902 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1903 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1904 mee_handler ("Options", menu_loop_options),
1905 mee_handler ("Controls", menu_loop_keyconfig),
1906 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1907 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1908 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1912 // ----------------------------
1914 static void menu_leave_emu(void);
1916 void menu_loop(void)
1922 if (bioses[1] == NULL && !warned_about_bios) {
1924 warned_about_bios = 1;
1927 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1928 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1929 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1930 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1932 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1935 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1936 } while (!ready_to_go);
1938 /* wait until menu, ok, back is released */
1939 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1942 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1947 static int qsort_strcmp(const void *p1, const void *p2)
1949 char * const *s1 = (char * const *)p1;
1950 char * const *s2 = (char * const *)p2;
1951 return strcasecmp(*s1, *s2);
1954 static void scan_bios_plugins(void)
1956 char fname[MAXPATHLEN];
1958 int bios_i, gpu_i, spu_i, mc_i;
1963 gpu_plugins[0] = "builtin_gpu";
1964 spu_plugins[0] = "builtin_spu";
1965 memcards[0] = "(none)";
1966 bios_i = gpu_i = spu_i = mc_i = 1;
1968 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1969 dir = opendir(fname);
1971 perror("scan_bios_plugins bios opendir");
1986 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1989 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1990 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1991 printf("bad BIOS file: %s\n", ent->d_name);
1995 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1996 bioses[bios_i++] = strdup(ent->d_name);
2000 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2006 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2007 dir = opendir(fname);
2009 perror("scan_bios_plugins plugins opendir");
2023 p = strstr(ent->d_name, ".so");
2027 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2028 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2030 fprintf(stderr, "%s\n", dlerror());
2034 // now what do we have here?
2035 tmp = dlsym(h, "GPUinit");
2038 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2039 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2043 tmp = dlsym(h, "SPUinit");
2046 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2047 spu_plugins[spu_i++] = strdup(ent->d_name);
2051 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2058 dir = opendir("." MEMCARD_DIR);
2060 perror("scan_bios_plugins memcards opendir");
2075 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2078 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2079 if (stat(fname, &st) != 0) {
2080 printf("bad memcard file: %s\n", ent->d_name);
2084 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2085 memcards[mc_i++] = strdup(ent->d_name);
2089 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2093 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2098 void menu_init(void)
2100 char buff[MAXPATHLEN];
2102 strcpy(last_selected_fname, "/media");
2104 scan_bios_plugins();
2108 menu_set_defconfig();
2109 menu_load_config(0);
2114 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2115 if (g_menubg_src_ptr == NULL)
2117 emu_make_path(buff, "skin/background.png", sizeof(buff));
2118 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2120 #ifndef __ARM_ARCH_7A__ /* XXX */
2121 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2122 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2124 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2125 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2129 void menu_notify_mode_change(int w, int h, int bpp)
2140 g_layer_w = w; g_layer_h = h;
2144 if (h > g_menuscreen_h || (240 < h && h <= 360))
2145 goto fractional_4_3;
2147 // 4:3 that prefers integer scaling
2148 imult = g_menuscreen_h / h;
2149 g_layer_w = w * imult;
2150 g_layer_h = h * imult;
2151 mult = (float)g_layer_w / (float)g_layer_h;
2152 if (mult < 1.25f || mult > 1.666f)
2153 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2154 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2159 mult = 240.0f / (float)h * 4.0f / 3.0f;
2162 g_layer_w = mult * (float)g_menuscreen_h;
2163 g_layer_h = g_menuscreen_h;
2164 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2167 case SCALE_FULLSCREEN:
2168 g_layer_w = g_menuscreen_w;
2169 g_layer_h = g_menuscreen_h;
2176 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2177 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2178 if (g_layer_x < 0) g_layer_x = 0;
2179 if (g_layer_y < 0) g_layer_y = 0;
2180 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2181 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2184 static void menu_leave_emu(void)
2186 if (GPU_close != NULL) {
2187 int ret = GPU_close();
2189 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2192 plat_video_menu_enter(ready_to_go);
2194 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2195 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2196 int x = max(0, g_menuscreen_w - last_psx_w);
2197 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2198 int w = min(g_menuscreen_w, last_psx_w);
2199 int h = min(g_menuscreen_h, last_psx_h);
2200 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2201 u16 *s = pl_vout_buf;
2203 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2204 menu_darken_bg(d, s, w, 0);
2208 cpu_clock = plat_cpu_clock_get();
2211 void menu_prepare_emu(void)
2213 R3000Acpu *prev_cpu = psxCpu;
2215 plat_video_menu_leave();
2217 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2219 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2220 if (psxCpu != prev_cpu)
2221 // note that this does not really reset, just clears drc caches
2224 // core doesn't care about Config.Cdda changes,
2225 // so handle them manually here
2230 apply_lcdrate(Config.PsxType);
2231 apply_filter(filter);
2232 plat_cpu_clock_apply(cpu_clock);
2234 // push config to GPU plugin
2235 plugin_call_rearmed_cbs();
2237 if (GPU_open != NULL) {
2238 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2240 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2246 void me_update_msg(const char *msg)
2248 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2249 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2251 menu_error_time = plat_get_ticks_ms();
2252 lprintf("msg: %s\n", menu_error_msg);