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_INTVAL_V(val, ver) \
245 { #val #ver, sizeof(val), &val }
247 #define CE_INTVAL_PV(val, ver) \
248 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
250 static const struct {
258 // CE_CONFIG_STR(Cdr),
263 CE_CONFIG_VAL(Debug),
264 CE_CONFIG_VAL(PsxOut),
265 CE_CONFIG_VAL(SpuIrq),
266 CE_CONFIG_VAL(RCntFix),
267 CE_CONFIG_VAL(VSyncWA),
269 CE_CONFIG_VAL(CdrReschedule),
271 CE_INTVAL_V(scaling, 2),
272 CE_INTVAL(g_layer_x),
273 CE_INTVAL(g_layer_y),
274 CE_INTVAL(g_layer_w),
275 CE_INTVAL(g_layer_h),
277 CE_INTVAL(state_slot),
278 CE_INTVAL(cpu_clock),
280 CE_INTVAL(in_type_sel1),
281 CE_INTVAL(in_type_sel2),
282 CE_INTVAL(analog_deadzone),
283 CE_INTVAL_V(frameskip, 3),
284 CE_INTVAL_P(gpu_peops.iUseDither),
285 CE_INTVAL_P(gpu_peops.dwActFixes),
286 CE_INTVAL_P(gpu_unai.abe_hack),
287 CE_INTVAL_P(gpu_unai.no_light),
288 CE_INTVAL_P(gpu_unai.no_blend),
289 CE_INTVAL_V(iUseReverb, 3),
290 CE_INTVAL_V(iXAPitch, 3),
291 CE_INTVAL_V(iUseInterpolation, 3),
292 CE_INTVAL_V(iSPUIRQWait, 3),
293 CE_INTVAL_V(iUseTimer, 3),
294 CE_INTVAL(warned_about_bios),
295 CE_INTVAL(in_evdev_allow_abs_only),
296 CE_INTVAL(volume_boost),
297 CE_INTVAL(psx_clock),
298 CE_INTVAL(new_dynarec_hacks),
299 CE_INTVAL(in_enable_vibration),
302 static char *get_cd_label(void)
304 static char trimlabel[33];
307 strncpy(trimlabel, CdromLabel, 32);
309 for (j = 31; j >= 0; j--)
310 if (trimlabel[j] == ' ')
316 static void make_cfg_fname(char *buf, size_t size, int is_game)
319 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
321 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
324 static void keys_write_all(FILE *f);
326 static int menu_write_config(int is_game)
328 char cfgfile[MAXPATHLEN];
332 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
333 f = fopen(cfgfile, "w");
335 printf("menu_write_config: failed to open: %s\n", cfgfile);
339 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
340 fprintf(f, "%s = ", config_data[i].name);
341 switch (config_data[i].len) {
343 fprintf(f, "%s\n", (char *)config_data[i].val);
346 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
349 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
352 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
355 printf("menu_write_config: unhandled len %d for %s\n",
356 config_data[i].len, config_data[i].name);
362 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
370 static void parse_str_val(char *cval, const char *src)
373 strncpy(cval, src, MAXPATHLEN);
374 cval[MAXPATHLEN - 1] = 0;
375 tmp = strchr(cval, '\n');
377 tmp = strchr(cval, '\r');
382 static void keys_load_all(const char *cfg);
384 static int menu_load_config(int is_game)
386 char cfgfile[MAXPATHLEN];
392 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
393 f = fopen(cfgfile, "r");
395 printf("menu_load_config: failed to open: %s\n", cfgfile);
399 fseek(f, 0, SEEK_END);
402 printf("bad size %ld: %s\n", size, cfgfile);
406 cfg = malloc(size + 1);
410 fseek(f, 0, SEEK_SET);
411 if (fread(cfg, 1, size, f) != size) {
412 printf("failed to read: %s\n", cfgfile);
417 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
421 tmp = strstr(cfg, config_data[i].name);
424 tmp += strlen(config_data[i].name);
425 if (strncmp(tmp, " = ", 3) != 0)
429 if (config_data[i].len == 0) {
430 parse_str_val(config_data[i].val, tmp);
435 val = strtoul(tmp, &tmp2, 16);
436 if (tmp2 == NULL || tmp == tmp2)
437 continue; // parse failed
439 switch (config_data[i].len) {
441 *(u8 *)config_data[i].val = val;
444 *(u16 *)config_data[i].val = val;
447 *(u32 *)config_data[i].val = val;
450 printf("menu_load_config: unhandled len %d for %s\n",
451 config_data[i].len, config_data[i].name);
457 char *tmp = strstr(cfg, "lastcdimg = ");
460 parse_str_val(last_selected_fname, tmp);
475 for (i = bios_sel = 0; bioses[i] != NULL; i++)
476 if (strcmp(Config.Bios, bioses[i]) == 0)
477 { bios_sel = i; break; }
479 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
480 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
481 { gpu_plugsel = i; break; }
483 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
484 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
485 { spu_plugsel = i; break; }
490 // rrrr rggg gggb bbbb
491 static unsigned short fname2color(const char *fname)
493 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
494 ".bz", ".znx", ".pbp", ".cbn" };
495 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
496 ".table", ".index", ".sbi" };
497 const char *ext = strrchr(fname, '.');
502 for (i = 0; i < array_size(cdimg_exts); i++)
503 if (strcasecmp(ext, cdimg_exts[i]) == 0)
505 for (i = 0; i < array_size(other_exts); i++)
506 if (strcasecmp(ext, other_exts[i]) == 0)
511 static void draw_savestate_bg(int slot);
513 static const char *filter_exts[] = {
514 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
517 #define MENU_ALIGN_LEFT
518 #ifdef __ARM_ARCH_7A__ // assume hires device
524 #define menu_init menu_init_common
525 #include "common/menu.c"
528 // a bit of black magic here
529 static void draw_savestate_bg(int slot)
531 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
533 char fname[MAXPATHLEN];
540 ret = get_state_filename(fname, sizeof(fname), slot);
544 f = gzopen(fname, "rb");
548 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
549 fprintf(stderr, "gzseek failed\n");
554 gpu = malloc(sizeof(*gpu));
560 ret = gzread(f, gpu, sizeof(*gpu));
562 if (ret != sizeof(*gpu)) {
563 fprintf(stderr, "gzread failed\n");
567 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
569 if (gpu->ulStatus & 0x800000)
570 goto out; // disabled
572 x = gpu->ulControl[5] & 0x3ff;
573 y = (gpu->ulControl[5] >> 10) & 0x1ff;
574 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
575 w = psx_widths[(gpu->ulStatus >> 16) & 7];
576 tmp = gpu->ulControl[7];
577 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
578 if (gpu->ulStatus & 0x80000) // doubleheight
581 x = max(0, g_menuscreen_w - w) & ~3;
582 y = max(0, g_menuscreen_h / 2 - h / 2);
583 w = min(g_menuscreen_w, w);
584 h = min(g_menuscreen_h, h);
585 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
587 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
588 if (gpu->ulStatus & 0x200000)
589 bgr888_to_rgb565(d, s, w * 3);
591 bgr555_to_rgb565(d, s, w * 2);
592 #ifndef __ARM_ARCH_7A__
593 // better darken this on small screens
594 menu_darken_bg(d, d, w * 2, 0);
602 // ---------- XXX: pandora specific -----------
604 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
605 static char **pnd_filter_list;
607 static void apply_filter(int which)
613 if (pnd_filter_list == NULL || which == old)
616 for (i = 0; i < which; i++)
617 if (pnd_filter_list[i] == NULL)
620 if (pnd_filter_list[i] == NULL)
623 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
628 static void apply_lcdrate(int pal)
636 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
637 pnd_script_base, pal ? 50 : 60);
642 static menu_entry e_menu_gfx_options[];
644 static void pnd_menu_init(void)
652 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
654 dir = opendir("/etc/pandora/conf/dss_fir");
656 perror("filter opendir");
669 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
678 mfilters = calloc(count + 1, sizeof(mfilters[0]));
679 if (mfilters == NULL)
683 for (i = 0; (ent = readdir(dir)); ) {
686 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
689 len = strlen(ent->d_name);
691 // skip pre-HF5 extra files
692 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
694 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
697 // have to cut "_up_h" for pre-HF5
698 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
701 if (len > sizeof(buff) - 1)
704 strncpy(buff, ent->d_name, len);
706 mfilters[i] = strdup(buff);
707 if (mfilters[i] != NULL)
712 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
713 e_menu_gfx_options[i].data = (void *)mfilters;
714 pnd_filter_list = mfilters;
717 void menu_finish(void)
719 plat_cpu_clock_apply(cpu_clock_st);
722 // -------------- key config --------------
724 me_bind_action me_ctrl_actions[] =
726 { "UP ", 1 << DKEY_UP},
727 { "DOWN ", 1 << DKEY_DOWN },
728 { "LEFT ", 1 << DKEY_LEFT },
729 { "RIGHT ", 1 << DKEY_RIGHT },
730 { "TRIANGLE", 1 << DKEY_TRIANGLE },
731 { "CIRCLE ", 1 << DKEY_CIRCLE },
732 { "CROSS ", 1 << DKEY_CROSS },
733 { "SQUARE ", 1 << DKEY_SQUARE },
734 { "L1 ", 1 << DKEY_L1 },
735 { "R1 ", 1 << DKEY_R1 },
736 { "L2 ", 1 << DKEY_L2 },
737 { "R2 ", 1 << DKEY_R2 },
738 { "L3 ", 1 << DKEY_L3 },
739 { "R3 ", 1 << DKEY_R3 },
740 { "START ", 1 << DKEY_START },
741 { "SELECT ", 1 << DKEY_SELECT },
745 me_bind_action emuctrl_actions[] =
747 { "Save State ", 1 << SACTION_SAVE_STATE },
748 { "Load State ", 1 << SACTION_LOAD_STATE },
749 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
750 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
751 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
752 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
753 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
754 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
755 { "Gun A button ", 1 << SACTION_GUN_A },
756 { "Gun B button ", 1 << SACTION_GUN_B },
757 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
758 #ifndef __ARM_ARCH_7A__ /* XXX */
759 { "Volume Up ", 1 << SACTION_VOLUME_UP },
760 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
765 static char *mystrip(char *str)
770 for (i = 0; i < len; i++)
771 if (str[i] != ' ') break;
772 if (i > 0) memmove(str, str + i, len - i + 1);
775 for (i = len - 1; i >= 0; i--)
776 if (str[i] != ' ') break;
782 static void get_line(char *d, size_t size, const char *s)
787 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
798 static void keys_write_all(FILE *f)
802 for (d = 0; d < IN_MAX_DEVS; d++)
804 const int *binds = in_get_dev_binds(d);
805 const char *name = in_get_dev_name(d, 0, 0);
808 if (binds == NULL || name == NULL)
811 fprintf(f, "binddev = %s\n", name);
812 in_get_config(d, IN_CFG_BIND_COUNT, &count);
814 for (k = 0; k < count; k++)
819 act[0] = act[31] = 0;
820 name = in_get_key_name(d, k);
822 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
823 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
824 mask = me_ctrl_actions[i].mask;
826 strncpy(act, me_ctrl_actions[i].name, 31);
827 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
830 mask = me_ctrl_actions[i].mask << 16;
832 strncpy(act, me_ctrl_actions[i].name, 31);
833 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
838 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
839 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
840 mask = emuctrl_actions[i].mask;
842 strncpy(act, emuctrl_actions[i].name, 31);
843 fprintf(f, "bind %s = %s\n", name, mystrip(act));
849 for (k = 0; k < array_size(in_adev); k++)
852 fprintf(f, "bind_analog = %d\n", k);
857 static int parse_bind_val(const char *val, int *type)
861 *type = IN_BINDTYPE_NONE;
865 if (strncasecmp(val, "player", 6) == 0)
867 int player, shift = 0;
868 player = atoi(val + 6) - 1;
870 if ((unsigned int)player > 1)
875 *type = IN_BINDTYPE_PLAYER12;
876 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
877 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
878 return me_ctrl_actions[i].mask << shift;
881 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
882 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
883 *type = IN_BINDTYPE_EMU;
884 return emuctrl_actions[i].mask;
891 static void keys_load_all(const char *cfg)
893 char dev[256], key[128], *act;
899 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
902 get_line(dev, sizeof(dev), p);
903 dev_id = in_config_parse_dev(dev);
905 printf("input: can't handle dev: %s\n", dev);
909 in_unbind_all(dev_id, -1, -1);
910 while ((p = strstr(p, "bind"))) {
911 if (strncmp(p, "binddev = ", 10) == 0)
914 if (strncmp(p, "bind_analog", 11) == 0) {
915 ret = sscanf(p, "bind_analog = %d", &bind);
918 printf("input: parse error: %16s..\n", p);
921 if ((unsigned int)bind >= array_size(in_adev)) {
922 printf("input: analog id %d out of range\n", bind);
925 in_adev[bind] = dev_id;
931 printf("input: parse error: %16s..\n", p);
935 get_line(key, sizeof(key), p);
936 act = strchr(key, '=');
938 printf("parse failed: %16s..\n", p);
946 bind = parse_bind_val(act, &bindtype);
947 if (bind != -1 && bind != 0) {
948 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
949 in_config_bind_key(dev_id, key, bind, bindtype);
952 lprintf("config: unhandled action \"%s\"\n", act);
958 static int key_config_loop_wrap(int id, int keys)
961 case MA_CTRL_PLAYER1:
962 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
964 case MA_CTRL_PLAYER2:
965 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
968 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
976 static const char *adevnames[IN_MAX_DEVS + 2];
977 static int stick_sel[2];
979 static menu_entry e_menu_keyconfig_analog[] =
981 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
982 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
983 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
984 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
985 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
986 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
990 static int key_config_analog(int id, int keys)
992 int i, d, count, sel = 0;
993 int sel2dev_map[IN_MAX_DEVS];
995 memset(adevnames, 0, sizeof(adevnames));
996 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
997 memset(stick_sel, 0, sizeof(stick_sel));
999 adevnames[0] = "None";
1001 for (d = 0; d < IN_MAX_DEVS; d++)
1003 const char *name = in_get_dev_name(d, 0, 1);
1008 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1012 if (in_adev[0] == d) stick_sel[0] = i;
1013 if (in_adev[1] == d) stick_sel[1] = i;
1015 adevnames[i++] = name;
1017 adevnames[i] = NULL;
1019 me_loop(e_menu_keyconfig_analog, &sel);
1021 in_adev[0] = sel2dev_map[stick_sel[0]];
1022 in_adev[1] = sel2dev_map[stick_sel[1]];
1027 static const char *mgn_dev_name(int id, int *offs)
1029 const char *name = NULL;
1032 if (id == MA_CTRL_DEV_FIRST)
1035 for (; it < IN_MAX_DEVS; it++) {
1036 name = in_get_dev_name(it, 1, 1);
1045 static const char *mgn_saveloadcfg(int id, int *offs)
1050 static int mh_savecfg(int id, int keys)
1052 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1053 me_update_msg("config saved");
1055 me_update_msg("failed to write config");
1060 static int mh_input_rescan(int id, int keys)
1062 //menu_sync_config();
1064 me_update_msg("rescan complete.");
1069 static const char *men_in_type_sel[] = {
1070 "Standard (SCPH-1080)",
1071 "Analog (SCPH-1150)",
1075 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1076 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1077 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1079 static menu_entry e_menu_keyconfig[] =
1081 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1082 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1083 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1084 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1086 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1087 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1088 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1089 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1090 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1091 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1092 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1093 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1094 mee_handler ("Rescan devices:", mh_input_rescan),
1096 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1097 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1098 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1099 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1100 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1106 static int menu_loop_keyconfig(int id, int keys)
1110 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1111 me_loop(e_menu_keyconfig, &sel);
1115 // ------------ gfx options menu ------------
1117 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1118 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1119 "using d-pad or move it using R+d-pad";
1120 static const char *men_dummy[] = { NULL };
1122 static int menu_loop_cscaler(int id, int keys)
1126 scaling = SCALE_CUSTOM;
1128 omap_enable_layer(1);
1133 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1134 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1135 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1138 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1139 if (inp & PBTN_UP) g_layer_y--;
1140 if (inp & PBTN_DOWN) g_layer_y++;
1141 if (inp & PBTN_LEFT) g_layer_x--;
1142 if (inp & PBTN_RIGHT) g_layer_x++;
1143 if (!(inp & PBTN_R)) {
1144 if (inp & PBTN_UP) g_layer_h += 2;
1145 if (inp & PBTN_DOWN) g_layer_h -= 2;
1146 if (inp & PBTN_LEFT) g_layer_w += 2;
1147 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1149 if (inp & (PBTN_MOK|PBTN_MBACK))
1152 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1153 if (g_layer_x < 0) g_layer_x = 0;
1154 if (g_layer_x > 640) g_layer_x = 640;
1155 if (g_layer_y < 0) g_layer_y = 0;
1156 if (g_layer_y > 420) g_layer_y = 420;
1157 if (g_layer_w < 160) g_layer_w = 160;
1158 if (g_layer_h < 60) g_layer_h = 60;
1159 if (g_layer_x + g_layer_w > 800)
1160 g_layer_w = 800 - g_layer_x;
1161 if (g_layer_y + g_layer_h > 480)
1162 g_layer_h = 480 - g_layer_y;
1163 omap_enable_layer(1);
1167 omap_enable_layer(0);
1172 static menu_entry e_menu_gfx_options[] =
1174 mee_enum ("Scaler", 0, scaling, men_scaler),
1175 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1176 // mee_onoff ("Vsync", 0, vsync, 1),
1177 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1181 static int menu_loop_gfx_options(int id, int keys)
1185 me_loop(e_menu_gfx_options, &sel);
1190 // ------------ bios/plugins ------------
1192 static menu_entry e_menu_plugin_gpu_unai[] =
1194 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1195 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1196 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1200 static int menu_loop_plugin_gpu_unai(int id, int keys)
1203 me_loop(e_menu_plugin_gpu_unai, &sel);
1207 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1208 static const char h_gpu_0[] = "Needed for Chrono Cross";
1209 static const char h_gpu_1[] = "Capcom fighting games";
1210 static const char h_gpu_2[] = "Black screens in Lunar";
1211 static const char h_gpu_3[] = "Compatibility mode";
1212 static const char h_gpu_6[] = "Pandemonium 2";
1213 static const char h_gpu_7[] = "Skip every second frame";
1214 static const char h_gpu_8[] = "Needed by Dark Forces";
1215 static const char h_gpu_9[] = "better g-colors, worse textures";
1216 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1218 static menu_entry e_menu_plugin_gpu_peops[] =
1220 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1221 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1222 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1223 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1224 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1225 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1226 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1227 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1228 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1229 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1233 static int menu_loop_plugin_gpu_peops(int id, int keys)
1236 me_loop(e_menu_plugin_gpu_peops, &sel);
1240 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1241 static const char h_spu_volboost[] = "Large values cause distortion";
1242 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1243 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1245 static menu_entry e_menu_plugin_spu[] =
1247 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1248 mee_onoff ("Reverb", 0, iUseReverb, 2),
1249 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1250 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1251 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1252 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1256 static int menu_loop_plugin_spu(int id, int keys)
1259 me_loop(e_menu_plugin_spu, &sel);
1263 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1264 "savestates and can't be changed there. Must save\n"
1265 "config and reload the game for change to take effect";
1266 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1267 "for plugin change to take effect";
1268 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1269 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1270 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1272 static menu_entry e_menu_plugin_options[] =
1274 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1275 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1276 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1277 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1278 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1279 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1283 static menu_entry e_menu_main2[];
1285 static int menu_loop_plugin_options(int id, int keys)
1288 me_loop(e_menu_plugin_options, &sel);
1290 // sync BIOS/plugins
1291 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1292 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1293 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1294 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1299 // ------------ adv options menu ------------
1301 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1302 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1303 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1304 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1306 static menu_entry e_menu_speed_hacks[] =
1308 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1309 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1310 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1311 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1315 static int menu_loop_speed_hacks(int id, int keys)
1318 me_loop(e_menu_speed_hacks, &sel);
1322 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1323 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1324 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1325 "(green: normal, red: fmod, blue: noise)";
1326 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1327 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1328 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1329 "(proper .cue/.bin dump is needed otherwise)";
1330 static const char h_cfg_sio[] = "You should not need this, breaks games";
1331 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1332 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1333 "(timing hack, breaks other games)";
1334 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1335 "(timing hack, breaks other games)";
1336 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1337 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1338 "Might be useful to overcome some dynarec bugs";
1339 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1340 "must reload game for any change to take effect";
1342 static menu_entry e_menu_adv_options[] =
1344 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1345 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1346 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1347 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1348 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1349 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1350 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1351 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1352 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1353 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1354 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1355 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1359 static int menu_loop_adv_options(int id, int keys)
1362 me_loop(e_menu_adv_options, &sel);
1366 // ------------ options menu ------------
1368 static int mh_restore_defaults(int id, int keys)
1370 menu_set_defconfig();
1371 me_update_msg("defaults restored");
1375 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1376 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1378 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1379 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1380 "loading state or both";
1382 static const char h_restore_def[] = "Switches back to default / recommended\n"
1384 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1386 static menu_entry e_menu_options[] =
1388 // mee_range ("Save slot", 0, state_slot, 0, 9),
1389 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1390 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1391 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1392 mee_enum ("Region", 0, region, men_region),
1393 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1394 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1395 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1396 mee_handler ("[Advanced]", menu_loop_adv_options),
1397 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1398 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1399 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1403 static int menu_loop_options(int id, int keys)
1408 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1409 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1410 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1412 me_loop(e_menu_options, &sel);
1417 // ------------ debug menu ------------
1419 static void draw_frame_debug(GPUFreeze_t *gpuf)
1421 int w = min(g_menuscreen_w, 1024);
1422 int h = min(g_menuscreen_h, 512);
1423 u16 *d = g_menuscreen_ptr;
1424 u16 *s = (u16 *)gpuf->psxVRam;
1428 gpuf->ulFreezeVersion = 1;
1429 if (GPU_freeze != NULL)
1430 GPU_freeze(1, gpuf);
1432 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1433 bgr555_to_rgb565(d, s, w * 2);
1435 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1436 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1437 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1438 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1439 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1442 static void debug_menu_loop(void)
1447 gpuf = malloc(sizeof(*gpuf));
1454 draw_frame_debug(gpuf);
1457 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1458 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1459 if (inp & PBTN_MBACK)
1466 // --------- memcard manager ---------
1468 static void draw_mc_icon(int dx, int dy, const u16 *s)
1473 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1475 for (y = 0; y < 16; y++, s += 16) {
1476 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1477 for (x = 0; x < 16; x++) {
1479 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1480 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1486 static void draw_mc_bg(void)
1488 McdBlock *blocks1, *blocks2;
1492 blocks1 = malloc(15 * sizeof(blocks1[0]));
1493 blocks2 = malloc(15 * sizeof(blocks1[0]));
1494 if (blocks1 == NULL || blocks2 == NULL)
1497 for (i = 0; i < 15; i++) {
1498 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1499 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1504 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1506 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1510 maxicons = g_menuscreen_h / 32;
1513 row2 = g_menuscreen_w / 2;
1514 for (i = 0; i < maxicons; i++) {
1515 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1516 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1518 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1519 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1522 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1530 static void handle_memcard_sel(void)
1533 if (memcard1_sel != 0)
1534 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1536 if (memcard2_sel != 0)
1537 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1538 LoadMcds(Config.Mcd1, Config.Mcd2);
1542 static menu_entry e_memcard_options[] =
1544 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1545 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1549 static int menu_loop_memcards(int id, int keys)
1555 memcard1_sel = memcard2_sel = 0;
1556 p = strrchr(Config.Mcd1, '/');
1558 for (i = 0; memcards[i] != NULL; i++)
1559 if (strcmp(p + 1, memcards[i]) == 0)
1560 { memcard1_sel = i; break; }
1561 p = strrchr(Config.Mcd2, '/');
1563 for (i = 0; memcards[i] != NULL; i++)
1564 if (strcmp(p + 1, memcards[i]) == 0)
1565 { memcard2_sel = i; break; }
1567 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1569 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1574 // --------- main menu help ----------
1576 static void menu_bios_warn(void)
1579 static const char msg[] =
1580 "You don't seem to have copied any BIOS\n"
1582 #ifdef __ARM_ARCH_7A__ // XXX
1583 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1585 "pcsx_rearmed/bios/\n\n"
1587 "While many games work fine with fake\n"
1588 "(HLE) BIOS, others (like MGS and FF8)\n"
1589 "require BIOS to work.\n"
1590 "After copying the file, you'll also need\n"
1591 "to select it in the emu's menu:\n"
1592 "options->[BIOS/Plugins]\n\n"
1593 "The file is usually named SCPH1001.BIN,\n"
1594 "but other not compressed files can be\n"
1596 "Press (B) or (X) to continue";
1600 draw_menu_message(msg, NULL);
1602 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1603 if (inp & (PBTN_MBACK|PBTN_MOK))
1608 // ------------ main menu ------------
1612 static void draw_frame_main(void)
1619 if (CdromId[0] != 0) {
1620 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1621 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1622 Config.HLE ? "HLE" : "BIOS");
1623 smalltext_out16(4, 1, buff, 0x105f);
1628 tmp = localtime(<ime);
1629 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1630 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1631 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1635 static void draw_frame_credits(void)
1637 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1640 static const char credits_text[] =
1642 "(C) 1999-2003 PCSX Team\n"
1643 "(C) 2005-2009 PCSX-df Team\n"
1644 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1645 "GPU and SPU code by Pete Bernert\n"
1646 " and the P.E.Op.S. team\n"
1647 "ARM recompiler (C) 2009-2011 Ari64\n"
1648 "PCSX4ALL plugins by PCSX4ALL team\n"
1649 " Chui, Franxis, Unai\n\n"
1650 "integration, optimization and\n"
1651 " frontend (C) 2010-2011 notaz\n";
1653 static int reset_game(void)
1656 if (bios_sel == 0 && !Config.HLE)
1662 if (CheckCdrom() != -1) {
1668 static int reload_plugins(const char *cdimg)
1674 set_cd_image(cdimg);
1676 pcnt_hook_plugins();
1678 if (OpenPlugins() == -1) {
1679 me_update_msg("failed to open plugins");
1682 plugin_call_rearmed_cbs();
1684 cdrIsoMultidiskCount = 1;
1686 CdromLabel[0] = '\0';
1691 static int run_bios(void)
1697 if (reload_plugins(NULL) != 0)
1705 static int run_exe(void)
1709 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1714 if (reload_plugins(NULL) != 0)
1718 if (Load(fname) != 0) {
1719 me_update_msg("exe load failed, bad file?");
1728 static int run_cd_image(const char *fname)
1731 reload_plugins(fname);
1733 // always autodetect, menu_sync_config will override as needed
1736 if (CheckCdrom() == -1) {
1737 // Only check the CD if we are starting the console with a CD
1739 me_update_msg("unsupported/invalid CD image");
1745 // Read main executable directly from CDRom and start it
1746 if (LoadCdrom() == -1) {
1748 me_update_msg("failed to load CD image");
1753 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1758 static int romsel_run(void)
1760 int prev_gpu, prev_spu;
1763 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1767 printf("selected file: %s\n", fname);
1769 new_dynarec_clear_full();
1771 if (run_cd_image(fname) != 0)
1774 prev_gpu = gpu_plugsel;
1775 prev_spu = spu_plugsel;
1776 if (menu_load_config(1) != 0)
1777 menu_load_config(0);
1779 // check for plugin changes, have to repeat
1780 // loading if game config changed plugins to reload them
1781 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1782 printf("plugin change detected, reloading plugins..\n");
1783 if (run_cd_image(fname) != 0)
1788 printf("note: running without BIOS, expect compatibility problems\n");
1790 strcpy(last_selected_fname, rom_fname_reload);
1794 static int swap_cd_image(void)
1798 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1802 printf("selected file: %s\n", fname);
1805 CdromLabel[0] = '\0';
1807 set_cd_image(fname);
1808 if (ReloadCdromPlugin() < 0) {
1809 me_update_msg("failed to load cdr plugin");
1812 if (CDR_open() < 0) {
1813 me_update_msg("failed to open cdr plugin");
1817 SetCdOpenCaseTime(time(NULL) + 2);
1820 strcpy(last_selected_fname, rom_fname_reload);
1824 static int swap_cd_multidisk(void)
1826 cdrIsoMultidiskSelect++;
1828 CdromLabel[0] = '\0';
1831 if (CDR_open() < 0) {
1832 me_update_msg("failed to open cdr plugin");
1836 SetCdOpenCaseTime(time(NULL) + 2);
1842 static int main_menu_handler(int id, int keys)
1846 case MA_MAIN_RESUME_GAME:
1850 case MA_MAIN_SAVE_STATE:
1852 return menu_loop_savestate(0);
1854 case MA_MAIN_LOAD_STATE:
1856 return menu_loop_savestate(1);
1858 case MA_MAIN_RESET_GAME:
1859 if (ready_to_go && reset_game() == 0)
1862 case MA_MAIN_LOAD_ROM:
1863 if (romsel_run() == 0)
1866 case MA_MAIN_SWAP_CD:
1867 if (swap_cd_image() == 0)
1870 case MA_MAIN_SWAP_CD_MULTI:
1871 if (swap_cd_multidisk() == 0)
1874 case MA_MAIN_RUN_BIOS:
1875 if (run_bios() == 0)
1878 case MA_MAIN_RUN_EXE:
1882 case MA_MAIN_CREDITS:
1883 draw_menu_message(credits_text, draw_frame_credits);
1884 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1890 lprintf("%s: something unknown selected\n", __FUNCTION__);
1897 static menu_entry e_menu_main2[] =
1899 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1900 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1901 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1902 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1903 mee_handler ("Memcard manager", menu_loop_memcards),
1907 static int main_menu2_handler(int id, int keys)
1911 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1912 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1913 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1915 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1918 static const char h_extra[] = "Change CD, manage memcards..\n";
1920 static menu_entry e_menu_main[] =
1924 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1925 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1926 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1927 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1928 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1929 mee_handler ("Options", menu_loop_options),
1930 mee_handler ("Controls", menu_loop_keyconfig),
1931 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1932 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1933 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1937 // ----------------------------
1939 static void menu_leave_emu(void);
1941 void menu_loop(void)
1947 if (bioses[1] == NULL && !warned_about_bios) {
1949 warned_about_bios = 1;
1952 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1953 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1954 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1955 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1957 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1960 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1961 } while (!ready_to_go);
1963 /* wait until menu, ok, back is released */
1964 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1967 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1972 static int qsort_strcmp(const void *p1, const void *p2)
1974 char * const *s1 = (char * const *)p1;
1975 char * const *s2 = (char * const *)p2;
1976 return strcasecmp(*s1, *s2);
1979 static void scan_bios_plugins(void)
1981 char fname[MAXPATHLEN];
1983 int bios_i, gpu_i, spu_i, mc_i;
1988 gpu_plugins[0] = "builtin_gpu";
1989 spu_plugins[0] = "builtin_spu";
1990 memcards[0] = "(none)";
1991 bios_i = gpu_i = spu_i = mc_i = 1;
1993 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1994 dir = opendir(fname);
1996 perror("scan_bios_plugins bios opendir");
2011 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2014 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2015 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2016 printf("bad BIOS file: %s\n", ent->d_name);
2020 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2021 bioses[bios_i++] = strdup(ent->d_name);
2025 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2031 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2032 dir = opendir(fname);
2034 perror("scan_bios_plugins plugins opendir");
2048 p = strstr(ent->d_name, ".so");
2052 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2053 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2055 fprintf(stderr, "%s\n", dlerror());
2059 // now what do we have here?
2060 tmp = dlsym(h, "GPUinit");
2063 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2064 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2068 tmp = dlsym(h, "SPUinit");
2071 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2072 spu_plugins[spu_i++] = strdup(ent->d_name);
2076 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2083 dir = opendir("." MEMCARD_DIR);
2085 perror("scan_bios_plugins memcards opendir");
2100 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2103 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2104 if (stat(fname, &st) != 0) {
2105 printf("bad memcard file: %s\n", ent->d_name);
2109 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2110 memcards[mc_i++] = strdup(ent->d_name);
2114 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2118 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2123 void menu_init(void)
2125 char buff[MAXPATHLEN];
2127 strcpy(last_selected_fname, "/media");
2129 scan_bios_plugins();
2133 menu_set_defconfig();
2134 menu_load_config(0);
2139 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2140 if (g_menubg_src_ptr == NULL)
2142 emu_make_path(buff, "skin/background.png", sizeof(buff));
2143 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2145 #ifndef __ARM_ARCH_7A__ /* XXX */
2146 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2147 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2149 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2150 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2154 void menu_notify_mode_change(int w, int h, int bpp)
2165 g_layer_w = w; g_layer_h = h;
2169 if (h > g_menuscreen_h || (240 < h && h <= 360))
2170 goto fractional_4_3;
2172 // 4:3 that prefers integer scaling
2173 imult = g_menuscreen_h / h;
2174 g_layer_w = w * imult;
2175 g_layer_h = h * imult;
2176 mult = (float)g_layer_w / (float)g_layer_h;
2177 if (mult < 1.25f || mult > 1.666f)
2178 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2179 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2184 mult = 240.0f / (float)h * 4.0f / 3.0f;
2187 g_layer_w = mult * (float)g_menuscreen_h;
2188 g_layer_h = g_menuscreen_h;
2189 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2192 case SCALE_FULLSCREEN:
2193 g_layer_w = g_menuscreen_w;
2194 g_layer_h = g_menuscreen_h;
2201 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2202 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2203 if (g_layer_x < 0) g_layer_x = 0;
2204 if (g_layer_y < 0) g_layer_y = 0;
2205 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2206 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2209 static void menu_leave_emu(void)
2211 if (GPU_close != NULL) {
2212 int ret = GPU_close();
2214 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2217 plat_video_menu_enter(ready_to_go);
2219 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2220 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2221 int x = max(0, g_menuscreen_w - last_psx_w);
2222 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2223 int w = min(g_menuscreen_w, last_psx_w);
2224 int h = min(g_menuscreen_h, last_psx_h);
2225 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2226 u16 *s = pl_vout_buf;
2228 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2229 menu_darken_bg(d, s, w, 0);
2233 cpu_clock = plat_cpu_clock_get();
2236 void menu_prepare_emu(void)
2238 R3000Acpu *prev_cpu = psxCpu;
2240 plat_video_menu_leave();
2242 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2244 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2245 if (psxCpu != prev_cpu)
2246 // note that this does not really reset, just clears drc caches
2249 // core doesn't care about Config.Cdda changes,
2250 // so handle them manually here
2255 apply_lcdrate(Config.PsxType);
2256 apply_filter(filter);
2257 plat_cpu_clock_apply(cpu_clock);
2259 // push config to GPU plugin
2260 plugin_call_rearmed_cbs();
2262 if (GPU_open != NULL) {
2263 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2265 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2271 void me_update_msg(const char *msg)
2273 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2274 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2276 menu_error_time = plat_get_ticks_ms();
2277 lprintf("msg: %s\n", menu_error_msg);