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/psemu_plugin_defs.h"
34 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
35 #include "../plugins/dfinput/main.h"
36 #include "../plugins/gpulib/cspace.h"
39 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
41 #define array_size(x) (sizeof(x) / sizeof(x[0]))
52 MA_MAIN_SWAP_CD_MULTI,
86 static int last_psx_w, last_psx_h, last_psx_bpp;
87 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
88 static char rom_fname_reload[MAXPATHLEN];
89 static char last_selected_fname[MAXPATHLEN];
90 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
92 static int memcard1_sel, memcard2_sel;
94 int soft_scaling, analog_deadzone; // for Caanoo
96 #ifdef __ARM_ARCH_7A__
97 #define DEFAULT_PSX_CLOCK 57
98 #define DEFAULT_PSX_CLOCK_S "57"
100 #define DEFAULT_PSX_CLOCK 50
101 #define DEFAULT_PSX_CLOCK_S "50"
105 extern int iUseReverb;
106 extern int iUseInterpolation;
108 extern int iSPUIRQWait;
109 extern int iUseTimer;
112 static const char *bioses[24];
113 static const char *gpu_plugins[16];
114 static const char *spu_plugins[16];
115 static const char *memcards[32];
116 static int bios_sel, gpu_plugsel, spu_plugsel;
119 static int min(int x, int y) { return x < y ? x : y; }
120 static int max(int x, int y) { return x > y ? x : y; }
122 void emu_make_path(char *buff, const char *end, int size)
126 end_len = strlen(end);
127 pos = plat_get_root_dir(buff, size);
128 strncpy(buff + pos, end, size - pos);
130 if (pos + end_len > size - 1)
131 printf("Warning: path truncated: %s\n", buff);
134 static int emu_check_save_file(int slot, int *time)
136 char fname[MAXPATHLEN];
140 ret = emu_check_state(slot);
141 if (ret != 0 || time == NULL)
142 return ret == 0 ? 1 : 0;
144 ret = get_state_filename(fname, sizeof(fname), slot);
148 ret = stat(fname, &status);
152 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
153 return 1; // probably bad rtc like on some Caanoos
155 *time = status.st_mtime;
160 static int emu_save_load_game(int load, int unused)
165 ret = emu_load_state(state_slot);
167 // reflect hle/bios mode from savestate
170 else if (bios_sel == 0 && bioses[1] != NULL)
171 // XXX: maybe find the right bios instead
175 ret = emu_save_state(state_slot);
180 // propagate menu settings to the emu vars
181 static void menu_sync_config(void)
183 static int allow_abs_only_old;
188 Config.PsxType = region - 1;
190 cycle_multiplier = 10000 / psx_clock;
192 switch (in_type_sel1) {
193 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
194 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
195 default: in_type1 = PSE_PAD_TYPE_STANDARD;
197 switch (in_type_sel2) {
198 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
199 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
200 default: in_type2 = PSE_PAD_TYPE_STANDARD;
202 if (in_evdev_allow_abs_only != allow_abs_only_old) {
204 allow_abs_only_old = in_evdev_allow_abs_only;
207 iVolume = 768 + 128 * volume_boost;
208 pl_rearmed_cbs.frameskip = frameskip - 1;
209 pl_timing_prepare(Config.PsxType);
212 static void menu_set_defconfig(void)
214 emu_set_default_config();
220 analog_deadzone = 50;
222 psx_clock = DEFAULT_PSX_CLOCK;
225 in_type_sel1 = in_type_sel2 = 0;
226 in_evdev_allow_abs_only = 0;
231 #define CE_CONFIG_STR(val) \
232 { #val, 0, Config.val }
234 #define CE_CONFIG_VAL(val) \
235 { #val, sizeof(Config.val), &Config.val }
237 #define CE_STR(val) \
240 #define CE_INTVAL(val) \
241 { #val, sizeof(val), &val }
243 #define CE_INTVAL_P(val) \
244 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
246 // 'versioned' var, used when defaults change
247 #define CE_CONFIG_STR_V(val, ver) \
248 { #val #ver, 0, Config.val }
250 #define CE_INTVAL_V(val, ver) \
251 { #val #ver, sizeof(val), &val }
253 #define CE_INTVAL_PV(val, ver) \
254 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
256 static const struct {
262 CE_CONFIG_STR_V(Gpu, 2),
264 // CE_CONFIG_STR(Cdr),
269 CE_CONFIG_VAL(Debug),
270 CE_CONFIG_VAL(PsxOut),
271 CE_CONFIG_VAL(SpuIrq),
272 CE_CONFIG_VAL(RCntFix),
273 CE_CONFIG_VAL(VSyncWA),
275 CE_CONFIG_VAL(CdrReschedule),
277 CE_INTVAL_V(scaling, 2),
278 CE_INTVAL(g_layer_x),
279 CE_INTVAL(g_layer_y),
280 CE_INTVAL(g_layer_w),
281 CE_INTVAL(g_layer_h),
283 CE_INTVAL(state_slot),
284 CE_INTVAL(cpu_clock),
286 CE_INTVAL(in_type_sel1),
287 CE_INTVAL(in_type_sel2),
288 CE_INTVAL(analog_deadzone),
289 CE_INTVAL_V(frameskip, 3),
290 CE_INTVAL_P(gpu_peops.iUseDither),
291 CE_INTVAL_P(gpu_peops.dwActFixes),
292 CE_INTVAL_P(gpu_unai.lineskip),
293 CE_INTVAL_P(gpu_unai.abe_hack),
294 CE_INTVAL_P(gpu_unai.no_light),
295 CE_INTVAL_P(gpu_unai.no_blend),
296 CE_INTVAL_P(gpu_neon.allow_interlace),
297 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
298 CE_INTVAL_P(gpu_peopsgl.iFilterType),
299 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
300 CE_INTVAL_P(gpu_peopsgl.iUseMask),
301 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
302 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
303 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
304 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
305 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
306 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
307 CE_INTVAL_V(iUseReverb, 3),
308 CE_INTVAL_V(iXAPitch, 3),
309 CE_INTVAL_V(iUseInterpolation, 3),
310 CE_INTVAL_V(iSPUIRQWait, 3),
311 CE_INTVAL_V(iUseTimer, 3),
312 CE_INTVAL(warned_about_bios),
313 CE_INTVAL(in_evdev_allow_abs_only),
314 CE_INTVAL(volume_boost),
315 CE_INTVAL(psx_clock),
316 CE_INTVAL(new_dynarec_hacks),
317 CE_INTVAL(in_enable_vibration),
320 static char *get_cd_label(void)
322 static char trimlabel[33];
325 strncpy(trimlabel, CdromLabel, 32);
327 for (j = 31; j >= 0; j--)
328 if (trimlabel[j] == ' ')
334 static void make_cfg_fname(char *buf, size_t size, int is_game)
337 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
339 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
342 static void keys_write_all(FILE *f);
344 static int menu_write_config(int is_game)
346 char cfgfile[MAXPATHLEN];
350 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
351 f = fopen(cfgfile, "w");
353 printf("menu_write_config: failed to open: %s\n", cfgfile);
357 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
358 fprintf(f, "%s = ", config_data[i].name);
359 switch (config_data[i].len) {
361 fprintf(f, "%s\n", (char *)config_data[i].val);
364 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
367 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
370 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
373 printf("menu_write_config: unhandled len %d for %s\n",
374 config_data[i].len, config_data[i].name);
380 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
388 static void parse_str_val(char *cval, const char *src)
391 strncpy(cval, src, MAXPATHLEN);
392 cval[MAXPATHLEN - 1] = 0;
393 tmp = strchr(cval, '\n');
395 tmp = strchr(cval, '\r');
400 static void keys_load_all(const char *cfg);
402 static int menu_load_config(int is_game)
404 char cfgfile[MAXPATHLEN];
410 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
411 f = fopen(cfgfile, "r");
413 printf("menu_load_config: failed to open: %s\n", cfgfile);
417 fseek(f, 0, SEEK_END);
420 printf("bad size %ld: %s\n", size, cfgfile);
424 cfg = malloc(size + 1);
428 fseek(f, 0, SEEK_SET);
429 if (fread(cfg, 1, size, f) != size) {
430 printf("failed to read: %s\n", cfgfile);
435 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
439 tmp = strstr(cfg, config_data[i].name);
442 tmp += strlen(config_data[i].name);
443 if (strncmp(tmp, " = ", 3) != 0)
447 if (config_data[i].len == 0) {
448 parse_str_val(config_data[i].val, tmp);
453 val = strtoul(tmp, &tmp2, 16);
454 if (tmp2 == NULL || tmp == tmp2)
455 continue; // parse failed
457 switch (config_data[i].len) {
459 *(u8 *)config_data[i].val = val;
462 *(u16 *)config_data[i].val = val;
465 *(u32 *)config_data[i].val = val;
468 printf("menu_load_config: unhandled len %d for %s\n",
469 config_data[i].len, config_data[i].name);
475 char *tmp = strstr(cfg, "lastcdimg = ");
478 parse_str_val(last_selected_fname, tmp);
493 for (i = bios_sel = 0; bioses[i] != NULL; i++)
494 if (strcmp(Config.Bios, bioses[i]) == 0)
495 { bios_sel = i; break; }
497 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
498 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
499 { gpu_plugsel = i; break; }
501 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
502 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
503 { spu_plugsel = i; break; }
508 // rrrr rggg gggb bbbb
509 static unsigned short fname2color(const char *fname)
511 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
512 ".bz", ".znx", ".pbp", ".cbn" };
513 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
514 ".table", ".index", ".sbi" };
515 const char *ext = strrchr(fname, '.');
520 for (i = 0; i < array_size(cdimg_exts); i++)
521 if (strcasecmp(ext, cdimg_exts[i]) == 0)
523 for (i = 0; i < array_size(other_exts); i++)
524 if (strcasecmp(ext, other_exts[i]) == 0)
529 static void draw_savestate_bg(int slot);
531 static const char *filter_exts[] = {
532 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
535 #define MENU_ALIGN_LEFT
536 #ifdef __ARM_ARCH_7A__ // assume hires device
542 #define menu_init menu_init_common
543 #include "common/menu.c"
546 // a bit of black magic here
547 static void draw_savestate_bg(int slot)
549 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
551 char fname[MAXPATHLEN];
558 ret = get_state_filename(fname, sizeof(fname), slot);
562 f = gzopen(fname, "rb");
566 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
567 fprintf(stderr, "gzseek failed\n");
572 gpu = malloc(sizeof(*gpu));
578 ret = gzread(f, gpu, sizeof(*gpu));
580 if (ret != sizeof(*gpu)) {
581 fprintf(stderr, "gzread failed\n");
585 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
587 if (gpu->ulStatus & 0x800000)
588 goto out; // disabled
590 x = gpu->ulControl[5] & 0x3ff;
591 y = (gpu->ulControl[5] >> 10) & 0x1ff;
592 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
593 w = psx_widths[(gpu->ulStatus >> 16) & 7];
594 tmp = gpu->ulControl[7];
595 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
596 if (gpu->ulStatus & 0x80000) // doubleheight
599 x = max(0, g_menuscreen_w - w) & ~3;
600 y = max(0, g_menuscreen_h / 2 - h / 2);
601 w = min(g_menuscreen_w, w);
602 h = min(g_menuscreen_h, h);
603 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
605 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
606 if (gpu->ulStatus & 0x200000)
607 bgr888_to_rgb565(d, s, w * 3);
609 bgr555_to_rgb565(d, s, w * 2);
610 #ifndef __ARM_ARCH_7A__
611 // better darken this on small screens
612 menu_darken_bg(d, d, w * 2, 0);
620 // ---------- XXX: pandora specific -----------
622 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
623 static char **pnd_filter_list;
625 static void apply_filter(int which)
631 if (pnd_filter_list == NULL || which == old)
634 for (i = 0; i < which; i++)
635 if (pnd_filter_list[i] == NULL)
638 if (pnd_filter_list[i] == NULL)
641 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
646 static void apply_lcdrate(int pal)
654 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
655 pnd_script_base, pal ? 50 : 60);
660 static menu_entry e_menu_gfx_options[];
662 static void pnd_menu_init(void)
670 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
672 dir = opendir("/etc/pandora/conf/dss_fir");
674 perror("filter opendir");
687 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
696 mfilters = calloc(count + 1, sizeof(mfilters[0]));
697 if (mfilters == NULL)
701 for (i = 0; (ent = readdir(dir)); ) {
704 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
707 len = strlen(ent->d_name);
709 // skip pre-HF5 extra files
710 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
712 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
715 // have to cut "_up_h" for pre-HF5
716 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
719 if (len > sizeof(buff) - 1)
722 strncpy(buff, ent->d_name, len);
724 mfilters[i] = strdup(buff);
725 if (mfilters[i] != NULL)
730 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
731 e_menu_gfx_options[i].data = (void *)mfilters;
732 pnd_filter_list = mfilters;
735 void menu_finish(void)
737 plat_cpu_clock_apply(cpu_clock_st);
740 // -------------- key config --------------
742 me_bind_action me_ctrl_actions[] =
744 { "UP ", 1 << DKEY_UP},
745 { "DOWN ", 1 << DKEY_DOWN },
746 { "LEFT ", 1 << DKEY_LEFT },
747 { "RIGHT ", 1 << DKEY_RIGHT },
748 { "TRIANGLE", 1 << DKEY_TRIANGLE },
749 { "CIRCLE ", 1 << DKEY_CIRCLE },
750 { "CROSS ", 1 << DKEY_CROSS },
751 { "SQUARE ", 1 << DKEY_SQUARE },
752 { "L1 ", 1 << DKEY_L1 },
753 { "R1 ", 1 << DKEY_R1 },
754 { "L2 ", 1 << DKEY_L2 },
755 { "R2 ", 1 << DKEY_R2 },
756 { "L3 ", 1 << DKEY_L3 },
757 { "R3 ", 1 << DKEY_R3 },
758 { "START ", 1 << DKEY_START },
759 { "SELECT ", 1 << DKEY_SELECT },
763 me_bind_action emuctrl_actions[] =
765 { "Save State ", 1 << SACTION_SAVE_STATE },
766 { "Load State ", 1 << SACTION_LOAD_STATE },
767 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
768 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
769 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
770 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
771 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
772 #ifdef __ARM_ARCH_7A__ /* XXX */
773 { "Minimize ", 1 << SACTION_MINIMIZE },
775 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
776 { "Gun A button ", 1 << SACTION_GUN_A },
777 { "Gun B button ", 1 << SACTION_GUN_B },
778 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
779 #ifndef __ARM_ARCH_7A__ /* XXX */
780 { "Volume Up ", 1 << SACTION_VOLUME_UP },
781 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
786 static char *mystrip(char *str)
791 for (i = 0; i < len; i++)
792 if (str[i] != ' ') break;
793 if (i > 0) memmove(str, str + i, len - i + 1);
796 for (i = len - 1; i >= 0; i--)
797 if (str[i] != ' ') break;
803 static void get_line(char *d, size_t size, const char *s)
808 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
819 static void keys_write_all(FILE *f)
823 for (d = 0; d < IN_MAX_DEVS; d++)
825 const int *binds = in_get_dev_binds(d);
826 const char *name = in_get_dev_name(d, 0, 0);
829 if (binds == NULL || name == NULL)
832 fprintf(f, "binddev = %s\n", name);
833 in_get_config(d, IN_CFG_BIND_COUNT, &count);
835 for (k = 0; k < count; k++)
840 act[0] = act[31] = 0;
841 name = in_get_key_name(d, k);
843 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
844 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
845 mask = me_ctrl_actions[i].mask;
847 strncpy(act, me_ctrl_actions[i].name, 31);
848 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
851 mask = me_ctrl_actions[i].mask << 16;
853 strncpy(act, me_ctrl_actions[i].name, 31);
854 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
859 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
860 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
861 mask = emuctrl_actions[i].mask;
863 strncpy(act, emuctrl_actions[i].name, 31);
864 fprintf(f, "bind %s = %s\n", name, mystrip(act));
870 for (k = 0; k < array_size(in_adev); k++)
873 fprintf(f, "bind_analog = %d\n", k);
878 static int parse_bind_val(const char *val, int *type)
882 *type = IN_BINDTYPE_NONE;
886 if (strncasecmp(val, "player", 6) == 0)
888 int player, shift = 0;
889 player = atoi(val + 6) - 1;
891 if ((unsigned int)player > 1)
896 *type = IN_BINDTYPE_PLAYER12;
897 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
898 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
899 return me_ctrl_actions[i].mask << shift;
902 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
903 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
904 *type = IN_BINDTYPE_EMU;
905 return emuctrl_actions[i].mask;
912 static void keys_load_all(const char *cfg)
914 char dev[256], key[128], *act;
920 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
923 get_line(dev, sizeof(dev), p);
924 dev_id = in_config_parse_dev(dev);
926 printf("input: can't handle dev: %s\n", dev);
930 in_unbind_all(dev_id, -1, -1);
931 while ((p = strstr(p, "bind"))) {
932 if (strncmp(p, "binddev = ", 10) == 0)
935 if (strncmp(p, "bind_analog", 11) == 0) {
936 ret = sscanf(p, "bind_analog = %d", &bind);
939 printf("input: parse error: %16s..\n", p);
942 if ((unsigned int)bind >= array_size(in_adev)) {
943 printf("input: analog id %d out of range\n", bind);
946 in_adev[bind] = dev_id;
952 printf("input: parse error: %16s..\n", p);
956 get_line(key, sizeof(key), p);
957 act = strchr(key, '=');
959 printf("parse failed: %16s..\n", p);
967 bind = parse_bind_val(act, &bindtype);
968 if (bind != -1 && bind != 0) {
969 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
970 in_config_bind_key(dev_id, key, bind, bindtype);
973 lprintf("config: unhandled action \"%s\"\n", act);
979 static int key_config_loop_wrap(int id, int keys)
982 case MA_CTRL_PLAYER1:
983 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
985 case MA_CTRL_PLAYER2:
986 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
989 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
997 static const char *adevnames[IN_MAX_DEVS + 2];
998 static int stick_sel[2];
1000 static menu_entry e_menu_keyconfig_analog[] =
1002 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
1003 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
1004 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
1005 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
1006 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
1007 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
1011 static int key_config_analog(int id, int keys)
1013 int i, d, count, sel = 0;
1014 int sel2dev_map[IN_MAX_DEVS];
1016 memset(adevnames, 0, sizeof(adevnames));
1017 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1018 memset(stick_sel, 0, sizeof(stick_sel));
1020 adevnames[0] = "None";
1022 for (d = 0; d < IN_MAX_DEVS; d++)
1024 const char *name = in_get_dev_name(d, 0, 1);
1029 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1033 if (in_adev[0] == d) stick_sel[0] = i;
1034 if (in_adev[1] == d) stick_sel[1] = i;
1036 adevnames[i++] = name;
1038 adevnames[i] = NULL;
1040 me_loop(e_menu_keyconfig_analog, &sel);
1042 in_adev[0] = sel2dev_map[stick_sel[0]];
1043 in_adev[1] = sel2dev_map[stick_sel[1]];
1048 static const char *mgn_dev_name(int id, int *offs)
1050 const char *name = NULL;
1053 if (id == MA_CTRL_DEV_FIRST)
1056 for (; it < IN_MAX_DEVS; it++) {
1057 name = in_get_dev_name(it, 1, 1);
1066 static const char *mgn_saveloadcfg(int id, int *offs)
1071 static int mh_savecfg(int id, int keys)
1073 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1074 me_update_msg("config saved");
1076 me_update_msg("failed to write config");
1081 static int mh_input_rescan(int id, int keys)
1083 //menu_sync_config();
1085 me_update_msg("rescan complete.");
1090 static const char *men_in_type_sel[] = {
1091 "Standard (SCPH-1080)",
1092 "Analog (SCPH-1150)",
1096 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1097 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1098 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1100 static menu_entry e_menu_keyconfig[] =
1102 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1103 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1104 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1105 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1107 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1108 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1109 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1110 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1111 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1112 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1113 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1114 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1115 mee_handler ("Rescan devices:", mh_input_rescan),
1117 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1118 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1119 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1120 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1121 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1122 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1123 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1127 static int menu_loop_keyconfig(int id, int keys)
1131 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1132 me_loop(e_menu_keyconfig, &sel);
1136 // ------------ gfx options menu ------------
1138 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1139 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1140 "using d-pad or move it using R+d-pad";
1141 static const char *men_dummy[] = { NULL };
1143 static int menu_loop_cscaler(int id, int keys)
1147 scaling = SCALE_CUSTOM;
1154 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1155 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1156 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1159 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1160 if (inp & PBTN_UP) g_layer_y--;
1161 if (inp & PBTN_DOWN) g_layer_y++;
1162 if (inp & PBTN_LEFT) g_layer_x--;
1163 if (inp & PBTN_RIGHT) g_layer_x++;
1164 if (!(inp & PBTN_R)) {
1165 if (inp & PBTN_UP) g_layer_h += 2;
1166 if (inp & PBTN_DOWN) g_layer_h -= 2;
1167 if (inp & PBTN_LEFT) g_layer_w += 2;
1168 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1170 if (inp & (PBTN_MOK|PBTN_MBACK))
1173 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1174 if (g_layer_x < 0) g_layer_x = 0;
1175 if (g_layer_x > 640) g_layer_x = 640;
1176 if (g_layer_y < 0) g_layer_y = 0;
1177 if (g_layer_y > 420) g_layer_y = 420;
1178 if (g_layer_w < 160) g_layer_w = 160;
1179 if (g_layer_h < 60) g_layer_h = 60;
1180 if (g_layer_x + g_layer_w > 800)
1181 g_layer_w = 800 - g_layer_x;
1182 if (g_layer_y + g_layer_h > 480)
1183 g_layer_h = 480 - g_layer_y;
1189 plat_gvideo_close();
1194 static menu_entry e_menu_gfx_options[] =
1196 mee_enum ("Scaler", MA_OPT_SCALER, scaling, men_scaler),
1197 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1198 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1199 // mee_onoff ("Vsync", 0, vsync, 1),
1200 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1204 static int menu_loop_gfx_options(int id, int keys)
1208 me_loop(e_menu_gfx_options, &sel);
1213 // ------------ bios/plugins ------------
1217 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1218 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1220 static menu_entry e_menu_plugin_gpu_neon[] =
1222 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1226 static int menu_loop_plugin_gpu_neon(int id, int keys)
1229 me_loop(e_menu_plugin_gpu_neon, &sel);
1235 static menu_entry e_menu_plugin_gpu_unai[] =
1237 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1238 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1239 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1240 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1244 static int menu_loop_plugin_gpu_unai(int id, int keys)
1247 me_loop(e_menu_plugin_gpu_unai, &sel);
1251 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1252 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1253 static const char h_gpu_1[] = "Capcom fighting games";
1254 static const char h_gpu_2[] = "Black screens in Lunar";
1255 static const char h_gpu_3[] = "Compatibility mode";
1256 static const char h_gpu_6[] = "Pandemonium 2";
1257 //static const char h_gpu_7[] = "Skip every second frame";
1258 static const char h_gpu_8[] = "Needed by Dark Forces";
1259 static const char h_gpu_9[] = "better g-colors, worse textures";
1260 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1262 static menu_entry e_menu_plugin_gpu_peops[] =
1264 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1265 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1266 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1267 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1268 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1269 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1270 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1271 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1272 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1273 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1277 static int menu_loop_plugin_gpu_peops(int id, int keys)
1280 me_loop(e_menu_plugin_gpu_peops, &sel);
1284 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1285 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1286 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1288 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1290 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1291 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1292 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1293 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1294 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1295 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1296 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1297 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1298 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1299 mee_label ("Fixes/hacks:"),
1300 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1301 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1302 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1303 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1304 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1305 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1306 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1307 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1308 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1309 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1310 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1314 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1317 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1321 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1322 static const char h_spu_volboost[] = "Large values cause distortion";
1323 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1324 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1326 static menu_entry e_menu_plugin_spu[] =
1328 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1329 mee_onoff ("Reverb", 0, iUseReverb, 2),
1330 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1331 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1332 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1333 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1337 static int menu_loop_plugin_spu(int id, int keys)
1340 me_loop(e_menu_plugin_spu, &sel);
1344 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1345 "savestates and can't be changed there. Must save\n"
1346 "config and reload the game for change to take effect";
1347 static const char h_plugin_gpu[] =
1349 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1354 "is Pete's soft GPU, slow but accurate\n"
1355 "gpuPCSX4ALL is GPU from PCSX4ALL, fast but glitchy\n"
1356 "gpuGLES Pete's hw GPU, uses 3D chip but is glitchy\n"
1357 "must save config and reload the game if changed";
1358 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1359 "must save config and reload the game if changed";
1360 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1361 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1362 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1363 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1365 static menu_entry e_menu_plugin_options[] =
1367 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1368 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1369 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1371 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1373 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1374 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1375 mee_handler_h ("Configure GLES GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1376 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1380 static menu_entry e_menu_main2[];
1382 static int menu_loop_plugin_options(int id, int keys)
1385 me_loop(e_menu_plugin_options, &sel);
1387 // sync BIOS/plugins
1388 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1389 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1390 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1391 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1396 // ------------ adv options menu ------------
1398 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1399 "(lower value - less work for the emu, may be faster)";
1400 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1401 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1402 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1404 static menu_entry e_menu_speed_hacks[] =
1406 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1407 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1408 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1409 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1413 static int menu_loop_speed_hacks(int id, int keys)
1416 me_loop(e_menu_speed_hacks, &sel);
1420 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1421 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1422 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1423 "(green: normal, red: fmod, blue: noise)";
1424 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1425 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1426 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1427 "(proper .cue/.bin dump is needed otherwise)";
1428 static const char h_cfg_sio[] = "You should not need this, breaks games";
1429 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1430 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1431 "(timing hack, breaks other games)";
1432 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1433 "(timing hack, breaks other games)";
1434 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1435 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1436 "Might be useful to overcome some dynarec bugs";
1437 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1438 "must reload game for any change to take effect";
1440 static menu_entry e_menu_adv_options[] =
1442 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1443 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1444 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1445 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1446 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1447 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1448 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1449 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1450 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1451 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1452 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1453 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1457 static int menu_loop_adv_options(int id, int keys)
1460 me_loop(e_menu_adv_options, &sel);
1464 // ------------ options menu ------------
1466 static int mh_restore_defaults(int id, int keys)
1468 menu_set_defconfig();
1469 me_update_msg("defaults restored");
1473 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1474 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1476 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1477 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1478 "loading state or both";
1480 static const char h_restore_def[] = "Switches back to default / recommended\n"
1482 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1484 static menu_entry e_menu_options[] =
1486 // mee_range ("Save slot", 0, state_slot, 0, 9),
1487 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1488 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1489 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1490 mee_enum ("Region", 0, region, men_region),
1491 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1492 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1493 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1494 mee_handler ("[Advanced]", menu_loop_adv_options),
1495 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1496 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1497 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1501 static int menu_loop_options(int id, int keys)
1506 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1507 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1508 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1510 me_loop(e_menu_options, &sel);
1515 // ------------ debug menu ------------
1517 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1519 int w = min(g_menuscreen_w, 1024);
1520 int h = min(g_menuscreen_h, 512);
1521 u16 *d = g_menuscreen_ptr;
1522 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1526 gpuf->ulFreezeVersion = 1;
1527 if (GPU_freeze != NULL)
1528 GPU_freeze(1, gpuf);
1530 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1531 bgr555_to_rgb565(d, s, w * 2);
1533 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1534 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1535 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1536 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1537 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1540 static void debug_menu_loop(void)
1542 int inp, df_x = 0, df_y = 0;
1545 gpuf = malloc(sizeof(*gpuf));
1552 draw_frame_debug(gpuf, df_x, df_y);
1555 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1556 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 10);
1557 if (inp & PBTN_MBACK) break;
1558 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1559 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1560 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x--; }
1561 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x++; }
1567 // --------- memcard manager ---------
1569 static void draw_mc_icon(int dx, int dy, const u16 *s)
1574 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1576 for (y = 0; y < 16; y++, s += 16) {
1577 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1578 for (x = 0; x < 16; x++) {
1580 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1581 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1587 static void draw_mc_bg(void)
1589 McdBlock *blocks1, *blocks2;
1593 blocks1 = malloc(15 * sizeof(blocks1[0]));
1594 blocks2 = malloc(15 * sizeof(blocks1[0]));
1595 if (blocks1 == NULL || blocks2 == NULL)
1598 for (i = 0; i < 15; i++) {
1599 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1600 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1605 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1607 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1611 maxicons = g_menuscreen_h / 32;
1614 row2 = g_menuscreen_w / 2;
1615 for (i = 0; i < maxicons; i++) {
1616 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1617 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1619 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1620 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1623 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1631 static void handle_memcard_sel(void)
1634 if (memcard1_sel != 0)
1635 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1637 if (memcard2_sel != 0)
1638 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1639 LoadMcds(Config.Mcd1, Config.Mcd2);
1643 static menu_entry e_memcard_options[] =
1645 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1646 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1650 static int menu_loop_memcards(int id, int keys)
1656 memcard1_sel = memcard2_sel = 0;
1657 p = strrchr(Config.Mcd1, '/');
1659 for (i = 0; memcards[i] != NULL; i++)
1660 if (strcmp(p + 1, memcards[i]) == 0)
1661 { memcard1_sel = i; break; }
1662 p = strrchr(Config.Mcd2, '/');
1664 for (i = 0; memcards[i] != NULL; i++)
1665 if (strcmp(p + 1, memcards[i]) == 0)
1666 { memcard2_sel = i; break; }
1668 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1670 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1675 // --------- main menu help ----------
1677 static void menu_bios_warn(void)
1680 static const char msg[] =
1681 "You don't seem to have copied any BIOS\n"
1683 #ifdef __ARM_ARCH_7A__ // XXX
1684 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1686 "pcsx_rearmed/bios/\n\n"
1688 "While many games work fine with fake\n"
1689 "(HLE) BIOS, others (like MGS and FF8)\n"
1690 "require BIOS to work.\n"
1691 "After copying the file, you'll also need\n"
1692 "to select it in the emu's menu:\n"
1693 "options->[BIOS/Plugins]\n\n"
1694 "The file is usually named SCPH1001.BIN,\n"
1695 "but other not compressed files can be\n"
1697 "Press (B) or (X) to continue";
1701 draw_menu_message(msg, NULL);
1703 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1704 if (inp & (PBTN_MBACK|PBTN_MOK))
1709 // ------------ main menu ------------
1713 static void draw_frame_main(void)
1722 if (CdromId[0] != 0) {
1723 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1724 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1725 Config.HLE ? "HLE" : "BIOS");
1726 smalltext_out16(4, 1, buff, 0x105f);
1730 capacity = plat_get_bat_capacity();
1732 tmp = localtime(<ime);
1733 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1734 if (capacity >= 0) {
1735 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1740 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1744 static void draw_frame_credits(void)
1746 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1749 static const char credits_text[] =
1751 "(C) 1999-2003 PCSX Team\n"
1752 "(C) 2005-2009 PCSX-df Team\n"
1753 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1754 "ARM recompiler (C) 2009-2011 Ari64\n"
1756 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1758 "PEOpS GPU and SPU by Pete Bernert\n"
1759 " and the P.E.Op.S. team\n"
1760 "PCSX4ALL plugin by PCSX4ALL team\n"
1761 " Chui, Franxis, Unai\n\n"
1762 "integration, optimization and\n"
1763 " frontend (C) 2010-2012 notaz\n";
1765 static int reset_game(void)
1768 if (bios_sel == 0 && !Config.HLE)
1774 if (CheckCdrom() != -1) {
1780 static int reload_plugins(const char *cdimg)
1786 set_cd_image(cdimg);
1788 pcnt_hook_plugins();
1790 if (OpenPlugins() == -1) {
1791 me_update_msg("failed to open plugins");
1794 plugin_call_rearmed_cbs();
1796 cdrIsoMultidiskCount = 1;
1798 CdromLabel[0] = '\0';
1803 static int run_bios(void)
1809 if (reload_plugins(NULL) != 0)
1817 static int run_exe(void)
1821 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1826 if (reload_plugins(NULL) != 0)
1830 if (Load(fname) != 0) {
1831 me_update_msg("exe load failed, bad file?");
1840 static int run_cd_image(const char *fname)
1843 reload_plugins(fname);
1845 // always autodetect, menu_sync_config will override as needed
1848 if (CheckCdrom() == -1) {
1849 // Only check the CD if we are starting the console with a CD
1851 me_update_msg("unsupported/invalid CD image");
1857 // Read main executable directly from CDRom and start it
1858 if (LoadCdrom() == -1) {
1860 me_update_msg("failed to load CD image");
1865 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1870 static int romsel_run(void)
1872 int prev_gpu, prev_spu;
1875 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1879 printf("selected file: %s\n", fname);
1881 new_dynarec_clear_full();
1883 if (run_cd_image(fname) != 0)
1886 prev_gpu = gpu_plugsel;
1887 prev_spu = spu_plugsel;
1888 if (menu_load_config(1) != 0)
1889 menu_load_config(0);
1891 // check for plugin changes, have to repeat
1892 // loading if game config changed plugins to reload them
1893 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1894 printf("plugin change detected, reloading plugins..\n");
1895 if (run_cd_image(fname) != 0)
1900 printf("note: running without BIOS, expect compatibility problems\n");
1902 strcpy(last_selected_fname, rom_fname_reload);
1906 static int swap_cd_image(void)
1910 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1914 printf("selected file: %s\n", fname);
1917 CdromLabel[0] = '\0';
1919 set_cd_image(fname);
1920 if (ReloadCdromPlugin() < 0) {
1921 me_update_msg("failed to load cdr plugin");
1924 if (CDR_open() < 0) {
1925 me_update_msg("failed to open cdr plugin");
1929 SetCdOpenCaseTime(time(NULL) + 2);
1932 strcpy(last_selected_fname, rom_fname_reload);
1936 static int swap_cd_multidisk(void)
1938 cdrIsoMultidiskSelect++;
1940 CdromLabel[0] = '\0';
1943 if (CDR_open() < 0) {
1944 me_update_msg("failed to open cdr plugin");
1948 SetCdOpenCaseTime(time(NULL) + 2);
1954 static int main_menu_handler(int id, int keys)
1958 case MA_MAIN_RESUME_GAME:
1962 case MA_MAIN_SAVE_STATE:
1964 return menu_loop_savestate(0);
1966 case MA_MAIN_LOAD_STATE:
1968 return menu_loop_savestate(1);
1970 case MA_MAIN_RESET_GAME:
1971 if (ready_to_go && reset_game() == 0)
1974 case MA_MAIN_LOAD_ROM:
1975 if (romsel_run() == 0)
1978 case MA_MAIN_SWAP_CD:
1979 if (swap_cd_image() == 0)
1982 case MA_MAIN_SWAP_CD_MULTI:
1983 if (swap_cd_multidisk() == 0)
1986 case MA_MAIN_RUN_BIOS:
1987 if (run_bios() == 0)
1990 case MA_MAIN_RUN_EXE:
1994 case MA_MAIN_CREDITS:
1995 draw_menu_message(credits_text, draw_frame_credits);
1996 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
2002 lprintf("%s: something unknown selected\n", __FUNCTION__);
2009 static menu_entry e_menu_main2[] =
2011 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2012 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2013 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2014 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2015 mee_handler ("Memcard manager", menu_loop_memcards),
2019 static int main_menu2_handler(int id, int keys)
2023 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2024 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2025 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2027 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2030 static const char h_extra[] = "Change CD, manage memcards..\n";
2032 static menu_entry e_menu_main[] =
2036 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2037 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2038 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2039 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2040 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2041 mee_handler ("Options", menu_loop_options),
2042 mee_handler ("Controls", menu_loop_keyconfig),
2043 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2044 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2045 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2049 // ----------------------------
2051 static void menu_leave_emu(void);
2053 void menu_loop(void)
2059 if (bioses[1] == NULL && !warned_about_bios) {
2061 warned_about_bios = 1;
2064 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2065 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2066 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2067 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2069 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2072 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2073 } while (!ready_to_go);
2075 /* wait until menu, ok, back is released */
2076 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2079 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2084 static int qsort_strcmp(const void *p1, const void *p2)
2086 char * const *s1 = (char * const *)p1;
2087 char * const *s2 = (char * const *)p2;
2088 return strcasecmp(*s1, *s2);
2091 static void scan_bios_plugins(void)
2093 char fname[MAXPATHLEN];
2095 int bios_i, gpu_i, spu_i, mc_i;
2100 gpu_plugins[0] = "builtin_gpu";
2101 spu_plugins[0] = "builtin_spu";
2102 memcards[0] = "(none)";
2103 bios_i = gpu_i = spu_i = mc_i = 1;
2105 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2106 dir = opendir(fname);
2108 perror("scan_bios_plugins bios opendir");
2123 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2126 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2127 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2128 printf("bad BIOS file: %s\n", ent->d_name);
2132 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2133 bioses[bios_i++] = strdup(ent->d_name);
2137 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2143 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2144 dir = opendir(fname);
2146 perror("scan_bios_plugins plugins opendir");
2160 p = strstr(ent->d_name, ".so");
2164 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2165 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2167 fprintf(stderr, "%s\n", dlerror());
2171 // now what do we have here?
2172 tmp = dlsym(h, "GPUinit");
2175 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2176 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2180 tmp = dlsym(h, "SPUinit");
2183 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2184 spu_plugins[spu_i++] = strdup(ent->d_name);
2188 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2195 dir = opendir("." MEMCARD_DIR);
2197 perror("scan_bios_plugins memcards opendir");
2212 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2215 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2216 if (stat(fname, &st) != 0) {
2217 printf("bad memcard file: %s\n", ent->d_name);
2221 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2222 memcards[mc_i++] = strdup(ent->d_name);
2226 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2230 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2235 void menu_init(void)
2237 char buff[MAXPATHLEN];
2239 strcpy(last_selected_fname, "/media");
2241 scan_bios_plugins();
2245 menu_set_defconfig();
2246 menu_load_config(0);
2251 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2252 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2253 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2254 fprintf(stderr, "OOM\n");
2258 emu_make_path(buff, "skin/background.png", sizeof(buff));
2259 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2261 #ifndef __ARM_ARCH_7A__ /* XXX */
2262 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2263 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2264 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2265 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2267 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2268 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2269 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2273 // XXX: should really menu code cotrol the layer size?
2274 void menu_notify_mode_change(int w, int h, int bpp)
2285 g_layer_w = w; g_layer_h = h;
2289 if (h > g_menuscreen_h || (240 < h && h <= 360))
2290 goto fractional_4_3;
2292 // 4:3 that prefers integer scaling
2293 imult = g_menuscreen_h / h;
2294 g_layer_w = w * imult;
2295 g_layer_h = h * imult;
2296 mult = (float)g_layer_w / (float)g_layer_h;
2297 if (mult < 1.25f || mult > 1.666f)
2298 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2299 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2304 mult = 240.0f / (float)h * 4.0f / 3.0f;
2307 g_layer_w = mult * (float)g_menuscreen_h;
2308 g_layer_h = g_menuscreen_h;
2309 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2312 case SCALE_FULLSCREEN:
2313 g_layer_w = g_menuscreen_w;
2314 g_layer_h = g_menuscreen_h;
2321 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2322 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2323 if (g_layer_x < 0) g_layer_x = 0;
2324 if (g_layer_y < 0) g_layer_y = 0;
2325 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2326 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2329 static void menu_leave_emu(void)
2331 if (GPU_close != NULL) {
2332 int ret = GPU_close();
2334 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2337 plat_video_menu_enter(ready_to_go);
2339 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2340 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2341 int x = max(0, g_menuscreen_w - last_psx_w);
2342 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2343 int w = min(g_menuscreen_w, last_psx_w);
2344 int h = min(g_menuscreen_h, last_psx_h);
2345 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2346 u16 *s = pl_vout_buf;
2348 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2349 menu_darken_bg(d, s, w, 0);
2353 cpu_clock = plat_cpu_clock_get();
2356 void menu_prepare_emu(void)
2358 R3000Acpu *prev_cpu = psxCpu;
2360 plat_video_menu_leave();
2362 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2364 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2365 if (psxCpu != prev_cpu)
2366 // note that this does not really reset, just clears drc caches
2369 // core doesn't care about Config.Cdda changes,
2370 // so handle them manually here
2375 apply_lcdrate(Config.PsxType);
2376 apply_filter(filter);
2378 plat_cpu_clock_apply(cpu_clock);
2380 // push config to GPU plugin
2381 plugin_call_rearmed_cbs();
2383 if (GPU_open != NULL) {
2384 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2386 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2392 void me_update_msg(const char *msg)
2394 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2395 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2397 menu_error_time = plat_get_ticks_ms();
2398 lprintf("msg: %s\n", menu_error_msg);