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,
89 static int last_vout_w, last_vout_h, last_vout_bpp;
90 static int scaling, cpu_clock, cpu_clock_st, volume_boost, frameskip;
91 static char rom_fname_reload[MAXPATHLEN];
92 static char last_selected_fname[MAXPATHLEN];
93 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
95 static int memcard1_sel, memcard2_sel;
97 int soft_scaling, analog_deadzone; // for Caanoo
100 #ifdef __ARM_ARCH_7A__
101 #define DEFAULT_PSX_CLOCK 57
102 #define DEFAULT_PSX_CLOCK_S "57"
104 #define DEFAULT_PSX_CLOCK 50
105 #define DEFAULT_PSX_CLOCK_S "50"
109 extern int iUseReverb;
110 extern int iUseInterpolation;
114 static const char *bioses[24];
115 static const char *gpu_plugins[16];
116 static const char *spu_plugins[16];
117 static const char *memcards[32];
118 static int bios_sel, gpu_plugsel, spu_plugsel;
121 static int min(int x, int y) { return x < y ? x : y; }
122 static int max(int x, int y) { return x > y ? x : y; }
124 void emu_make_path(char *buff, const char *end, int size)
128 end_len = strlen(end);
129 pos = plat_get_root_dir(buff, size);
130 strncpy(buff + pos, end, size - pos);
132 if (pos + end_len > size - 1)
133 printf("Warning: path truncated: %s\n", buff);
136 static int emu_check_save_file(int slot, int *time)
138 char fname[MAXPATHLEN];
142 ret = emu_check_state(slot);
143 if (ret != 0 || time == NULL)
144 return ret == 0 ? 1 : 0;
146 ret = get_state_filename(fname, sizeof(fname), slot);
150 ret = stat(fname, &status);
154 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
155 return 1; // probably bad rtc like on some Caanoos
157 *time = status.st_mtime;
162 static int emu_save_load_game(int load, int unused)
167 ret = emu_load_state(state_slot);
169 // reflect hle/bios mode from savestate
172 else if (bios_sel == 0 && bioses[1] != NULL)
173 // XXX: maybe find the right bios instead
177 ret = emu_save_state(state_slot);
182 // propagate menu settings to the emu vars
183 static void menu_sync_config(void)
185 static int allow_abs_only_old;
190 Config.PsxType = region - 1;
192 cycle_multiplier = 10000 / psx_clock;
194 switch (in_type_sel1) {
195 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
196 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
197 default: in_type1 = PSE_PAD_TYPE_STANDARD;
199 switch (in_type_sel2) {
200 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
201 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
202 default: in_type2 = PSE_PAD_TYPE_STANDARD;
204 if (in_evdev_allow_abs_only != allow_abs_only_old) {
206 allow_abs_only_old = in_evdev_allow_abs_only;
209 iVolume = 768 + 128 * volume_boost;
210 pl_rearmed_cbs.frameskip = frameskip - 1;
211 pl_timing_prepare(Config.PsxType);
214 static void menu_set_defconfig(void)
216 emu_set_default_config();
222 analog_deadzone = 50;
224 psx_clock = DEFAULT_PSX_CLOCK;
227 in_type_sel1 = in_type_sel2 = 0;
228 in_evdev_allow_abs_only = 0;
233 #define CE_CONFIG_STR(val) \
234 { #val, 0, Config.val }
236 #define CE_CONFIG_VAL(val) \
237 { #val, sizeof(Config.val), &Config.val }
239 #define CE_STR(val) \
242 #define CE_INTVAL(val) \
243 { #val, sizeof(val), &val }
245 #define CE_INTVAL_P(val) \
246 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
248 // 'versioned' var, used when defaults change
249 #define CE_CONFIG_STR_V(val, ver) \
250 { #val #ver, 0, Config.val }
252 #define CE_INTVAL_V(val, ver) \
253 { #val #ver, sizeof(val), &val }
255 #define CE_INTVAL_PV(val, ver) \
256 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
258 static const struct {
264 CE_CONFIG_STR_V(Gpu, 3),
266 // CE_CONFIG_STR(Cdr),
271 CE_CONFIG_VAL(Debug),
272 CE_CONFIG_VAL(PsxOut),
273 CE_CONFIG_VAL(SpuIrq),
274 CE_CONFIG_VAL(RCntFix),
275 CE_CONFIG_VAL(VSyncWA),
277 CE_CONFIG_VAL(CdrReschedule),
279 CE_INTVAL_V(scaling, 2),
280 CE_INTVAL(g_layer_x),
281 CE_INTVAL(g_layer_y),
282 CE_INTVAL(g_layer_w),
283 CE_INTVAL(g_layer_h),
285 CE_INTVAL(state_slot),
286 CE_INTVAL(cpu_clock),
288 CE_INTVAL(in_type_sel1),
289 CE_INTVAL(in_type_sel2),
290 CE_INTVAL(analog_deadzone),
291 CE_INTVAL_V(frameskip, 3),
292 CE_INTVAL_P(gpu_peops.iUseDither),
293 CE_INTVAL_P(gpu_peops.dwActFixes),
294 CE_INTVAL_P(gpu_unai.lineskip),
295 CE_INTVAL_P(gpu_unai.abe_hack),
296 CE_INTVAL_P(gpu_unai.no_light),
297 CE_INTVAL_P(gpu_unai.no_blend),
298 CE_INTVAL_P(gpu_neon.allow_interlace),
299 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
300 CE_INTVAL_P(gpu_peopsgl.iFilterType),
301 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
302 CE_INTVAL_P(gpu_peopsgl.iUseMask),
303 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
304 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
305 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
306 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
307 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
308 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
309 CE_INTVAL_V(iUseReverb, 3),
310 CE_INTVAL_V(iXAPitch, 3),
311 CE_INTVAL_V(iUseInterpolation, 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);
343 static char *mystrip(char *str);
345 static int menu_write_config(int is_game)
347 char cfgfile[MAXPATHLEN];
351 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
352 f = fopen(cfgfile, "w");
354 printf("menu_write_config: failed to open: %s\n", cfgfile);
358 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
359 fprintf(f, "%s = ", config_data[i].name);
360 switch (config_data[i].len) {
362 fprintf(f, "%s\n", (char *)config_data[i].val);
365 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
368 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
371 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
374 printf("menu_write_config: unhandled len %d for %s\n",
375 config_data[i].len, config_data[i].name);
386 static int menu_do_last_cd_img(int is_get)
392 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
393 f = fopen(path, is_get ? "r" : "w");
398 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
399 last_selected_fname[ret] = 0;
400 mystrip(last_selected_fname);
403 fprintf(f, "%s\n", last_selected_fname);
409 static void parse_str_val(char *cval, const char *src)
412 strncpy(cval, src, MAXPATHLEN);
413 cval[MAXPATHLEN - 1] = 0;
414 tmp = strchr(cval, '\n');
416 tmp = strchr(cval, '\r');
421 static void keys_load_all(const char *cfg);
423 static int menu_load_config(int is_game)
425 char cfgfile[MAXPATHLEN];
431 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
432 f = fopen(cfgfile, "r");
434 printf("menu_load_config: failed to open: %s\n", cfgfile);
438 fseek(f, 0, SEEK_END);
441 printf("bad size %ld: %s\n", size, cfgfile);
445 cfg = malloc(size + 1);
449 fseek(f, 0, SEEK_SET);
450 if (fread(cfg, 1, size, f) != size) {
451 printf("failed to read: %s\n", cfgfile);
456 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
460 tmp = strstr(cfg, config_data[i].name);
463 tmp += strlen(config_data[i].name);
464 if (strncmp(tmp, " = ", 3) != 0)
468 if (config_data[i].len == 0) {
469 parse_str_val(config_data[i].val, tmp);
474 val = strtoul(tmp, &tmp2, 16);
475 if (tmp2 == NULL || tmp == tmp2)
476 continue; // parse failed
478 switch (config_data[i].len) {
480 *(u8 *)config_data[i].val = val;
483 *(u16 *)config_data[i].val = val;
486 *(u32 *)config_data[i].val = val;
489 printf("menu_load_config: unhandled len %d for %s\n",
490 config_data[i].len, config_data[i].name);
496 char *tmp = strstr(cfg, "lastcdimg = ");
499 parse_str_val(last_selected_fname, tmp);
514 for (i = bios_sel = 0; bioses[i] != NULL; i++)
515 if (strcmp(Config.Bios, bioses[i]) == 0)
516 { bios_sel = i; break; }
518 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
519 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
520 { gpu_plugsel = i; break; }
522 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
523 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
524 { spu_plugsel = i; break; }
529 // rrrr rggg gggb bbbb
530 static unsigned short fname2color(const char *fname)
532 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
533 ".bz", ".znx", ".pbp", ".cbn" };
534 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
535 ".table", ".index", ".sbi" };
536 const char *ext = strrchr(fname, '.');
541 for (i = 0; i < array_size(cdimg_exts); i++)
542 if (strcasecmp(ext, cdimg_exts[i]) == 0)
544 for (i = 0; i < array_size(other_exts); i++)
545 if (strcasecmp(ext, other_exts[i]) == 0)
550 static void draw_savestate_bg(int slot);
552 static const char *filter_exts[] = {
553 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
556 #define MENU_ALIGN_LEFT
557 #ifdef __ARM_ARCH_7A__ // assume hires device
563 #define menu_init menu_init_common
564 #include "common/menu.c"
567 // a bit of black magic here
568 static void draw_savestate_bg(int slot)
570 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
572 char fname[MAXPATHLEN];
579 ret = get_state_filename(fname, sizeof(fname), slot);
583 f = gzopen(fname, "rb");
587 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
588 fprintf(stderr, "gzseek failed\n");
593 gpu = malloc(sizeof(*gpu));
599 ret = gzread(f, gpu, sizeof(*gpu));
601 if (ret != sizeof(*gpu)) {
602 fprintf(stderr, "gzread failed\n");
606 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
608 if (gpu->ulStatus & 0x800000)
609 goto out; // disabled
611 x = gpu->ulControl[5] & 0x3ff;
612 y = (gpu->ulControl[5] >> 10) & 0x1ff;
613 s = (u16 *)gpu->psxVRam + y * 1024 + x;
614 w = psx_widths[(gpu->ulStatus >> 16) & 7];
615 tmp = gpu->ulControl[7];
616 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
617 if (gpu->ulStatus & 0x80000) // doubleheight
620 x = max(0, g_menuscreen_w - w) & ~3;
621 y = max(0, g_menuscreen_h / 2 - h / 2);
622 w = min(g_menuscreen_w, w);
623 h = min(g_menuscreen_h, h);
624 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
626 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
627 if (gpu->ulStatus & 0x200000)
628 bgr888_to_rgb565(d, s, w * 3);
630 bgr555_to_rgb565(d, s, w * 2);
632 // darken this so that menu text is visible
633 if (g_menuscreen_w - w < 320)
634 menu_darken_bg(d, d, w * 2, 0);
641 // -------------- key config --------------
643 me_bind_action me_ctrl_actions[] =
645 { "UP ", 1 << DKEY_UP},
646 { "DOWN ", 1 << DKEY_DOWN },
647 { "LEFT ", 1 << DKEY_LEFT },
648 { "RIGHT ", 1 << DKEY_RIGHT },
649 { "TRIANGLE", 1 << DKEY_TRIANGLE },
650 { "CIRCLE ", 1 << DKEY_CIRCLE },
651 { "CROSS ", 1 << DKEY_CROSS },
652 { "SQUARE ", 1 << DKEY_SQUARE },
653 { "L1 ", 1 << DKEY_L1 },
654 { "R1 ", 1 << DKEY_R1 },
655 { "L2 ", 1 << DKEY_L2 },
656 { "R2 ", 1 << DKEY_R2 },
657 { "L3 ", 1 << DKEY_L3 },
658 { "R3 ", 1 << DKEY_R3 },
659 { "START ", 1 << DKEY_START },
660 { "SELECT ", 1 << DKEY_SELECT },
664 me_bind_action emuctrl_actions[] =
666 { "Save State ", 1 << SACTION_SAVE_STATE },
667 { "Load State ", 1 << SACTION_LOAD_STATE },
668 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
669 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
670 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
671 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
672 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
673 #ifdef __ARM_ARCH_7A__ /* XXX */
674 { "Minimize ", 1 << SACTION_MINIMIZE },
676 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
677 { "Gun A button ", 1 << SACTION_GUN_A },
678 { "Gun B button ", 1 << SACTION_GUN_B },
679 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
680 #ifndef __ARM_ARCH_7A__ /* XXX */
681 { "Volume Up ", 1 << SACTION_VOLUME_UP },
682 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
687 static char *mystrip(char *str)
692 for (i = 0; i < len; i++)
693 if (str[i] != ' ') break;
694 if (i > 0) memmove(str, str + i, len - i + 1);
697 for (i = len - 1; i >= 0; i--)
698 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
704 static void get_line(char *d, size_t size, const char *s)
709 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
720 static void keys_write_all(FILE *f)
724 for (d = 0; d < IN_MAX_DEVS; d++)
726 const int *binds = in_get_dev_binds(d);
727 const char *name = in_get_dev_name(d, 0, 0);
730 if (binds == NULL || name == NULL)
733 fprintf(f, "binddev = %s\n", name);
734 in_get_config(d, IN_CFG_BIND_COUNT, &count);
736 for (k = 0; k < count; k++)
741 act[0] = act[31] = 0;
742 name = in_get_key_name(d, k);
744 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
745 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
746 mask = me_ctrl_actions[i].mask;
748 strncpy(act, me_ctrl_actions[i].name, 31);
749 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
752 mask = me_ctrl_actions[i].mask << 16;
754 strncpy(act, me_ctrl_actions[i].name, 31);
755 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
760 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
761 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
762 mask = emuctrl_actions[i].mask;
764 strncpy(act, emuctrl_actions[i].name, 31);
765 fprintf(f, "bind %s = %s\n", name, mystrip(act));
771 for (k = 0; k < array_size(in_adev); k++)
774 fprintf(f, "bind_analog = %d\n", k);
779 static int parse_bind_val(const char *val, int *type)
783 *type = IN_BINDTYPE_NONE;
787 if (strncasecmp(val, "player", 6) == 0)
789 int player, shift = 0;
790 player = atoi(val + 6) - 1;
792 if ((unsigned int)player > 1)
797 *type = IN_BINDTYPE_PLAYER12;
798 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
799 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
800 return me_ctrl_actions[i].mask << shift;
803 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
804 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
805 *type = IN_BINDTYPE_EMU;
806 return emuctrl_actions[i].mask;
813 static void keys_load_all(const char *cfg)
815 char dev[256], key[128], *act;
821 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
824 get_line(dev, sizeof(dev), p);
825 dev_id = in_config_parse_dev(dev);
827 printf("input: can't handle dev: %s\n", dev);
831 in_unbind_all(dev_id, -1, -1);
832 while ((p = strstr(p, "bind"))) {
833 if (strncmp(p, "binddev = ", 10) == 0)
836 if (strncmp(p, "bind_analog", 11) == 0) {
837 ret = sscanf(p, "bind_analog = %d", &bind);
840 printf("input: parse error: %16s..\n", p);
843 if ((unsigned int)bind >= array_size(in_adev)) {
844 printf("input: analog id %d out of range\n", bind);
847 in_adev[bind] = dev_id;
853 printf("input: parse error: %16s..\n", p);
857 get_line(key, sizeof(key), p);
858 act = strchr(key, '=');
860 printf("parse failed: %16s..\n", p);
868 bind = parse_bind_val(act, &bindtype);
869 if (bind != -1 && bind != 0) {
870 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
871 in_config_bind_key(dev_id, key, bind, bindtype);
874 lprintf("config: unhandled action \"%s\"\n", act);
880 static int key_config_loop_wrap(int id, int keys)
883 case MA_CTRL_PLAYER1:
884 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
886 case MA_CTRL_PLAYER2:
887 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
890 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
898 static const char *adevnames[IN_MAX_DEVS + 2];
899 static int stick_sel[2];
901 static menu_entry e_menu_keyconfig_analog[] =
903 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
904 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
905 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
906 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
907 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
908 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
912 static int key_config_analog(int id, int keys)
914 int i, d, count, sel = 0;
915 int sel2dev_map[IN_MAX_DEVS];
917 memset(adevnames, 0, sizeof(adevnames));
918 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
919 memset(stick_sel, 0, sizeof(stick_sel));
921 adevnames[0] = "None";
923 for (d = 0; d < IN_MAX_DEVS; d++)
925 const char *name = in_get_dev_name(d, 0, 1);
930 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
934 if (in_adev[0] == d) stick_sel[0] = i;
935 if (in_adev[1] == d) stick_sel[1] = i;
937 adevnames[i++] = name;
941 me_loop(e_menu_keyconfig_analog, &sel);
943 in_adev[0] = sel2dev_map[stick_sel[0]];
944 in_adev[1] = sel2dev_map[stick_sel[1]];
949 static const char *mgn_dev_name(int id, int *offs)
951 const char *name = NULL;
954 if (id == MA_CTRL_DEV_FIRST)
957 for (; it < IN_MAX_DEVS; it++) {
958 name = in_get_dev_name(it, 1, 1);
967 static const char *mgn_saveloadcfg(int id, int *offs)
972 static int mh_savecfg(int id, int keys)
974 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
975 me_update_msg("config saved");
977 me_update_msg("failed to write config");
982 static int mh_input_rescan(int id, int keys)
984 //menu_sync_config();
986 me_update_msg("rescan complete.");
991 static const char *men_in_type_sel[] = {
992 "Standard (SCPH-1080)",
993 "Analog (SCPH-1150)",
997 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
998 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
999 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1001 static menu_entry e_menu_keyconfig[] =
1003 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1004 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1005 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1006 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1008 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1009 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1010 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1011 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1012 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1013 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1014 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1015 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1016 mee_handler ("Rescan devices:", mh_input_rescan),
1018 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1019 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1020 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1021 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1022 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1023 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1024 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1028 static int menu_loop_keyconfig(int id, int keys)
1032 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1033 me_loop(e_menu_keyconfig, &sel);
1037 // ------------ gfx options menu ------------
1039 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1040 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1041 "using d-pad or move it using R+d-pad";
1042 static const char *men_dummy[] = { NULL };
1044 static int menu_loop_cscaler(int id, int keys)
1048 scaling = SCALE_CUSTOM;
1050 plat_gvideo_open(Config.PsxType);
1055 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1056 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1057 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1060 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1061 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1062 if (inp & PBTN_UP) g_layer_y--;
1063 if (inp & PBTN_DOWN) g_layer_y++;
1064 if (inp & PBTN_LEFT) g_layer_x--;
1065 if (inp & PBTN_RIGHT) g_layer_x++;
1066 if (!(inp & PBTN_R)) {
1067 if (inp & PBTN_UP) g_layer_h += 2;
1068 if (inp & PBTN_DOWN) g_layer_h -= 2;
1069 if (inp & PBTN_LEFT) g_layer_w += 2;
1070 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1072 if (inp & (PBTN_MOK|PBTN_MBACK))
1075 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1076 if (g_layer_x < 0) g_layer_x = 0;
1077 if (g_layer_x > 640) g_layer_x = 640;
1078 if (g_layer_y < 0) g_layer_y = 0;
1079 if (g_layer_y > 420) g_layer_y = 420;
1080 if (g_layer_w < 160) g_layer_w = 160;
1081 if (g_layer_h < 60) g_layer_h = 60;
1082 if (g_layer_x + g_layer_w > 800)
1083 g_layer_w = 800 - g_layer_x;
1084 if (g_layer_y + g_layer_h > 480)
1085 g_layer_h = 480 - g_layer_y;
1087 plat_gvideo_open(Config.PsxType);
1091 plat_gvideo_close();
1096 static menu_entry e_menu_gfx_options[] =
1098 mee_enum ("Scaler", MA_OPT_SCALER, scaling, men_scaler),
1099 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1100 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1101 // mee_onoff ("Vsync", 0, vsync, 1),
1102 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1106 static int menu_loop_gfx_options(int id, int keys)
1110 me_loop(e_menu_gfx_options, &sel);
1116 void menu_set_filter_list(void *filters)
1120 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1121 e_menu_gfx_options[i].data = filters;
1122 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1125 // ------------ bios/plugins ------------
1129 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1130 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1132 static menu_entry e_menu_plugin_gpu_neon[] =
1134 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1138 static int menu_loop_plugin_gpu_neon(int id, int keys)
1141 me_loop(e_menu_plugin_gpu_neon, &sel);
1147 static menu_entry e_menu_plugin_gpu_unai[] =
1149 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1150 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1151 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1152 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1156 static int menu_loop_plugin_gpu_unai(int id, int keys)
1159 me_loop(e_menu_plugin_gpu_unai, &sel);
1163 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1164 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1165 static const char h_gpu_1[] = "Capcom fighting games";
1166 static const char h_gpu_2[] = "Black screens in Lunar";
1167 static const char h_gpu_3[] = "Compatibility mode";
1168 static const char h_gpu_6[] = "Pandemonium 2";
1169 //static const char h_gpu_7[] = "Skip every second frame";
1170 static const char h_gpu_8[] = "Needed by Dark Forces";
1171 static const char h_gpu_9[] = "better g-colors, worse textures";
1172 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1174 static menu_entry e_menu_plugin_gpu_peops[] =
1176 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1177 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1178 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1179 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1180 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1181 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1182 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1183 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1184 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1185 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1189 static int menu_loop_plugin_gpu_peops(int id, int keys)
1192 me_loop(e_menu_plugin_gpu_peops, &sel);
1196 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1197 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1198 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1200 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1202 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1203 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1204 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1205 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1206 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1207 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1208 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1209 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1210 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1211 mee_label ("Fixes/hacks:"),
1212 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1213 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1214 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1215 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1216 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1217 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1218 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1219 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1220 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1221 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1222 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1226 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1229 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1233 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1234 static const char h_spu_volboost[] = "Large values cause distortion";
1236 static menu_entry e_menu_plugin_spu[] =
1238 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1239 mee_onoff ("Reverb", 0, iUseReverb, 2),
1240 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1241 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1245 static int menu_loop_plugin_spu(int id, int keys)
1248 me_loop(e_menu_plugin_spu, &sel);
1252 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1253 "savestates and can't be changed there. Must save\n"
1254 "config and reload the game for change to take effect";
1255 static const char h_plugin_gpu[] =
1257 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1259 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1260 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1261 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1262 "must save config and reload the game if changed";
1263 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1264 "must save config and reload the game if changed";
1265 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1266 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1267 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1268 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1270 static menu_entry e_menu_plugin_options[] =
1272 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1273 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1274 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1276 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1278 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1279 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1280 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1281 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1285 static menu_entry e_menu_main2[];
1287 static int menu_loop_plugin_options(int id, int keys)
1290 me_loop(e_menu_plugin_options, &sel);
1292 // sync BIOS/plugins
1293 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1294 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1295 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1296 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1301 // ------------ adv options menu ------------
1303 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1304 "(lower value - less work for the emu, may be faster)";
1305 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1306 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1307 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1309 static menu_entry e_menu_speed_hacks[] =
1311 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1312 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1313 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1314 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1318 static int menu_loop_speed_hacks(int id, int keys)
1321 me_loop(e_menu_speed_hacks, &sel);
1325 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1326 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1327 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1328 "(green: normal, red: fmod, blue: noise)";
1329 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1330 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1331 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1332 "(proper .cue/.bin dump is needed otherwise)";
1333 static const char h_cfg_sio[] = "You should not need this, breaks games";
1334 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1335 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1336 "(timing hack, breaks other games)";
1337 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1338 "(timing hack, breaks other games)";
1339 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1340 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1341 "Might be useful to overcome some dynarec bugs";
1342 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1343 "must reload game for any change to take effect";
1345 static menu_entry e_menu_adv_options[] =
1347 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1348 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1349 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1350 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1351 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1352 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1353 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1354 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1355 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1356 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1357 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1358 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1362 static int menu_loop_adv_options(int id, int keys)
1365 me_loop(e_menu_adv_options, &sel);
1369 // ------------ options menu ------------
1371 static int mh_restore_defaults(int id, int keys)
1373 menu_set_defconfig();
1374 me_update_msg("defaults restored");
1378 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1379 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1381 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1382 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1383 "loading state or both";
1385 static const char h_restore_def[] = "Switches back to default / recommended\n"
1387 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1389 static menu_entry e_menu_options[] =
1391 // mee_range ("Save slot", 0, state_slot, 0, 9),
1392 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1393 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1394 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1395 mee_enum ("Region", 0, region, men_region),
1396 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1397 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1398 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1399 mee_handler ("[Advanced]", menu_loop_adv_options),
1400 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1401 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1402 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1406 static int menu_loop_options(int id, int keys)
1411 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1412 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1413 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1415 me_loop(e_menu_options, &sel);
1420 // ------------ debug menu ------------
1422 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1424 int w = min(g_menuscreen_w, 1024);
1425 int h = min(g_menuscreen_h, 512);
1426 u16 *d = g_menuscreen_ptr;
1427 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1431 gpuf->ulFreezeVersion = 1;
1432 if (GPU_freeze != NULL)
1433 GPU_freeze(1, gpuf);
1435 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1436 bgr555_to_rgb565(d, s, w * 2);
1438 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1439 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1440 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1441 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1442 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1445 static void debug_menu_loop(void)
1447 int inp, df_x = 0, df_y = 0;
1450 gpuf = malloc(sizeof(*gpuf));
1457 draw_frame_debug(gpuf, df_x, df_y);
1460 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1461 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1462 if (inp & PBTN_MBACK) break;
1463 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1464 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1465 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1466 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1472 // --------- memcard manager ---------
1474 static void draw_mc_icon(int dx, int dy, const u16 *s)
1479 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1481 for (y = 0; y < 16; y++, s += 16) {
1482 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1483 for (x = 0; x < 16; x++) {
1485 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1486 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1492 static void draw_mc_bg(void)
1494 McdBlock *blocks1, *blocks2;
1498 blocks1 = malloc(15 * sizeof(blocks1[0]));
1499 blocks2 = malloc(15 * sizeof(blocks1[0]));
1500 if (blocks1 == NULL || blocks2 == NULL)
1503 for (i = 0; i < 15; i++) {
1504 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1505 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1510 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1512 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1516 maxicons = g_menuscreen_h / 32;
1519 row2 = g_menuscreen_w / 2;
1520 for (i = 0; i < maxicons; i++) {
1521 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1522 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1524 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1525 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1528 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1536 static void handle_memcard_sel(void)
1539 if (memcard1_sel != 0)
1540 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1542 if (memcard2_sel != 0)
1543 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1544 LoadMcds(Config.Mcd1, Config.Mcd2);
1548 static menu_entry e_memcard_options[] =
1550 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1551 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1555 static int menu_loop_memcards(int id, int keys)
1561 memcard1_sel = memcard2_sel = 0;
1562 p = strrchr(Config.Mcd1, '/');
1564 for (i = 0; memcards[i] != NULL; i++)
1565 if (strcmp(p + 1, memcards[i]) == 0)
1566 { memcard1_sel = i; break; }
1567 p = strrchr(Config.Mcd2, '/');
1569 for (i = 0; memcards[i] != NULL; i++)
1570 if (strcmp(p + 1, memcards[i]) == 0)
1571 { memcard2_sel = i; break; }
1573 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1575 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1580 // ------------ cheats menu ------------
1582 static void draw_cheatlist(int sel)
1584 int max_cnt, start, i, pos, active;
1586 max_cnt = g_menuscreen_h / me_sfont_h;
1587 start = max_cnt / 2 - sel;
1591 for (i = 0; i < NumCheats; i++) {
1593 if (pos < 0) continue;
1594 if (pos >= max_cnt) break;
1595 active = Cheats[i].Enabled;
1596 smalltext_out16(14, pos * me_sfont_h,
1597 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1598 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1599 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1603 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1605 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1609 static void menu_loop_cheats(void)
1611 static int menu_sel = 0;
1616 draw_cheatlist(menu_sel);
1617 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1618 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1619 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1620 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1621 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1622 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1623 if (inp & PBTN_MOK) { // action
1624 if (menu_sel < NumCheats)
1625 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1628 if (inp & PBTN_MBACK)
1633 // --------- main menu help ----------
1635 static void menu_bios_warn(void)
1638 static const char msg[] =
1639 "You don't seem to have copied any BIOS\n"
1641 #ifdef __ARM_ARCH_7A__ // XXX
1642 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1644 "pcsx_rearmed/bios/\n\n"
1646 "While many games work fine with fake\n"
1647 "(HLE) BIOS, others (like MGS and FF8)\n"
1648 "require BIOS to work.\n"
1649 "After copying the file, you'll also need\n"
1650 "to select it in the emu's menu:\n"
1651 "options->[BIOS/Plugins]\n\n"
1652 "The file is usually named SCPH1001.BIN,\n"
1653 "but other not compressed files can be\n"
1655 "Press %s or %s to continue";
1656 char tmp_msg[sizeof(msg) + 64];
1658 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1659 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1662 draw_menu_message(tmp_msg, NULL);
1664 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1665 if (inp & (PBTN_MBACK|PBTN_MOK))
1670 // ------------ main menu ------------
1672 static menu_entry e_menu_main[];
1675 static void draw_frame_main(void)
1684 if (CdromId[0] != 0) {
1685 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1686 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1687 Config.HLE ? "HLE" : "BIOS");
1688 smalltext_out16(4, 1, buff, 0x105f);
1692 capacity = plat_get_bat_capacity();
1694 tmp = localtime(<ime);
1695 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1696 if (capacity >= 0) {
1697 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1702 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1706 static void draw_frame_credits(void)
1708 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1711 static const char credits_text[] =
1713 "(C) 1999-2003 PCSX Team\n"
1714 "(C) 2005-2009 PCSX-df Team\n"
1715 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1716 "ARM recompiler (C) 2009-2011 Ari64\n"
1718 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1720 "PEOpS GPU and SPU by Pete Bernert\n"
1721 " and the P.E.Op.S. team\n"
1722 "PCSX4ALL plugin by PCSX4ALL team\n"
1723 " Chui, Franxis, Unai\n\n"
1724 "integration, optimization and\n"
1725 " frontend (C) 2010-2012 notaz\n";
1727 static int reset_game(void)
1730 if (bios_sel == 0 && !Config.HLE)
1736 if (CheckCdrom() != -1) {
1742 static int reload_plugins(const char *cdimg)
1748 set_cd_image(cdimg);
1750 pcnt_hook_plugins();
1752 if (OpenPlugins() == -1) {
1753 me_update_msg("failed to open plugins");
1756 plugin_call_rearmed_cbs();
1758 cdrIsoMultidiskCount = 1;
1760 CdromLabel[0] = '\0';
1765 static int run_bios(void)
1771 if (reload_plugins(NULL) != 0)
1779 static int run_exe(void)
1783 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1788 if (reload_plugins(NULL) != 0)
1792 if (Load(fname) != 0) {
1793 me_update_msg("exe load failed, bad file?");
1802 static int run_cd_image(const char *fname)
1805 reload_plugins(fname);
1807 // always autodetect, menu_sync_config will override as needed
1810 if (CheckCdrom() == -1) {
1811 // Only check the CD if we are starting the console with a CD
1813 me_update_msg("unsupported/invalid CD image");
1819 // Read main executable directly from CDRom and start it
1820 if (LoadCdrom() == -1) {
1822 me_update_msg("failed to load CD image");
1832 static int romsel_run(void)
1834 int prev_gpu, prev_spu;
1837 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1841 printf("selected file: %s\n", fname);
1843 new_dynarec_clear_full();
1845 if (run_cd_image(fname) != 0)
1848 prev_gpu = gpu_plugsel;
1849 prev_spu = spu_plugsel;
1850 if (menu_load_config(1) != 0)
1851 menu_load_config(0);
1853 // check for plugin changes, have to repeat
1854 // loading if game config changed plugins to reload them
1855 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1856 printf("plugin change detected, reloading plugins..\n");
1857 if (run_cd_image(fname) != 0)
1861 strcpy(last_selected_fname, rom_fname_reload);
1865 static int swap_cd_image(void)
1869 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1873 printf("selected file: %s\n", fname);
1876 CdromLabel[0] = '\0';
1878 set_cd_image(fname);
1879 if (ReloadCdromPlugin() < 0) {
1880 me_update_msg("failed to load cdr plugin");
1883 if (CDR_open() < 0) {
1884 me_update_msg("failed to open cdr plugin");
1888 SetCdOpenCaseTime(time(NULL) + 2);
1891 strcpy(last_selected_fname, rom_fname_reload);
1895 static int swap_cd_multidisk(void)
1897 cdrIsoMultidiskSelect++;
1899 CdromLabel[0] = '\0';
1902 if (CDR_open() < 0) {
1903 me_update_msg("failed to open cdr plugin");
1907 SetCdOpenCaseTime(time(NULL) + 2);
1913 static void load_pcsx_cht(void)
1919 fname = menu_loop_romsel(path, sizeof(path));
1923 printf("selected cheat file: %s\n", fname);
1926 if (NumCheats == 0 && NumCodes == 0)
1927 me_update_msg("failed to load cheats");
1929 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1930 me_update_msg(path);
1932 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1935 static int main_menu_handler(int id, int keys)
1939 case MA_MAIN_RESUME_GAME:
1943 case MA_MAIN_SAVE_STATE:
1945 return menu_loop_savestate(0);
1947 case MA_MAIN_LOAD_STATE:
1949 return menu_loop_savestate(1);
1951 case MA_MAIN_RESET_GAME:
1952 if (ready_to_go && reset_game() == 0)
1955 case MA_MAIN_LOAD_ROM:
1956 if (romsel_run() == 0)
1959 case MA_MAIN_SWAP_CD:
1960 if (swap_cd_image() == 0)
1963 case MA_MAIN_SWAP_CD_MULTI:
1964 if (swap_cd_multidisk() == 0)
1967 case MA_MAIN_RUN_BIOS:
1968 if (run_bios() == 0)
1971 case MA_MAIN_RUN_EXE:
1975 case MA_MAIN_CHEATS:
1978 case MA_MAIN_LOAD_CHEATS:
1981 case MA_MAIN_CREDITS:
1982 draw_menu_message(credits_text, draw_frame_credits);
1983 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1989 lprintf("%s: something unknown selected\n", __FUNCTION__);
1996 static menu_entry e_menu_main2[] =
1998 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1999 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2000 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2001 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2002 mee_handler ("Memcard manager", menu_loop_memcards),
2003 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2007 static int main_menu2_handler(int id, int keys)
2011 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2012 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2013 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2014 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2016 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2019 static const char h_extra[] = "Change CD, manage memcards..\n";
2021 static menu_entry e_menu_main[] =
2025 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2026 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2027 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2028 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2029 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2030 mee_handler ("Options", menu_loop_options),
2031 mee_handler ("Controls", menu_loop_keyconfig),
2032 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2033 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2034 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2035 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2039 // ----------------------------
2041 static void menu_leave_emu(void);
2043 void menu_loop(void)
2049 if (bioses[1] == NULL && !warned_about_bios) {
2051 warned_about_bios = 1;
2054 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2055 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2056 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2057 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2058 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2060 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2063 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2064 } while (!ready_to_go);
2066 /* wait until menu, ok, back is released */
2067 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2070 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2075 static int qsort_strcmp(const void *p1, const void *p2)
2077 char * const *s1 = (char * const *)p1;
2078 char * const *s2 = (char * const *)p2;
2079 return strcasecmp(*s1, *s2);
2082 static void scan_bios_plugins(void)
2084 char fname[MAXPATHLEN];
2086 int bios_i, gpu_i, spu_i, mc_i;
2091 gpu_plugins[0] = "builtin_gpu";
2092 spu_plugins[0] = "builtin_spu";
2093 memcards[0] = "(none)";
2094 bios_i = gpu_i = spu_i = mc_i = 1;
2096 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2097 dir = opendir(fname);
2099 perror("scan_bios_plugins bios opendir");
2114 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2117 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2118 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2119 printf("bad BIOS file: %s\n", ent->d_name);
2123 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2124 bioses[bios_i++] = strdup(ent->d_name);
2128 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2134 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2135 dir = opendir(fname);
2137 perror("scan_bios_plugins plugins opendir");
2151 p = strstr(ent->d_name, ".so");
2155 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2156 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2158 fprintf(stderr, "%s\n", dlerror());
2162 // now what do we have here?
2163 tmp = dlsym(h, "GPUinit");
2166 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2167 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2171 tmp = dlsym(h, "SPUinit");
2174 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2175 spu_plugins[spu_i++] = strdup(ent->d_name);
2179 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2186 dir = opendir("." MEMCARD_DIR);
2188 perror("scan_bios_plugins memcards opendir");
2203 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2206 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2207 if (stat(fname, &st) != 0) {
2208 printf("bad memcard file: %s\n", ent->d_name);
2212 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2213 memcards[mc_i++] = strdup(ent->d_name);
2217 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2221 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2226 void menu_init(void)
2228 char buff[MAXPATHLEN];
2230 strcpy(last_selected_fname, "/media");
2232 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2234 scan_bios_plugins();
2237 menu_set_defconfig();
2238 menu_load_config(0);
2239 menu_do_last_cd_img(1);
2244 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2245 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2246 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2247 fprintf(stderr, "OOM\n");
2251 emu_make_path(buff, "skin/background.png", sizeof(buff));
2252 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2254 #ifndef __ARM_ARCH_7A__ /* XXX */
2255 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2256 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2257 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2258 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2260 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2261 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2262 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2266 void menu_notify_mode_change(int w, int h, int bpp)
2273 last_vout_bpp = bpp;
2275 // XXX: should really menu code cotrol the layer size?
2278 g_layer_w = w; g_layer_h = h;
2282 if (h > g_menuscreen_h || (240 < h && h <= 360))
2283 goto fractional_4_3;
2285 // 4:3 that prefers integer scaling
2286 imult = g_menuscreen_h / h;
2287 g_layer_w = w * imult;
2288 g_layer_h = h * imult;
2289 mult = (float)g_layer_w / (float)g_layer_h;
2290 if (mult < 1.25f || mult > 1.666f)
2291 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2292 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2297 mult = 240.0f / (float)h * 4.0f / 3.0f;
2300 g_layer_w = mult * (float)g_menuscreen_h;
2301 g_layer_h = g_menuscreen_h;
2302 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2305 case SCALE_FULLSCREEN:
2306 g_layer_w = g_menuscreen_w;
2307 g_layer_h = g_menuscreen_h;
2314 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2315 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2316 if (g_layer_x < 0) g_layer_x = 0;
2317 if (g_layer_y < 0) g_layer_y = 0;
2318 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2319 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2322 static void menu_leave_emu(void)
2324 if (GPU_close != NULL) {
2325 int ret = GPU_close();
2327 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2330 plat_video_menu_enter(ready_to_go);
2332 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2333 if (pl_vout_buf != NULL && ready_to_go) {
2334 int x = max(0, g_menuscreen_w - last_vout_w);
2335 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2336 int w = min(g_menuscreen_w, last_vout_w);
2337 int h = min(g_menuscreen_h, last_vout_h);
2338 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2339 char *s = pl_vout_buf;
2341 if (last_vout_bpp == 16) {
2342 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2343 menu_darken_bg(d, s, w, 0);
2346 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2347 rgb888_to_rgb565(d, s, w * 3);
2348 menu_darken_bg(d, d, w, 0);
2354 cpu_clock = plat_cpu_clock_get();
2357 void menu_prepare_emu(void)
2359 R3000Acpu *prev_cpu = psxCpu;
2361 plat_video_menu_leave();
2363 menu_notify_mode_change(last_vout_w, last_vout_h, last_vout_bpp);
2365 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2366 if (psxCpu != prev_cpu)
2367 // note that this does not really reset, just clears drc caches
2370 // core doesn't care about Config.Cdda changes,
2371 // so handle them manually here
2377 plat_cpu_clock_apply(cpu_clock);
2379 // push config to GPU plugin
2380 plugin_call_rearmed_cbs();
2382 if (GPU_open != NULL) {
2383 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2385 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2391 void me_update_msg(const char *msg)
2393 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2394 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2396 menu_error_time = plat_get_ticks_ms();
2397 lprintf("msg: %s\n", menu_error_msg);
2400 void menu_finish(void)
2402 menu_do_last_cd_img(0);
2403 plat_cpu_clock_apply(cpu_clock_st);