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_V(iUseReverb, 3),
294 CE_INTVAL_V(iXAPitch, 3),
295 CE_INTVAL_V(iUseInterpolation, 3),
296 CE_INTVAL_V(iSPUIRQWait, 3),
297 CE_INTVAL_V(iUseTimer, 3),
298 CE_INTVAL(warned_about_bios),
299 CE_INTVAL(in_evdev_allow_abs_only),
300 CE_INTVAL(volume_boost),
301 CE_INTVAL(psx_clock),
302 CE_INTVAL(new_dynarec_hacks),
303 CE_INTVAL(in_enable_vibration),
306 static char *get_cd_label(void)
308 static char trimlabel[33];
311 strncpy(trimlabel, CdromLabel, 32);
313 for (j = 31; j >= 0; j--)
314 if (trimlabel[j] == ' ')
320 static void make_cfg_fname(char *buf, size_t size, int is_game)
323 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
325 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
328 static void keys_write_all(FILE *f);
330 static int menu_write_config(int is_game)
332 char cfgfile[MAXPATHLEN];
336 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
337 f = fopen(cfgfile, "w");
339 printf("menu_write_config: failed to open: %s\n", cfgfile);
343 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
344 fprintf(f, "%s = ", config_data[i].name);
345 switch (config_data[i].len) {
347 fprintf(f, "%s\n", (char *)config_data[i].val);
350 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
353 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
356 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
359 printf("menu_write_config: unhandled len %d for %s\n",
360 config_data[i].len, config_data[i].name);
366 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
374 static void parse_str_val(char *cval, const char *src)
377 strncpy(cval, src, MAXPATHLEN);
378 cval[MAXPATHLEN - 1] = 0;
379 tmp = strchr(cval, '\n');
381 tmp = strchr(cval, '\r');
386 static void keys_load_all(const char *cfg);
388 static int menu_load_config(int is_game)
390 char cfgfile[MAXPATHLEN];
396 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
397 f = fopen(cfgfile, "r");
399 printf("menu_load_config: failed to open: %s\n", cfgfile);
403 fseek(f, 0, SEEK_END);
406 printf("bad size %ld: %s\n", size, cfgfile);
410 cfg = malloc(size + 1);
414 fseek(f, 0, SEEK_SET);
415 if (fread(cfg, 1, size, f) != size) {
416 printf("failed to read: %s\n", cfgfile);
421 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
425 tmp = strstr(cfg, config_data[i].name);
428 tmp += strlen(config_data[i].name);
429 if (strncmp(tmp, " = ", 3) != 0)
433 if (config_data[i].len == 0) {
434 parse_str_val(config_data[i].val, tmp);
439 val = strtoul(tmp, &tmp2, 16);
440 if (tmp2 == NULL || tmp == tmp2)
441 continue; // parse failed
443 switch (config_data[i].len) {
445 *(u8 *)config_data[i].val = val;
448 *(u16 *)config_data[i].val = val;
451 *(u32 *)config_data[i].val = val;
454 printf("menu_load_config: unhandled len %d for %s\n",
455 config_data[i].len, config_data[i].name);
461 char *tmp = strstr(cfg, "lastcdimg = ");
464 parse_str_val(last_selected_fname, tmp);
479 for (i = bios_sel = 0; bioses[i] != NULL; i++)
480 if (strcmp(Config.Bios, bioses[i]) == 0)
481 { bios_sel = i; break; }
483 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
484 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
485 { gpu_plugsel = i; break; }
487 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
488 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
489 { spu_plugsel = i; break; }
494 // rrrr rggg gggb bbbb
495 static unsigned short fname2color(const char *fname)
497 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
498 ".bz", ".znx", ".pbp", ".cbn" };
499 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
500 ".table", ".index", ".sbi" };
501 const char *ext = strrchr(fname, '.');
506 for (i = 0; i < array_size(cdimg_exts); i++)
507 if (strcasecmp(ext, cdimg_exts[i]) == 0)
509 for (i = 0; i < array_size(other_exts); i++)
510 if (strcasecmp(ext, other_exts[i]) == 0)
515 static void draw_savestate_bg(int slot);
517 static const char *filter_exts[] = {
518 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
521 #define MENU_ALIGN_LEFT
522 #ifdef __ARM_ARCH_7A__ // assume hires device
528 #define menu_init menu_init_common
529 #include "common/menu.c"
532 // a bit of black magic here
533 static void draw_savestate_bg(int slot)
535 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
537 char fname[MAXPATHLEN];
544 ret = get_state_filename(fname, sizeof(fname), slot);
548 f = gzopen(fname, "rb");
552 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
553 fprintf(stderr, "gzseek failed\n");
558 gpu = malloc(sizeof(*gpu));
564 ret = gzread(f, gpu, sizeof(*gpu));
566 if (ret != sizeof(*gpu)) {
567 fprintf(stderr, "gzread failed\n");
571 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
573 if (gpu->ulStatus & 0x800000)
574 goto out; // disabled
576 x = gpu->ulControl[5] & 0x3ff;
577 y = (gpu->ulControl[5] >> 10) & 0x1ff;
578 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
579 w = psx_widths[(gpu->ulStatus >> 16) & 7];
580 tmp = gpu->ulControl[7];
581 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
582 if (gpu->ulStatus & 0x80000) // doubleheight
585 x = max(0, g_menuscreen_w - w) & ~3;
586 y = max(0, g_menuscreen_h / 2 - h / 2);
587 w = min(g_menuscreen_w, w);
588 h = min(g_menuscreen_h, h);
589 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
591 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
592 if (gpu->ulStatus & 0x200000)
593 bgr888_to_rgb565(d, s, w * 3);
595 bgr555_to_rgb565(d, s, w * 2);
596 #ifndef __ARM_ARCH_7A__
597 // better darken this on small screens
598 menu_darken_bg(d, d, w * 2, 0);
606 // ---------- XXX: pandora specific -----------
608 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
609 static char **pnd_filter_list;
611 static void apply_filter(int which)
617 if (pnd_filter_list == NULL || which == old)
620 for (i = 0; i < which; i++)
621 if (pnd_filter_list[i] == NULL)
624 if (pnd_filter_list[i] == NULL)
627 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
632 static void apply_lcdrate(int pal)
640 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
641 pnd_script_base, pal ? 50 : 60);
646 static menu_entry e_menu_gfx_options[];
648 static void pnd_menu_init(void)
656 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
658 dir = opendir("/etc/pandora/conf/dss_fir");
660 perror("filter opendir");
673 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
682 mfilters = calloc(count + 1, sizeof(mfilters[0]));
683 if (mfilters == NULL)
687 for (i = 0; (ent = readdir(dir)); ) {
690 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
693 len = strlen(ent->d_name);
695 // skip pre-HF5 extra files
696 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
698 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
701 // have to cut "_up_h" for pre-HF5
702 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
705 if (len > sizeof(buff) - 1)
708 strncpy(buff, ent->d_name, len);
710 mfilters[i] = strdup(buff);
711 if (mfilters[i] != NULL)
716 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
717 e_menu_gfx_options[i].data = (void *)mfilters;
718 pnd_filter_list = mfilters;
721 void menu_finish(void)
723 plat_cpu_clock_apply(cpu_clock_st);
726 // -------------- key config --------------
728 me_bind_action me_ctrl_actions[] =
730 { "UP ", 1 << DKEY_UP},
731 { "DOWN ", 1 << DKEY_DOWN },
732 { "LEFT ", 1 << DKEY_LEFT },
733 { "RIGHT ", 1 << DKEY_RIGHT },
734 { "TRIANGLE", 1 << DKEY_TRIANGLE },
735 { "CIRCLE ", 1 << DKEY_CIRCLE },
736 { "CROSS ", 1 << DKEY_CROSS },
737 { "SQUARE ", 1 << DKEY_SQUARE },
738 { "L1 ", 1 << DKEY_L1 },
739 { "R1 ", 1 << DKEY_R1 },
740 { "L2 ", 1 << DKEY_L2 },
741 { "R2 ", 1 << DKEY_R2 },
742 { "L3 ", 1 << DKEY_L3 },
743 { "R3 ", 1 << DKEY_R3 },
744 { "START ", 1 << DKEY_START },
745 { "SELECT ", 1 << DKEY_SELECT },
749 me_bind_action emuctrl_actions[] =
751 { "Save State ", 1 << SACTION_SAVE_STATE },
752 { "Load State ", 1 << SACTION_LOAD_STATE },
753 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
754 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
755 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
756 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
757 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
758 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
759 { "Gun A button ", 1 << SACTION_GUN_A },
760 { "Gun B button ", 1 << SACTION_GUN_B },
761 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
762 #ifndef __ARM_ARCH_7A__ /* XXX */
763 { "Volume Up ", 1 << SACTION_VOLUME_UP },
764 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
769 static char *mystrip(char *str)
774 for (i = 0; i < len; i++)
775 if (str[i] != ' ') break;
776 if (i > 0) memmove(str, str + i, len - i + 1);
779 for (i = len - 1; i >= 0; i--)
780 if (str[i] != ' ') break;
786 static void get_line(char *d, size_t size, const char *s)
791 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
802 static void keys_write_all(FILE *f)
806 for (d = 0; d < IN_MAX_DEVS; d++)
808 const int *binds = in_get_dev_binds(d);
809 const char *name = in_get_dev_name(d, 0, 0);
812 if (binds == NULL || name == NULL)
815 fprintf(f, "binddev = %s\n", name);
816 in_get_config(d, IN_CFG_BIND_COUNT, &count);
818 for (k = 0; k < count; k++)
823 act[0] = act[31] = 0;
824 name = in_get_key_name(d, k);
826 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
827 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
828 mask = me_ctrl_actions[i].mask;
830 strncpy(act, me_ctrl_actions[i].name, 31);
831 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
834 mask = me_ctrl_actions[i].mask << 16;
836 strncpy(act, me_ctrl_actions[i].name, 31);
837 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
842 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
843 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
844 mask = emuctrl_actions[i].mask;
846 strncpy(act, emuctrl_actions[i].name, 31);
847 fprintf(f, "bind %s = %s\n", name, mystrip(act));
853 for (k = 0; k < array_size(in_adev); k++)
856 fprintf(f, "bind_analog = %d\n", k);
861 static int parse_bind_val(const char *val, int *type)
865 *type = IN_BINDTYPE_NONE;
869 if (strncasecmp(val, "player", 6) == 0)
871 int player, shift = 0;
872 player = atoi(val + 6) - 1;
874 if ((unsigned int)player > 1)
879 *type = IN_BINDTYPE_PLAYER12;
880 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
881 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
882 return me_ctrl_actions[i].mask << shift;
885 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
886 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
887 *type = IN_BINDTYPE_EMU;
888 return emuctrl_actions[i].mask;
895 static void keys_load_all(const char *cfg)
897 char dev[256], key[128], *act;
903 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
906 get_line(dev, sizeof(dev), p);
907 dev_id = in_config_parse_dev(dev);
909 printf("input: can't handle dev: %s\n", dev);
913 in_unbind_all(dev_id, -1, -1);
914 while ((p = strstr(p, "bind"))) {
915 if (strncmp(p, "binddev = ", 10) == 0)
918 if (strncmp(p, "bind_analog", 11) == 0) {
919 ret = sscanf(p, "bind_analog = %d", &bind);
922 printf("input: parse error: %16s..\n", p);
925 if ((unsigned int)bind >= array_size(in_adev)) {
926 printf("input: analog id %d out of range\n", bind);
929 in_adev[bind] = dev_id;
935 printf("input: parse error: %16s..\n", p);
939 get_line(key, sizeof(key), p);
940 act = strchr(key, '=');
942 printf("parse failed: %16s..\n", p);
950 bind = parse_bind_val(act, &bindtype);
951 if (bind != -1 && bind != 0) {
952 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
953 in_config_bind_key(dev_id, key, bind, bindtype);
956 lprintf("config: unhandled action \"%s\"\n", act);
962 static int key_config_loop_wrap(int id, int keys)
965 case MA_CTRL_PLAYER1:
966 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
968 case MA_CTRL_PLAYER2:
969 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
972 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
980 static const char *adevnames[IN_MAX_DEVS + 2];
981 static int stick_sel[2];
983 static menu_entry e_menu_keyconfig_analog[] =
985 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
986 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
987 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
988 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
989 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
990 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
994 static int key_config_analog(int id, int keys)
996 int i, d, count, sel = 0;
997 int sel2dev_map[IN_MAX_DEVS];
999 memset(adevnames, 0, sizeof(adevnames));
1000 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1001 memset(stick_sel, 0, sizeof(stick_sel));
1003 adevnames[0] = "None";
1005 for (d = 0; d < IN_MAX_DEVS; d++)
1007 const char *name = in_get_dev_name(d, 0, 1);
1012 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1016 if (in_adev[0] == d) stick_sel[0] = i;
1017 if (in_adev[1] == d) stick_sel[1] = i;
1019 adevnames[i++] = name;
1021 adevnames[i] = NULL;
1023 me_loop(e_menu_keyconfig_analog, &sel);
1025 in_adev[0] = sel2dev_map[stick_sel[0]];
1026 in_adev[1] = sel2dev_map[stick_sel[1]];
1031 static const char *mgn_dev_name(int id, int *offs)
1033 const char *name = NULL;
1036 if (id == MA_CTRL_DEV_FIRST)
1039 for (; it < IN_MAX_DEVS; it++) {
1040 name = in_get_dev_name(it, 1, 1);
1049 static const char *mgn_saveloadcfg(int id, int *offs)
1054 static int mh_savecfg(int id, int keys)
1056 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1057 me_update_msg("config saved");
1059 me_update_msg("failed to write config");
1064 static int mh_input_rescan(int id, int keys)
1066 //menu_sync_config();
1068 me_update_msg("rescan complete.");
1073 static const char *men_in_type_sel[] = {
1074 "Standard (SCPH-1080)",
1075 "Analog (SCPH-1150)",
1079 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1080 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1081 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1083 static menu_entry e_menu_keyconfig[] =
1085 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1086 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1087 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1088 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1090 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1091 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1092 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1093 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1094 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1095 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1096 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1097 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1098 mee_handler ("Rescan devices:", mh_input_rescan),
1100 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1101 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1110 static int menu_loop_keyconfig(int id, int keys)
1114 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1115 me_loop(e_menu_keyconfig, &sel);
1119 // ------------ gfx options menu ------------
1121 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1122 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1123 "using d-pad or move it using R+d-pad";
1124 static const char *men_dummy[] = { NULL };
1126 static int menu_loop_cscaler(int id, int keys)
1130 scaling = SCALE_CUSTOM;
1132 omap_enable_layer(1);
1137 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1138 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1139 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1142 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1143 if (inp & PBTN_UP) g_layer_y--;
1144 if (inp & PBTN_DOWN) g_layer_y++;
1145 if (inp & PBTN_LEFT) g_layer_x--;
1146 if (inp & PBTN_RIGHT) g_layer_x++;
1147 if (!(inp & PBTN_R)) {
1148 if (inp & PBTN_UP) g_layer_h += 2;
1149 if (inp & PBTN_DOWN) g_layer_h -= 2;
1150 if (inp & PBTN_LEFT) g_layer_w += 2;
1151 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1153 if (inp & (PBTN_MOK|PBTN_MBACK))
1156 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1157 if (g_layer_x < 0) g_layer_x = 0;
1158 if (g_layer_x > 640) g_layer_x = 640;
1159 if (g_layer_y < 0) g_layer_y = 0;
1160 if (g_layer_y > 420) g_layer_y = 420;
1161 if (g_layer_w < 160) g_layer_w = 160;
1162 if (g_layer_h < 60) g_layer_h = 60;
1163 if (g_layer_x + g_layer_w > 800)
1164 g_layer_w = 800 - g_layer_x;
1165 if (g_layer_y + g_layer_h > 480)
1166 g_layer_h = 480 - g_layer_y;
1167 omap_enable_layer(1);
1171 omap_enable_layer(0);
1176 static menu_entry e_menu_gfx_options[] =
1178 mee_enum ("Scaler", 0, scaling, men_scaler),
1179 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1180 // mee_onoff ("Vsync", 0, vsync, 1),
1181 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1185 static int menu_loop_gfx_options(int id, int keys)
1189 me_loop(e_menu_gfx_options, &sel);
1194 // ------------ bios/plugins ------------
1196 static menu_entry e_menu_plugin_gpu_unai[] =
1198 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1199 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1200 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1201 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1205 static int menu_loop_plugin_gpu_unai(int id, int keys)
1208 me_loop(e_menu_plugin_gpu_unai, &sel);
1212 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1213 static const char h_gpu_0[] = "Needed for Chrono Cross";
1214 static const char h_gpu_1[] = "Capcom fighting games";
1215 static const char h_gpu_2[] = "Black screens in Lunar";
1216 static const char h_gpu_3[] = "Compatibility mode";
1217 static const char h_gpu_6[] = "Pandemonium 2";
1218 static const char h_gpu_7[] = "Skip every second frame";
1219 static const char h_gpu_8[] = "Needed by Dark Forces";
1220 static const char h_gpu_9[] = "better g-colors, worse textures";
1221 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1223 static menu_entry e_menu_plugin_gpu_peops[] =
1225 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1226 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1227 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1228 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1229 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1230 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1231 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1232 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1233 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1234 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1238 static int menu_loop_plugin_gpu_peops(int id, int keys)
1241 me_loop(e_menu_plugin_gpu_peops, &sel);
1245 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1246 static const char h_spu_volboost[] = "Large values cause distortion";
1247 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1248 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1250 static menu_entry e_menu_plugin_spu[] =
1252 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1253 mee_onoff ("Reverb", 0, iUseReverb, 2),
1254 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1255 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1256 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1257 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1261 static int menu_loop_plugin_spu(int id, int keys)
1264 me_loop(e_menu_plugin_spu, &sel);
1268 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1269 "savestates and can't be changed there. Must save\n"
1270 "config and reload the game for change to take effect";
1271 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1272 "for plugin change to take effect";
1273 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1274 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1275 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1277 static menu_entry e_menu_plugin_options[] =
1279 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1280 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1281 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1282 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1283 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1284 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1288 static menu_entry e_menu_main2[];
1290 static int menu_loop_plugin_options(int id, int keys)
1293 me_loop(e_menu_plugin_options, &sel);
1295 // sync BIOS/plugins
1296 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1297 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1298 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1299 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1304 // ------------ adv options menu ------------
1306 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1307 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1308 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1309 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1311 static menu_entry e_menu_speed_hacks[] =
1313 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1314 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1315 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1316 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1320 static int menu_loop_speed_hacks(int id, int keys)
1323 me_loop(e_menu_speed_hacks, &sel);
1327 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1328 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1329 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1330 "(green: normal, red: fmod, blue: noise)";
1331 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1332 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1333 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1334 "(proper .cue/.bin dump is needed otherwise)";
1335 static const char h_cfg_sio[] = "You should not need this, breaks games";
1336 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1337 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1338 "(timing hack, breaks other games)";
1339 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1340 "(timing hack, breaks other games)";
1341 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1342 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1343 "Might be useful to overcome some dynarec bugs";
1344 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1345 "must reload game for any change to take effect";
1347 static menu_entry e_menu_adv_options[] =
1349 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1350 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1351 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1352 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1353 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1354 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1355 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1356 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1357 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1358 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1359 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1360 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1364 static int menu_loop_adv_options(int id, int keys)
1367 me_loop(e_menu_adv_options, &sel);
1371 // ------------ options menu ------------
1373 static int mh_restore_defaults(int id, int keys)
1375 menu_set_defconfig();
1376 me_update_msg("defaults restored");
1380 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1381 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1383 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1384 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1385 "loading state or both";
1387 static const char h_restore_def[] = "Switches back to default / recommended\n"
1389 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1391 static menu_entry e_menu_options[] =
1393 // mee_range ("Save slot", 0, state_slot, 0, 9),
1394 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1395 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1396 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1397 mee_enum ("Region", 0, region, men_region),
1398 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1399 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1400 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1401 mee_handler ("[Advanced]", menu_loop_adv_options),
1402 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1403 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1404 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1408 static int menu_loop_options(int id, int keys)
1413 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1414 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1415 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1417 me_loop(e_menu_options, &sel);
1422 // ------------ debug menu ------------
1424 static void draw_frame_debug(GPUFreeze_t *gpuf)
1426 int w = min(g_menuscreen_w, 1024);
1427 int h = min(g_menuscreen_h, 512);
1428 u16 *d = g_menuscreen_ptr;
1429 u16 *s = (u16 *)gpuf->psxVRam;
1433 gpuf->ulFreezeVersion = 1;
1434 if (GPU_freeze != NULL)
1435 GPU_freeze(1, gpuf);
1437 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1438 bgr555_to_rgb565(d, s, w * 2);
1440 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1441 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1442 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1443 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1444 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1447 static void debug_menu_loop(void)
1452 gpuf = malloc(sizeof(*gpuf));
1459 draw_frame_debug(gpuf);
1462 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1463 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1464 if (inp & PBTN_MBACK)
1471 // --------- memcard manager ---------
1473 static void draw_mc_icon(int dx, int dy, const u16 *s)
1478 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1480 for (y = 0; y < 16; y++, s += 16) {
1481 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1482 for (x = 0; x < 16; x++) {
1484 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1485 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1491 static void draw_mc_bg(void)
1493 McdBlock *blocks1, *blocks2;
1497 blocks1 = malloc(15 * sizeof(blocks1[0]));
1498 blocks2 = malloc(15 * sizeof(blocks1[0]));
1499 if (blocks1 == NULL || blocks2 == NULL)
1502 for (i = 0; i < 15; i++) {
1503 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1504 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1509 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1511 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1515 maxicons = g_menuscreen_h / 32;
1518 row2 = g_menuscreen_w / 2;
1519 for (i = 0; i < maxicons; i++) {
1520 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1521 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1523 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1524 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1527 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1535 static void handle_memcard_sel(void)
1538 if (memcard1_sel != 0)
1539 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1541 if (memcard2_sel != 0)
1542 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1543 LoadMcds(Config.Mcd1, Config.Mcd2);
1547 static menu_entry e_memcard_options[] =
1549 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1550 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1554 static int menu_loop_memcards(int id, int keys)
1560 memcard1_sel = memcard2_sel = 0;
1561 p = strrchr(Config.Mcd1, '/');
1563 for (i = 0; memcards[i] != NULL; i++)
1564 if (strcmp(p + 1, memcards[i]) == 0)
1565 { memcard1_sel = i; break; }
1566 p = strrchr(Config.Mcd2, '/');
1568 for (i = 0; memcards[i] != NULL; i++)
1569 if (strcmp(p + 1, memcards[i]) == 0)
1570 { memcard2_sel = i; break; }
1572 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1574 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1579 // --------- main menu help ----------
1581 static void menu_bios_warn(void)
1584 static const char msg[] =
1585 "You don't seem to have copied any BIOS\n"
1587 #ifdef __ARM_ARCH_7A__ // XXX
1588 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1590 "pcsx_rearmed/bios/\n\n"
1592 "While many games work fine with fake\n"
1593 "(HLE) BIOS, others (like MGS and FF8)\n"
1594 "require BIOS to work.\n"
1595 "After copying the file, you'll also need\n"
1596 "to select it in the emu's menu:\n"
1597 "options->[BIOS/Plugins]\n\n"
1598 "The file is usually named SCPH1001.BIN,\n"
1599 "but other not compressed files can be\n"
1601 "Press (B) or (X) to continue";
1605 draw_menu_message(msg, NULL);
1607 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1608 if (inp & (PBTN_MBACK|PBTN_MOK))
1613 // ------------ main menu ------------
1617 static void draw_frame_main(void)
1624 if (CdromId[0] != 0) {
1625 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1626 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1627 Config.HLE ? "HLE" : "BIOS");
1628 smalltext_out16(4, 1, buff, 0x105f);
1633 tmp = localtime(<ime);
1634 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1635 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1636 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1640 static void draw_frame_credits(void)
1642 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1645 static const char credits_text[] =
1647 "(C) 1999-2003 PCSX Team\n"
1648 "(C) 2005-2009 PCSX-df Team\n"
1649 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1650 "ARM recompiler (C) 2009-2011 Ari64\n"
1652 "ARM NEON GPU (c) 2011 Exophase\n"
1654 "PEOpS GPU and SPU by Pete Bernert\n"
1655 " and the P.E.Op.S. team\n"
1656 "PCSX4ALL plugin by PCSX4ALL team\n"
1657 " Chui, Franxis, Unai\n\n"
1658 "integration, optimization and\n"
1659 " frontend (C) 2010-2011 notaz\n";
1661 static int reset_game(void)
1664 if (bios_sel == 0 && !Config.HLE)
1670 if (CheckCdrom() != -1) {
1676 static int reload_plugins(const char *cdimg)
1682 set_cd_image(cdimg);
1684 pcnt_hook_plugins();
1686 if (OpenPlugins() == -1) {
1687 me_update_msg("failed to open plugins");
1690 plugin_call_rearmed_cbs();
1692 cdrIsoMultidiskCount = 1;
1694 CdromLabel[0] = '\0';
1699 static int run_bios(void)
1705 if (reload_plugins(NULL) != 0)
1713 static int run_exe(void)
1717 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1722 if (reload_plugins(NULL) != 0)
1726 if (Load(fname) != 0) {
1727 me_update_msg("exe load failed, bad file?");
1736 static int run_cd_image(const char *fname)
1739 reload_plugins(fname);
1741 // always autodetect, menu_sync_config will override as needed
1744 if (CheckCdrom() == -1) {
1745 // Only check the CD if we are starting the console with a CD
1747 me_update_msg("unsupported/invalid CD image");
1753 // Read main executable directly from CDRom and start it
1754 if (LoadCdrom() == -1) {
1756 me_update_msg("failed to load CD image");
1761 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1766 static int romsel_run(void)
1768 int prev_gpu, prev_spu;
1771 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1775 printf("selected file: %s\n", fname);
1777 new_dynarec_clear_full();
1779 if (run_cd_image(fname) != 0)
1782 prev_gpu = gpu_plugsel;
1783 prev_spu = spu_plugsel;
1784 if (menu_load_config(1) != 0)
1785 menu_load_config(0);
1787 // check for plugin changes, have to repeat
1788 // loading if game config changed plugins to reload them
1789 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1790 printf("plugin change detected, reloading plugins..\n");
1791 if (run_cd_image(fname) != 0)
1796 printf("note: running without BIOS, expect compatibility problems\n");
1798 strcpy(last_selected_fname, rom_fname_reload);
1802 static int swap_cd_image(void)
1806 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1810 printf("selected file: %s\n", fname);
1813 CdromLabel[0] = '\0';
1815 set_cd_image(fname);
1816 if (ReloadCdromPlugin() < 0) {
1817 me_update_msg("failed to load cdr plugin");
1820 if (CDR_open() < 0) {
1821 me_update_msg("failed to open cdr plugin");
1825 SetCdOpenCaseTime(time(NULL) + 2);
1828 strcpy(last_selected_fname, rom_fname_reload);
1832 static int swap_cd_multidisk(void)
1834 cdrIsoMultidiskSelect++;
1836 CdromLabel[0] = '\0';
1839 if (CDR_open() < 0) {
1840 me_update_msg("failed to open cdr plugin");
1844 SetCdOpenCaseTime(time(NULL) + 2);
1850 static int main_menu_handler(int id, int keys)
1854 case MA_MAIN_RESUME_GAME:
1858 case MA_MAIN_SAVE_STATE:
1860 return menu_loop_savestate(0);
1862 case MA_MAIN_LOAD_STATE:
1864 return menu_loop_savestate(1);
1866 case MA_MAIN_RESET_GAME:
1867 if (ready_to_go && reset_game() == 0)
1870 case MA_MAIN_LOAD_ROM:
1871 if (romsel_run() == 0)
1874 case MA_MAIN_SWAP_CD:
1875 if (swap_cd_image() == 0)
1878 case MA_MAIN_SWAP_CD_MULTI:
1879 if (swap_cd_multidisk() == 0)
1882 case MA_MAIN_RUN_BIOS:
1883 if (run_bios() == 0)
1886 case MA_MAIN_RUN_EXE:
1890 case MA_MAIN_CREDITS:
1891 draw_menu_message(credits_text, draw_frame_credits);
1892 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1898 lprintf("%s: something unknown selected\n", __FUNCTION__);
1905 static menu_entry e_menu_main2[] =
1907 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1908 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1909 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1910 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1911 mee_handler ("Memcard manager", menu_loop_memcards),
1915 static int main_menu2_handler(int id, int keys)
1919 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1920 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1921 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1923 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1926 static const char h_extra[] = "Change CD, manage memcards..\n";
1928 static menu_entry e_menu_main[] =
1932 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1933 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1934 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1935 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1936 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1937 mee_handler ("Options", menu_loop_options),
1938 mee_handler ("Controls", menu_loop_keyconfig),
1939 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1940 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1941 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1945 // ----------------------------
1947 static void menu_leave_emu(void);
1949 void menu_loop(void)
1955 if (bioses[1] == NULL && !warned_about_bios) {
1957 warned_about_bios = 1;
1960 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1961 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1962 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1963 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1965 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1968 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1969 } while (!ready_to_go);
1971 /* wait until menu, ok, back is released */
1972 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1975 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1980 static int qsort_strcmp(const void *p1, const void *p2)
1982 char * const *s1 = (char * const *)p1;
1983 char * const *s2 = (char * const *)p2;
1984 return strcasecmp(*s1, *s2);
1987 static void scan_bios_plugins(void)
1989 char fname[MAXPATHLEN];
1991 int bios_i, gpu_i, spu_i, mc_i;
1996 gpu_plugins[0] = "builtin_gpu";
1997 spu_plugins[0] = "builtin_spu";
1998 memcards[0] = "(none)";
1999 bios_i = gpu_i = spu_i = mc_i = 1;
2001 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2002 dir = opendir(fname);
2004 perror("scan_bios_plugins bios opendir");
2019 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2022 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2023 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2024 printf("bad BIOS file: %s\n", ent->d_name);
2028 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2029 bioses[bios_i++] = strdup(ent->d_name);
2033 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2039 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2040 dir = opendir(fname);
2042 perror("scan_bios_plugins plugins opendir");
2056 p = strstr(ent->d_name, ".so");
2060 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2061 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2063 fprintf(stderr, "%s\n", dlerror());
2067 // now what do we have here?
2068 tmp = dlsym(h, "GPUinit");
2071 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2072 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2076 tmp = dlsym(h, "SPUinit");
2079 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2080 spu_plugins[spu_i++] = strdup(ent->d_name);
2084 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2091 dir = opendir("." MEMCARD_DIR);
2093 perror("scan_bios_plugins memcards opendir");
2108 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2111 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2112 if (stat(fname, &st) != 0) {
2113 printf("bad memcard file: %s\n", ent->d_name);
2117 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2118 memcards[mc_i++] = strdup(ent->d_name);
2122 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2126 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2131 void menu_init(void)
2133 char buff[MAXPATHLEN];
2135 strcpy(last_selected_fname, "/media");
2137 scan_bios_plugins();
2141 menu_set_defconfig();
2142 menu_load_config(0);
2147 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2148 if (g_menubg_src_ptr == NULL)
2150 emu_make_path(buff, "skin/background.png", sizeof(buff));
2151 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2153 #ifndef __ARM_ARCH_7A__ /* XXX */
2154 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2155 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2157 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2158 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2162 void menu_notify_mode_change(int w, int h, int bpp)
2173 g_layer_w = w; g_layer_h = h;
2177 if (h > g_menuscreen_h || (240 < h && h <= 360))
2178 goto fractional_4_3;
2180 // 4:3 that prefers integer scaling
2181 imult = g_menuscreen_h / h;
2182 g_layer_w = w * imult;
2183 g_layer_h = h * imult;
2184 mult = (float)g_layer_w / (float)g_layer_h;
2185 if (mult < 1.25f || mult > 1.666f)
2186 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2187 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2192 mult = 240.0f / (float)h * 4.0f / 3.0f;
2195 g_layer_w = mult * (float)g_menuscreen_h;
2196 g_layer_h = g_menuscreen_h;
2197 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2200 case SCALE_FULLSCREEN:
2201 g_layer_w = g_menuscreen_w;
2202 g_layer_h = g_menuscreen_h;
2209 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2210 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2211 if (g_layer_x < 0) g_layer_x = 0;
2212 if (g_layer_y < 0) g_layer_y = 0;
2213 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2214 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2217 static void menu_leave_emu(void)
2219 if (GPU_close != NULL) {
2220 int ret = GPU_close();
2222 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2225 plat_video_menu_enter(ready_to_go);
2227 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2228 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2229 int x = max(0, g_menuscreen_w - last_psx_w);
2230 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2231 int w = min(g_menuscreen_w, last_psx_w);
2232 int h = min(g_menuscreen_h, last_psx_h);
2233 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2234 u16 *s = pl_vout_buf;
2236 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2237 menu_darken_bg(d, s, w, 0);
2241 cpu_clock = plat_cpu_clock_get();
2244 void menu_prepare_emu(void)
2246 R3000Acpu *prev_cpu = psxCpu;
2248 plat_video_menu_leave();
2250 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2252 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2253 if (psxCpu != prev_cpu)
2254 // note that this does not really reset, just clears drc caches
2257 // core doesn't care about Config.Cdda changes,
2258 // so handle them manually here
2263 apply_lcdrate(Config.PsxType);
2264 apply_filter(filter);
2265 plat_cpu_clock_apply(cpu_clock);
2267 // push config to GPU plugin
2268 plugin_call_rearmed_cbs();
2270 if (GPU_open != NULL) {
2271 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2273 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2279 void me_update_msg(const char *msg)
2281 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2282 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2284 menu_error_time = plat_get_ticks_ms();
2285 lprintf("msg: %s\n", menu_error_msg);