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,
81 static int last_vout_w, last_vout_h, last_vout_bpp;
82 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
83 static char rom_fname_reload[MAXPATHLEN];
84 static char last_selected_fname[MAXPATHLEN];
85 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
87 static int memcard1_sel, memcard2_sel;
89 int soft_scaling, analog_deadzone; // for Caanoo
92 #ifdef __ARM_ARCH_7A__
93 #define DEFAULT_PSX_CLOCK 57
94 #define DEFAULT_PSX_CLOCK_S "57"
96 #define DEFAULT_PSX_CLOCK 50
97 #define DEFAULT_PSX_CLOCK_S "50"
101 extern int iUseReverb;
102 extern int iUseInterpolation;
106 static const char *bioses[24];
107 static const char *gpu_plugins[16];
108 static const char *spu_plugins[16];
109 static const char *memcards[32];
110 static int bios_sel, gpu_plugsel, spu_plugsel;
113 static int min(int x, int y) { return x < y ? x : y; }
114 static int max(int x, int y) { return x > y ? x : y; }
116 void emu_make_path(char *buff, const char *end, int size)
120 end_len = strlen(end);
121 pos = plat_get_root_dir(buff, size);
122 strncpy(buff + pos, end, size - pos);
124 if (pos + end_len > size - 1)
125 printf("Warning: path truncated: %s\n", buff);
128 static int emu_check_save_file(int slot, int *time)
130 char fname[MAXPATHLEN];
134 ret = emu_check_state(slot);
135 if (ret != 0 || time == NULL)
136 return ret == 0 ? 1 : 0;
138 ret = get_state_filename(fname, sizeof(fname), slot);
142 ret = stat(fname, &status);
146 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
147 return 1; // probably bad rtc like on some Caanoos
149 *time = status.st_mtime;
154 static int emu_save_load_game(int load, int unused)
159 ret = emu_load_state(state_slot);
161 // reflect hle/bios mode from savestate
164 else if (bios_sel == 0 && bioses[1] != NULL)
165 // XXX: maybe find the right bios instead
169 ret = emu_save_state(state_slot);
174 // propagate menu settings to the emu vars
175 static void menu_sync_config(void)
177 static int allow_abs_only_old;
182 Config.PsxType = region - 1;
184 cycle_multiplier = 10000 / psx_clock;
186 switch (in_type_sel1) {
187 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
188 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
189 default: in_type1 = PSE_PAD_TYPE_STANDARD;
191 switch (in_type_sel2) {
192 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
193 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
194 default: in_type2 = PSE_PAD_TYPE_STANDARD;
196 if (in_evdev_allow_abs_only != allow_abs_only_old) {
198 allow_abs_only_old = in_evdev_allow_abs_only;
201 iVolume = 768 + 128 * volume_boost;
202 pl_rearmed_cbs.frameskip = frameskip - 1;
203 pl_timing_prepare(Config.PsxType);
206 static void menu_set_defconfig(void)
208 emu_set_default_config();
211 g_scaler = SCALE_4_3;
214 analog_deadzone = 50;
216 psx_clock = DEFAULT_PSX_CLOCK;
219 in_type_sel1 = in_type_sel2 = 0;
220 in_evdev_allow_abs_only = 0;
225 #define CE_CONFIG_STR(val) \
226 { #val, 0, Config.val }
228 #define CE_CONFIG_VAL(val) \
229 { #val, sizeof(Config.val), &Config.val }
231 #define CE_STR(val) \
234 #define CE_INTVAL(val) \
235 { #val, sizeof(val), &val }
237 #define CE_INTVAL_P(val) \
238 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
240 // 'versioned' var, used when defaults change
241 #define CE_CONFIG_STR_V(val, ver) \
242 { #val #ver, 0, Config.val }
244 #define CE_INTVAL_V(val, ver) \
245 { #val #ver, sizeof(val), &val }
247 #define CE_INTVAL_PV(val, ver) \
248 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
250 static const struct {
256 CE_CONFIG_STR_V(Gpu, 3),
258 // CE_CONFIG_STR(Cdr),
263 CE_CONFIG_VAL(Debug),
264 CE_CONFIG_VAL(PsxOut),
265 CE_CONFIG_VAL(SpuIrq),
266 CE_CONFIG_VAL(RCntFix),
267 CE_CONFIG_VAL(VSyncWA),
269 CE_CONFIG_VAL(CdrReschedule),
271 CE_INTVAL_V(g_scaler, 2),
272 CE_INTVAL(g_layer_x),
273 CE_INTVAL(g_layer_y),
274 CE_INTVAL(g_layer_w),
275 CE_INTVAL(g_layer_h),
277 CE_INTVAL(state_slot),
278 CE_INTVAL(cpu_clock),
280 CE_INTVAL(in_type_sel1),
281 CE_INTVAL(in_type_sel2),
282 CE_INTVAL(analog_deadzone),
283 CE_INTVAL_V(frameskip, 3),
284 CE_INTVAL_P(gpu_peops.iUseDither),
285 CE_INTVAL_P(gpu_peops.dwActFixes),
286 CE_INTVAL_P(gpu_unai.lineskip),
287 CE_INTVAL_P(gpu_unai.abe_hack),
288 CE_INTVAL_P(gpu_unai.no_light),
289 CE_INTVAL_P(gpu_unai.no_blend),
290 CE_INTVAL_P(gpu_neon.allow_interlace),
291 CE_INTVAL_P(gpu_neon.enhancement_enable),
292 CE_INTVAL_P(gpu_neon.enhancement_no_main),
293 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
294 CE_INTVAL_P(gpu_peopsgl.iFilterType),
295 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
296 CE_INTVAL_P(gpu_peopsgl.iUseMask),
297 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
298 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
299 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
300 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
301 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
302 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
303 CE_INTVAL_V(iUseReverb, 3),
304 CE_INTVAL_V(iXAPitch, 3),
305 CE_INTVAL_V(iUseInterpolation, 3),
306 CE_INTVAL(warned_about_bios),
307 CE_INTVAL(in_evdev_allow_abs_only),
308 CE_INTVAL(volume_boost),
309 CE_INTVAL(psx_clock),
310 CE_INTVAL(new_dynarec_hacks),
311 CE_INTVAL(in_enable_vibration),
314 static char *get_cd_label(void)
316 static char trimlabel[33];
319 strncpy(trimlabel, CdromLabel, 32);
321 for (j = 31; j >= 0; j--)
322 if (trimlabel[j] == ' ')
328 static void make_cfg_fname(char *buf, size_t size, int is_game)
331 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
333 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
336 static void keys_write_all(FILE *f);
337 static char *mystrip(char *str);
339 static int menu_write_config(int is_game)
341 char cfgfile[MAXPATHLEN];
345 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
346 f = fopen(cfgfile, "w");
348 printf("menu_write_config: failed to open: %s\n", cfgfile);
352 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
353 fprintf(f, "%s = ", config_data[i].name);
354 switch (config_data[i].len) {
356 fprintf(f, "%s\n", (char *)config_data[i].val);
359 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
362 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
365 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
368 printf("menu_write_config: unhandled len %d for %s\n",
369 (int)config_data[i].len, config_data[i].name);
380 static int menu_do_last_cd_img(int is_get)
386 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
387 f = fopen(path, is_get ? "r" : "w");
392 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
393 last_selected_fname[ret] = 0;
394 mystrip(last_selected_fname);
397 fprintf(f, "%s\n", last_selected_fname);
403 static void parse_str_val(char *cval, const char *src)
406 strncpy(cval, src, MAXPATHLEN);
407 cval[MAXPATHLEN - 1] = 0;
408 tmp = strchr(cval, '\n');
410 tmp = strchr(cval, '\r');
415 static void keys_load_all(const char *cfg);
417 static int menu_load_config(int is_game)
419 char cfgfile[MAXPATHLEN];
425 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
426 f = fopen(cfgfile, "r");
428 printf("menu_load_config: failed to open: %s\n", cfgfile);
432 fseek(f, 0, SEEK_END);
435 printf("bad size %ld: %s\n", size, cfgfile);
439 cfg = malloc(size + 1);
443 fseek(f, 0, SEEK_SET);
444 if (fread(cfg, 1, size, f) != size) {
445 printf("failed to read: %s\n", cfgfile);
450 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
454 tmp = strstr(cfg, config_data[i].name);
457 tmp += strlen(config_data[i].name);
458 if (strncmp(tmp, " = ", 3) != 0)
462 if (config_data[i].len == 0) {
463 parse_str_val(config_data[i].val, tmp);
468 val = strtoul(tmp, &tmp2, 16);
469 if (tmp2 == NULL || tmp == tmp2)
470 continue; // parse failed
472 switch (config_data[i].len) {
474 *(u8 *)config_data[i].val = val;
477 *(u16 *)config_data[i].val = val;
480 *(u32 *)config_data[i].val = val;
483 printf("menu_load_config: unhandled len %d for %s\n",
484 (int)config_data[i].len, config_data[i].name);
490 char *tmp = strstr(cfg, "lastcdimg = ");
493 parse_str_val(last_selected_fname, tmp);
508 for (i = bios_sel = 0; bioses[i] != NULL; i++)
509 if (strcmp(Config.Bios, bioses[i]) == 0)
510 { bios_sel = i; break; }
512 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
513 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
514 { gpu_plugsel = i; break; }
516 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
517 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
518 { spu_plugsel = i; break; }
523 // rrrr rggg gggb bbbb
524 static unsigned short fname2color(const char *fname)
526 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
527 ".bz", ".znx", ".pbp", ".cbn" };
528 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
529 ".table", ".index", ".sbi" };
530 const char *ext = strrchr(fname, '.');
535 for (i = 0; i < array_size(cdimg_exts); i++)
536 if (strcasecmp(ext, cdimg_exts[i]) == 0)
538 for (i = 0; i < array_size(other_exts); i++)
539 if (strcasecmp(ext, other_exts[i]) == 0)
544 static void draw_savestate_bg(int slot);
546 static const char *filter_exts[] = {
547 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
550 #define MENU_ALIGN_LEFT
551 #ifdef __ARM_ARCH_7A__ // assume hires device
557 #define menu_init menu_init_common
558 #include "common/menu.c"
561 // a bit of black magic here
562 static void draw_savestate_bg(int slot)
564 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
566 char fname[MAXPATHLEN];
573 ret = get_state_filename(fname, sizeof(fname), slot);
577 f = gzopen(fname, "rb");
581 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
582 fprintf(stderr, "gzseek failed\n");
587 gpu = malloc(sizeof(*gpu));
593 ret = gzread(f, gpu, sizeof(*gpu));
595 if (ret != sizeof(*gpu)) {
596 fprintf(stderr, "gzread failed\n");
600 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
602 if (gpu->ulStatus & 0x800000)
603 goto out; // disabled
605 x = gpu->ulControl[5] & 0x3ff;
606 y = (gpu->ulControl[5] >> 10) & 0x1ff;
607 s = (u16 *)gpu->psxVRam + y * 1024 + x;
608 w = psx_widths[(gpu->ulStatus >> 16) & 7];
609 tmp = gpu->ulControl[7];
610 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
611 if (gpu->ulStatus & 0x80000) // doubleheight
614 x = max(0, g_menuscreen_w - w) & ~3;
615 y = max(0, g_menuscreen_h / 2 - h / 2);
616 w = min(g_menuscreen_w, w);
617 h = min(g_menuscreen_h, h);
618 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
620 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
621 if (gpu->ulStatus & 0x200000)
622 bgr888_to_rgb565(d, s, w * 3);
624 bgr555_to_rgb565(d, s, w * 2);
626 // darken this so that menu text is visible
627 if (g_menuscreen_w - w < 320)
628 menu_darken_bg(d, d, w * 2, 0);
635 // -------------- key config --------------
637 me_bind_action me_ctrl_actions[] =
639 { "UP ", 1 << DKEY_UP},
640 { "DOWN ", 1 << DKEY_DOWN },
641 { "LEFT ", 1 << DKEY_LEFT },
642 { "RIGHT ", 1 << DKEY_RIGHT },
643 { "TRIANGLE", 1 << DKEY_TRIANGLE },
644 { "CIRCLE ", 1 << DKEY_CIRCLE },
645 { "CROSS ", 1 << DKEY_CROSS },
646 { "SQUARE ", 1 << DKEY_SQUARE },
647 { "L1 ", 1 << DKEY_L1 },
648 { "R1 ", 1 << DKEY_R1 },
649 { "L2 ", 1 << DKEY_L2 },
650 { "R2 ", 1 << DKEY_R2 },
651 { "L3 ", 1 << DKEY_L3 },
652 { "R3 ", 1 << DKEY_R3 },
653 { "START ", 1 << DKEY_START },
654 { "SELECT ", 1 << DKEY_SELECT },
658 me_bind_action emuctrl_actions[] =
660 { "Save State ", 1 << SACTION_SAVE_STATE },
661 { "Load State ", 1 << SACTION_LOAD_STATE },
662 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
663 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
664 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
665 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
666 { "Toggle Renderer ", 1 << SACTION_TOGGLE_RENDERER },
667 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
668 #ifdef __ARM_ARCH_7A__ /* XXX */
669 { "Minimize ", 1 << SACTION_MINIMIZE },
671 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
672 { "Gun A button ", 1 << SACTION_GUN_A },
673 { "Gun B button ", 1 << SACTION_GUN_B },
674 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
675 #ifndef __ARM_ARCH_7A__ /* XXX */
676 { "Volume Up ", 1 << SACTION_VOLUME_UP },
677 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
682 static char *mystrip(char *str)
687 for (i = 0; i < len; i++)
688 if (str[i] != ' ') break;
689 if (i > 0) memmove(str, str + i, len - i + 1);
692 for (i = len - 1; i >= 0; i--)
693 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
699 static void get_line(char *d, size_t size, const char *s)
704 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
715 static void keys_write_all(FILE *f)
719 for (d = 0; d < IN_MAX_DEVS; d++)
721 const int *binds = in_get_dev_binds(d);
722 const char *name = in_get_dev_name(d, 0, 0);
725 if (binds == NULL || name == NULL)
728 fprintf(f, "binddev = %s\n", name);
729 in_get_config(d, IN_CFG_BIND_COUNT, &count);
731 for (k = 0; k < count; k++)
736 act[0] = act[31] = 0;
737 name = in_get_key_name(d, k);
739 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
740 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
741 mask = me_ctrl_actions[i].mask;
743 strncpy(act, me_ctrl_actions[i].name, 31);
744 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
747 mask = me_ctrl_actions[i].mask << 16;
749 strncpy(act, me_ctrl_actions[i].name, 31);
750 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
755 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
756 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
757 mask = emuctrl_actions[i].mask;
759 strncpy(act, emuctrl_actions[i].name, 31);
760 fprintf(f, "bind %s = %s\n", name, mystrip(act));
766 for (k = 0; k < array_size(in_adev); k++)
769 fprintf(f, "bind_analog = %d\n", k);
774 static int parse_bind_val(const char *val, int *type)
778 *type = IN_BINDTYPE_NONE;
782 if (strncasecmp(val, "player", 6) == 0)
784 int player, shift = 0;
785 player = atoi(val + 6) - 1;
787 if ((unsigned int)player > 1)
792 *type = IN_BINDTYPE_PLAYER12;
793 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
794 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
795 return me_ctrl_actions[i].mask << shift;
798 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
799 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
800 *type = IN_BINDTYPE_EMU;
801 return emuctrl_actions[i].mask;
808 static void keys_load_all(const char *cfg)
810 char dev[256], key[128], *act;
816 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
819 get_line(dev, sizeof(dev), p);
820 dev_id = in_config_parse_dev(dev);
822 printf("input: can't handle dev: %s\n", dev);
826 in_unbind_all(dev_id, -1, -1);
827 while ((p = strstr(p, "bind"))) {
828 if (strncmp(p, "binddev = ", 10) == 0)
831 if (strncmp(p, "bind_analog", 11) == 0) {
832 ret = sscanf(p, "bind_analog = %d", &bind);
835 printf("input: parse error: %16s..\n", p);
838 if ((unsigned int)bind >= array_size(in_adev)) {
839 printf("input: analog id %d out of range\n", bind);
842 in_adev[bind] = dev_id;
848 printf("input: parse error: %16s..\n", p);
852 get_line(key, sizeof(key), p);
853 act = strchr(key, '=');
855 printf("parse failed: %16s..\n", p);
863 bind = parse_bind_val(act, &bindtype);
864 if (bind != -1 && bind != 0) {
865 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
866 in_config_bind_key(dev_id, key, bind, bindtype);
869 lprintf("config: unhandled action \"%s\"\n", act);
875 static int key_config_loop_wrap(int id, int keys)
878 case MA_CTRL_PLAYER1:
879 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
881 case MA_CTRL_PLAYER2:
882 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
885 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
893 static const char *adevnames[IN_MAX_DEVS + 2];
894 static int stick_sel[2];
896 static menu_entry e_menu_keyconfig_analog[] =
898 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
899 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
900 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
901 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
902 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
903 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
907 static int key_config_analog(int id, int keys)
909 int i, d, count, sel = 0;
910 int sel2dev_map[IN_MAX_DEVS];
912 memset(adevnames, 0, sizeof(adevnames));
913 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
914 memset(stick_sel, 0, sizeof(stick_sel));
916 adevnames[0] = "None";
918 for (d = 0; d < IN_MAX_DEVS; d++)
920 const char *name = in_get_dev_name(d, 0, 1);
925 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
929 if (in_adev[0] == d) stick_sel[0] = i;
930 if (in_adev[1] == d) stick_sel[1] = i;
932 adevnames[i++] = name;
936 me_loop(e_menu_keyconfig_analog, &sel);
938 in_adev[0] = sel2dev_map[stick_sel[0]];
939 in_adev[1] = sel2dev_map[stick_sel[1]];
944 static const char *mgn_dev_name(int id, int *offs)
946 const char *name = NULL;
949 if (id == MA_CTRL_DEV_FIRST)
952 for (; it < IN_MAX_DEVS; it++) {
953 name = in_get_dev_name(it, 1, 1);
962 static const char *mgn_saveloadcfg(int id, int *offs)
967 static int mh_savecfg(int id, int keys)
969 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
970 me_update_msg("config saved");
972 me_update_msg("failed to write config");
977 static int mh_input_rescan(int id, int keys)
979 //menu_sync_config();
981 me_update_msg("rescan complete.");
986 static const char *men_in_type_sel[] = {
987 "Standard (SCPH-1080)",
988 "Analog (SCPH-1150)",
992 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
993 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
994 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
996 static menu_entry e_menu_keyconfig[] =
998 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
999 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1000 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1001 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1003 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1004 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1005 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1006 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1007 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1008 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1009 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1010 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1011 mee_handler ("Rescan devices:", mh_input_rescan),
1013 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1014 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1015 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1016 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1023 static int menu_loop_keyconfig(int id, int keys)
1027 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1028 me_loop(e_menu_keyconfig, &sel);
1032 // ------------ gfx options menu ------------
1034 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1035 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1036 "using d-pad or move it using R+d-pad";
1037 static const char *men_dummy[] = { NULL };
1039 static int menu_loop_cscaler(int id, int keys)
1043 g_scaler = SCALE_CUSTOM;
1045 plat_gvideo_open(Config.PsxType);
1050 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1051 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1052 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1055 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1056 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1057 if (inp & PBTN_UP) g_layer_y--;
1058 if (inp & PBTN_DOWN) g_layer_y++;
1059 if (inp & PBTN_LEFT) g_layer_x--;
1060 if (inp & PBTN_RIGHT) g_layer_x++;
1061 if (!(inp & PBTN_R)) {
1062 if (inp & PBTN_UP) g_layer_h += 2;
1063 if (inp & PBTN_DOWN) g_layer_h -= 2;
1064 if (inp & PBTN_LEFT) g_layer_w += 2;
1065 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1067 if (inp & (PBTN_MOK|PBTN_MBACK))
1070 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1071 if (g_layer_x < 0) g_layer_x = 0;
1072 if (g_layer_x > 640) g_layer_x = 640;
1073 if (g_layer_y < 0) g_layer_y = 0;
1074 if (g_layer_y > 420) g_layer_y = 420;
1075 if (g_layer_w < 160) g_layer_w = 160;
1076 if (g_layer_h < 60) g_layer_h = 60;
1077 if (g_layer_x + g_layer_w > 800)
1078 g_layer_w = 800 - g_layer_x;
1079 if (g_layer_y + g_layer_h > 480)
1080 g_layer_h = 480 - g_layer_y;
1082 plat_gvideo_open(Config.PsxType);
1086 plat_gvideo_close();
1091 static menu_entry e_menu_gfx_options[] =
1093 mee_enum ("Scaler", MA_OPT_SCALER, g_scaler, men_scaler),
1094 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1095 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1096 // mee_onoff ("Vsync", 0, vsync, 1),
1097 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1101 static int menu_loop_gfx_options(int id, int keys)
1105 me_loop(e_menu_gfx_options, &sel);
1111 void menu_set_filter_list(void *filters)
1115 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1116 e_menu_gfx_options[i].data = filters;
1117 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1120 // ------------ bios/plugins ------------
1124 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1125 static const char h_gpu_neon_enhanced[] = "Renders in double resolution at the cost of lower performance";
1126 static const char h_gpu_neon_enhanced_hack[] = "Speed hack for above option (glitches some games)";
1127 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1129 static menu_entry e_menu_plugin_gpu_neon[] =
1131 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1132 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1133 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
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"
1258 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1259 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1260 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1261 "must save config and reload the game if changed";
1262 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1263 "must save config and reload the game if changed";
1264 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1265 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1266 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1267 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1269 static menu_entry e_menu_plugin_options[] =
1271 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1272 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1273 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1275 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1277 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1278 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1279 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1280 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1284 static menu_entry e_menu_main2[];
1286 static int menu_loop_plugin_options(int id, int keys)
1289 me_loop(e_menu_plugin_options, &sel);
1291 // sync BIOS/plugins
1292 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1293 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1294 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1295 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1300 // ------------ adv options menu ------------
1302 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1303 "(lower value - less work for the emu, may be faster)";
1304 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1305 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1306 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1308 static menu_entry e_menu_speed_hacks[] =
1310 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1311 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1312 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1313 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1317 static int menu_loop_speed_hacks(int id, int keys)
1320 me_loop(e_menu_speed_hacks, &sel);
1324 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1325 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1326 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1327 "(green: normal, red: fmod, blue: noise)";
1328 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1329 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1330 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1331 "(proper .cue/.bin dump is needed otherwise)";
1332 static const char h_cfg_sio[] = "You should not need this, breaks games";
1333 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1334 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1335 "(timing hack, breaks other games)";
1336 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1337 "(timing hack, breaks other games)";
1338 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1339 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1340 "Might be useful to overcome some dynarec bugs";
1341 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1342 "must reload game for any change to take effect";
1344 static menu_entry e_menu_adv_options[] =
1346 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1347 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1348 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1349 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1350 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1351 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1352 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1353 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1354 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1355 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1356 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1357 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1361 static int menu_loop_adv_options(int id, int keys)
1364 me_loop(e_menu_adv_options, &sel);
1368 // ------------ options menu ------------
1370 static int mh_restore_defaults(int id, int keys)
1372 menu_set_defconfig();
1373 me_update_msg("defaults restored");
1377 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1378 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1380 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1381 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1382 "loading state or both";
1384 static const char h_restore_def[] = "Switches back to default / recommended\n"
1386 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1388 static menu_entry e_menu_options[] =
1390 // mee_range ("Save slot", 0, state_slot, 0, 9),
1391 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1392 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1393 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1394 mee_enum ("Region", 0, region, men_region),
1395 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1396 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1397 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1398 mee_handler ("[Advanced]", menu_loop_adv_options),
1399 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1400 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1401 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1405 static int menu_loop_options(int id, int keys)
1410 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1411 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1412 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1414 me_loop(e_menu_options, &sel);
1419 // ------------ debug menu ------------
1421 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1423 int w = min(g_menuscreen_w, 1024);
1424 int h = min(g_menuscreen_h, 512);
1425 u16 *d = g_menuscreen_ptr;
1426 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1430 gpuf->ulFreezeVersion = 1;
1431 if (GPU_freeze != NULL)
1432 GPU_freeze(1, gpuf);
1434 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1435 bgr555_to_rgb565(d, s, w * 2);
1437 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1438 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1439 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1440 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1441 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1444 static void debug_menu_loop(void)
1446 int inp, df_x = 0, df_y = 0;
1449 gpuf = malloc(sizeof(*gpuf));
1456 draw_frame_debug(gpuf, df_x, df_y);
1459 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1460 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1461 if (inp & PBTN_MBACK) break;
1462 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1463 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1464 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1465 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1471 // --------- memcard manager ---------
1473 static void draw_mc_icon(int dx, int dy, const u16 *s)
1478 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1480 for (y = 0; y < 16; y++, s += 16) {
1481 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1482 for (x = 0; x < 16; x++) {
1484 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1485 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1491 static void draw_mc_bg(void)
1493 McdBlock *blocks1, *blocks2;
1497 blocks1 = malloc(15 * sizeof(blocks1[0]));
1498 blocks2 = malloc(15 * sizeof(blocks1[0]));
1499 if (blocks1 == NULL || blocks2 == NULL)
1502 for (i = 0; i < 15; i++) {
1503 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1504 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1509 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1511 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1515 maxicons = g_menuscreen_h / 32;
1518 row2 = g_menuscreen_w / 2;
1519 for (i = 0; i < maxicons; i++) {
1520 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1521 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1523 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1524 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1527 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1535 static void handle_memcard_sel(void)
1538 if (memcard1_sel != 0)
1539 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1541 if (memcard2_sel != 0)
1542 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1543 LoadMcds(Config.Mcd1, Config.Mcd2);
1547 static menu_entry e_memcard_options[] =
1549 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1550 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1554 static int menu_loop_memcards(int id, int keys)
1560 memcard1_sel = memcard2_sel = 0;
1561 p = strrchr(Config.Mcd1, '/');
1563 for (i = 0; memcards[i] != NULL; i++)
1564 if (strcmp(p + 1, memcards[i]) == 0)
1565 { memcard1_sel = i; break; }
1566 p = strrchr(Config.Mcd2, '/');
1568 for (i = 0; memcards[i] != NULL; i++)
1569 if (strcmp(p + 1, memcards[i]) == 0)
1570 { memcard2_sel = i; break; }
1572 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1574 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1579 // ------------ cheats menu ------------
1581 static void draw_cheatlist(int sel)
1583 int max_cnt, start, i, pos, active;
1585 max_cnt = g_menuscreen_h / me_sfont_h;
1586 start = max_cnt / 2 - sel;
1590 for (i = 0; i < NumCheats; i++) {
1592 if (pos < 0) continue;
1593 if (pos >= max_cnt) break;
1594 active = Cheats[i].Enabled;
1595 smalltext_out16(14, pos * me_sfont_h,
1596 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1597 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1598 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1602 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1604 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1608 static void menu_loop_cheats(void)
1610 static int menu_sel = 0;
1615 draw_cheatlist(menu_sel);
1616 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1617 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1618 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1619 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1620 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1621 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1622 if (inp & PBTN_MOK) { // action
1623 if (menu_sel < NumCheats)
1624 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1627 if (inp & PBTN_MBACK)
1632 // --------- main menu help ----------
1634 static void menu_bios_warn(void)
1637 static const char msg[] =
1638 "You don't seem to have copied any BIOS\n"
1640 #ifdef __ARM_ARCH_7A__ // XXX
1641 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1643 "pcsx_rearmed/bios/\n\n"
1645 "While many games work fine with fake\n"
1646 "(HLE) BIOS, others (like MGS and FF8)\n"
1647 "require BIOS to work.\n"
1648 "After copying the file, you'll also need\n"
1649 "to select it in the emu's menu:\n"
1650 "options->[BIOS/Plugins]\n\n"
1651 "The file is usually named SCPH1001.BIN,\n"
1652 "but other not compressed files can be\n"
1654 "Press %s or %s to continue";
1655 char tmp_msg[sizeof(msg) + 64];
1657 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1658 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1661 draw_menu_message(tmp_msg, NULL);
1663 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1664 if (inp & (PBTN_MBACK|PBTN_MOK))
1669 // ------------ main menu ------------
1671 static menu_entry e_menu_main[];
1674 static void draw_frame_main(void)
1683 if (CdromId[0] != 0) {
1684 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1685 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1686 Config.HLE ? "HLE" : "BIOS");
1687 smalltext_out16(4, 1, buff, 0x105f);
1691 capacity = plat_get_bat_capacity();
1693 tmp = localtime(<ime);
1694 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1695 if (capacity >= 0) {
1696 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1701 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1705 static void draw_frame_credits(void)
1707 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1710 static const char credits_text[] =
1712 "(C) 1999-2003 PCSX Team\n"
1713 "(C) 2005-2009 PCSX-df Team\n"
1714 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1715 "ARM recompiler (C) 2009-2011 Ari64\n"
1717 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1719 "PEOpS GPU and SPU by Pete Bernert\n"
1720 " and the P.E.Op.S. team\n"
1721 "PCSX4ALL plugin by PCSX4ALL team\n"
1722 " Chui, Franxis, Unai\n\n"
1723 "integration, optimization and\n"
1724 " frontend (C) 2010-2012 notaz\n";
1726 static int reset_game(void)
1729 if (bios_sel == 0 && !Config.HLE)
1735 if (CheckCdrom() != -1) {
1741 static int reload_plugins(const char *cdimg)
1747 set_cd_image(cdimg);
1749 pcnt_hook_plugins();
1751 if (OpenPlugins() == -1) {
1752 me_update_msg("failed to open plugins");
1755 plugin_call_rearmed_cbs();
1757 cdrIsoMultidiskCount = 1;
1759 CdromLabel[0] = '\0';
1764 static int run_bios(void)
1770 if (reload_plugins(NULL) != 0)
1778 static int run_exe(void)
1782 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1787 if (reload_plugins(NULL) != 0)
1791 if (Load(fname) != 0) {
1792 me_update_msg("exe load failed, bad file?");
1801 static int run_cd_image(const char *fname)
1804 reload_plugins(fname);
1806 // always autodetect, menu_sync_config will override as needed
1809 if (CheckCdrom() == -1) {
1810 // Only check the CD if we are starting the console with a CD
1812 me_update_msg("unsupported/invalid CD image");
1818 // Read main executable directly from CDRom and start it
1819 if (LoadCdrom() == -1) {
1821 me_update_msg("failed to load CD image");
1831 static int romsel_run(void)
1833 int prev_gpu, prev_spu;
1836 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1840 printf("selected file: %s\n", fname);
1842 new_dynarec_clear_full();
1844 if (run_cd_image(fname) != 0)
1847 prev_gpu = gpu_plugsel;
1848 prev_spu = spu_plugsel;
1849 if (menu_load_config(1) != 0)
1850 menu_load_config(0);
1852 // check for plugin changes, have to repeat
1853 // loading if game config changed plugins to reload them
1854 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1855 printf("plugin change detected, reloading plugins..\n");
1856 if (run_cd_image(fname) != 0)
1860 strcpy(last_selected_fname, rom_fname_reload);
1861 menu_do_last_cd_img(0);
1865 static int swap_cd_image(void)
1869 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1873 printf("selected file: %s\n", fname);
1876 CdromLabel[0] = '\0';
1878 set_cd_image(fname);
1879 if (ReloadCdromPlugin() < 0) {
1880 me_update_msg("failed to load cdr plugin");
1883 if (CDR_open() < 0) {
1884 me_update_msg("failed to open cdr plugin");
1888 SetCdOpenCaseTime(time(NULL) + 2);
1891 strcpy(last_selected_fname, rom_fname_reload);
1895 static int swap_cd_multidisk(void)
1897 cdrIsoMultidiskSelect++;
1899 CdromLabel[0] = '\0';
1902 if (CDR_open() < 0) {
1903 me_update_msg("failed to open cdr plugin");
1907 SetCdOpenCaseTime(time(NULL) + 2);
1913 static void load_pcsx_cht(void)
1919 fname = menu_loop_romsel(path, sizeof(path));
1923 printf("selected cheat file: %s\n", fname);
1926 if (NumCheats == 0 && NumCodes == 0)
1927 me_update_msg("failed to load cheats");
1929 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1930 me_update_msg(path);
1932 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1935 static int main_menu_handler(int id, int keys)
1939 case MA_MAIN_RESUME_GAME:
1943 case MA_MAIN_SAVE_STATE:
1945 return menu_loop_savestate(0);
1947 case MA_MAIN_LOAD_STATE:
1949 return menu_loop_savestate(1);
1951 case MA_MAIN_RESET_GAME:
1952 if (ready_to_go && reset_game() == 0)
1955 case MA_MAIN_LOAD_ROM:
1956 if (romsel_run() == 0)
1959 case MA_MAIN_SWAP_CD:
1960 if (swap_cd_image() == 0)
1963 case MA_MAIN_SWAP_CD_MULTI:
1964 if (swap_cd_multidisk() == 0)
1967 case MA_MAIN_RUN_BIOS:
1968 if (run_bios() == 0)
1971 case MA_MAIN_RUN_EXE:
1975 case MA_MAIN_CHEATS:
1978 case MA_MAIN_LOAD_CHEATS:
1981 case MA_MAIN_CREDITS:
1982 draw_menu_message(credits_text, draw_frame_credits);
1983 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1989 lprintf("%s: something unknown selected\n", __FUNCTION__);
1996 static menu_entry e_menu_main2[] =
1998 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1999 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2000 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2001 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2002 mee_handler ("Memcard manager", menu_loop_memcards),
2003 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2007 static int main_menu2_handler(int id, int keys)
2011 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2012 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2013 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2014 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2016 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2019 static const char h_extra[] = "Change CD, manage memcards..\n";
2021 static menu_entry e_menu_main[] =
2025 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2026 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2027 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2028 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2029 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2030 mee_handler ("Options", menu_loop_options),
2031 mee_handler ("Controls", menu_loop_keyconfig),
2032 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2033 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2034 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2035 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2039 // ----------------------------
2041 static void menu_leave_emu(void);
2043 void menu_loop(void)
2049 if (bioses[1] == NULL && !warned_about_bios) {
2051 warned_about_bios = 1;
2054 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2055 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2056 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2057 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2058 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2060 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2063 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2064 } while (!ready_to_go);
2066 /* wait until menu, ok, back is released */
2067 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2070 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2075 static int qsort_strcmp(const void *p1, const void *p2)
2077 char * const *s1 = (char * const *)p1;
2078 char * const *s2 = (char * const *)p2;
2079 return strcasecmp(*s1, *s2);
2082 static void scan_bios_plugins(void)
2084 char fname[MAXPATHLEN];
2086 int bios_i, gpu_i, spu_i, mc_i;
2091 gpu_plugins[0] = "builtin_gpu";
2092 spu_plugins[0] = "builtin_spu";
2093 memcards[0] = "(none)";
2094 bios_i = gpu_i = spu_i = mc_i = 1;
2096 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2097 dir = opendir(fname);
2099 perror("scan_bios_plugins bios opendir");
2114 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2117 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2118 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2119 printf("bad BIOS file: %s\n", ent->d_name);
2123 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2124 bioses[bios_i++] = strdup(ent->d_name);
2128 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2134 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2135 dir = opendir(fname);
2137 perror("scan_bios_plugins plugins opendir");
2151 p = strstr(ent->d_name, ".so");
2155 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2156 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2158 fprintf(stderr, "%s\n", dlerror());
2162 // now what do we have here?
2163 tmp = dlsym(h, "GPUinit");
2166 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2167 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2171 tmp = dlsym(h, "SPUinit");
2174 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2175 spu_plugins[spu_i++] = strdup(ent->d_name);
2179 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2186 dir = opendir("." MEMCARD_DIR);
2188 perror("scan_bios_plugins memcards opendir");
2203 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2206 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2207 if (stat(fname, &st) != 0) {
2208 printf("bad memcard file: %s\n", ent->d_name);
2212 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2213 memcards[mc_i++] = strdup(ent->d_name);
2217 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2221 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2226 void menu_init(void)
2228 char buff[MAXPATHLEN];
2230 strcpy(last_selected_fname, "/media");
2232 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2234 scan_bios_plugins();
2237 menu_set_defconfig();
2238 menu_load_config(0);
2239 menu_do_last_cd_img(1);
2244 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2245 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2246 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2247 fprintf(stderr, "OOM\n");
2251 emu_make_path(buff, "skin/background.png", sizeof(buff));
2252 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2254 #ifndef __ARM_ARCH_7A__ /* XXX */
2255 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2256 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2257 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2258 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2260 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2261 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2262 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2266 void menu_notify_mode_change(int w, int h, int bpp)
2270 last_vout_bpp = bpp;
2273 static void menu_leave_emu(void)
2275 if (GPU_close != NULL) {
2276 int ret = GPU_close();
2278 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2281 plat_video_menu_enter(ready_to_go);
2283 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2284 if (pl_vout_buf != NULL && ready_to_go) {
2285 int x = max(0, g_menuscreen_w - last_vout_w);
2286 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2287 int w = min(g_menuscreen_w, last_vout_w);
2288 int h = min(g_menuscreen_h, last_vout_h);
2289 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2290 char *s = pl_vout_buf;
2292 if (last_vout_bpp == 16) {
2293 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2294 menu_darken_bg(d, s, w, 0);
2297 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2298 rgb888_to_rgb565(d, s, w * 3);
2299 menu_darken_bg(d, d, w, 0);
2305 cpu_clock = plat_cpu_clock_get();
2308 void menu_prepare_emu(void)
2310 R3000Acpu *prev_cpu = psxCpu;
2312 plat_video_menu_leave();
2314 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2315 if (psxCpu != prev_cpu)
2316 // note that this does not really reset, just clears drc caches
2319 // core doesn't care about Config.Cdda changes,
2320 // so handle them manually here
2326 plat_cpu_clock_apply(cpu_clock);
2328 // push config to GPU plugin
2329 plugin_call_rearmed_cbs();
2331 if (GPU_open != NULL) {
2332 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2334 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2340 void me_update_msg(const char *msg)
2342 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2343 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2345 menu_error_time = plat_get_ticks_ms();
2346 lprintf("msg: %s\n", menu_error_msg);
2349 void menu_finish(void)
2351 plat_cpu_clock_apply(cpu_clock_st);