2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
16 #include <sys/types.h>
24 #include "plugin_lib.h"
27 #include "common/plat.h"
28 #include "common/input.h"
29 #include "linux/in_evdev.h"
30 #include "../libpcsxcore/misc.h"
31 #include "../libpcsxcore/cdrom.h"
32 #include "../libpcsxcore/cdriso.h"
33 #include "../libpcsxcore/cheat.h"
34 #include "../libpcsxcore/psemu_plugin_defs.h"
35 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
36 #include "../plugins/dfinput/main.h"
37 #include "../plugins/gpulib/cspace.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,
81 static int last_vout_w, last_vout_h, last_vout_bpp;
82 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
83 static char rom_fname_reload[MAXPATHLEN];
84 static char last_selected_fname[MAXPATHLEN];
85 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
87 static int memcard1_sel, memcard2_sel;
89 int soft_scaling, analog_deadzone; // for Caanoo
92 #ifdef __ARM_ARCH_7A__
93 #define DEFAULT_PSX_CLOCK 57
94 #define DEFAULT_PSX_CLOCK_S "57"
96 #define DEFAULT_PSX_CLOCK 50
97 #define DEFAULT_PSX_CLOCK_S "50"
101 extern int iUseReverb;
102 extern int iUseInterpolation;
106 static const char *bioses[24];
107 static const char *gpu_plugins[16];
108 static const char *spu_plugins[16];
109 static const char *memcards[32];
110 static int bios_sel, gpu_plugsel, spu_plugsel;
113 static int min(int x, int y) { return x < y ? x : y; }
114 static int max(int x, int y) { return x > y ? x : y; }
116 void emu_make_path(char *buff, const char *end, int size)
120 end_len = strlen(end);
121 pos = plat_get_root_dir(buff, size);
122 strncpy(buff + pos, end, size - pos);
124 if (pos + end_len > size - 1)
125 printf("Warning: path truncated: %s\n", buff);
128 static int emu_check_save_file(int slot, int *time)
130 char fname[MAXPATHLEN];
134 ret = emu_check_state(slot);
135 if (ret != 0 || time == NULL)
136 return ret == 0 ? 1 : 0;
138 ret = get_state_filename(fname, sizeof(fname), slot);
142 ret = stat(fname, &status);
146 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
147 return 1; // probably bad rtc like on some Caanoos
149 *time = status.st_mtime;
154 static int emu_save_load_game(int load, int unused)
159 ret = emu_load_state(state_slot);
161 // reflect hle/bios mode from savestate
164 else if (bios_sel == 0 && bioses[1] != NULL)
165 // XXX: maybe find the right bios instead
169 ret = emu_save_state(state_slot);
174 // propagate menu settings to the emu vars
175 static void menu_sync_config(void)
177 static int allow_abs_only_old;
182 Config.PsxType = region - 1;
184 cycle_multiplier = 10000 / psx_clock;
186 switch (in_type_sel1) {
187 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
188 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
189 default: in_type1 = PSE_PAD_TYPE_STANDARD;
191 switch (in_type_sel2) {
192 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
193 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
194 default: in_type2 = PSE_PAD_TYPE_STANDARD;
196 if (in_evdev_allow_abs_only != allow_abs_only_old) {
198 allow_abs_only_old = in_evdev_allow_abs_only;
201 iVolume = 768 + 128 * volume_boost;
202 pl_rearmed_cbs.frameskip = frameskip - 1;
203 pl_timing_prepare(Config.PsxType);
206 static void menu_set_defconfig(void)
208 emu_set_default_config();
211 g_scaler = SCALE_4_3;
214 analog_deadzone = 50;
216 psx_clock = DEFAULT_PSX_CLOCK;
219 in_type_sel1 = in_type_sel2 = 0;
220 in_evdev_allow_abs_only = 0;
225 #define CE_CONFIG_STR(val) \
226 { #val, 0, Config.val }
228 #define CE_CONFIG_VAL(val) \
229 { #val, sizeof(Config.val), &Config.val }
231 #define CE_STR(val) \
234 #define CE_INTVAL(val) \
235 { #val, sizeof(val), &val }
237 #define CE_INTVAL_P(val) \
238 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
240 // 'versioned' var, used when defaults change
241 #define CE_CONFIG_STR_V(val, ver) \
242 { #val #ver, 0, Config.val }
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 {
256 CE_CONFIG_STR_V(Gpu, 3),
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(g_scaler, 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.lineskip),
287 CE_INTVAL_P(gpu_unai.abe_hack),
288 CE_INTVAL_P(gpu_unai.no_light),
289 CE_INTVAL_P(gpu_unai.no_blend),
290 CE_INTVAL_P(gpu_neon.allow_interlace),
291 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
292 CE_INTVAL_P(gpu_peopsgl.iFilterType),
293 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
294 CE_INTVAL_P(gpu_peopsgl.iUseMask),
295 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
296 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
297 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
298 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
299 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
300 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
301 CE_INTVAL_V(iUseReverb, 3),
302 CE_INTVAL_V(iXAPitch, 3),
303 CE_INTVAL_V(iUseInterpolation, 3),
304 CE_INTVAL(warned_about_bios),
305 CE_INTVAL(in_evdev_allow_abs_only),
306 CE_INTVAL(volume_boost),
307 CE_INTVAL(psx_clock),
308 CE_INTVAL(new_dynarec_hacks),
309 CE_INTVAL(in_enable_vibration),
312 static char *get_cd_label(void)
314 static char trimlabel[33];
317 strncpy(trimlabel, CdromLabel, 32);
319 for (j = 31; j >= 0; j--)
320 if (trimlabel[j] == ' ')
326 static void make_cfg_fname(char *buf, size_t size, int is_game)
329 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
331 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
334 static void keys_write_all(FILE *f);
335 static char *mystrip(char *str);
337 static int menu_write_config(int is_game)
339 char cfgfile[MAXPATHLEN];
343 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
344 f = fopen(cfgfile, "w");
346 printf("menu_write_config: failed to open: %s\n", cfgfile);
350 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
351 fprintf(f, "%s = ", config_data[i].name);
352 switch (config_data[i].len) {
354 fprintf(f, "%s\n", (char *)config_data[i].val);
357 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
360 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
363 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
366 printf("menu_write_config: unhandled len %d for %s\n",
367 config_data[i].len, config_data[i].name);
378 static int menu_do_last_cd_img(int is_get)
384 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
385 f = fopen(path, is_get ? "r" : "w");
390 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
391 last_selected_fname[ret] = 0;
392 mystrip(last_selected_fname);
395 fprintf(f, "%s\n", last_selected_fname);
401 static void parse_str_val(char *cval, const char *src)
404 strncpy(cval, src, MAXPATHLEN);
405 cval[MAXPATHLEN - 1] = 0;
406 tmp = strchr(cval, '\n');
408 tmp = strchr(cval, '\r');
413 static void keys_load_all(const char *cfg);
415 static int menu_load_config(int is_game)
417 char cfgfile[MAXPATHLEN];
423 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
424 f = fopen(cfgfile, "r");
426 printf("menu_load_config: failed to open: %s\n", cfgfile);
430 fseek(f, 0, SEEK_END);
433 printf("bad size %ld: %s\n", size, cfgfile);
437 cfg = malloc(size + 1);
441 fseek(f, 0, SEEK_SET);
442 if (fread(cfg, 1, size, f) != size) {
443 printf("failed to read: %s\n", cfgfile);
448 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
452 tmp = strstr(cfg, config_data[i].name);
455 tmp += strlen(config_data[i].name);
456 if (strncmp(tmp, " = ", 3) != 0)
460 if (config_data[i].len == 0) {
461 parse_str_val(config_data[i].val, tmp);
466 val = strtoul(tmp, &tmp2, 16);
467 if (tmp2 == NULL || tmp == tmp2)
468 continue; // parse failed
470 switch (config_data[i].len) {
472 *(u8 *)config_data[i].val = val;
475 *(u16 *)config_data[i].val = val;
478 *(u32 *)config_data[i].val = val;
481 printf("menu_load_config: unhandled len %d for %s\n",
482 config_data[i].len, config_data[i].name);
488 char *tmp = strstr(cfg, "lastcdimg = ");
491 parse_str_val(last_selected_fname, tmp);
506 for (i = bios_sel = 0; bioses[i] != NULL; i++)
507 if (strcmp(Config.Bios, bioses[i]) == 0)
508 { bios_sel = i; break; }
510 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
511 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
512 { gpu_plugsel = i; break; }
514 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
515 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
516 { spu_plugsel = i; break; }
521 // rrrr rggg gggb bbbb
522 static unsigned short fname2color(const char *fname)
524 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
525 ".bz", ".znx", ".pbp", ".cbn" };
526 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
527 ".table", ".index", ".sbi" };
528 const char *ext = strrchr(fname, '.');
533 for (i = 0; i < array_size(cdimg_exts); i++)
534 if (strcasecmp(ext, cdimg_exts[i]) == 0)
536 for (i = 0; i < array_size(other_exts); i++)
537 if (strcasecmp(ext, other_exts[i]) == 0)
542 static void draw_savestate_bg(int slot);
544 static const char *filter_exts[] = {
545 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
548 #define MENU_ALIGN_LEFT
549 #ifdef __ARM_ARCH_7A__ // assume hires device
555 #define menu_init menu_init_common
556 #include "common/menu.c"
559 // a bit of black magic here
560 static void draw_savestate_bg(int slot)
562 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
564 char fname[MAXPATHLEN];
571 ret = get_state_filename(fname, sizeof(fname), slot);
575 f = gzopen(fname, "rb");
579 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
580 fprintf(stderr, "gzseek failed\n");
585 gpu = malloc(sizeof(*gpu));
591 ret = gzread(f, gpu, sizeof(*gpu));
593 if (ret != sizeof(*gpu)) {
594 fprintf(stderr, "gzread failed\n");
598 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
600 if (gpu->ulStatus & 0x800000)
601 goto out; // disabled
603 x = gpu->ulControl[5] & 0x3ff;
604 y = (gpu->ulControl[5] >> 10) & 0x1ff;
605 s = (u16 *)gpu->psxVRam + y * 1024 + x;
606 w = psx_widths[(gpu->ulStatus >> 16) & 7];
607 tmp = gpu->ulControl[7];
608 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
609 if (gpu->ulStatus & 0x80000) // doubleheight
612 x = max(0, g_menuscreen_w - w) & ~3;
613 y = max(0, g_menuscreen_h / 2 - h / 2);
614 w = min(g_menuscreen_w, w);
615 h = min(g_menuscreen_h, h);
616 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
618 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
619 if (gpu->ulStatus & 0x200000)
620 bgr888_to_rgb565(d, s, w * 3);
622 bgr555_to_rgb565(d, s, w * 2);
624 // darken this so that menu text is visible
625 if (g_menuscreen_w - w < 320)
626 menu_darken_bg(d, d, w * 2, 0);
633 // -------------- key config --------------
635 me_bind_action me_ctrl_actions[] =
637 { "UP ", 1 << DKEY_UP},
638 { "DOWN ", 1 << DKEY_DOWN },
639 { "LEFT ", 1 << DKEY_LEFT },
640 { "RIGHT ", 1 << DKEY_RIGHT },
641 { "TRIANGLE", 1 << DKEY_TRIANGLE },
642 { "CIRCLE ", 1 << DKEY_CIRCLE },
643 { "CROSS ", 1 << DKEY_CROSS },
644 { "SQUARE ", 1 << DKEY_SQUARE },
645 { "L1 ", 1 << DKEY_L1 },
646 { "R1 ", 1 << DKEY_R1 },
647 { "L2 ", 1 << DKEY_L2 },
648 { "R2 ", 1 << DKEY_R2 },
649 { "L3 ", 1 << DKEY_L3 },
650 { "R3 ", 1 << DKEY_R3 },
651 { "START ", 1 << DKEY_START },
652 { "SELECT ", 1 << DKEY_SELECT },
656 me_bind_action emuctrl_actions[] =
658 { "Save State ", 1 << SACTION_SAVE_STATE },
659 { "Load State ", 1 << SACTION_LOAD_STATE },
660 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
661 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
662 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
663 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
664 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
665 #ifdef __ARM_ARCH_7A__ /* XXX */
666 { "Minimize ", 1 << SACTION_MINIMIZE },
668 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
669 { "Gun A button ", 1 << SACTION_GUN_A },
670 { "Gun B button ", 1 << SACTION_GUN_B },
671 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
672 #ifndef __ARM_ARCH_7A__ /* XXX */
673 { "Volume Up ", 1 << SACTION_VOLUME_UP },
674 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
679 static char *mystrip(char *str)
684 for (i = 0; i < len; i++)
685 if (str[i] != ' ') break;
686 if (i > 0) memmove(str, str + i, len - i + 1);
689 for (i = len - 1; i >= 0; i--)
690 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
696 static void get_line(char *d, size_t size, const char *s)
701 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
712 static void keys_write_all(FILE *f)
716 for (d = 0; d < IN_MAX_DEVS; d++)
718 const int *binds = in_get_dev_binds(d);
719 const char *name = in_get_dev_name(d, 0, 0);
722 if (binds == NULL || name == NULL)
725 fprintf(f, "binddev = %s\n", name);
726 in_get_config(d, IN_CFG_BIND_COUNT, &count);
728 for (k = 0; k < count; k++)
733 act[0] = act[31] = 0;
734 name = in_get_key_name(d, k);
736 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
737 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
738 mask = me_ctrl_actions[i].mask;
740 strncpy(act, me_ctrl_actions[i].name, 31);
741 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
744 mask = me_ctrl_actions[i].mask << 16;
746 strncpy(act, me_ctrl_actions[i].name, 31);
747 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
752 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
753 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
754 mask = emuctrl_actions[i].mask;
756 strncpy(act, emuctrl_actions[i].name, 31);
757 fprintf(f, "bind %s = %s\n", name, mystrip(act));
763 for (k = 0; k < array_size(in_adev); k++)
766 fprintf(f, "bind_analog = %d\n", k);
771 static int parse_bind_val(const char *val, int *type)
775 *type = IN_BINDTYPE_NONE;
779 if (strncasecmp(val, "player", 6) == 0)
781 int player, shift = 0;
782 player = atoi(val + 6) - 1;
784 if ((unsigned int)player > 1)
789 *type = IN_BINDTYPE_PLAYER12;
790 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
791 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
792 return me_ctrl_actions[i].mask << shift;
795 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
796 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
797 *type = IN_BINDTYPE_EMU;
798 return emuctrl_actions[i].mask;
805 static void keys_load_all(const char *cfg)
807 char dev[256], key[128], *act;
813 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
816 get_line(dev, sizeof(dev), p);
817 dev_id = in_config_parse_dev(dev);
819 printf("input: can't handle dev: %s\n", dev);
823 in_unbind_all(dev_id, -1, -1);
824 while ((p = strstr(p, "bind"))) {
825 if (strncmp(p, "binddev = ", 10) == 0)
828 if (strncmp(p, "bind_analog", 11) == 0) {
829 ret = sscanf(p, "bind_analog = %d", &bind);
832 printf("input: parse error: %16s..\n", p);
835 if ((unsigned int)bind >= array_size(in_adev)) {
836 printf("input: analog id %d out of range\n", bind);
839 in_adev[bind] = dev_id;
845 printf("input: parse error: %16s..\n", p);
849 get_line(key, sizeof(key), p);
850 act = strchr(key, '=');
852 printf("parse failed: %16s..\n", p);
860 bind = parse_bind_val(act, &bindtype);
861 if (bind != -1 && bind != 0) {
862 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
863 in_config_bind_key(dev_id, key, bind, bindtype);
866 lprintf("config: unhandled action \"%s\"\n", act);
872 static int key_config_loop_wrap(int id, int keys)
875 case MA_CTRL_PLAYER1:
876 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
878 case MA_CTRL_PLAYER2:
879 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
882 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
890 static const char *adevnames[IN_MAX_DEVS + 2];
891 static int stick_sel[2];
893 static menu_entry e_menu_keyconfig_analog[] =
895 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
896 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
897 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
898 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
899 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
900 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
904 static int key_config_analog(int id, int keys)
906 int i, d, count, sel = 0;
907 int sel2dev_map[IN_MAX_DEVS];
909 memset(adevnames, 0, sizeof(adevnames));
910 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
911 memset(stick_sel, 0, sizeof(stick_sel));
913 adevnames[0] = "None";
915 for (d = 0; d < IN_MAX_DEVS; d++)
917 const char *name = in_get_dev_name(d, 0, 1);
922 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
926 if (in_adev[0] == d) stick_sel[0] = i;
927 if (in_adev[1] == d) stick_sel[1] = i;
929 adevnames[i++] = name;
933 me_loop(e_menu_keyconfig_analog, &sel);
935 in_adev[0] = sel2dev_map[stick_sel[0]];
936 in_adev[1] = sel2dev_map[stick_sel[1]];
941 static const char *mgn_dev_name(int id, int *offs)
943 const char *name = NULL;
946 if (id == MA_CTRL_DEV_FIRST)
949 for (; it < IN_MAX_DEVS; it++) {
950 name = in_get_dev_name(it, 1, 1);
959 static const char *mgn_saveloadcfg(int id, int *offs)
964 static int mh_savecfg(int id, int keys)
966 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
967 me_update_msg("config saved");
969 me_update_msg("failed to write config");
974 static int mh_input_rescan(int id, int keys)
976 //menu_sync_config();
978 me_update_msg("rescan complete.");
983 static const char *men_in_type_sel[] = {
984 "Standard (SCPH-1080)",
985 "Analog (SCPH-1150)",
989 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
990 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
991 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
993 static menu_entry e_menu_keyconfig[] =
995 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
996 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
997 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
998 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1000 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1001 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1002 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1003 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1004 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1005 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1006 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1007 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1008 mee_handler ("Rescan devices:", mh_input_rescan),
1010 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1011 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1012 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1013 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1014 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1015 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1016 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1020 static int menu_loop_keyconfig(int id, int keys)
1024 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1025 me_loop(e_menu_keyconfig, &sel);
1029 // ------------ gfx options menu ------------
1031 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1032 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1033 "using d-pad or move it using R+d-pad";
1034 static const char *men_dummy[] = { NULL };
1036 static int menu_loop_cscaler(int id, int keys)
1040 g_scaler = SCALE_CUSTOM;
1042 plat_gvideo_open(Config.PsxType);
1047 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1048 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1049 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1052 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1053 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1054 if (inp & PBTN_UP) g_layer_y--;
1055 if (inp & PBTN_DOWN) g_layer_y++;
1056 if (inp & PBTN_LEFT) g_layer_x--;
1057 if (inp & PBTN_RIGHT) g_layer_x++;
1058 if (!(inp & PBTN_R)) {
1059 if (inp & PBTN_UP) g_layer_h += 2;
1060 if (inp & PBTN_DOWN) g_layer_h -= 2;
1061 if (inp & PBTN_LEFT) g_layer_w += 2;
1062 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1064 if (inp & (PBTN_MOK|PBTN_MBACK))
1067 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1068 if (g_layer_x < 0) g_layer_x = 0;
1069 if (g_layer_x > 640) g_layer_x = 640;
1070 if (g_layer_y < 0) g_layer_y = 0;
1071 if (g_layer_y > 420) g_layer_y = 420;
1072 if (g_layer_w < 160) g_layer_w = 160;
1073 if (g_layer_h < 60) g_layer_h = 60;
1074 if (g_layer_x + g_layer_w > 800)
1075 g_layer_w = 800 - g_layer_x;
1076 if (g_layer_y + g_layer_h > 480)
1077 g_layer_h = 480 - g_layer_y;
1079 plat_gvideo_open(Config.PsxType);
1083 plat_gvideo_close();
1088 static menu_entry e_menu_gfx_options[] =
1090 mee_enum ("Scaler", MA_OPT_SCALER, g_scaler, men_scaler),
1091 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1092 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1093 // mee_onoff ("Vsync", 0, vsync, 1),
1094 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1098 static int menu_loop_gfx_options(int id, int keys)
1102 me_loop(e_menu_gfx_options, &sel);
1108 void menu_set_filter_list(void *filters)
1112 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1113 e_menu_gfx_options[i].data = filters;
1114 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1117 // ------------ bios/plugins ------------
1121 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1122 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1124 static menu_entry e_menu_plugin_gpu_neon[] =
1126 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1130 static int menu_loop_plugin_gpu_neon(int id, int keys)
1133 me_loop(e_menu_plugin_gpu_neon, &sel);
1139 static menu_entry e_menu_plugin_gpu_unai[] =
1141 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1142 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1143 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1144 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1148 static int menu_loop_plugin_gpu_unai(int id, int keys)
1151 me_loop(e_menu_plugin_gpu_unai, &sel);
1155 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1156 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1157 static const char h_gpu_1[] = "Capcom fighting games";
1158 static const char h_gpu_2[] = "Black screens in Lunar";
1159 static const char h_gpu_3[] = "Compatibility mode";
1160 static const char h_gpu_6[] = "Pandemonium 2";
1161 //static const char h_gpu_7[] = "Skip every second frame";
1162 static const char h_gpu_8[] = "Needed by Dark Forces";
1163 static const char h_gpu_9[] = "better g-colors, worse textures";
1164 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1166 static menu_entry e_menu_plugin_gpu_peops[] =
1168 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1169 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1170 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1171 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1172 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1173 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1174 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1175 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1176 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1177 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1181 static int menu_loop_plugin_gpu_peops(int id, int keys)
1184 me_loop(e_menu_plugin_gpu_peops, &sel);
1188 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1189 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1190 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1192 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1194 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1195 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1196 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1197 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1198 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1199 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1200 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1201 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1202 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1203 mee_label ("Fixes/hacks:"),
1204 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1205 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1206 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1207 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1208 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1209 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1210 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1211 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1212 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1213 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1214 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1218 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1221 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1225 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1226 static const char h_spu_volboost[] = "Large values cause distortion";
1228 static menu_entry e_menu_plugin_spu[] =
1230 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1231 mee_onoff ("Reverb", 0, iUseReverb, 2),
1232 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1233 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1237 static int menu_loop_plugin_spu(int id, int keys)
1240 me_loop(e_menu_plugin_spu, &sel);
1244 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1245 "savestates and can't be changed there. Must save\n"
1246 "config and reload the game for change to take effect";
1247 static const char h_plugin_gpu[] =
1249 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1251 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1252 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1253 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1254 "must save config and reload the game if changed";
1255 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1256 "must save config and reload the game if changed";
1257 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1258 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1259 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1260 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1262 static menu_entry e_menu_plugin_options[] =
1264 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1265 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1266 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1268 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1270 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1271 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1272 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1273 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1277 static menu_entry e_menu_main2[];
1279 static int menu_loop_plugin_options(int id, int keys)
1282 me_loop(e_menu_plugin_options, &sel);
1284 // sync BIOS/plugins
1285 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1286 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1287 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1288 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1293 // ------------ adv options menu ------------
1295 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1296 "(lower value - less work for the emu, may be faster)";
1297 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1298 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1299 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1301 static menu_entry e_menu_speed_hacks[] =
1303 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1304 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1305 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1306 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1310 static int menu_loop_speed_hacks(int id, int keys)
1313 me_loop(e_menu_speed_hacks, &sel);
1317 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1318 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1319 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1320 "(green: normal, red: fmod, blue: noise)";
1321 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1322 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1323 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1324 "(proper .cue/.bin dump is needed otherwise)";
1325 static const char h_cfg_sio[] = "You should not need this, breaks games";
1326 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1327 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1328 "(timing hack, breaks other games)";
1329 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1330 "(timing hack, breaks other games)";
1331 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1332 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1333 "Might be useful to overcome some dynarec bugs";
1334 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1335 "must reload game for any change to take effect";
1337 static menu_entry e_menu_adv_options[] =
1339 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1340 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1341 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1342 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1343 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1344 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1345 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1346 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1347 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1348 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1349 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1350 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1354 static int menu_loop_adv_options(int id, int keys)
1357 me_loop(e_menu_adv_options, &sel);
1361 // ------------ options menu ------------
1363 static int mh_restore_defaults(int id, int keys)
1365 menu_set_defconfig();
1366 me_update_msg("defaults restored");
1370 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1371 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1373 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1374 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1375 "loading state or both";
1377 static const char h_restore_def[] = "Switches back to default / recommended\n"
1379 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1381 static menu_entry e_menu_options[] =
1383 // mee_range ("Save slot", 0, state_slot, 0, 9),
1384 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1385 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1386 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1387 mee_enum ("Region", 0, region, men_region),
1388 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1389 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1390 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1391 mee_handler ("[Advanced]", menu_loop_adv_options),
1392 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1393 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1394 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1398 static int menu_loop_options(int id, int keys)
1403 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1404 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1405 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1407 me_loop(e_menu_options, &sel);
1412 // ------------ debug menu ------------
1414 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1416 int w = min(g_menuscreen_w, 1024);
1417 int h = min(g_menuscreen_h, 512);
1418 u16 *d = g_menuscreen_ptr;
1419 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1423 gpuf->ulFreezeVersion = 1;
1424 if (GPU_freeze != NULL)
1425 GPU_freeze(1, gpuf);
1427 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1428 bgr555_to_rgb565(d, s, w * 2);
1430 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1431 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1432 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1433 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1434 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1437 static void debug_menu_loop(void)
1439 int inp, df_x = 0, df_y = 0;
1442 gpuf = malloc(sizeof(*gpuf));
1449 draw_frame_debug(gpuf, df_x, df_y);
1452 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1453 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1454 if (inp & PBTN_MBACK) break;
1455 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1456 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1457 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1458 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1464 // --------- memcard manager ---------
1466 static void draw_mc_icon(int dx, int dy, const u16 *s)
1471 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1473 for (y = 0; y < 16; y++, s += 16) {
1474 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1475 for (x = 0; x < 16; x++) {
1477 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1478 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1484 static void draw_mc_bg(void)
1486 McdBlock *blocks1, *blocks2;
1490 blocks1 = malloc(15 * sizeof(blocks1[0]));
1491 blocks2 = malloc(15 * sizeof(blocks1[0]));
1492 if (blocks1 == NULL || blocks2 == NULL)
1495 for (i = 0; i < 15; i++) {
1496 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1497 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1502 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1504 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1508 maxicons = g_menuscreen_h / 32;
1511 row2 = g_menuscreen_w / 2;
1512 for (i = 0; i < maxicons; i++) {
1513 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1514 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1516 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1517 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1520 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1528 static void handle_memcard_sel(void)
1531 if (memcard1_sel != 0)
1532 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1534 if (memcard2_sel != 0)
1535 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1536 LoadMcds(Config.Mcd1, Config.Mcd2);
1540 static menu_entry e_memcard_options[] =
1542 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1543 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1547 static int menu_loop_memcards(int id, int keys)
1553 memcard1_sel = memcard2_sel = 0;
1554 p = strrchr(Config.Mcd1, '/');
1556 for (i = 0; memcards[i] != NULL; i++)
1557 if (strcmp(p + 1, memcards[i]) == 0)
1558 { memcard1_sel = i; break; }
1559 p = strrchr(Config.Mcd2, '/');
1561 for (i = 0; memcards[i] != NULL; i++)
1562 if (strcmp(p + 1, memcards[i]) == 0)
1563 { memcard2_sel = i; break; }
1565 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1567 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1572 // ------------ cheats menu ------------
1574 static void draw_cheatlist(int sel)
1576 int max_cnt, start, i, pos, active;
1578 max_cnt = g_menuscreen_h / me_sfont_h;
1579 start = max_cnt / 2 - sel;
1583 for (i = 0; i < NumCheats; i++) {
1585 if (pos < 0) continue;
1586 if (pos >= max_cnt) break;
1587 active = Cheats[i].Enabled;
1588 smalltext_out16(14, pos * me_sfont_h,
1589 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1590 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1591 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1595 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1597 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1601 static void menu_loop_cheats(void)
1603 static int menu_sel = 0;
1608 draw_cheatlist(menu_sel);
1609 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1610 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1611 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1612 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1613 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1614 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1615 if (inp & PBTN_MOK) { // action
1616 if (menu_sel < NumCheats)
1617 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1620 if (inp & PBTN_MBACK)
1625 // --------- main menu help ----------
1627 static void menu_bios_warn(void)
1630 static const char msg[] =
1631 "You don't seem to have copied any BIOS\n"
1633 #ifdef __ARM_ARCH_7A__ // XXX
1634 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1636 "pcsx_rearmed/bios/\n\n"
1638 "While many games work fine with fake\n"
1639 "(HLE) BIOS, others (like MGS and FF8)\n"
1640 "require BIOS to work.\n"
1641 "After copying the file, you'll also need\n"
1642 "to select it in the emu's menu:\n"
1643 "options->[BIOS/Plugins]\n\n"
1644 "The file is usually named SCPH1001.BIN,\n"
1645 "but other not compressed files can be\n"
1647 "Press %s or %s to continue";
1648 char tmp_msg[sizeof(msg) + 64];
1650 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1651 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1654 draw_menu_message(tmp_msg, NULL);
1656 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1657 if (inp & (PBTN_MBACK|PBTN_MOK))
1662 // ------------ main menu ------------
1664 static menu_entry e_menu_main[];
1667 static void draw_frame_main(void)
1676 if (CdromId[0] != 0) {
1677 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1678 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1679 Config.HLE ? "HLE" : "BIOS");
1680 smalltext_out16(4, 1, buff, 0x105f);
1684 capacity = plat_get_bat_capacity();
1686 tmp = localtime(<ime);
1687 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1688 if (capacity >= 0) {
1689 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1694 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1698 static void draw_frame_credits(void)
1700 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1703 static const char credits_text[] =
1705 "(C) 1999-2003 PCSX Team\n"
1706 "(C) 2005-2009 PCSX-df Team\n"
1707 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1708 "ARM recompiler (C) 2009-2011 Ari64\n"
1710 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1712 "PEOpS GPU and SPU by Pete Bernert\n"
1713 " and the P.E.Op.S. team\n"
1714 "PCSX4ALL plugin by PCSX4ALL team\n"
1715 " Chui, Franxis, Unai\n\n"
1716 "integration, optimization and\n"
1717 " frontend (C) 2010-2012 notaz\n";
1719 static int reset_game(void)
1722 if (bios_sel == 0 && !Config.HLE)
1728 if (CheckCdrom() != -1) {
1734 static int reload_plugins(const char *cdimg)
1740 set_cd_image(cdimg);
1742 pcnt_hook_plugins();
1744 if (OpenPlugins() == -1) {
1745 me_update_msg("failed to open plugins");
1748 plugin_call_rearmed_cbs();
1750 cdrIsoMultidiskCount = 1;
1752 CdromLabel[0] = '\0';
1757 static int run_bios(void)
1763 if (reload_plugins(NULL) != 0)
1771 static int run_exe(void)
1775 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1780 if (reload_plugins(NULL) != 0)
1784 if (Load(fname) != 0) {
1785 me_update_msg("exe load failed, bad file?");
1794 static int run_cd_image(const char *fname)
1797 reload_plugins(fname);
1799 // always autodetect, menu_sync_config will override as needed
1802 if (CheckCdrom() == -1) {
1803 // Only check the CD if we are starting the console with a CD
1805 me_update_msg("unsupported/invalid CD image");
1811 // Read main executable directly from CDRom and start it
1812 if (LoadCdrom() == -1) {
1814 me_update_msg("failed to load CD image");
1824 static int romsel_run(void)
1826 int prev_gpu, prev_spu;
1829 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1833 printf("selected file: %s\n", fname);
1835 new_dynarec_clear_full();
1837 if (run_cd_image(fname) != 0)
1840 prev_gpu = gpu_plugsel;
1841 prev_spu = spu_plugsel;
1842 if (menu_load_config(1) != 0)
1843 menu_load_config(0);
1845 // check for plugin changes, have to repeat
1846 // loading if game config changed plugins to reload them
1847 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1848 printf("plugin change detected, reloading plugins..\n");
1849 if (run_cd_image(fname) != 0)
1853 strcpy(last_selected_fname, rom_fname_reload);
1854 menu_do_last_cd_img(0);
1858 static int swap_cd_image(void)
1862 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1866 printf("selected file: %s\n", fname);
1869 CdromLabel[0] = '\0';
1871 set_cd_image(fname);
1872 if (ReloadCdromPlugin() < 0) {
1873 me_update_msg("failed to load cdr plugin");
1876 if (CDR_open() < 0) {
1877 me_update_msg("failed to open cdr plugin");
1881 SetCdOpenCaseTime(time(NULL) + 2);
1884 strcpy(last_selected_fname, rom_fname_reload);
1888 static int swap_cd_multidisk(void)
1890 cdrIsoMultidiskSelect++;
1892 CdromLabel[0] = '\0';
1895 if (CDR_open() < 0) {
1896 me_update_msg("failed to open cdr plugin");
1900 SetCdOpenCaseTime(time(NULL) + 2);
1906 static void load_pcsx_cht(void)
1912 fname = menu_loop_romsel(path, sizeof(path));
1916 printf("selected cheat file: %s\n", fname);
1919 if (NumCheats == 0 && NumCodes == 0)
1920 me_update_msg("failed to load cheats");
1922 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1923 me_update_msg(path);
1925 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1928 static int main_menu_handler(int id, int keys)
1932 case MA_MAIN_RESUME_GAME:
1936 case MA_MAIN_SAVE_STATE:
1938 return menu_loop_savestate(0);
1940 case MA_MAIN_LOAD_STATE:
1942 return menu_loop_savestate(1);
1944 case MA_MAIN_RESET_GAME:
1945 if (ready_to_go && reset_game() == 0)
1948 case MA_MAIN_LOAD_ROM:
1949 if (romsel_run() == 0)
1952 case MA_MAIN_SWAP_CD:
1953 if (swap_cd_image() == 0)
1956 case MA_MAIN_SWAP_CD_MULTI:
1957 if (swap_cd_multidisk() == 0)
1960 case MA_MAIN_RUN_BIOS:
1961 if (run_bios() == 0)
1964 case MA_MAIN_RUN_EXE:
1968 case MA_MAIN_CHEATS:
1971 case MA_MAIN_LOAD_CHEATS:
1974 case MA_MAIN_CREDITS:
1975 draw_menu_message(credits_text, draw_frame_credits);
1976 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1982 lprintf("%s: something unknown selected\n", __FUNCTION__);
1989 static menu_entry e_menu_main2[] =
1991 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1992 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1993 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1994 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1995 mee_handler ("Memcard manager", menu_loop_memcards),
1996 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2000 static int main_menu2_handler(int id, int keys)
2004 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2005 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2006 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2007 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2009 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2012 static const char h_extra[] = "Change CD, manage memcards..\n";
2014 static menu_entry e_menu_main[] =
2018 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2019 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2020 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2021 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2022 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2023 mee_handler ("Options", menu_loop_options),
2024 mee_handler ("Controls", menu_loop_keyconfig),
2025 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2026 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2027 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2028 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2032 // ----------------------------
2034 static void menu_leave_emu(void);
2036 void menu_loop(void)
2042 if (bioses[1] == NULL && !warned_about_bios) {
2044 warned_about_bios = 1;
2047 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2048 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2049 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2050 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2051 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2053 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2056 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2057 } while (!ready_to_go);
2059 /* wait until menu, ok, back is released */
2060 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2063 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2068 static int qsort_strcmp(const void *p1, const void *p2)
2070 char * const *s1 = (char * const *)p1;
2071 char * const *s2 = (char * const *)p2;
2072 return strcasecmp(*s1, *s2);
2075 static void scan_bios_plugins(void)
2077 char fname[MAXPATHLEN];
2079 int bios_i, gpu_i, spu_i, mc_i;
2084 gpu_plugins[0] = "builtin_gpu";
2085 spu_plugins[0] = "builtin_spu";
2086 memcards[0] = "(none)";
2087 bios_i = gpu_i = spu_i = mc_i = 1;
2089 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2090 dir = opendir(fname);
2092 perror("scan_bios_plugins bios opendir");
2107 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2110 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2111 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2112 printf("bad BIOS file: %s\n", ent->d_name);
2116 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2117 bioses[bios_i++] = strdup(ent->d_name);
2121 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2127 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2128 dir = opendir(fname);
2130 perror("scan_bios_plugins plugins opendir");
2144 p = strstr(ent->d_name, ".so");
2148 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2149 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2151 fprintf(stderr, "%s\n", dlerror());
2155 // now what do we have here?
2156 tmp = dlsym(h, "GPUinit");
2159 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2160 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2164 tmp = dlsym(h, "SPUinit");
2167 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2168 spu_plugins[spu_i++] = strdup(ent->d_name);
2172 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2179 dir = opendir("." MEMCARD_DIR);
2181 perror("scan_bios_plugins memcards opendir");
2196 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2199 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2200 if (stat(fname, &st) != 0) {
2201 printf("bad memcard file: %s\n", ent->d_name);
2205 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2206 memcards[mc_i++] = strdup(ent->d_name);
2210 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2214 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2219 void menu_init(void)
2221 char buff[MAXPATHLEN];
2223 strcpy(last_selected_fname, "/media");
2225 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2227 scan_bios_plugins();
2230 menu_set_defconfig();
2231 menu_load_config(0);
2232 menu_do_last_cd_img(1);
2237 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2238 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2239 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2240 fprintf(stderr, "OOM\n");
2244 emu_make_path(buff, "skin/background.png", sizeof(buff));
2245 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2247 #ifndef __ARM_ARCH_7A__ /* XXX */
2248 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2249 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2250 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2251 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2253 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2254 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2255 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2259 void menu_notify_mode_change(int w, int h, int bpp)
2263 last_vout_bpp = bpp;
2266 static void menu_leave_emu(void)
2268 if (GPU_close != NULL) {
2269 int ret = GPU_close();
2271 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2274 plat_video_menu_enter(ready_to_go);
2276 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2277 if (pl_vout_buf != NULL && ready_to_go) {
2278 int x = max(0, g_menuscreen_w - last_vout_w);
2279 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2280 int w = min(g_menuscreen_w, last_vout_w);
2281 int h = min(g_menuscreen_h, last_vout_h);
2282 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2283 char *s = pl_vout_buf;
2285 if (last_vout_bpp == 16) {
2286 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2287 menu_darken_bg(d, s, w, 0);
2290 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2291 rgb888_to_rgb565(d, s, w * 3);
2292 menu_darken_bg(d, d, w, 0);
2298 cpu_clock = plat_cpu_clock_get();
2301 void menu_prepare_emu(void)
2303 R3000Acpu *prev_cpu = psxCpu;
2305 plat_video_menu_leave();
2307 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2308 if (psxCpu != prev_cpu)
2309 // note that this does not really reset, just clears drc caches
2312 // core doesn't care about Config.Cdda changes,
2313 // so handle them manually here
2319 plat_cpu_clock_apply(cpu_clock);
2321 // push config to GPU plugin
2322 plugin_call_rearmed_cbs();
2324 if (GPU_open != NULL) {
2325 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2327 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2333 void me_update_msg(const char *msg)
2335 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2336 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2338 menu_error_time = plat_get_ticks_ms();
2339 lprintf("msg: %s\n", menu_error_msg);
2342 void menu_finish(void)
2344 plat_cpu_clock_apply(cpu_clock_st);