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"
29 #include "common/plat.h"
30 #include "common/input.h"
31 #include "linux/in_evdev.h"
32 #include "../libpcsxcore/misc.h"
33 #include "../libpcsxcore/cdrom.h"
34 #include "../libpcsxcore/cdriso.h"
35 #include "../libpcsxcore/psemu_plugin_defs.h"
36 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
37 #include "../plugins/dfinput/main.h"
40 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
42 #define array_size(x) (sizeof(x) / sizeof(x[0]))
53 MA_MAIN_SWAP_CD_MULTI,
84 static int last_psx_w, last_psx_h, last_psx_bpp;
85 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
86 static char rom_fname_reload[MAXPATHLEN];
87 static char last_selected_fname[MAXPATHLEN];
88 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
90 static int memcard1_sel, memcard2_sel;
92 int analog_deadzone; // for Caanoo
94 #ifdef __ARM_ARCH_7A__
95 #define DEFAULT_PSX_CLOCK 57
96 #define DEFAULT_PSX_CLOCK_S "57"
98 #define DEFAULT_PSX_CLOCK 50
99 #define DEFAULT_PSX_CLOCK_S "50"
103 extern int iUseReverb;
104 extern int iUseInterpolation;
106 extern int iSPUIRQWait;
107 extern int iUseTimer;
110 static const char *bioses[24];
111 static const char *gpu_plugins[16];
112 static const char *spu_plugins[16];
113 static const char *memcards[32];
114 static int bios_sel, gpu_plugsel, spu_plugsel;
117 static int min(int x, int y) { return x < y ? x : y; }
118 static int max(int x, int y) { return x > y ? x : y; }
120 void emu_make_path(char *buff, const char *end, int size)
124 end_len = strlen(end);
125 pos = plat_get_root_dir(buff, size);
126 strncpy(buff + pos, end, size - pos);
128 if (pos + end_len > size - 1)
129 printf("Warning: path truncated: %s\n", buff);
132 static int emu_check_save_file(int slot, int *time)
134 char fname[MAXPATHLEN];
138 ret = emu_check_state(slot);
139 if (ret != 0 || time == NULL)
140 return ret == 0 ? 1 : 0;
142 ret = get_state_filename(fname, sizeof(fname), slot);
146 ret = stat(fname, &status);
150 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
151 return 1; // probably bad rtc like on some Caanoos
153 *time = status.st_mtime;
158 static int emu_save_load_game(int load, int unused)
163 ret = emu_load_state(state_slot);
165 // reflect hle/bios mode from savestate
168 else if (bios_sel == 0 && bioses[1] != NULL)
169 // XXX: maybe find the right bios instead
173 ret = emu_save_state(state_slot);
178 // propagate menu settings to the emu vars
179 static void menu_sync_config(void)
181 static int allow_abs_only_old;
186 Config.PsxType = region - 1;
188 cycle_multiplier = 10000 / psx_clock;
190 switch (in_type_sel1) {
191 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
192 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
193 default: in_type1 = PSE_PAD_TYPE_STANDARD;
195 switch (in_type_sel2) {
196 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
197 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
198 default: in_type2 = PSE_PAD_TYPE_STANDARD;
200 if (in_evdev_allow_abs_only != allow_abs_only_old) {
202 allow_abs_only_old = in_evdev_allow_abs_only;
205 iVolume = 768 + 128 * volume_boost;
206 pl_rearmed_cbs.frameskip = frameskip - 1;
207 pl_timing_prepare(Config.PsxType);
210 static void menu_set_defconfig(void)
212 emu_set_default_config();
218 analog_deadzone = 50;
219 psx_clock = DEFAULT_PSX_CLOCK;
222 in_type_sel1 = in_type_sel2 = 0;
223 in_evdev_allow_abs_only = 0;
228 #define CE_CONFIG_STR(val) \
229 { #val, 0, Config.val }
231 #define CE_CONFIG_VAL(val) \
232 { #val, sizeof(Config.val), &Config.val }
234 #define CE_STR(val) \
237 #define CE_INTVAL(val) \
238 { #val, sizeof(val), &val }
240 #define CE_INTVAL_P(val) \
241 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
243 // 'versioned' var, used when defaults change
244 #define CE_CONFIG_STR_V(val, ver) \
245 { #val #ver, 0, Config.val }
247 #define CE_INTVAL_V(val, ver) \
248 { #val #ver, sizeof(val), &val }
250 #define CE_INTVAL_PV(val, ver) \
251 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
253 static const struct {
259 CE_CONFIG_STR_V(Gpu, 2),
261 // CE_CONFIG_STR(Cdr),
266 CE_CONFIG_VAL(Debug),
267 CE_CONFIG_VAL(PsxOut),
268 CE_CONFIG_VAL(SpuIrq),
269 CE_CONFIG_VAL(RCntFix),
270 CE_CONFIG_VAL(VSyncWA),
272 CE_CONFIG_VAL(CdrReschedule),
274 CE_INTVAL_V(scaling, 2),
275 CE_INTVAL(g_layer_x),
276 CE_INTVAL(g_layer_y),
277 CE_INTVAL(g_layer_w),
278 CE_INTVAL(g_layer_h),
280 CE_INTVAL(state_slot),
281 CE_INTVAL(cpu_clock),
283 CE_INTVAL(in_type_sel1),
284 CE_INTVAL(in_type_sel2),
285 CE_INTVAL(analog_deadzone),
286 CE_INTVAL_V(frameskip, 3),
287 CE_INTVAL_P(gpu_peops.iUseDither),
288 CE_INTVAL_P(gpu_peops.dwActFixes),
289 CE_INTVAL_P(gpu_unai.lineskip),
290 CE_INTVAL_P(gpu_unai.abe_hack),
291 CE_INTVAL_P(gpu_unai.no_light),
292 CE_INTVAL_P(gpu_unai.no_blend),
293 CE_INTVAL_P(gpu_neon.allow_interlace),
294 CE_INTVAL_V(iUseReverb, 3),
295 CE_INTVAL_V(iXAPitch, 3),
296 CE_INTVAL_V(iUseInterpolation, 3),
297 CE_INTVAL_V(iSPUIRQWait, 3),
298 CE_INTVAL_V(iUseTimer, 3),
299 CE_INTVAL(warned_about_bios),
300 CE_INTVAL(in_evdev_allow_abs_only),
301 CE_INTVAL(volume_boost),
302 CE_INTVAL(psx_clock),
303 CE_INTVAL(new_dynarec_hacks),
304 CE_INTVAL(in_enable_vibration),
307 static char *get_cd_label(void)
309 static char trimlabel[33];
312 strncpy(trimlabel, CdromLabel, 32);
314 for (j = 31; j >= 0; j--)
315 if (trimlabel[j] == ' ')
321 static void make_cfg_fname(char *buf, size_t size, int is_game)
324 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
326 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
329 static void keys_write_all(FILE *f);
331 static int menu_write_config(int is_game)
333 char cfgfile[MAXPATHLEN];
337 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
338 f = fopen(cfgfile, "w");
340 printf("menu_write_config: failed to open: %s\n", cfgfile);
344 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
345 fprintf(f, "%s = ", config_data[i].name);
346 switch (config_data[i].len) {
348 fprintf(f, "%s\n", (char *)config_data[i].val);
351 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
354 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
357 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
360 printf("menu_write_config: unhandled len %d for %s\n",
361 config_data[i].len, config_data[i].name);
367 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
375 static void parse_str_val(char *cval, const char *src)
378 strncpy(cval, src, MAXPATHLEN);
379 cval[MAXPATHLEN - 1] = 0;
380 tmp = strchr(cval, '\n');
382 tmp = strchr(cval, '\r');
387 static void keys_load_all(const char *cfg);
389 static int menu_load_config(int is_game)
391 char cfgfile[MAXPATHLEN];
397 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
398 f = fopen(cfgfile, "r");
400 printf("menu_load_config: failed to open: %s\n", cfgfile);
404 fseek(f, 0, SEEK_END);
407 printf("bad size %ld: %s\n", size, cfgfile);
411 cfg = malloc(size + 1);
415 fseek(f, 0, SEEK_SET);
416 if (fread(cfg, 1, size, f) != size) {
417 printf("failed to read: %s\n", cfgfile);
422 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
426 tmp = strstr(cfg, config_data[i].name);
429 tmp += strlen(config_data[i].name);
430 if (strncmp(tmp, " = ", 3) != 0)
434 if (config_data[i].len == 0) {
435 parse_str_val(config_data[i].val, tmp);
440 val = strtoul(tmp, &tmp2, 16);
441 if (tmp2 == NULL || tmp == tmp2)
442 continue; // parse failed
444 switch (config_data[i].len) {
446 *(u8 *)config_data[i].val = val;
449 *(u16 *)config_data[i].val = val;
452 *(u32 *)config_data[i].val = val;
455 printf("menu_load_config: unhandled len %d for %s\n",
456 config_data[i].len, config_data[i].name);
462 char *tmp = strstr(cfg, "lastcdimg = ");
465 parse_str_val(last_selected_fname, tmp);
480 for (i = bios_sel = 0; bioses[i] != NULL; i++)
481 if (strcmp(Config.Bios, bioses[i]) == 0)
482 { bios_sel = i; break; }
484 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
485 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
486 { gpu_plugsel = i; break; }
488 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
489 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
490 { spu_plugsel = i; break; }
495 // rrrr rggg gggb bbbb
496 static unsigned short fname2color(const char *fname)
498 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
499 ".bz", ".znx", ".pbp", ".cbn" };
500 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
501 ".table", ".index", ".sbi" };
502 const char *ext = strrchr(fname, '.');
507 for (i = 0; i < array_size(cdimg_exts); i++)
508 if (strcasecmp(ext, cdimg_exts[i]) == 0)
510 for (i = 0; i < array_size(other_exts); i++)
511 if (strcasecmp(ext, other_exts[i]) == 0)
516 static void draw_savestate_bg(int slot);
518 static const char *filter_exts[] = {
519 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
522 #define MENU_ALIGN_LEFT
523 #ifdef __ARM_ARCH_7A__ // assume hires device
529 #define menu_init menu_init_common
530 #include "common/menu.c"
533 // a bit of black magic here
534 static void draw_savestate_bg(int slot)
536 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
538 char fname[MAXPATHLEN];
545 ret = get_state_filename(fname, sizeof(fname), slot);
549 f = gzopen(fname, "rb");
553 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
554 fprintf(stderr, "gzseek failed\n");
559 gpu = malloc(sizeof(*gpu));
565 ret = gzread(f, gpu, sizeof(*gpu));
567 if (ret != sizeof(*gpu)) {
568 fprintf(stderr, "gzread failed\n");
572 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
574 if (gpu->ulStatus & 0x800000)
575 goto out; // disabled
577 x = gpu->ulControl[5] & 0x3ff;
578 y = (gpu->ulControl[5] >> 10) & 0x1ff;
579 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
580 w = psx_widths[(gpu->ulStatus >> 16) & 7];
581 tmp = gpu->ulControl[7];
582 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
583 if (gpu->ulStatus & 0x80000) // doubleheight
586 x = max(0, g_menuscreen_w - w) & ~3;
587 y = max(0, g_menuscreen_h / 2 - h / 2);
588 w = min(g_menuscreen_w, w);
589 h = min(g_menuscreen_h, h);
590 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
592 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
593 if (gpu->ulStatus & 0x200000)
594 bgr888_to_rgb565(d, s, w * 3);
596 bgr555_to_rgb565(d, s, w * 2);
597 #ifndef __ARM_ARCH_7A__
598 // better darken this on small screens
599 menu_darken_bg(d, d, w * 2, 0);
607 // ---------- XXX: pandora specific -----------
609 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
610 static char **pnd_filter_list;
612 static void apply_filter(int which)
618 if (pnd_filter_list == NULL || which == old)
621 for (i = 0; i < which; i++)
622 if (pnd_filter_list[i] == NULL)
625 if (pnd_filter_list[i] == NULL)
628 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
633 static void apply_lcdrate(int pal)
641 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
642 pnd_script_base, pal ? 50 : 60);
647 static menu_entry e_menu_gfx_options[];
649 static void pnd_menu_init(void)
657 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
659 dir = opendir("/etc/pandora/conf/dss_fir");
661 perror("filter opendir");
674 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
683 mfilters = calloc(count + 1, sizeof(mfilters[0]));
684 if (mfilters == NULL)
688 for (i = 0; (ent = readdir(dir)); ) {
691 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
694 len = strlen(ent->d_name);
696 // skip pre-HF5 extra files
697 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
699 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
702 // have to cut "_up_h" for pre-HF5
703 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
706 if (len > sizeof(buff) - 1)
709 strncpy(buff, ent->d_name, len);
711 mfilters[i] = strdup(buff);
712 if (mfilters[i] != NULL)
717 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
718 e_menu_gfx_options[i].data = (void *)mfilters;
719 pnd_filter_list = mfilters;
722 void menu_finish(void)
724 plat_cpu_clock_apply(cpu_clock_st);
727 // -------------- key config --------------
729 me_bind_action me_ctrl_actions[] =
731 { "UP ", 1 << DKEY_UP},
732 { "DOWN ", 1 << DKEY_DOWN },
733 { "LEFT ", 1 << DKEY_LEFT },
734 { "RIGHT ", 1 << DKEY_RIGHT },
735 { "TRIANGLE", 1 << DKEY_TRIANGLE },
736 { "CIRCLE ", 1 << DKEY_CIRCLE },
737 { "CROSS ", 1 << DKEY_CROSS },
738 { "SQUARE ", 1 << DKEY_SQUARE },
739 { "L1 ", 1 << DKEY_L1 },
740 { "R1 ", 1 << DKEY_R1 },
741 { "L2 ", 1 << DKEY_L2 },
742 { "R2 ", 1 << DKEY_R2 },
743 { "L3 ", 1 << DKEY_L3 },
744 { "R3 ", 1 << DKEY_R3 },
745 { "START ", 1 << DKEY_START },
746 { "SELECT ", 1 << DKEY_SELECT },
750 me_bind_action emuctrl_actions[] =
752 { "Save State ", 1 << SACTION_SAVE_STATE },
753 { "Load State ", 1 << SACTION_LOAD_STATE },
754 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
755 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
756 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
757 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
758 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
759 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
760 { "Gun A button ", 1 << SACTION_GUN_A },
761 { "Gun B button ", 1 << SACTION_GUN_B },
762 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
763 #ifndef __ARM_ARCH_7A__ /* XXX */
764 { "Volume Up ", 1 << SACTION_VOLUME_UP },
765 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
770 static char *mystrip(char *str)
775 for (i = 0; i < len; i++)
776 if (str[i] != ' ') break;
777 if (i > 0) memmove(str, str + i, len - i + 1);
780 for (i = len - 1; i >= 0; i--)
781 if (str[i] != ' ') break;
787 static void get_line(char *d, size_t size, const char *s)
792 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
803 static void keys_write_all(FILE *f)
807 for (d = 0; d < IN_MAX_DEVS; d++)
809 const int *binds = in_get_dev_binds(d);
810 const char *name = in_get_dev_name(d, 0, 0);
813 if (binds == NULL || name == NULL)
816 fprintf(f, "binddev = %s\n", name);
817 in_get_config(d, IN_CFG_BIND_COUNT, &count);
819 for (k = 0; k < count; k++)
824 act[0] = act[31] = 0;
825 name = in_get_key_name(d, k);
827 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
828 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
829 mask = me_ctrl_actions[i].mask;
831 strncpy(act, me_ctrl_actions[i].name, 31);
832 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
835 mask = me_ctrl_actions[i].mask << 16;
837 strncpy(act, me_ctrl_actions[i].name, 31);
838 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
843 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
844 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
845 mask = emuctrl_actions[i].mask;
847 strncpy(act, emuctrl_actions[i].name, 31);
848 fprintf(f, "bind %s = %s\n", name, mystrip(act));
854 for (k = 0; k < array_size(in_adev); k++)
857 fprintf(f, "bind_analog = %d\n", k);
862 static int parse_bind_val(const char *val, int *type)
866 *type = IN_BINDTYPE_NONE;
870 if (strncasecmp(val, "player", 6) == 0)
872 int player, shift = 0;
873 player = atoi(val + 6) - 1;
875 if ((unsigned int)player > 1)
880 *type = IN_BINDTYPE_PLAYER12;
881 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
882 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
883 return me_ctrl_actions[i].mask << shift;
886 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
887 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
888 *type = IN_BINDTYPE_EMU;
889 return emuctrl_actions[i].mask;
896 static void keys_load_all(const char *cfg)
898 char dev[256], key[128], *act;
904 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
907 get_line(dev, sizeof(dev), p);
908 dev_id = in_config_parse_dev(dev);
910 printf("input: can't handle dev: %s\n", dev);
914 in_unbind_all(dev_id, -1, -1);
915 while ((p = strstr(p, "bind"))) {
916 if (strncmp(p, "binddev = ", 10) == 0)
919 if (strncmp(p, "bind_analog", 11) == 0) {
920 ret = sscanf(p, "bind_analog = %d", &bind);
923 printf("input: parse error: %16s..\n", p);
926 if ((unsigned int)bind >= array_size(in_adev)) {
927 printf("input: analog id %d out of range\n", bind);
930 in_adev[bind] = dev_id;
936 printf("input: parse error: %16s..\n", p);
940 get_line(key, sizeof(key), p);
941 act = strchr(key, '=');
943 printf("parse failed: %16s..\n", p);
951 bind = parse_bind_val(act, &bindtype);
952 if (bind != -1 && bind != 0) {
953 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
954 in_config_bind_key(dev_id, key, bind, bindtype);
957 lprintf("config: unhandled action \"%s\"\n", act);
963 static int key_config_loop_wrap(int id, int keys)
966 case MA_CTRL_PLAYER1:
967 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
969 case MA_CTRL_PLAYER2:
970 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
973 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
981 static const char *adevnames[IN_MAX_DEVS + 2];
982 static int stick_sel[2];
984 static menu_entry e_menu_keyconfig_analog[] =
986 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
987 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
988 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
989 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
990 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
991 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
995 static int key_config_analog(int id, int keys)
997 int i, d, count, sel = 0;
998 int sel2dev_map[IN_MAX_DEVS];
1000 memset(adevnames, 0, sizeof(adevnames));
1001 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1002 memset(stick_sel, 0, sizeof(stick_sel));
1004 adevnames[0] = "None";
1006 for (d = 0; d < IN_MAX_DEVS; d++)
1008 const char *name = in_get_dev_name(d, 0, 1);
1013 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1017 if (in_adev[0] == d) stick_sel[0] = i;
1018 if (in_adev[1] == d) stick_sel[1] = i;
1020 adevnames[i++] = name;
1022 adevnames[i] = NULL;
1024 me_loop(e_menu_keyconfig_analog, &sel);
1026 in_adev[0] = sel2dev_map[stick_sel[0]];
1027 in_adev[1] = sel2dev_map[stick_sel[1]];
1032 static const char *mgn_dev_name(int id, int *offs)
1034 const char *name = NULL;
1037 if (id == MA_CTRL_DEV_FIRST)
1040 for (; it < IN_MAX_DEVS; it++) {
1041 name = in_get_dev_name(it, 1, 1);
1050 static const char *mgn_saveloadcfg(int id, int *offs)
1055 static int mh_savecfg(int id, int keys)
1057 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1058 me_update_msg("config saved");
1060 me_update_msg("failed to write config");
1065 static int mh_input_rescan(int id, int keys)
1067 //menu_sync_config();
1069 me_update_msg("rescan complete.");
1074 static const char *men_in_type_sel[] = {
1075 "Standard (SCPH-1080)",
1076 "Analog (SCPH-1150)",
1080 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1081 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1082 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1084 static menu_entry e_menu_keyconfig[] =
1086 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1087 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1088 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1089 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1091 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1092 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1093 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1094 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1095 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1096 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1097 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1098 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1099 mee_handler ("Rescan devices:", mh_input_rescan),
1101 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1102 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1103 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1104 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1105 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1106 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1107 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1111 static int menu_loop_keyconfig(int id, int keys)
1115 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1116 me_loop(e_menu_keyconfig, &sel);
1120 // ------------ gfx options menu ------------
1122 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1123 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1124 "using d-pad or move it using R+d-pad";
1125 static const char *men_dummy[] = { NULL };
1127 static int menu_loop_cscaler(int id, int keys)
1131 scaling = SCALE_CUSTOM;
1133 omap_enable_layer(1);
1138 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1139 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1140 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1143 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1144 if (inp & PBTN_UP) g_layer_y--;
1145 if (inp & PBTN_DOWN) g_layer_y++;
1146 if (inp & PBTN_LEFT) g_layer_x--;
1147 if (inp & PBTN_RIGHT) g_layer_x++;
1148 if (!(inp & PBTN_R)) {
1149 if (inp & PBTN_UP) g_layer_h += 2;
1150 if (inp & PBTN_DOWN) g_layer_h -= 2;
1151 if (inp & PBTN_LEFT) g_layer_w += 2;
1152 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1154 if (inp & (PBTN_MOK|PBTN_MBACK))
1157 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1158 if (g_layer_x < 0) g_layer_x = 0;
1159 if (g_layer_x > 640) g_layer_x = 640;
1160 if (g_layer_y < 0) g_layer_y = 0;
1161 if (g_layer_y > 420) g_layer_y = 420;
1162 if (g_layer_w < 160) g_layer_w = 160;
1163 if (g_layer_h < 60) g_layer_h = 60;
1164 if (g_layer_x + g_layer_w > 800)
1165 g_layer_w = 800 - g_layer_x;
1166 if (g_layer_y + g_layer_h > 480)
1167 g_layer_h = 480 - g_layer_y;
1168 omap_enable_layer(1);
1172 omap_enable_layer(0);
1177 static menu_entry e_menu_gfx_options[] =
1179 mee_enum ("Scaler", 0, scaling, men_scaler),
1180 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1181 // mee_onoff ("Vsync", 0, vsync, 1),
1182 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1186 static int menu_loop_gfx_options(int id, int keys)
1190 me_loop(e_menu_gfx_options, &sel);
1195 // ------------ bios/plugins ------------
1199 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1200 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1202 static menu_entry e_menu_plugin_gpu_neon[] =
1204 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1208 static int menu_loop_plugin_gpu_neon(int id, int keys)
1211 me_loop(e_menu_plugin_gpu_neon, &sel);
1217 static menu_entry e_menu_plugin_gpu_unai[] =
1219 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1220 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1221 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1222 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1226 static int menu_loop_plugin_gpu_unai(int id, int keys)
1229 me_loop(e_menu_plugin_gpu_unai, &sel);
1233 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1234 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1235 static const char h_gpu_1[] = "Capcom fighting games";
1236 static const char h_gpu_2[] = "Black screens in Lunar";
1237 static const char h_gpu_3[] = "Compatibility mode";
1238 static const char h_gpu_6[] = "Pandemonium 2";
1239 //static const char h_gpu_7[] = "Skip every second frame";
1240 static const char h_gpu_8[] = "Needed by Dark Forces";
1241 static const char h_gpu_9[] = "better g-colors, worse textures";
1242 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1244 static menu_entry e_menu_plugin_gpu_peops[] =
1246 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1247 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1248 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1249 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1250 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1251 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1252 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1253 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1254 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1255 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1259 static int menu_loop_plugin_gpu_peops(int id, int keys)
1262 me_loop(e_menu_plugin_gpu_peops, &sel);
1266 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1267 static const char h_spu_volboost[] = "Large values cause distortion";
1268 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1269 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1271 static menu_entry e_menu_plugin_spu[] =
1273 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1274 mee_onoff ("Reverb", 0, iUseReverb, 2),
1275 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1276 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1277 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1278 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1282 static int menu_loop_plugin_spu(int id, int keys)
1285 me_loop(e_menu_plugin_spu, &sel);
1289 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1290 "savestates and can't be changed there. Must save\n"
1291 "config and reload the game for change to take effect";
1292 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1293 "for plugin change to take effect";
1294 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1295 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1296 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1298 static menu_entry e_menu_plugin_options[] =
1300 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1301 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1302 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1304 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1306 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1307 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1308 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1312 static menu_entry e_menu_main2[];
1314 static int menu_loop_plugin_options(int id, int keys)
1317 me_loop(e_menu_plugin_options, &sel);
1319 // sync BIOS/plugins
1320 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1321 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1322 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1323 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1328 // ------------ adv options menu ------------
1330 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1331 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1332 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1333 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1335 static menu_entry e_menu_speed_hacks[] =
1337 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1338 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1339 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1340 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1344 static int menu_loop_speed_hacks(int id, int keys)
1347 me_loop(e_menu_speed_hacks, &sel);
1351 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1352 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1353 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1354 "(green: normal, red: fmod, blue: noise)";
1355 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1356 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1357 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1358 "(proper .cue/.bin dump is needed otherwise)";
1359 static const char h_cfg_sio[] = "You should not need this, breaks games";
1360 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1361 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1362 "(timing hack, breaks other games)";
1363 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1364 "(timing hack, breaks other games)";
1365 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1366 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1367 "Might be useful to overcome some dynarec bugs";
1368 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1369 "must reload game for any change to take effect";
1371 static menu_entry e_menu_adv_options[] =
1373 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1374 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1375 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1376 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1377 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1378 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1379 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1380 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1381 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1382 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1383 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1384 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1388 static int menu_loop_adv_options(int id, int keys)
1391 me_loop(e_menu_adv_options, &sel);
1395 // ------------ options menu ------------
1397 static int mh_restore_defaults(int id, int keys)
1399 menu_set_defconfig();
1400 me_update_msg("defaults restored");
1404 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1405 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1407 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1408 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1409 "loading state or both";
1411 static const char h_restore_def[] = "Switches back to default / recommended\n"
1413 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1415 static menu_entry e_menu_options[] =
1417 // mee_range ("Save slot", 0, state_slot, 0, 9),
1418 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1419 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1420 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1421 mee_enum ("Region", 0, region, men_region),
1422 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1423 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1424 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1425 mee_handler ("[Advanced]", menu_loop_adv_options),
1426 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1427 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1428 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1432 static int menu_loop_options(int id, int keys)
1437 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1438 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1439 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1441 me_loop(e_menu_options, &sel);
1446 // ------------ debug menu ------------
1448 static void draw_frame_debug(GPUFreeze_t *gpuf)
1450 int w = min(g_menuscreen_w, 1024);
1451 int h = min(g_menuscreen_h, 512);
1452 u16 *d = g_menuscreen_ptr;
1453 u16 *s = (u16 *)gpuf->psxVRam;
1457 gpuf->ulFreezeVersion = 1;
1458 if (GPU_freeze != NULL)
1459 GPU_freeze(1, gpuf);
1461 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1462 bgr555_to_rgb565(d, s, w * 2);
1464 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1465 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1466 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1467 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1468 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1471 static void debug_menu_loop(void)
1476 gpuf = malloc(sizeof(*gpuf));
1483 draw_frame_debug(gpuf);
1486 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1487 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1488 if (inp & PBTN_MBACK)
1495 // --------- memcard manager ---------
1497 static void draw_mc_icon(int dx, int dy, const u16 *s)
1502 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1504 for (y = 0; y < 16; y++, s += 16) {
1505 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1506 for (x = 0; x < 16; x++) {
1508 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1509 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1515 static void draw_mc_bg(void)
1517 McdBlock *blocks1, *blocks2;
1521 blocks1 = malloc(15 * sizeof(blocks1[0]));
1522 blocks2 = malloc(15 * sizeof(blocks1[0]));
1523 if (blocks1 == NULL || blocks2 == NULL)
1526 for (i = 0; i < 15; i++) {
1527 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1528 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1533 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1535 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1539 maxicons = g_menuscreen_h / 32;
1542 row2 = g_menuscreen_w / 2;
1543 for (i = 0; i < maxicons; i++) {
1544 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1545 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1547 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1548 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1551 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1559 static void handle_memcard_sel(void)
1562 if (memcard1_sel != 0)
1563 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1565 if (memcard2_sel != 0)
1566 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1567 LoadMcds(Config.Mcd1, Config.Mcd2);
1571 static menu_entry e_memcard_options[] =
1573 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1574 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1578 static int menu_loop_memcards(int id, int keys)
1584 memcard1_sel = memcard2_sel = 0;
1585 p = strrchr(Config.Mcd1, '/');
1587 for (i = 0; memcards[i] != NULL; i++)
1588 if (strcmp(p + 1, memcards[i]) == 0)
1589 { memcard1_sel = i; break; }
1590 p = strrchr(Config.Mcd2, '/');
1592 for (i = 0; memcards[i] != NULL; i++)
1593 if (strcmp(p + 1, memcards[i]) == 0)
1594 { memcard2_sel = i; break; }
1596 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1598 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1603 // --------- main menu help ----------
1605 static void menu_bios_warn(void)
1608 static const char msg[] =
1609 "You don't seem to have copied any BIOS\n"
1611 #ifdef __ARM_ARCH_7A__ // XXX
1612 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1614 "pcsx_rearmed/bios/\n\n"
1616 "While many games work fine with fake\n"
1617 "(HLE) BIOS, others (like MGS and FF8)\n"
1618 "require BIOS to work.\n"
1619 "After copying the file, you'll also need\n"
1620 "to select it in the emu's menu:\n"
1621 "options->[BIOS/Plugins]\n\n"
1622 "The file is usually named SCPH1001.BIN,\n"
1623 "but other not compressed files can be\n"
1625 "Press (B) or (X) to continue";
1629 draw_menu_message(msg, NULL);
1631 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1632 if (inp & (PBTN_MBACK|PBTN_MOK))
1637 // ------------ main menu ------------
1641 static void draw_frame_main(void)
1648 if (CdromId[0] != 0) {
1649 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1650 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1651 Config.HLE ? "HLE" : "BIOS");
1652 smalltext_out16(4, 1, buff, 0x105f);
1657 tmp = localtime(<ime);
1658 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1659 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1660 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1664 static void draw_frame_credits(void)
1666 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1669 static const char credits_text[] =
1671 "(C) 1999-2003 PCSX Team\n"
1672 "(C) 2005-2009 PCSX-df Team\n"
1673 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1674 "ARM recompiler (C) 2009-2011 Ari64\n"
1676 "ARM NEON GPU (c) 2011 Exophase\n"
1678 "PEOpS GPU and SPU by Pete Bernert\n"
1679 " and the P.E.Op.S. team\n"
1680 "PCSX4ALL plugin by PCSX4ALL team\n"
1681 " Chui, Franxis, Unai\n\n"
1682 "integration, optimization and\n"
1683 " frontend (C) 2010-2011 notaz\n";
1685 static int reset_game(void)
1688 if (bios_sel == 0 && !Config.HLE)
1694 if (CheckCdrom() != -1) {
1700 static int reload_plugins(const char *cdimg)
1706 set_cd_image(cdimg);
1708 pcnt_hook_plugins();
1710 if (OpenPlugins() == -1) {
1711 me_update_msg("failed to open plugins");
1714 plugin_call_rearmed_cbs();
1716 cdrIsoMultidiskCount = 1;
1718 CdromLabel[0] = '\0';
1723 static int run_bios(void)
1729 if (reload_plugins(NULL) != 0)
1737 static int run_exe(void)
1741 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1746 if (reload_plugins(NULL) != 0)
1750 if (Load(fname) != 0) {
1751 me_update_msg("exe load failed, bad file?");
1760 static int run_cd_image(const char *fname)
1763 reload_plugins(fname);
1765 // always autodetect, menu_sync_config will override as needed
1768 if (CheckCdrom() == -1) {
1769 // Only check the CD if we are starting the console with a CD
1771 me_update_msg("unsupported/invalid CD image");
1777 // Read main executable directly from CDRom and start it
1778 if (LoadCdrom() == -1) {
1780 me_update_msg("failed to load CD image");
1785 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1790 static int romsel_run(void)
1792 int prev_gpu, prev_spu;
1795 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1799 printf("selected file: %s\n", fname);
1801 new_dynarec_clear_full();
1803 if (run_cd_image(fname) != 0)
1806 prev_gpu = gpu_plugsel;
1807 prev_spu = spu_plugsel;
1808 if (menu_load_config(1) != 0)
1809 menu_load_config(0);
1811 // check for plugin changes, have to repeat
1812 // loading if game config changed plugins to reload them
1813 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1814 printf("plugin change detected, reloading plugins..\n");
1815 if (run_cd_image(fname) != 0)
1820 printf("note: running without BIOS, expect compatibility problems\n");
1822 strcpy(last_selected_fname, rom_fname_reload);
1826 static int swap_cd_image(void)
1830 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1834 printf("selected file: %s\n", fname);
1837 CdromLabel[0] = '\0';
1839 set_cd_image(fname);
1840 if (ReloadCdromPlugin() < 0) {
1841 me_update_msg("failed to load cdr plugin");
1844 if (CDR_open() < 0) {
1845 me_update_msg("failed to open cdr plugin");
1849 SetCdOpenCaseTime(time(NULL) + 2);
1852 strcpy(last_selected_fname, rom_fname_reload);
1856 static int swap_cd_multidisk(void)
1858 cdrIsoMultidiskSelect++;
1860 CdromLabel[0] = '\0';
1863 if (CDR_open() < 0) {
1864 me_update_msg("failed to open cdr plugin");
1868 SetCdOpenCaseTime(time(NULL) + 2);
1874 static int main_menu_handler(int id, int keys)
1878 case MA_MAIN_RESUME_GAME:
1882 case MA_MAIN_SAVE_STATE:
1884 return menu_loop_savestate(0);
1886 case MA_MAIN_LOAD_STATE:
1888 return menu_loop_savestate(1);
1890 case MA_MAIN_RESET_GAME:
1891 if (ready_to_go && reset_game() == 0)
1894 case MA_MAIN_LOAD_ROM:
1895 if (romsel_run() == 0)
1898 case MA_MAIN_SWAP_CD:
1899 if (swap_cd_image() == 0)
1902 case MA_MAIN_SWAP_CD_MULTI:
1903 if (swap_cd_multidisk() == 0)
1906 case MA_MAIN_RUN_BIOS:
1907 if (run_bios() == 0)
1910 case MA_MAIN_RUN_EXE:
1914 case MA_MAIN_CREDITS:
1915 draw_menu_message(credits_text, draw_frame_credits);
1916 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1922 lprintf("%s: something unknown selected\n", __FUNCTION__);
1929 static menu_entry e_menu_main2[] =
1931 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1932 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1933 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1934 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1935 mee_handler ("Memcard manager", menu_loop_memcards),
1939 static int main_menu2_handler(int id, int keys)
1943 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1944 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1945 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1947 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1950 static const char h_extra[] = "Change CD, manage memcards..\n";
1952 static menu_entry e_menu_main[] =
1956 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1957 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1958 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1959 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1960 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1961 mee_handler ("Options", menu_loop_options),
1962 mee_handler ("Controls", menu_loop_keyconfig),
1963 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1964 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1965 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1969 // ----------------------------
1971 static void menu_leave_emu(void);
1973 void menu_loop(void)
1979 if (bioses[1] == NULL && !warned_about_bios) {
1981 warned_about_bios = 1;
1984 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1985 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1986 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1987 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1989 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1992 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1993 } while (!ready_to_go);
1995 /* wait until menu, ok, back is released */
1996 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1999 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2004 static int qsort_strcmp(const void *p1, const void *p2)
2006 char * const *s1 = (char * const *)p1;
2007 char * const *s2 = (char * const *)p2;
2008 return strcasecmp(*s1, *s2);
2011 static void scan_bios_plugins(void)
2013 char fname[MAXPATHLEN];
2015 int bios_i, gpu_i, spu_i, mc_i;
2020 gpu_plugins[0] = "builtin_gpu";
2021 spu_plugins[0] = "builtin_spu";
2022 memcards[0] = "(none)";
2023 bios_i = gpu_i = spu_i = mc_i = 1;
2025 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2026 dir = opendir(fname);
2028 perror("scan_bios_plugins bios opendir");
2043 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2046 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2047 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2048 printf("bad BIOS file: %s\n", ent->d_name);
2052 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2053 bioses[bios_i++] = strdup(ent->d_name);
2057 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2063 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2064 dir = opendir(fname);
2066 perror("scan_bios_plugins plugins opendir");
2080 p = strstr(ent->d_name, ".so");
2084 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2085 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2087 fprintf(stderr, "%s\n", dlerror());
2091 // now what do we have here?
2092 tmp = dlsym(h, "GPUinit");
2095 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2096 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2100 tmp = dlsym(h, "SPUinit");
2103 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2104 spu_plugins[spu_i++] = strdup(ent->d_name);
2108 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2115 dir = opendir("." MEMCARD_DIR);
2117 perror("scan_bios_plugins memcards opendir");
2132 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2135 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2136 if (stat(fname, &st) != 0) {
2137 printf("bad memcard file: %s\n", ent->d_name);
2141 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2142 memcards[mc_i++] = strdup(ent->d_name);
2146 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2150 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2155 void menu_init(void)
2157 char buff[MAXPATHLEN];
2159 strcpy(last_selected_fname, "/media");
2161 scan_bios_plugins();
2165 menu_set_defconfig();
2166 menu_load_config(0);
2171 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2172 if (g_menubg_src_ptr == NULL)
2174 emu_make_path(buff, "skin/background.png", sizeof(buff));
2175 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2177 #ifndef __ARM_ARCH_7A__ /* XXX */
2178 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2179 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2181 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2182 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2186 void menu_notify_mode_change(int w, int h, int bpp)
2197 g_layer_w = w; g_layer_h = h;
2201 if (h > g_menuscreen_h || (240 < h && h <= 360))
2202 goto fractional_4_3;
2204 // 4:3 that prefers integer scaling
2205 imult = g_menuscreen_h / h;
2206 g_layer_w = w * imult;
2207 g_layer_h = h * imult;
2208 mult = (float)g_layer_w / (float)g_layer_h;
2209 if (mult < 1.25f || mult > 1.666f)
2210 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2211 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2216 mult = 240.0f / (float)h * 4.0f / 3.0f;
2219 g_layer_w = mult * (float)g_menuscreen_h;
2220 g_layer_h = g_menuscreen_h;
2221 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2224 case SCALE_FULLSCREEN:
2225 g_layer_w = g_menuscreen_w;
2226 g_layer_h = g_menuscreen_h;
2233 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2234 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2235 if (g_layer_x < 0) g_layer_x = 0;
2236 if (g_layer_y < 0) g_layer_y = 0;
2237 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2238 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2241 static void menu_leave_emu(void)
2243 if (GPU_close != NULL) {
2244 int ret = GPU_close();
2246 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2249 plat_video_menu_enter(ready_to_go);
2251 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2252 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2253 int x = max(0, g_menuscreen_w - last_psx_w);
2254 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2255 int w = min(g_menuscreen_w, last_psx_w);
2256 int h = min(g_menuscreen_h, last_psx_h);
2257 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2258 u16 *s = pl_vout_buf;
2260 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2261 menu_darken_bg(d, s, w, 0);
2265 cpu_clock = plat_cpu_clock_get();
2268 void menu_prepare_emu(void)
2270 R3000Acpu *prev_cpu = psxCpu;
2272 plat_video_menu_leave();
2274 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2276 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2277 if (psxCpu != prev_cpu)
2278 // note that this does not really reset, just clears drc caches
2281 // core doesn't care about Config.Cdda changes,
2282 // so handle them manually here
2287 apply_lcdrate(Config.PsxType);
2288 apply_filter(filter);
2289 plat_cpu_clock_apply(cpu_clock);
2291 // push config to GPU plugin
2292 plugin_call_rearmed_cbs();
2294 if (GPU_open != NULL) {
2295 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2297 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2303 void me_update_msg(const char *msg)
2305 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2306 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2308 menu_error_time = plat_get_ticks_ms();
2309 lprintf("msg: %s\n", menu_error_msg);