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_psx_w, last_psx_h, last_psx_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, 2),
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);
344 static int menu_write_config(int is_game)
346 char cfgfile[MAXPATHLEN];
350 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
351 f = fopen(cfgfile, "w");
353 printf("menu_write_config: failed to open: %s\n", cfgfile);
357 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
358 fprintf(f, "%s = ", config_data[i].name);
359 switch (config_data[i].len) {
361 fprintf(f, "%s\n", (char *)config_data[i].val);
364 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
367 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
370 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
373 printf("menu_write_config: unhandled len %d for %s\n",
374 config_data[i].len, config_data[i].name);
385 static int menu_do_last_cd_img(int is_get)
390 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
391 f = fopen(path, is_get ? "r" : "w");
396 fscanf(f, "%255s", last_selected_fname);
398 fprintf(f, "%s\n", last_selected_fname);
404 static void parse_str_val(char *cval, const char *src)
407 strncpy(cval, src, MAXPATHLEN);
408 cval[MAXPATHLEN - 1] = 0;
409 tmp = strchr(cval, '\n');
411 tmp = strchr(cval, '\r');
416 static void keys_load_all(const char *cfg);
418 static int menu_load_config(int is_game)
420 char cfgfile[MAXPATHLEN];
426 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
427 f = fopen(cfgfile, "r");
429 printf("menu_load_config: failed to open: %s\n", cfgfile);
433 fseek(f, 0, SEEK_END);
436 printf("bad size %ld: %s\n", size, cfgfile);
440 cfg = malloc(size + 1);
444 fseek(f, 0, SEEK_SET);
445 if (fread(cfg, 1, size, f) != size) {
446 printf("failed to read: %s\n", cfgfile);
451 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
455 tmp = strstr(cfg, config_data[i].name);
458 tmp += strlen(config_data[i].name);
459 if (strncmp(tmp, " = ", 3) != 0)
463 if (config_data[i].len == 0) {
464 parse_str_val(config_data[i].val, tmp);
469 val = strtoul(tmp, &tmp2, 16);
470 if (tmp2 == NULL || tmp == tmp2)
471 continue; // parse failed
473 switch (config_data[i].len) {
475 *(u8 *)config_data[i].val = val;
478 *(u16 *)config_data[i].val = val;
481 *(u32 *)config_data[i].val = val;
484 printf("menu_load_config: unhandled len %d for %s\n",
485 config_data[i].len, config_data[i].name);
491 char *tmp = strstr(cfg, "lastcdimg = ");
494 parse_str_val(last_selected_fname, tmp);
508 // caanoo old config compat hack
509 if (strcmp(Config.Gpu, "gpuPCSX4ALL.so") == 0)
510 strcpy(Config.Gpu, "gpu_unai.so");
513 for (i = bios_sel = 0; bioses[i] != NULL; i++)
514 if (strcmp(Config.Bios, bioses[i]) == 0)
515 { bios_sel = i; break; }
517 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
518 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
519 { gpu_plugsel = i; break; }
521 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
522 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
523 { spu_plugsel = i; break; }
528 // rrrr rggg gggb bbbb
529 static unsigned short fname2color(const char *fname)
531 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
532 ".bz", ".znx", ".pbp", ".cbn" };
533 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
534 ".table", ".index", ".sbi" };
535 const char *ext = strrchr(fname, '.');
540 for (i = 0; i < array_size(cdimg_exts); i++)
541 if (strcasecmp(ext, cdimg_exts[i]) == 0)
543 for (i = 0; i < array_size(other_exts); i++)
544 if (strcasecmp(ext, other_exts[i]) == 0)
549 static void draw_savestate_bg(int slot);
551 static const char *filter_exts[] = {
552 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
555 #define MENU_ALIGN_LEFT
556 #ifdef __ARM_ARCH_7A__ // assume hires device
562 #define menu_init menu_init_common
563 #include "common/menu.c"
566 // a bit of black magic here
567 static void draw_savestate_bg(int slot)
569 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
571 char fname[MAXPATHLEN];
578 ret = get_state_filename(fname, sizeof(fname), slot);
582 f = gzopen(fname, "rb");
586 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
587 fprintf(stderr, "gzseek failed\n");
592 gpu = malloc(sizeof(*gpu));
598 ret = gzread(f, gpu, sizeof(*gpu));
600 if (ret != sizeof(*gpu)) {
601 fprintf(stderr, "gzread failed\n");
605 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
607 if (gpu->ulStatus & 0x800000)
608 goto out; // disabled
610 x = gpu->ulControl[5] & 0x3ff;
611 y = (gpu->ulControl[5] >> 10) & 0x1ff;
612 s = (u16 *)gpu->psxVRam + y * 1024 + x;
613 w = psx_widths[(gpu->ulStatus >> 16) & 7];
614 tmp = gpu->ulControl[7];
615 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
616 if (gpu->ulStatus & 0x80000) // doubleheight
619 x = max(0, g_menuscreen_w - w) & ~3;
620 y = max(0, g_menuscreen_h / 2 - h / 2);
621 w = min(g_menuscreen_w, w);
622 h = min(g_menuscreen_h, h);
623 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
625 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
626 if (gpu->ulStatus & 0x200000)
627 bgr888_to_rgb565(d, s, w * 3);
629 bgr555_to_rgb565(d, s, w * 2);
631 // darken this so that menu text is visible
632 if (g_menuscreen_w - w < 320)
633 menu_darken_bg(d, d, w * 2, 0);
640 // -------------- key config --------------
642 me_bind_action me_ctrl_actions[] =
644 { "UP ", 1 << DKEY_UP},
645 { "DOWN ", 1 << DKEY_DOWN },
646 { "LEFT ", 1 << DKEY_LEFT },
647 { "RIGHT ", 1 << DKEY_RIGHT },
648 { "TRIANGLE", 1 << DKEY_TRIANGLE },
649 { "CIRCLE ", 1 << DKEY_CIRCLE },
650 { "CROSS ", 1 << DKEY_CROSS },
651 { "SQUARE ", 1 << DKEY_SQUARE },
652 { "L1 ", 1 << DKEY_L1 },
653 { "R1 ", 1 << DKEY_R1 },
654 { "L2 ", 1 << DKEY_L2 },
655 { "R2 ", 1 << DKEY_R2 },
656 { "L3 ", 1 << DKEY_L3 },
657 { "R3 ", 1 << DKEY_R3 },
658 { "START ", 1 << DKEY_START },
659 { "SELECT ", 1 << DKEY_SELECT },
663 me_bind_action emuctrl_actions[] =
665 { "Save State ", 1 << SACTION_SAVE_STATE },
666 { "Load State ", 1 << SACTION_LOAD_STATE },
667 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
668 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
669 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
670 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
671 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
672 #ifdef __ARM_ARCH_7A__ /* XXX */
673 { "Minimize ", 1 << SACTION_MINIMIZE },
675 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
676 { "Gun A button ", 1 << SACTION_GUN_A },
677 { "Gun B button ", 1 << SACTION_GUN_B },
678 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
679 #ifndef __ARM_ARCH_7A__ /* XXX */
680 { "Volume Up ", 1 << SACTION_VOLUME_UP },
681 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
686 static char *mystrip(char *str)
691 for (i = 0; i < len; i++)
692 if (str[i] != ' ') break;
693 if (i > 0) memmove(str, str + i, len - i + 1);
696 for (i = len - 1; i >= 0; i--)
697 if (str[i] != ' ') break;
703 static void get_line(char *d, size_t size, const char *s)
708 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
719 static void keys_write_all(FILE *f)
723 for (d = 0; d < IN_MAX_DEVS; d++)
725 const int *binds = in_get_dev_binds(d);
726 const char *name = in_get_dev_name(d, 0, 0);
729 if (binds == NULL || name == NULL)
732 fprintf(f, "binddev = %s\n", name);
733 in_get_config(d, IN_CFG_BIND_COUNT, &count);
735 for (k = 0; k < count; k++)
740 act[0] = act[31] = 0;
741 name = in_get_key_name(d, k);
743 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
744 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
745 mask = me_ctrl_actions[i].mask;
747 strncpy(act, me_ctrl_actions[i].name, 31);
748 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
751 mask = me_ctrl_actions[i].mask << 16;
753 strncpy(act, me_ctrl_actions[i].name, 31);
754 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
759 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
760 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
761 mask = emuctrl_actions[i].mask;
763 strncpy(act, emuctrl_actions[i].name, 31);
764 fprintf(f, "bind %s = %s\n", name, mystrip(act));
770 for (k = 0; k < array_size(in_adev); k++)
773 fprintf(f, "bind_analog = %d\n", k);
778 static int parse_bind_val(const char *val, int *type)
782 *type = IN_BINDTYPE_NONE;
786 if (strncasecmp(val, "player", 6) == 0)
788 int player, shift = 0;
789 player = atoi(val + 6) - 1;
791 if ((unsigned int)player > 1)
796 *type = IN_BINDTYPE_PLAYER12;
797 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
798 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
799 return me_ctrl_actions[i].mask << shift;
802 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
803 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
804 *type = IN_BINDTYPE_EMU;
805 return emuctrl_actions[i].mask;
812 static void keys_load_all(const char *cfg)
814 char dev[256], key[128], *act;
820 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
823 get_line(dev, sizeof(dev), p);
824 dev_id = in_config_parse_dev(dev);
826 printf("input: can't handle dev: %s\n", dev);
830 in_unbind_all(dev_id, -1, -1);
831 while ((p = strstr(p, "bind"))) {
832 if (strncmp(p, "binddev = ", 10) == 0)
835 if (strncmp(p, "bind_analog", 11) == 0) {
836 ret = sscanf(p, "bind_analog = %d", &bind);
839 printf("input: parse error: %16s..\n", p);
842 if ((unsigned int)bind >= array_size(in_adev)) {
843 printf("input: analog id %d out of range\n", bind);
846 in_adev[bind] = dev_id;
852 printf("input: parse error: %16s..\n", p);
856 get_line(key, sizeof(key), p);
857 act = strchr(key, '=');
859 printf("parse failed: %16s..\n", p);
867 bind = parse_bind_val(act, &bindtype);
868 if (bind != -1 && bind != 0) {
869 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
870 in_config_bind_key(dev_id, key, bind, bindtype);
873 lprintf("config: unhandled action \"%s\"\n", act);
879 static int key_config_loop_wrap(int id, int keys)
882 case MA_CTRL_PLAYER1:
883 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
885 case MA_CTRL_PLAYER2:
886 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
889 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
897 static const char *adevnames[IN_MAX_DEVS + 2];
898 static int stick_sel[2];
900 static menu_entry e_menu_keyconfig_analog[] =
902 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
903 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
904 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
905 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
906 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
907 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
911 static int key_config_analog(int id, int keys)
913 int i, d, count, sel = 0;
914 int sel2dev_map[IN_MAX_DEVS];
916 memset(adevnames, 0, sizeof(adevnames));
917 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
918 memset(stick_sel, 0, sizeof(stick_sel));
920 adevnames[0] = "None";
922 for (d = 0; d < IN_MAX_DEVS; d++)
924 const char *name = in_get_dev_name(d, 0, 1);
929 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
933 if (in_adev[0] == d) stick_sel[0] = i;
934 if (in_adev[1] == d) stick_sel[1] = i;
936 adevnames[i++] = name;
940 me_loop(e_menu_keyconfig_analog, &sel);
942 in_adev[0] = sel2dev_map[stick_sel[0]];
943 in_adev[1] = sel2dev_map[stick_sel[1]];
948 static const char *mgn_dev_name(int id, int *offs)
950 const char *name = NULL;
953 if (id == MA_CTRL_DEV_FIRST)
956 for (; it < IN_MAX_DEVS; it++) {
957 name = in_get_dev_name(it, 1, 1);
966 static const char *mgn_saveloadcfg(int id, int *offs)
971 static int mh_savecfg(int id, int keys)
973 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
974 me_update_msg("config saved");
976 me_update_msg("failed to write config");
981 static int mh_input_rescan(int id, int keys)
983 //menu_sync_config();
985 me_update_msg("rescan complete.");
990 static const char *men_in_type_sel[] = {
991 "Standard (SCPH-1080)",
992 "Analog (SCPH-1150)",
996 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
997 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
998 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1000 static menu_entry e_menu_keyconfig[] =
1002 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1003 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1004 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1005 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1007 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1008 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1009 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1010 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1011 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1012 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1013 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1014 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1015 mee_handler ("Rescan devices:", mh_input_rescan),
1017 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1018 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1027 static int menu_loop_keyconfig(int id, int keys)
1031 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1032 me_loop(e_menu_keyconfig, &sel);
1036 // ------------ gfx options menu ------------
1038 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1039 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1040 "using d-pad or move it using R+d-pad";
1041 static const char *men_dummy[] = { NULL };
1043 static int menu_loop_cscaler(int id, int keys)
1047 scaling = SCALE_CUSTOM;
1049 plat_gvideo_open(Config.PsxType);
1054 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1055 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1056 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1059 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1060 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1061 if (inp & PBTN_UP) g_layer_y--;
1062 if (inp & PBTN_DOWN) g_layer_y++;
1063 if (inp & PBTN_LEFT) g_layer_x--;
1064 if (inp & PBTN_RIGHT) g_layer_x++;
1065 if (!(inp & PBTN_R)) {
1066 if (inp & PBTN_UP) g_layer_h += 2;
1067 if (inp & PBTN_DOWN) g_layer_h -= 2;
1068 if (inp & PBTN_LEFT) g_layer_w += 2;
1069 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1071 if (inp & (PBTN_MOK|PBTN_MBACK))
1074 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1075 if (g_layer_x < 0) g_layer_x = 0;
1076 if (g_layer_x > 640) g_layer_x = 640;
1077 if (g_layer_y < 0) g_layer_y = 0;
1078 if (g_layer_y > 420) g_layer_y = 420;
1079 if (g_layer_w < 160) g_layer_w = 160;
1080 if (g_layer_h < 60) g_layer_h = 60;
1081 if (g_layer_x + g_layer_w > 800)
1082 g_layer_w = 800 - g_layer_x;
1083 if (g_layer_y + g_layer_h > 480)
1084 g_layer_h = 480 - g_layer_y;
1086 plat_gvideo_open(Config.PsxType);
1090 plat_gvideo_close();
1095 static menu_entry e_menu_gfx_options[] =
1097 mee_enum ("Scaler", MA_OPT_SCALER, scaling, men_scaler),
1098 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1099 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1100 // mee_onoff ("Vsync", 0, vsync, 1),
1101 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1105 static int menu_loop_gfx_options(int id, int keys)
1109 me_loop(e_menu_gfx_options, &sel);
1115 void menu_set_filter_list(void *filters)
1119 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1120 e_menu_gfx_options[i].data = filters;
1121 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1124 // ------------ bios/plugins ------------
1128 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1129 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1131 static menu_entry e_menu_plugin_gpu_neon[] =
1133 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1137 static int menu_loop_plugin_gpu_neon(int id, int keys)
1140 me_loop(e_menu_plugin_gpu_neon, &sel);
1146 static menu_entry e_menu_plugin_gpu_unai[] =
1148 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1149 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1150 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1151 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1155 static int menu_loop_plugin_gpu_unai(int id, int keys)
1158 me_loop(e_menu_plugin_gpu_unai, &sel);
1162 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1163 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1164 static const char h_gpu_1[] = "Capcom fighting games";
1165 static const char h_gpu_2[] = "Black screens in Lunar";
1166 static const char h_gpu_3[] = "Compatibility mode";
1167 static const char h_gpu_6[] = "Pandemonium 2";
1168 //static const char h_gpu_7[] = "Skip every second frame";
1169 static const char h_gpu_8[] = "Needed by Dark Forces";
1170 static const char h_gpu_9[] = "better g-colors, worse textures";
1171 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1173 static menu_entry e_menu_plugin_gpu_peops[] =
1175 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1176 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1177 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1178 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1179 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1180 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1181 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1182 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1183 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1184 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1188 static int menu_loop_plugin_gpu_peops(int id, int keys)
1191 me_loop(e_menu_plugin_gpu_peops, &sel);
1195 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1196 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1197 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1199 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1201 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1202 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1203 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1204 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1205 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1206 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1207 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1208 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1209 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1210 mee_label ("Fixes/hacks:"),
1211 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1212 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1213 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1214 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1215 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1216 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1217 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1218 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1219 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1220 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1221 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1225 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1228 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1232 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1233 static const char h_spu_volboost[] = "Large values cause distortion";
1235 static menu_entry e_menu_plugin_spu[] =
1237 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1238 mee_onoff ("Reverb", 0, iUseReverb, 2),
1239 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1240 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1244 static int menu_loop_plugin_spu(int id, int keys)
1247 me_loop(e_menu_plugin_spu, &sel);
1251 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1252 "savestates and can't be changed there. Must save\n"
1253 "config and reload the game for change to take effect";
1254 static const char h_plugin_gpu[] =
1256 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1261 "is Pete's soft GPU, slow but accurate\n"
1262 "gpuPCSX4ALL is GPU from PCSX4ALL, fast but glitchy\n"
1263 "gpuGLES Pete's hw GPU, uses 3D chip but is glitchy\n"
1264 "must save config and reload the game if changed";
1265 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1266 "must save config and reload the game if changed";
1267 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1268 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1269 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1270 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1272 static menu_entry e_menu_plugin_options[] =
1274 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1275 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1276 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1278 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1280 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1281 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1282 mee_handler_h ("Configure GLES GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1283 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1287 static menu_entry e_menu_main2[];
1289 static int menu_loop_plugin_options(int id, int keys)
1292 me_loop(e_menu_plugin_options, &sel);
1294 // sync BIOS/plugins
1295 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1296 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1297 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1298 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1303 // ------------ adv options menu ------------
1305 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1306 "(lower value - less work for the emu, may be faster)";
1307 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1308 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1309 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1311 static menu_entry e_menu_speed_hacks[] =
1313 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1314 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1315 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1316 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1320 static int menu_loop_speed_hacks(int id, int keys)
1323 me_loop(e_menu_speed_hacks, &sel);
1327 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1328 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1329 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1330 "(green: normal, red: fmod, blue: noise)";
1331 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1332 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1333 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1334 "(proper .cue/.bin dump is needed otherwise)";
1335 static const char h_cfg_sio[] = "You should not need this, breaks games";
1336 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1337 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1338 "(timing hack, breaks other games)";
1339 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1340 "(timing hack, breaks other games)";
1341 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1342 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1343 "Might be useful to overcome some dynarec bugs";
1344 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1345 "must reload game for any change to take effect";
1347 static menu_entry e_menu_adv_options[] =
1349 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1350 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1351 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1352 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1353 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1354 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1355 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1356 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1357 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1358 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1359 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1360 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1364 static int menu_loop_adv_options(int id, int keys)
1367 me_loop(e_menu_adv_options, &sel);
1371 // ------------ options menu ------------
1373 static int mh_restore_defaults(int id, int keys)
1375 menu_set_defconfig();
1376 me_update_msg("defaults restored");
1380 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1381 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1383 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1384 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1385 "loading state or both";
1387 static const char h_restore_def[] = "Switches back to default / recommended\n"
1389 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1391 static menu_entry e_menu_options[] =
1393 // mee_range ("Save slot", 0, state_slot, 0, 9),
1394 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1395 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1396 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1397 mee_enum ("Region", 0, region, men_region),
1398 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1399 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1400 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1401 mee_handler ("[Advanced]", menu_loop_adv_options),
1402 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1403 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1404 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1408 static int menu_loop_options(int id, int keys)
1413 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1414 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1415 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1417 me_loop(e_menu_options, &sel);
1422 // ------------ debug menu ------------
1424 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1426 int w = min(g_menuscreen_w, 1024);
1427 int h = min(g_menuscreen_h, 512);
1428 u16 *d = g_menuscreen_ptr;
1429 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1433 gpuf->ulFreezeVersion = 1;
1434 if (GPU_freeze != NULL)
1435 GPU_freeze(1, gpuf);
1437 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1438 bgr555_to_rgb565(d, s, w * 2);
1440 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1441 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1442 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1443 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1444 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1447 static void debug_menu_loop(void)
1449 int inp, df_x = 0, df_y = 0;
1452 gpuf = malloc(sizeof(*gpuf));
1459 draw_frame_debug(gpuf, df_x, df_y);
1462 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1463 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1464 if (inp & PBTN_MBACK) break;
1465 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1466 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1467 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1468 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1474 // --------- memcard manager ---------
1476 static void draw_mc_icon(int dx, int dy, const u16 *s)
1481 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1483 for (y = 0; y < 16; y++, s += 16) {
1484 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1485 for (x = 0; x < 16; x++) {
1487 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1488 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1494 static void draw_mc_bg(void)
1496 McdBlock *blocks1, *blocks2;
1500 blocks1 = malloc(15 * sizeof(blocks1[0]));
1501 blocks2 = malloc(15 * sizeof(blocks1[0]));
1502 if (blocks1 == NULL || blocks2 == NULL)
1505 for (i = 0; i < 15; i++) {
1506 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1507 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1512 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1514 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1518 maxicons = g_menuscreen_h / 32;
1521 row2 = g_menuscreen_w / 2;
1522 for (i = 0; i < maxicons; i++) {
1523 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1524 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1526 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1527 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1530 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1538 static void handle_memcard_sel(void)
1541 if (memcard1_sel != 0)
1542 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1544 if (memcard2_sel != 0)
1545 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1546 LoadMcds(Config.Mcd1, Config.Mcd2);
1550 static menu_entry e_memcard_options[] =
1552 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1553 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1557 static int menu_loop_memcards(int id, int keys)
1563 memcard1_sel = memcard2_sel = 0;
1564 p = strrchr(Config.Mcd1, '/');
1566 for (i = 0; memcards[i] != NULL; i++)
1567 if (strcmp(p + 1, memcards[i]) == 0)
1568 { memcard1_sel = i; break; }
1569 p = strrchr(Config.Mcd2, '/');
1571 for (i = 0; memcards[i] != NULL; i++)
1572 if (strcmp(p + 1, memcards[i]) == 0)
1573 { memcard2_sel = i; break; }
1575 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1577 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1582 // ------------ cheats menu ------------
1584 static void draw_cheatlist(int sel)
1586 int max_cnt, start, i, pos, active;
1588 max_cnt = g_menuscreen_h / me_sfont_h;
1589 start = max_cnt / 2 - sel;
1593 for (i = 0; i < NumCheats; i++) {
1595 if (pos < 0) continue;
1596 if (pos >= max_cnt) break;
1597 active = Cheats[i].Enabled;
1598 smalltext_out16(14, pos * me_sfont_h,
1599 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1600 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1601 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1605 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1607 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1611 static void menu_loop_cheats(void)
1613 static int menu_sel = 0;
1618 draw_cheatlist(menu_sel);
1619 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1620 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1621 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1622 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1623 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1624 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1625 if (inp & PBTN_MOK) { // action
1626 if (menu_sel < NumCheats)
1627 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1630 if (inp & PBTN_MBACK)
1635 // --------- main menu help ----------
1637 static void menu_bios_warn(void)
1640 static const char msg[] =
1641 "You don't seem to have copied any BIOS\n"
1643 #ifdef __ARM_ARCH_7A__ // XXX
1644 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1646 "pcsx_rearmed/bios/\n\n"
1648 "While many games work fine with fake\n"
1649 "(HLE) BIOS, others (like MGS and FF8)\n"
1650 "require BIOS to work.\n"
1651 "After copying the file, you'll also need\n"
1652 "to select it in the emu's menu:\n"
1653 "options->[BIOS/Plugins]\n\n"
1654 "The file is usually named SCPH1001.BIN,\n"
1655 "but other not compressed files can be\n"
1657 "Press %s or %s to continue";
1658 char tmp_msg[sizeof(msg) + 64];
1660 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1661 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1664 draw_menu_message(tmp_msg, NULL);
1666 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1667 if (inp & (PBTN_MBACK|PBTN_MOK))
1672 // ------------ main menu ------------
1674 static menu_entry e_menu_main[];
1677 static void draw_frame_main(void)
1686 if (CdromId[0] != 0) {
1687 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1688 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1689 Config.HLE ? "HLE" : "BIOS");
1690 smalltext_out16(4, 1, buff, 0x105f);
1694 capacity = plat_get_bat_capacity();
1696 tmp = localtime(<ime);
1697 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1698 if (capacity >= 0) {
1699 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1704 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1708 static void draw_frame_credits(void)
1710 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1713 static const char credits_text[] =
1715 "(C) 1999-2003 PCSX Team\n"
1716 "(C) 2005-2009 PCSX-df Team\n"
1717 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1718 "ARM recompiler (C) 2009-2011 Ari64\n"
1720 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1722 "PEOpS GPU and SPU by Pete Bernert\n"
1723 " and the P.E.Op.S. team\n"
1724 "PCSX4ALL plugin by PCSX4ALL team\n"
1725 " Chui, Franxis, Unai\n\n"
1726 "integration, optimization and\n"
1727 " frontend (C) 2010-2012 notaz\n";
1729 static int reset_game(void)
1732 if (bios_sel == 0 && !Config.HLE)
1738 if (CheckCdrom() != -1) {
1744 static int reload_plugins(const char *cdimg)
1750 set_cd_image(cdimg);
1752 pcnt_hook_plugins();
1754 if (OpenPlugins() == -1) {
1755 me_update_msg("failed to open plugins");
1758 plugin_call_rearmed_cbs();
1760 cdrIsoMultidiskCount = 1;
1762 CdromLabel[0] = '\0';
1767 static int run_bios(void)
1773 if (reload_plugins(NULL) != 0)
1781 static int run_exe(void)
1785 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1790 if (reload_plugins(NULL) != 0)
1794 if (Load(fname) != 0) {
1795 me_update_msg("exe load failed, bad file?");
1804 static int run_cd_image(const char *fname)
1807 reload_plugins(fname);
1809 // always autodetect, menu_sync_config will override as needed
1812 if (CheckCdrom() == -1) {
1813 // Only check the CD if we are starting the console with a CD
1815 me_update_msg("unsupported/invalid CD image");
1821 // Read main executable directly from CDRom and start it
1822 if (LoadCdrom() == -1) {
1824 me_update_msg("failed to load CD image");
1834 static int romsel_run(void)
1836 int prev_gpu, prev_spu;
1839 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1843 printf("selected file: %s\n", fname);
1845 new_dynarec_clear_full();
1847 if (run_cd_image(fname) != 0)
1850 prev_gpu = gpu_plugsel;
1851 prev_spu = spu_plugsel;
1852 if (menu_load_config(1) != 0)
1853 menu_load_config(0);
1855 // check for plugin changes, have to repeat
1856 // loading if game config changed plugins to reload them
1857 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1858 printf("plugin change detected, reloading plugins..\n");
1859 if (run_cd_image(fname) != 0)
1863 strcpy(last_selected_fname, rom_fname_reload);
1867 static int swap_cd_image(void)
1871 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1875 printf("selected file: %s\n", fname);
1878 CdromLabel[0] = '\0';
1880 set_cd_image(fname);
1881 if (ReloadCdromPlugin() < 0) {
1882 me_update_msg("failed to load cdr plugin");
1885 if (CDR_open() < 0) {
1886 me_update_msg("failed to open cdr plugin");
1890 SetCdOpenCaseTime(time(NULL) + 2);
1893 strcpy(last_selected_fname, rom_fname_reload);
1897 static int swap_cd_multidisk(void)
1899 cdrIsoMultidiskSelect++;
1901 CdromLabel[0] = '\0';
1904 if (CDR_open() < 0) {
1905 me_update_msg("failed to open cdr plugin");
1909 SetCdOpenCaseTime(time(NULL) + 2);
1915 static void load_pcsx_cht(void)
1921 fname = menu_loop_romsel(path, sizeof(path));
1925 printf("selected cheat file: %s\n", fname);
1928 if (NumCheats == 0 && NumCodes == 0)
1929 me_update_msg("failed to load cheats");
1931 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1932 me_update_msg(path);
1934 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1937 static int main_menu_handler(int id, int keys)
1941 case MA_MAIN_RESUME_GAME:
1945 case MA_MAIN_SAVE_STATE:
1947 return menu_loop_savestate(0);
1949 case MA_MAIN_LOAD_STATE:
1951 return menu_loop_savestate(1);
1953 case MA_MAIN_RESET_GAME:
1954 if (ready_to_go && reset_game() == 0)
1957 case MA_MAIN_LOAD_ROM:
1958 if (romsel_run() == 0)
1961 case MA_MAIN_SWAP_CD:
1962 if (swap_cd_image() == 0)
1965 case MA_MAIN_SWAP_CD_MULTI:
1966 if (swap_cd_multidisk() == 0)
1969 case MA_MAIN_RUN_BIOS:
1970 if (run_bios() == 0)
1973 case MA_MAIN_RUN_EXE:
1977 case MA_MAIN_CHEATS:
1980 case MA_MAIN_LOAD_CHEATS:
1983 case MA_MAIN_CREDITS:
1984 draw_menu_message(credits_text, draw_frame_credits);
1985 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1991 lprintf("%s: something unknown selected\n", __FUNCTION__);
1998 static menu_entry e_menu_main2[] =
2000 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2001 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2002 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2003 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2004 mee_handler ("Memcard manager", menu_loop_memcards),
2005 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2009 static int main_menu2_handler(int id, int keys)
2013 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2014 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2015 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2016 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2018 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2021 static const char h_extra[] = "Change CD, manage memcards..\n";
2023 static menu_entry e_menu_main[] =
2027 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2028 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2029 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2030 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2031 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2032 mee_handler ("Options", menu_loop_options),
2033 mee_handler ("Controls", menu_loop_keyconfig),
2034 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2035 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2036 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2037 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2041 // ----------------------------
2043 static void menu_leave_emu(void);
2045 void menu_loop(void)
2051 if (bioses[1] == NULL && !warned_about_bios) {
2053 warned_about_bios = 1;
2056 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2057 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2058 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2059 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2060 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2062 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2065 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2066 } while (!ready_to_go);
2068 /* wait until menu, ok, back is released */
2069 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2072 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2077 static int qsort_strcmp(const void *p1, const void *p2)
2079 char * const *s1 = (char * const *)p1;
2080 char * const *s2 = (char * const *)p2;
2081 return strcasecmp(*s1, *s2);
2084 static void scan_bios_plugins(void)
2086 char fname[MAXPATHLEN];
2088 int bios_i, gpu_i, spu_i, mc_i;
2093 gpu_plugins[0] = "builtin_gpu";
2094 spu_plugins[0] = "builtin_spu";
2095 memcards[0] = "(none)";
2096 bios_i = gpu_i = spu_i = mc_i = 1;
2098 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2099 dir = opendir(fname);
2101 perror("scan_bios_plugins bios opendir");
2116 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2119 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2120 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2121 printf("bad BIOS file: %s\n", ent->d_name);
2125 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2126 bioses[bios_i++] = strdup(ent->d_name);
2130 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2136 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2137 dir = opendir(fname);
2139 perror("scan_bios_plugins plugins opendir");
2153 p = strstr(ent->d_name, ".so");
2157 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2158 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2160 fprintf(stderr, "%s\n", dlerror());
2164 // now what do we have here?
2165 tmp = dlsym(h, "GPUinit");
2168 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2169 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2173 tmp = dlsym(h, "SPUinit");
2176 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2177 spu_plugins[spu_i++] = strdup(ent->d_name);
2181 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2188 dir = opendir("." MEMCARD_DIR);
2190 perror("scan_bios_plugins memcards opendir");
2205 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2208 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2209 if (stat(fname, &st) != 0) {
2210 printf("bad memcard file: %s\n", ent->d_name);
2214 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2215 memcards[mc_i++] = strdup(ent->d_name);
2219 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2223 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2228 void menu_init(void)
2230 char buff[MAXPATHLEN];
2232 strcpy(last_selected_fname, "/media");
2234 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2236 scan_bios_plugins();
2239 menu_set_defconfig();
2240 menu_load_config(0);
2241 menu_do_last_cd_img(1);
2246 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2247 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2248 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2249 fprintf(stderr, "OOM\n");
2253 emu_make_path(buff, "skin/background.png", sizeof(buff));
2254 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2256 #ifndef __ARM_ARCH_7A__ /* XXX */
2257 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2258 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2259 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2260 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2262 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2263 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2264 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2268 void menu_notify_mode_change(int w, int h, int bpp)
2277 // XXX: should really menu code cotrol the layer size?
2280 g_layer_w = w; g_layer_h = h;
2284 if (h > g_menuscreen_h || (240 < h && h <= 360))
2285 goto fractional_4_3;
2287 // 4:3 that prefers integer scaling
2288 imult = g_menuscreen_h / h;
2289 g_layer_w = w * imult;
2290 g_layer_h = h * imult;
2291 mult = (float)g_layer_w / (float)g_layer_h;
2292 if (mult < 1.25f || mult > 1.666f)
2293 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2294 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2299 mult = 240.0f / (float)h * 4.0f / 3.0f;
2302 g_layer_w = mult * (float)g_menuscreen_h;
2303 g_layer_h = g_menuscreen_h;
2304 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2307 case SCALE_FULLSCREEN:
2308 g_layer_w = g_menuscreen_w;
2309 g_layer_h = g_menuscreen_h;
2316 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2317 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2318 if (g_layer_x < 0) g_layer_x = 0;
2319 if (g_layer_y < 0) g_layer_y = 0;
2320 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2321 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2324 static void menu_leave_emu(void)
2326 if (GPU_close != NULL) {
2327 int ret = GPU_close();
2329 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2332 plat_video_menu_enter(ready_to_go);
2334 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2335 if (pl_vout_buf != NULL && ready_to_go) {
2336 int x = max(0, g_menuscreen_w - last_psx_w);
2337 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2338 int w = min(g_menuscreen_w, last_psx_w);
2339 int h = min(g_menuscreen_h, last_psx_h);
2340 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2341 char *s = pl_vout_buf;
2343 if (last_psx_bpp == 16) {
2344 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 2)
2345 menu_darken_bg(d, s, w, 0);
2348 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 3) {
2349 rgb888_to_rgb565(d, s, w * 3);
2350 menu_darken_bg(d, d, w, 0);
2356 cpu_clock = plat_cpu_clock_get();
2359 void menu_prepare_emu(void)
2361 R3000Acpu *prev_cpu = psxCpu;
2363 plat_video_menu_leave();
2365 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2367 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2368 if (psxCpu != prev_cpu)
2369 // note that this does not really reset, just clears drc caches
2372 // core doesn't care about Config.Cdda changes,
2373 // so handle them manually here
2379 plat_cpu_clock_apply(cpu_clock);
2381 // push config to GPU plugin
2382 plugin_call_rearmed_cbs();
2384 if (GPU_open != NULL) {
2385 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2387 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2393 void me_update_msg(const char *msg)
2395 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2396 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2398 menu_error_time = plat_get_ticks_ms();
2399 lprintf("msg: %s\n", menu_error_msg);
2402 void menu_finish(void)
2404 menu_do_last_cd_img(0);
2405 plat_cpu_clock_apply(cpu_clock_st);