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,
82 static int last_vout_w, last_vout_h, last_vout_bpp;
83 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
84 static char rom_fname_reload[MAXPATHLEN];
85 static char last_selected_fname[MAXPATHLEN];
86 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
88 static int memcard1_sel, memcard2_sel;
90 int soft_scaling, analog_deadzone; // for Caanoo
91 int filter, soft_filter;
93 #ifdef __ARM_ARCH_7A__
94 #define DEFAULT_PSX_CLOCK 57
95 #define DEFAULT_PSX_CLOCK_S "57"
97 #define DEFAULT_PSX_CLOCK 50
98 #define DEFAULT_PSX_CLOCK_S "50"
102 extern int iUseReverb;
103 extern int iUseInterpolation;
107 static const char *bioses[24];
108 static const char *gpu_plugins[16];
109 static const char *spu_plugins[16];
110 static const char *memcards[32];
111 static int bios_sel, gpu_plugsel, spu_plugsel;
114 static int min(int x, int y) { return x < y ? x : y; }
115 static int max(int x, int y) { return x > y ? x : y; }
117 void emu_make_path(char *buff, const char *end, int size)
121 end_len = strlen(end);
122 pos = plat_get_root_dir(buff, size);
123 strncpy(buff + pos, end, size - pos);
125 if (pos + end_len > size - 1)
126 printf("Warning: path truncated: %s\n", buff);
129 static int emu_check_save_file(int slot, int *time)
131 char fname[MAXPATHLEN];
135 ret = emu_check_state(slot);
136 if (ret != 0 || time == NULL)
137 return ret == 0 ? 1 : 0;
139 ret = get_state_filename(fname, sizeof(fname), slot);
143 ret = stat(fname, &status);
147 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
148 return 1; // probably bad rtc like on some Caanoos
150 *time = status.st_mtime;
155 static int emu_save_load_game(int load, int unused)
160 ret = emu_load_state(state_slot);
162 // reflect hle/bios mode from savestate
165 else if (bios_sel == 0 && bioses[1] != NULL)
166 // XXX: maybe find the right bios instead
170 ret = emu_save_state(state_slot);
175 // propagate menu settings to the emu vars
176 static void menu_sync_config(void)
178 static int allow_abs_only_old;
183 Config.PsxType = region - 1;
185 cycle_multiplier = 10000 / psx_clock;
187 switch (in_type_sel1) {
188 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
189 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
190 default: in_type1 = PSE_PAD_TYPE_STANDARD;
192 switch (in_type_sel2) {
193 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
194 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
195 default: in_type2 = PSE_PAD_TYPE_STANDARD;
197 if (in_evdev_allow_abs_only != allow_abs_only_old) {
199 allow_abs_only_old = in_evdev_allow_abs_only;
202 iVolume = 768 + 128 * volume_boost;
203 pl_rearmed_cbs.frameskip = frameskip - 1;
204 pl_timing_prepare(Config.PsxType);
207 static void menu_set_defconfig(void)
209 emu_set_default_config();
212 g_scaler = SCALE_4_3;
215 analog_deadzone = 50;
218 psx_clock = DEFAULT_PSX_CLOCK;
221 in_type_sel1 = in_type_sel2 = 0;
222 in_evdev_allow_abs_only = 0;
227 #define CE_CONFIG_STR(val) \
228 { #val, 0, Config.val }
230 #define CE_CONFIG_VAL(val) \
231 { #val, sizeof(Config.val), &Config.val }
233 #define CE_STR(val) \
236 #define CE_INTVAL(val) \
237 { #val, sizeof(val), &val }
239 #define CE_INTVAL_P(val) \
240 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
242 // 'versioned' var, used when defaults change
243 #define CE_CONFIG_STR_V(val, ver) \
244 { #val #ver, 0, Config.val }
246 #define CE_INTVAL_V(val, ver) \
247 { #val #ver, sizeof(val), &val }
249 #define CE_INTVAL_PV(val, ver) \
250 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
252 static const struct {
258 CE_CONFIG_STR_V(Gpu, 3),
260 // CE_CONFIG_STR(Cdr),
265 CE_CONFIG_VAL(Debug),
266 CE_CONFIG_VAL(PsxOut),
267 CE_CONFIG_VAL(SpuIrq),
268 CE_CONFIG_VAL(RCntFix),
269 CE_CONFIG_VAL(VSyncWA),
271 CE_CONFIG_VAL(CdrReschedule),
273 CE_INTVAL_V(g_scaler, 2),
274 CE_INTVAL(g_layer_x),
275 CE_INTVAL(g_layer_y),
276 CE_INTVAL(g_layer_w),
277 CE_INTVAL(g_layer_h),
279 CE_INTVAL(soft_filter),
280 CE_INTVAL(state_slot),
281 CE_INTVAL(cpu_clock),
283 CE_INTVAL(in_type_sel1),
284 CE_INTVAL(in_type_sel2),
285 CE_INTVAL(analog_deadzone),
286 CE_INTVAL_V(frameskip, 3),
287 CE_INTVAL_P(gpu_peops.iUseDither),
288 CE_INTVAL_P(gpu_peops.dwActFixes),
289 CE_INTVAL_P(gpu_unai.lineskip),
290 CE_INTVAL_P(gpu_unai.abe_hack),
291 CE_INTVAL_P(gpu_unai.no_light),
292 CE_INTVAL_P(gpu_unai.no_blend),
293 CE_INTVAL_P(gpu_neon.allow_interlace),
294 CE_INTVAL_P(gpu_neon.enhancement_enable),
295 CE_INTVAL_P(gpu_neon.enhancement_no_main),
296 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
297 CE_INTVAL_P(gpu_peopsgl.iFilterType),
298 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
299 CE_INTVAL_P(gpu_peopsgl.iUseMask),
300 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
301 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
302 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
303 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
304 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
305 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
306 CE_INTVAL_V(iUseReverb, 3),
307 CE_INTVAL_V(iXAPitch, 3),
308 CE_INTVAL_V(iUseInterpolation, 3),
309 CE_INTVAL(warned_about_bios),
310 CE_INTVAL(in_evdev_allow_abs_only),
311 CE_INTVAL(volume_boost),
312 CE_INTVAL(psx_clock),
313 CE_INTVAL(new_dynarec_hacks),
314 CE_INTVAL(in_enable_vibration),
317 static char *get_cd_label(void)
319 static char trimlabel[33];
322 strncpy(trimlabel, CdromLabel, 32);
324 for (j = 31; j >= 0; j--)
325 if (trimlabel[j] == ' ')
331 static void make_cfg_fname(char *buf, size_t size, int is_game)
334 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
336 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
339 static void keys_write_all(FILE *f);
340 static char *mystrip(char *str);
342 static int menu_write_config(int is_game)
344 char cfgfile[MAXPATHLEN];
348 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
349 f = fopen(cfgfile, "w");
351 printf("menu_write_config: failed to open: %s\n", cfgfile);
355 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
356 fprintf(f, "%s = ", config_data[i].name);
357 switch (config_data[i].len) {
359 fprintf(f, "%s\n", (char *)config_data[i].val);
362 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
365 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
368 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
371 printf("menu_write_config: unhandled len %d for %s\n",
372 (int)config_data[i].len, config_data[i].name);
383 static int menu_do_last_cd_img(int is_get)
389 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
390 f = fopen(path, is_get ? "r" : "w");
395 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
396 last_selected_fname[ret] = 0;
397 mystrip(last_selected_fname);
400 fprintf(f, "%s\n", last_selected_fname);
406 static void parse_str_val(char *cval, const char *src)
409 strncpy(cval, src, MAXPATHLEN);
410 cval[MAXPATHLEN - 1] = 0;
411 tmp = strchr(cval, '\n');
413 tmp = strchr(cval, '\r');
418 static void keys_load_all(const char *cfg);
420 static int menu_load_config(int is_game)
422 char cfgfile[MAXPATHLEN];
428 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
429 f = fopen(cfgfile, "r");
431 printf("menu_load_config: failed to open: %s\n", cfgfile);
435 fseek(f, 0, SEEK_END);
438 printf("bad size %ld: %s\n", size, cfgfile);
442 cfg = malloc(size + 1);
446 fseek(f, 0, SEEK_SET);
447 if (fread(cfg, 1, size, f) != size) {
448 printf("failed to read: %s\n", cfgfile);
453 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
457 tmp = strstr(cfg, config_data[i].name);
460 tmp += strlen(config_data[i].name);
461 if (strncmp(tmp, " = ", 3) != 0)
465 if (config_data[i].len == 0) {
466 parse_str_val(config_data[i].val, tmp);
471 val = strtoul(tmp, &tmp2, 16);
472 if (tmp2 == NULL || tmp == tmp2)
473 continue; // parse failed
475 switch (config_data[i].len) {
477 *(u8 *)config_data[i].val = val;
480 *(u16 *)config_data[i].val = val;
483 *(u32 *)config_data[i].val = val;
486 printf("menu_load_config: unhandled len %d for %s\n",
487 (int)config_data[i].len, config_data[i].name);
493 char *tmp = strstr(cfg, "lastcdimg = ");
496 parse_str_val(last_selected_fname, tmp);
511 for (i = bios_sel = 0; bioses[i] != NULL; i++)
512 if (strcmp(Config.Bios, bioses[i]) == 0)
513 { bios_sel = i; break; }
515 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
516 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
517 { gpu_plugsel = i; break; }
519 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
520 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
521 { spu_plugsel = i; break; }
526 // rrrr rggg gggb bbbb
527 static unsigned short fname2color(const char *fname)
529 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
530 ".bz", ".znx", ".pbp", ".cbn" };
531 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
532 ".table", ".index", ".sbi" };
533 const char *ext = strrchr(fname, '.');
538 for (i = 0; i < array_size(cdimg_exts); i++)
539 if (strcasecmp(ext, cdimg_exts[i]) == 0)
541 for (i = 0; i < array_size(other_exts); i++)
542 if (strcasecmp(ext, other_exts[i]) == 0)
547 static void draw_savestate_bg(int slot);
549 static const char *filter_exts[] = {
550 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
553 #define MENU_ALIGN_LEFT
554 #ifdef __ARM_ARCH_7A__ // assume hires device
560 #define menu_init menu_init_common
561 #include "common/menu.c"
564 // a bit of black magic here
565 static void draw_savestate_bg(int slot)
567 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
569 char fname[MAXPATHLEN];
576 ret = get_state_filename(fname, sizeof(fname), slot);
580 f = gzopen(fname, "rb");
584 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
585 fprintf(stderr, "gzseek failed\n");
590 gpu = malloc(sizeof(*gpu));
596 ret = gzread(f, gpu, sizeof(*gpu));
598 if (ret != sizeof(*gpu)) {
599 fprintf(stderr, "gzread failed\n");
603 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
605 if (gpu->ulStatus & 0x800000)
606 goto out; // disabled
608 x = gpu->ulControl[5] & 0x3ff;
609 y = (gpu->ulControl[5] >> 10) & 0x1ff;
610 s = (u16 *)gpu->psxVRam + y * 1024 + x;
611 w = psx_widths[(gpu->ulStatus >> 16) & 7];
612 tmp = gpu->ulControl[7];
613 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
614 if (gpu->ulStatus & 0x80000) // doubleheight
617 x = max(0, g_menuscreen_w - w) & ~3;
618 y = max(0, g_menuscreen_h / 2 - h / 2);
619 w = min(g_menuscreen_w, w);
620 h = min(g_menuscreen_h, h);
621 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
623 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
624 if (gpu->ulStatus & 0x200000)
625 bgr888_to_rgb565(d, s, w * 3);
627 bgr555_to_rgb565(d, s, w * 2);
629 // darken this so that menu text is visible
630 if (g_menuscreen_w - w < 320)
631 menu_darken_bg(d, d, w * 2, 0);
638 // -------------- key config --------------
640 me_bind_action me_ctrl_actions[] =
642 { "UP ", 1 << DKEY_UP},
643 { "DOWN ", 1 << DKEY_DOWN },
644 { "LEFT ", 1 << DKEY_LEFT },
645 { "RIGHT ", 1 << DKEY_RIGHT },
646 { "TRIANGLE", 1 << DKEY_TRIANGLE },
647 { "CIRCLE ", 1 << DKEY_CIRCLE },
648 { "CROSS ", 1 << DKEY_CROSS },
649 { "SQUARE ", 1 << DKEY_SQUARE },
650 { "L1 ", 1 << DKEY_L1 },
651 { "R1 ", 1 << DKEY_R1 },
652 { "L2 ", 1 << DKEY_L2 },
653 { "R2 ", 1 << DKEY_R2 },
654 { "L3 ", 1 << DKEY_L3 },
655 { "R3 ", 1 << DKEY_R3 },
656 { "START ", 1 << DKEY_START },
657 { "SELECT ", 1 << DKEY_SELECT },
661 me_bind_action emuctrl_actions[] =
663 { "Save State ", 1 << SACTION_SAVE_STATE },
664 { "Load State ", 1 << SACTION_LOAD_STATE },
665 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
666 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
667 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
668 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
669 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
670 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
671 #ifdef __ARM_ARCH_7A__ /* XXX */
672 { "Minimize ", 1 << SACTION_MINIMIZE },
674 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
675 { "Gun A button ", 1 << SACTION_GUN_A },
676 { "Gun B button ", 1 << SACTION_GUN_B },
677 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
678 #ifndef __ARM_ARCH_7A__ /* XXX */
679 { "Volume Up ", 1 << SACTION_VOLUME_UP },
680 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
685 static char *mystrip(char *str)
690 for (i = 0; i < len; i++)
691 if (str[i] != ' ') break;
692 if (i > 0) memmove(str, str + i, len - i + 1);
695 for (i = len - 1; i >= 0; i--)
696 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
702 static void get_line(char *d, size_t size, const char *s)
707 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
718 static void keys_write_all(FILE *f)
722 for (d = 0; d < IN_MAX_DEVS; d++)
724 const int *binds = in_get_dev_binds(d);
725 const char *name = in_get_dev_name(d, 0, 0);
728 if (binds == NULL || name == NULL)
731 fprintf(f, "binddev = %s\n", name);
732 in_get_config(d, IN_CFG_BIND_COUNT, &count);
734 for (k = 0; k < count; k++)
739 act[0] = act[31] = 0;
740 name = in_get_key_name(d, k);
742 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
743 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
744 mask = me_ctrl_actions[i].mask;
746 strncpy(act, me_ctrl_actions[i].name, 31);
747 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
750 mask = me_ctrl_actions[i].mask << 16;
752 strncpy(act, me_ctrl_actions[i].name, 31);
753 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
758 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
759 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
760 mask = emuctrl_actions[i].mask;
762 strncpy(act, emuctrl_actions[i].name, 31);
763 fprintf(f, "bind %s = %s\n", name, mystrip(act));
769 for (k = 0; k < array_size(in_adev); k++)
772 fprintf(f, "bind_analog = %d\n", k);
777 static int parse_bind_val(const char *val, int *type)
781 *type = IN_BINDTYPE_NONE;
785 if (strncasecmp(val, "player", 6) == 0)
787 int player, shift = 0;
788 player = atoi(val + 6) - 1;
790 if ((unsigned int)player > 1)
795 *type = IN_BINDTYPE_PLAYER12;
796 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
797 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
798 return me_ctrl_actions[i].mask << shift;
801 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
802 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
803 *type = IN_BINDTYPE_EMU;
804 return emuctrl_actions[i].mask;
811 static void keys_load_all(const char *cfg)
813 char dev[256], key[128], *act;
819 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
822 get_line(dev, sizeof(dev), p);
823 dev_id = in_config_parse_dev(dev);
825 printf("input: can't handle dev: %s\n", dev);
829 in_unbind_all(dev_id, -1, -1);
830 while ((p = strstr(p, "bind"))) {
831 if (strncmp(p, "binddev = ", 10) == 0)
834 if (strncmp(p, "bind_analog", 11) == 0) {
835 ret = sscanf(p, "bind_analog = %d", &bind);
838 printf("input: parse error: %16s..\n", p);
841 if ((unsigned int)bind >= array_size(in_adev)) {
842 printf("input: analog id %d out of range\n", bind);
845 in_adev[bind] = dev_id;
851 printf("input: parse error: %16s..\n", p);
855 get_line(key, sizeof(key), p);
856 act = strchr(key, '=');
858 printf("parse failed: %16s..\n", p);
866 bind = parse_bind_val(act, &bindtype);
867 if (bind != -1 && bind != 0) {
868 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
869 in_config_bind_key(dev_id, key, bind, bindtype);
872 lprintf("config: unhandled action \"%s\"\n", act);
878 static int key_config_loop_wrap(int id, int keys)
881 case MA_CTRL_PLAYER1:
882 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
884 case MA_CTRL_PLAYER2:
885 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
888 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
896 static const char *adevnames[IN_MAX_DEVS + 2];
897 static int stick_sel[2];
899 static menu_entry e_menu_keyconfig_analog[] =
901 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
902 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
903 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
904 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
905 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
906 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
910 static int key_config_analog(int id, int keys)
912 int i, d, count, sel = 0;
913 int sel2dev_map[IN_MAX_DEVS];
915 memset(adevnames, 0, sizeof(adevnames));
916 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
917 memset(stick_sel, 0, sizeof(stick_sel));
919 adevnames[0] = "None";
921 for (d = 0; d < IN_MAX_DEVS; d++)
923 const char *name = in_get_dev_name(d, 0, 1);
928 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
932 if (in_adev[0] == d) stick_sel[0] = i;
933 if (in_adev[1] == d) stick_sel[1] = i;
935 adevnames[i++] = name;
939 me_loop(e_menu_keyconfig_analog, &sel);
941 in_adev[0] = sel2dev_map[stick_sel[0]];
942 in_adev[1] = sel2dev_map[stick_sel[1]];
947 static const char *mgn_dev_name(int id, int *offs)
949 const char *name = NULL;
952 if (id == MA_CTRL_DEV_FIRST)
955 for (; it < IN_MAX_DEVS; it++) {
956 name = in_get_dev_name(it, 1, 1);
965 static const char *mgn_saveloadcfg(int id, int *offs)
970 static int mh_savecfg(int id, int keys)
972 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
973 me_update_msg("config saved");
975 me_update_msg("failed to write config");
980 static int mh_input_rescan(int id, int keys)
982 //menu_sync_config();
984 me_update_msg("rescan complete.");
989 static const char *men_in_type_sel[] = {
990 "Standard (SCPH-1080)",
991 "Analog (SCPH-1150)",
995 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
996 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
997 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
999 static menu_entry e_menu_keyconfig[] =
1001 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1002 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1003 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1004 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1006 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1007 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1008 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1009 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1010 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1011 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1012 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1013 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1014 mee_handler ("Rescan devices:", mh_input_rescan),
1016 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1017 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1026 static int menu_loop_keyconfig(int id, int keys)
1030 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1031 me_loop(e_menu_keyconfig, &sel);
1035 // ------------ gfx options menu ------------
1037 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1038 static const char *men_soft_filter[] = { "None",
1040 "scale2x", "eagle2x",
1043 static const char *men_dummy[] = { NULL };
1044 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1045 "using d-pad or move it using R+d-pad";
1046 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1048 static int menu_loop_cscaler(int id, int keys)
1052 g_scaler = SCALE_CUSTOM;
1054 plat_gvideo_open(Config.PsxType);
1059 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1060 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1061 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1064 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1065 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1066 if (inp & PBTN_UP) g_layer_y--;
1067 if (inp & PBTN_DOWN) g_layer_y++;
1068 if (inp & PBTN_LEFT) g_layer_x--;
1069 if (inp & PBTN_RIGHT) g_layer_x++;
1070 if (!(inp & PBTN_R)) {
1071 if (inp & PBTN_UP) g_layer_h += 2;
1072 if (inp & PBTN_DOWN) g_layer_h -= 2;
1073 if (inp & PBTN_LEFT) g_layer_w += 2;
1074 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1076 if (inp & (PBTN_MOK|PBTN_MBACK))
1079 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1080 if (g_layer_x < 0) g_layer_x = 0;
1081 if (g_layer_x > 640) g_layer_x = 640;
1082 if (g_layer_y < 0) g_layer_y = 0;
1083 if (g_layer_y > 420) g_layer_y = 420;
1084 if (g_layer_w < 160) g_layer_w = 160;
1085 if (g_layer_h < 60) g_layer_h = 60;
1086 if (g_layer_x + g_layer_w > 800)
1087 g_layer_w = 800 - g_layer_x;
1088 if (g_layer_y + g_layer_h > 480)
1089 g_layer_h = 480 - g_layer_y;
1091 plat_gvideo_open(Config.PsxType);
1095 plat_gvideo_close();
1100 static menu_entry e_menu_gfx_options[] =
1102 mee_enum ("Scaler", MA_OPT_SCALER, g_scaler, men_scaler),
1103 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1104 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1105 mee_enum_h ("Software Filter", MA_OPT_FILTERING2, soft_filter, men_soft_filter, h_soft_filter),
1106 // mee_onoff ("Vsync", 0, vsync, 1),
1107 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1111 static int menu_loop_gfx_options(int id, int keys)
1115 me_loop(e_menu_gfx_options, &sel);
1121 void menu_set_filter_list(void *filters)
1125 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1126 e_menu_gfx_options[i].data = filters;
1127 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1130 // ------------ bios/plugins ------------
1134 static const char h_gpu_neon[] =
1135 "Configure built-in NEON GPU plugin";
1136 static const char h_gpu_neon_enhanced[] =
1137 "Renders in double resolution at the cost of lower performance\n"
1138 "(not available for high resolution games)";
1139 static const char h_gpu_neon_enhanced_hack[] =
1140 "Speed hack for above option (glitches some games)";
1141 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1143 static menu_entry e_menu_plugin_gpu_neon[] =
1145 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1146 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1147 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1151 static int menu_loop_plugin_gpu_neon(int id, int keys)
1154 me_loop(e_menu_plugin_gpu_neon, &sel);
1160 static menu_entry e_menu_plugin_gpu_unai[] =
1162 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1163 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1164 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1165 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1169 static int menu_loop_plugin_gpu_unai(int id, int keys)
1172 me_loop(e_menu_plugin_gpu_unai, &sel);
1176 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1177 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1178 static const char h_gpu_1[] = "Capcom fighting games";
1179 static const char h_gpu_2[] = "Black screens in Lunar";
1180 static const char h_gpu_3[] = "Compatibility mode";
1181 static const char h_gpu_6[] = "Pandemonium 2";
1182 //static const char h_gpu_7[] = "Skip every second frame";
1183 static const char h_gpu_8[] = "Needed by Dark Forces";
1184 static const char h_gpu_9[] = "better g-colors, worse textures";
1185 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1187 static menu_entry e_menu_plugin_gpu_peops[] =
1189 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1190 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1191 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1192 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1193 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1194 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1195 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1196 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1197 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1198 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1202 static int menu_loop_plugin_gpu_peops(int id, int keys)
1205 me_loop(e_menu_plugin_gpu_peops, &sel);
1209 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1210 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1211 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1213 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1215 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1216 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1217 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1218 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1219 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1220 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1221 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1222 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1223 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1224 mee_label ("Fixes/hacks:"),
1225 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1226 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1227 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1228 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1229 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1230 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1231 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1232 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1233 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1234 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1235 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1239 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1242 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1246 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1247 static const char h_spu_volboost[] = "Large values cause distortion";
1249 static menu_entry e_menu_plugin_spu[] =
1251 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1252 mee_onoff ("Reverb", 0, iUseReverb, 2),
1253 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1254 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1258 static int menu_loop_plugin_spu(int id, int keys)
1261 me_loop(e_menu_plugin_spu, &sel);
1265 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1266 "savestates and can't be changed there. Must save\n"
1267 "config and reload the game for change to take effect";
1268 static const char h_plugin_gpu[] =
1270 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1272 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1273 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1274 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1275 "must save config and reload the game if changed";
1276 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1277 "must save config and reload the game if changed";
1278 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1279 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1280 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1281 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1283 static menu_entry e_menu_plugin_options[] =
1285 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1286 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1287 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1289 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1291 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1292 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1293 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1294 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1298 static menu_entry e_menu_main2[];
1300 static int menu_loop_plugin_options(int id, int keys)
1303 me_loop(e_menu_plugin_options, &sel);
1305 // sync BIOS/plugins
1306 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1307 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1308 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1309 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1314 // ------------ adv options menu ------------
1316 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1317 "(lower value - less work for the emu, may be faster)";
1318 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1319 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1320 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1322 static menu_entry e_menu_speed_hacks[] =
1324 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1325 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1326 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1327 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1331 static int menu_loop_speed_hacks(int id, int keys)
1334 me_loop(e_menu_speed_hacks, &sel);
1338 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1339 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1340 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1341 "(green: normal, red: fmod, blue: noise)";
1342 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1343 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1344 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1345 "(proper .cue/.bin dump is needed otherwise)";
1346 static const char h_cfg_sio[] = "You should not need this, breaks games";
1347 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1348 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1349 "(timing hack, breaks other games)";
1350 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1351 "(timing hack, breaks other games)";
1352 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1353 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1354 "Might be useful to overcome some dynarec bugs";
1355 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1356 "must reload game for any change to take effect";
1358 static menu_entry e_menu_adv_options[] =
1360 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1361 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1362 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1363 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1364 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1365 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1366 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1367 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1368 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1369 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1370 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1371 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1375 static int menu_loop_adv_options(int id, int keys)
1378 me_loop(e_menu_adv_options, &sel);
1382 // ------------ options menu ------------
1384 static int mh_restore_defaults(int id, int keys)
1386 menu_set_defconfig();
1387 me_update_msg("defaults restored");
1391 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1392 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1394 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1395 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1396 "loading state or both";
1398 static const char h_restore_def[] = "Switches back to default / recommended\n"
1400 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1402 static menu_entry e_menu_options[] =
1404 // mee_range ("Save slot", 0, state_slot, 0, 9),
1405 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1406 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1407 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1408 mee_enum ("Region", 0, region, men_region),
1409 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1410 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1411 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1412 mee_handler ("[Advanced]", menu_loop_adv_options),
1413 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1414 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1415 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1419 static int menu_loop_options(int id, int keys)
1424 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1425 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1426 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1428 me_loop(e_menu_options, &sel);
1433 // ------------ debug menu ------------
1435 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1437 int w = min(g_menuscreen_w, 1024);
1438 int h = min(g_menuscreen_h, 512);
1439 u16 *d = g_menuscreen_ptr;
1440 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1444 gpuf->ulFreezeVersion = 1;
1445 if (GPU_freeze != NULL)
1446 GPU_freeze(1, gpuf);
1448 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1449 bgr555_to_rgb565(d, s, w * 2);
1451 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1452 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1453 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1454 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1455 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1458 static void debug_menu_loop(void)
1460 int inp, df_x = 0, df_y = 0;
1463 gpuf = malloc(sizeof(*gpuf));
1470 draw_frame_debug(gpuf, df_x, df_y);
1473 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1474 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1475 if (inp & PBTN_MBACK) break;
1476 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1477 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1478 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1479 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1485 // --------- memcard manager ---------
1487 static void draw_mc_icon(int dx, int dy, const u16 *s)
1492 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1494 for (y = 0; y < 16; y++, s += 16) {
1495 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1496 for (x = 0; x < 16; x++) {
1498 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1499 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1505 static void draw_mc_bg(void)
1507 McdBlock *blocks1, *blocks2;
1511 blocks1 = malloc(15 * sizeof(blocks1[0]));
1512 blocks2 = malloc(15 * sizeof(blocks1[0]));
1513 if (blocks1 == NULL || blocks2 == NULL)
1516 for (i = 0; i < 15; i++) {
1517 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1518 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1523 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1525 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1529 maxicons = g_menuscreen_h / 32;
1532 row2 = g_menuscreen_w / 2;
1533 for (i = 0; i < maxicons; i++) {
1534 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1535 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1537 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1538 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1541 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1549 static void handle_memcard_sel(void)
1552 if (memcard1_sel != 0)
1553 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1555 if (memcard2_sel != 0)
1556 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1557 LoadMcds(Config.Mcd1, Config.Mcd2);
1561 static menu_entry e_memcard_options[] =
1563 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1564 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1568 static int menu_loop_memcards(int id, int keys)
1574 memcard1_sel = memcard2_sel = 0;
1575 p = strrchr(Config.Mcd1, '/');
1577 for (i = 0; memcards[i] != NULL; i++)
1578 if (strcmp(p + 1, memcards[i]) == 0)
1579 { memcard1_sel = i; break; }
1580 p = strrchr(Config.Mcd2, '/');
1582 for (i = 0; memcards[i] != NULL; i++)
1583 if (strcmp(p + 1, memcards[i]) == 0)
1584 { memcard2_sel = i; break; }
1586 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1588 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1593 // ------------ cheats menu ------------
1595 static void draw_cheatlist(int sel)
1597 int max_cnt, start, i, pos, active;
1599 max_cnt = g_menuscreen_h / me_sfont_h;
1600 start = max_cnt / 2 - sel;
1604 for (i = 0; i < NumCheats; i++) {
1606 if (pos < 0) continue;
1607 if (pos >= max_cnt) break;
1608 active = Cheats[i].Enabled;
1609 smalltext_out16(14, pos * me_sfont_h,
1610 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1611 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1612 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1616 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1618 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1622 static void menu_loop_cheats(void)
1624 static int menu_sel = 0;
1629 draw_cheatlist(menu_sel);
1630 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1631 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1632 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1633 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1634 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1635 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1636 if (inp & PBTN_MOK) { // action
1637 if (menu_sel < NumCheats)
1638 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1641 if (inp & PBTN_MBACK)
1646 // --------- main menu help ----------
1648 static void menu_bios_warn(void)
1651 static const char msg[] =
1652 "You don't seem to have copied any BIOS\n"
1654 #ifdef __ARM_ARCH_7A__ // XXX
1655 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1657 "pcsx_rearmed/bios/\n\n"
1659 "While many games work fine with fake\n"
1660 "(HLE) BIOS, others (like MGS and FF8)\n"
1661 "require BIOS to work.\n"
1662 "After copying the file, you'll also need\n"
1663 "to select it in the emu's menu:\n"
1664 "options->[BIOS/Plugins]\n\n"
1665 "The file is usually named SCPH1001.BIN,\n"
1666 "but other not compressed files can be\n"
1668 "Press %s or %s to continue";
1669 char tmp_msg[sizeof(msg) + 64];
1671 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1672 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1675 draw_menu_message(tmp_msg, NULL);
1677 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1678 if (inp & (PBTN_MBACK|PBTN_MOK))
1683 // ------------ main menu ------------
1685 static menu_entry e_menu_main[];
1688 static void draw_frame_main(void)
1697 if (CdromId[0] != 0) {
1698 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1699 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1700 Config.HLE ? "HLE" : "BIOS");
1701 smalltext_out16(4, 1, buff, 0x105f);
1705 capacity = plat_get_bat_capacity();
1707 tmp = localtime(<ime);
1708 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1709 if (capacity >= 0) {
1710 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1715 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1719 static void draw_frame_credits(void)
1721 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1724 static const char credits_text[] =
1726 "(C) 1999-2003 PCSX Team\n"
1727 "(C) 2005-2009 PCSX-df Team\n"
1728 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1729 "ARM recompiler (C) 2009-2011 Ari64\n"
1731 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1733 "PEOpS GPU and SPU by Pete Bernert\n"
1734 " and the P.E.Op.S. team\n"
1735 "PCSX4ALL plugin by PCSX4ALL team\n"
1736 " Chui, Franxis, Unai\n\n"
1737 "integration, optimization and\n"
1738 " frontend (C) 2010-2012 notaz\n";
1740 static int reset_game(void)
1743 if (bios_sel == 0 && !Config.HLE)
1749 if (CheckCdrom() != -1) {
1755 static int reload_plugins(const char *cdimg)
1761 set_cd_image(cdimg);
1763 pcnt_hook_plugins();
1765 if (OpenPlugins() == -1) {
1766 me_update_msg("failed to open plugins");
1769 plugin_call_rearmed_cbs();
1771 cdrIsoMultidiskCount = 1;
1773 CdromLabel[0] = '\0';
1778 static int run_bios(void)
1784 if (reload_plugins(NULL) != 0)
1792 static int run_exe(void)
1796 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1801 if (reload_plugins(NULL) != 0)
1805 if (Load(fname) != 0) {
1806 me_update_msg("exe load failed, bad file?");
1815 static int run_cd_image(const char *fname)
1818 reload_plugins(fname);
1820 // always autodetect, menu_sync_config will override as needed
1823 if (CheckCdrom() == -1) {
1824 // Only check the CD if we are starting the console with a CD
1826 me_update_msg("unsupported/invalid CD image");
1832 // Read main executable directly from CDRom and start it
1833 if (LoadCdrom() == -1) {
1835 me_update_msg("failed to load CD image");
1845 static int romsel_run(void)
1847 int prev_gpu, prev_spu;
1850 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1854 printf("selected file: %s\n", fname);
1856 new_dynarec_clear_full();
1858 if (run_cd_image(fname) != 0)
1861 prev_gpu = gpu_plugsel;
1862 prev_spu = spu_plugsel;
1863 if (menu_load_config(1) != 0)
1864 menu_load_config(0);
1866 // check for plugin changes, have to repeat
1867 // loading if game config changed plugins to reload them
1868 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1869 printf("plugin change detected, reloading plugins..\n");
1870 if (run_cd_image(fname) != 0)
1874 strcpy(last_selected_fname, rom_fname_reload);
1875 menu_do_last_cd_img(0);
1879 static int swap_cd_image(void)
1883 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1887 printf("selected file: %s\n", fname);
1890 CdromLabel[0] = '\0';
1892 set_cd_image(fname);
1893 if (ReloadCdromPlugin() < 0) {
1894 me_update_msg("failed to load cdr plugin");
1897 if (CDR_open() < 0) {
1898 me_update_msg("failed to open cdr plugin");
1902 SetCdOpenCaseTime(time(NULL) + 2);
1905 strcpy(last_selected_fname, rom_fname_reload);
1909 static int swap_cd_multidisk(void)
1911 cdrIsoMultidiskSelect++;
1913 CdromLabel[0] = '\0';
1916 if (CDR_open() < 0) {
1917 me_update_msg("failed to open cdr plugin");
1921 SetCdOpenCaseTime(time(NULL) + 2);
1927 static void load_pcsx_cht(void)
1933 fname = menu_loop_romsel(path, sizeof(path));
1937 printf("selected cheat file: %s\n", fname);
1940 if (NumCheats == 0 && NumCodes == 0)
1941 me_update_msg("failed to load cheats");
1943 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1944 me_update_msg(path);
1946 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1949 static int main_menu_handler(int id, int keys)
1953 case MA_MAIN_RESUME_GAME:
1957 case MA_MAIN_SAVE_STATE:
1959 return menu_loop_savestate(0);
1961 case MA_MAIN_LOAD_STATE:
1963 return menu_loop_savestate(1);
1965 case MA_MAIN_RESET_GAME:
1966 if (ready_to_go && reset_game() == 0)
1969 case MA_MAIN_LOAD_ROM:
1970 if (romsel_run() == 0)
1973 case MA_MAIN_SWAP_CD:
1974 if (swap_cd_image() == 0)
1977 case MA_MAIN_SWAP_CD_MULTI:
1978 if (swap_cd_multidisk() == 0)
1981 case MA_MAIN_RUN_BIOS:
1982 if (run_bios() == 0)
1985 case MA_MAIN_RUN_EXE:
1989 case MA_MAIN_CHEATS:
1992 case MA_MAIN_LOAD_CHEATS:
1995 case MA_MAIN_CREDITS:
1996 draw_menu_message(credits_text, draw_frame_credits);
1997 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2003 lprintf("%s: something unknown selected\n", __FUNCTION__);
2010 static menu_entry e_menu_main2[] =
2012 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2013 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2014 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2015 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2016 mee_handler ("Memcard manager", menu_loop_memcards),
2017 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2021 static int main_menu2_handler(int id, int keys)
2025 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2026 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2027 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2028 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2030 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2033 static const char h_extra[] = "Change CD, manage memcards..\n";
2035 static menu_entry e_menu_main[] =
2039 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2040 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2041 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2042 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2043 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2044 mee_handler ("Options", menu_loop_options),
2045 mee_handler ("Controls", menu_loop_keyconfig),
2046 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2047 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2048 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2049 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2053 // ----------------------------
2055 static void menu_leave_emu(void);
2057 void menu_loop(void)
2063 if (bioses[1] == NULL && !warned_about_bios) {
2065 warned_about_bios = 1;
2068 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2069 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2070 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2071 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2072 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2074 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2077 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2078 } while (!ready_to_go);
2080 /* wait until menu, ok, back is released */
2081 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2084 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2089 static int qsort_strcmp(const void *p1, const void *p2)
2091 char * const *s1 = (char * const *)p1;
2092 char * const *s2 = (char * const *)p2;
2093 return strcasecmp(*s1, *s2);
2096 static void scan_bios_plugins(void)
2098 char fname[MAXPATHLEN];
2100 int bios_i, gpu_i, spu_i, mc_i;
2105 gpu_plugins[0] = "builtin_gpu";
2106 spu_plugins[0] = "builtin_spu";
2107 memcards[0] = "(none)";
2108 bios_i = gpu_i = spu_i = mc_i = 1;
2110 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2111 dir = opendir(fname);
2113 perror("scan_bios_plugins bios opendir");
2128 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2131 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2132 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2133 printf("bad BIOS file: %s\n", ent->d_name);
2137 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2138 bioses[bios_i++] = strdup(ent->d_name);
2142 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2148 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2149 dir = opendir(fname);
2151 perror("scan_bios_plugins plugins opendir");
2165 p = strstr(ent->d_name, ".so");
2169 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2170 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2172 fprintf(stderr, "%s\n", dlerror());
2176 // now what do we have here?
2177 tmp = dlsym(h, "GPUinit");
2180 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2181 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2185 tmp = dlsym(h, "SPUinit");
2188 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2189 spu_plugins[spu_i++] = strdup(ent->d_name);
2193 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2200 dir = opendir("." MEMCARD_DIR);
2202 perror("scan_bios_plugins memcards opendir");
2217 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2220 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2221 if (stat(fname, &st) != 0) {
2222 printf("bad memcard file: %s\n", ent->d_name);
2226 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2227 memcards[mc_i++] = strdup(ent->d_name);
2231 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2235 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2240 void menu_init(void)
2242 char buff[MAXPATHLEN];
2244 strcpy(last_selected_fname, "/media");
2246 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2248 scan_bios_plugins();
2251 menu_set_defconfig();
2252 menu_load_config(0);
2253 menu_do_last_cd_img(1);
2258 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2259 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2260 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2261 fprintf(stderr, "OOM\n");
2265 emu_make_path(buff, "skin/background.png", sizeof(buff));
2266 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2268 #ifndef __ARM_ARCH_7A__ /* XXX */
2269 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2270 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2271 me_enable(e_menu_gfx_options, MA_OPT_FILTERING2, 0);
2272 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2273 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2275 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2276 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2277 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2281 void menu_notify_mode_change(int w, int h, int bpp)
2285 last_vout_bpp = bpp;
2288 static void menu_leave_emu(void)
2290 if (GPU_close != NULL) {
2291 int ret = GPU_close();
2293 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2296 plat_video_menu_enter(ready_to_go);
2298 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2299 if (pl_vout_buf != NULL && ready_to_go) {
2300 int x = max(0, g_menuscreen_w - last_vout_w);
2301 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2302 int w = min(g_menuscreen_w, last_vout_w);
2303 int h = min(g_menuscreen_h, last_vout_h);
2304 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2305 char *s = pl_vout_buf;
2307 if (last_vout_bpp == 16) {
2308 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2309 menu_darken_bg(d, s, w, 0);
2312 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2313 rgb888_to_rgb565(d, s, w * 3);
2314 menu_darken_bg(d, d, w, 0);
2320 cpu_clock = plat_cpu_clock_get();
2323 void menu_prepare_emu(void)
2325 R3000Acpu *prev_cpu = psxCpu;
2327 plat_video_menu_leave();
2329 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2330 if (psxCpu != prev_cpu)
2331 // note that this does not really reset, just clears drc caches
2334 // core doesn't care about Config.Cdda changes,
2335 // so handle them manually here
2341 plat_cpu_clock_apply(cpu_clock);
2343 // push config to GPU plugin
2344 plugin_call_rearmed_cbs();
2346 if (GPU_open != NULL) {
2347 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2349 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2355 void me_update_msg(const char *msg)
2357 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2358 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2360 menu_error_time = plat_get_ticks_ms();
2361 lprintf("msg: %s\n", menu_error_msg);
2364 void menu_finish(void)
2366 plat_cpu_clock_apply(cpu_clock_st);