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);
1862 menu_do_last_cd_img(0);
1866 static int swap_cd_image(void)
1870 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1874 printf("selected file: %s\n", fname);
1877 CdromLabel[0] = '\0';
1879 set_cd_image(fname);
1880 if (ReloadCdromPlugin() < 0) {
1881 me_update_msg("failed to load cdr plugin");
1884 if (CDR_open() < 0) {
1885 me_update_msg("failed to open cdr plugin");
1889 SetCdOpenCaseTime(time(NULL) + 2);
1892 strcpy(last_selected_fname, rom_fname_reload);
1896 static int swap_cd_multidisk(void)
1898 cdrIsoMultidiskSelect++;
1900 CdromLabel[0] = '\0';
1903 if (CDR_open() < 0) {
1904 me_update_msg("failed to open cdr plugin");
1908 SetCdOpenCaseTime(time(NULL) + 2);
1914 static void load_pcsx_cht(void)
1920 fname = menu_loop_romsel(path, sizeof(path));
1924 printf("selected cheat file: %s\n", fname);
1927 if (NumCheats == 0 && NumCodes == 0)
1928 me_update_msg("failed to load cheats");
1930 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1931 me_update_msg(path);
1933 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1936 static int main_menu_handler(int id, int keys)
1940 case MA_MAIN_RESUME_GAME:
1944 case MA_MAIN_SAVE_STATE:
1946 return menu_loop_savestate(0);
1948 case MA_MAIN_LOAD_STATE:
1950 return menu_loop_savestate(1);
1952 case MA_MAIN_RESET_GAME:
1953 if (ready_to_go && reset_game() == 0)
1956 case MA_MAIN_LOAD_ROM:
1957 if (romsel_run() == 0)
1960 case MA_MAIN_SWAP_CD:
1961 if (swap_cd_image() == 0)
1964 case MA_MAIN_SWAP_CD_MULTI:
1965 if (swap_cd_multidisk() == 0)
1968 case MA_MAIN_RUN_BIOS:
1969 if (run_bios() == 0)
1972 case MA_MAIN_RUN_EXE:
1976 case MA_MAIN_CHEATS:
1979 case MA_MAIN_LOAD_CHEATS:
1982 case MA_MAIN_CREDITS:
1983 draw_menu_message(credits_text, draw_frame_credits);
1984 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1990 lprintf("%s: something unknown selected\n", __FUNCTION__);
1997 static menu_entry e_menu_main2[] =
1999 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2000 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2001 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2002 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2003 mee_handler ("Memcard manager", menu_loop_memcards),
2004 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2008 static int main_menu2_handler(int id, int keys)
2012 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2013 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2014 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2015 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2017 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2020 static const char h_extra[] = "Change CD, manage memcards..\n";
2022 static menu_entry e_menu_main[] =
2026 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2027 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2028 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2029 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2030 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2031 mee_handler ("Options", menu_loop_options),
2032 mee_handler ("Controls", menu_loop_keyconfig),
2033 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2034 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2035 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2036 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2040 // ----------------------------
2042 static void menu_leave_emu(void);
2044 void menu_loop(void)
2050 if (bioses[1] == NULL && !warned_about_bios) {
2052 warned_about_bios = 1;
2055 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2056 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2057 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2058 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2059 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2061 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2064 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2065 } while (!ready_to_go);
2067 /* wait until menu, ok, back is released */
2068 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2071 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2076 static int qsort_strcmp(const void *p1, const void *p2)
2078 char * const *s1 = (char * const *)p1;
2079 char * const *s2 = (char * const *)p2;
2080 return strcasecmp(*s1, *s2);
2083 static void scan_bios_plugins(void)
2085 char fname[MAXPATHLEN];
2087 int bios_i, gpu_i, spu_i, mc_i;
2092 gpu_plugins[0] = "builtin_gpu";
2093 spu_plugins[0] = "builtin_spu";
2094 memcards[0] = "(none)";
2095 bios_i = gpu_i = spu_i = mc_i = 1;
2097 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2098 dir = opendir(fname);
2100 perror("scan_bios_plugins bios opendir");
2115 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2118 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2119 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2120 printf("bad BIOS file: %s\n", ent->d_name);
2124 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2125 bioses[bios_i++] = strdup(ent->d_name);
2129 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2135 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2136 dir = opendir(fname);
2138 perror("scan_bios_plugins plugins opendir");
2152 p = strstr(ent->d_name, ".so");
2156 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2157 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2159 fprintf(stderr, "%s\n", dlerror());
2163 // now what do we have here?
2164 tmp = dlsym(h, "GPUinit");
2167 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2168 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2172 tmp = dlsym(h, "SPUinit");
2175 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2176 spu_plugins[spu_i++] = strdup(ent->d_name);
2180 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2187 dir = opendir("." MEMCARD_DIR);
2189 perror("scan_bios_plugins memcards opendir");
2204 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2207 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2208 if (stat(fname, &st) != 0) {
2209 printf("bad memcard file: %s\n", ent->d_name);
2213 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2214 memcards[mc_i++] = strdup(ent->d_name);
2218 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2222 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2227 void menu_init(void)
2229 char buff[MAXPATHLEN];
2231 strcpy(last_selected_fname, "/media");
2233 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2235 scan_bios_plugins();
2238 menu_set_defconfig();
2239 menu_load_config(0);
2240 menu_do_last_cd_img(1);
2245 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2246 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2247 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2248 fprintf(stderr, "OOM\n");
2252 emu_make_path(buff, "skin/background.png", sizeof(buff));
2253 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2255 #ifndef __ARM_ARCH_7A__ /* XXX */
2256 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2257 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2258 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2259 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2261 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2262 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2263 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2267 void menu_notify_mode_change(int w, int h, int bpp)
2274 last_vout_bpp = bpp;
2276 // XXX: should really menu code cotrol the layer size?
2279 g_layer_w = w; g_layer_h = h;
2283 if (h > g_menuscreen_h || (240 < h && h <= 360))
2284 goto fractional_4_3;
2286 // 4:3 that prefers integer scaling
2287 imult = g_menuscreen_h / h;
2288 g_layer_w = w * imult;
2289 g_layer_h = h * imult;
2290 mult = (float)g_layer_w / (float)g_layer_h;
2291 if (mult < 1.25f || mult > 1.666f)
2292 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2293 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2298 mult = 240.0f / (float)h * 4.0f / 3.0f;
2301 g_layer_w = mult * (float)g_menuscreen_h;
2302 g_layer_h = g_menuscreen_h;
2303 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2306 case SCALE_FULLSCREEN:
2307 g_layer_w = g_menuscreen_w;
2308 g_layer_h = g_menuscreen_h;
2315 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2316 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2317 if (g_layer_x < 0) g_layer_x = 0;
2318 if (g_layer_y < 0) g_layer_y = 0;
2319 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2320 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2323 static void menu_leave_emu(void)
2325 if (GPU_close != NULL) {
2326 int ret = GPU_close();
2328 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2331 plat_video_menu_enter(ready_to_go);
2333 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2334 if (pl_vout_buf != NULL && ready_to_go) {
2335 int x = max(0, g_menuscreen_w - last_vout_w);
2336 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2337 int w = min(g_menuscreen_w, last_vout_w);
2338 int h = min(g_menuscreen_h, last_vout_h);
2339 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2340 char *s = pl_vout_buf;
2342 if (last_vout_bpp == 16) {
2343 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2344 menu_darken_bg(d, s, w, 0);
2347 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2348 rgb888_to_rgb565(d, s, w * 3);
2349 menu_darken_bg(d, d, w, 0);
2355 cpu_clock = plat_cpu_clock_get();
2358 void menu_prepare_emu(void)
2360 R3000Acpu *prev_cpu = psxCpu;
2362 plat_video_menu_leave();
2364 menu_notify_mode_change(last_vout_w, last_vout_h, last_vout_bpp);
2366 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2367 if (psxCpu != prev_cpu)
2368 // note that this does not really reset, just clears drc caches
2371 // core doesn't care about Config.Cdda changes,
2372 // so handle them manually here
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);
2401 void menu_finish(void)
2403 plat_cpu_clock_apply(cpu_clock_st);