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 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
667 #ifdef __ARM_ARCH_7A__ /* XXX */
668 { "Minimize ", 1 << SACTION_MINIMIZE },
670 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
671 { "Gun A button ", 1 << SACTION_GUN_A },
672 { "Gun B button ", 1 << SACTION_GUN_B },
673 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
674 #ifndef __ARM_ARCH_7A__ /* XXX */
675 { "Volume Up ", 1 << SACTION_VOLUME_UP },
676 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
681 static char *mystrip(char *str)
686 for (i = 0; i < len; i++)
687 if (str[i] != ' ') break;
688 if (i > 0) memmove(str, str + i, len - i + 1);
691 for (i = len - 1; i >= 0; i--)
692 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
698 static void get_line(char *d, size_t size, const char *s)
703 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
714 static void keys_write_all(FILE *f)
718 for (d = 0; d < IN_MAX_DEVS; d++)
720 const int *binds = in_get_dev_binds(d);
721 const char *name = in_get_dev_name(d, 0, 0);
724 if (binds == NULL || name == NULL)
727 fprintf(f, "binddev = %s\n", name);
728 in_get_config(d, IN_CFG_BIND_COUNT, &count);
730 for (k = 0; k < count; k++)
735 act[0] = act[31] = 0;
736 name = in_get_key_name(d, k);
738 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
739 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
740 mask = me_ctrl_actions[i].mask;
742 strncpy(act, me_ctrl_actions[i].name, 31);
743 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
746 mask = me_ctrl_actions[i].mask << 16;
748 strncpy(act, me_ctrl_actions[i].name, 31);
749 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
754 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
755 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
756 mask = emuctrl_actions[i].mask;
758 strncpy(act, emuctrl_actions[i].name, 31);
759 fprintf(f, "bind %s = %s\n", name, mystrip(act));
765 for (k = 0; k < array_size(in_adev); k++)
768 fprintf(f, "bind_analog = %d\n", k);
773 static int parse_bind_val(const char *val, int *type)
777 *type = IN_BINDTYPE_NONE;
781 if (strncasecmp(val, "player", 6) == 0)
783 int player, shift = 0;
784 player = atoi(val + 6) - 1;
786 if ((unsigned int)player > 1)
791 *type = IN_BINDTYPE_PLAYER12;
792 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
793 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
794 return me_ctrl_actions[i].mask << shift;
797 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
798 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
799 *type = IN_BINDTYPE_EMU;
800 return emuctrl_actions[i].mask;
807 static void keys_load_all(const char *cfg)
809 char dev[256], key[128], *act;
815 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
818 get_line(dev, sizeof(dev), p);
819 dev_id = in_config_parse_dev(dev);
821 printf("input: can't handle dev: %s\n", dev);
825 in_unbind_all(dev_id, -1, -1);
826 while ((p = strstr(p, "bind"))) {
827 if (strncmp(p, "binddev = ", 10) == 0)
830 if (strncmp(p, "bind_analog", 11) == 0) {
831 ret = sscanf(p, "bind_analog = %d", &bind);
834 printf("input: parse error: %16s..\n", p);
837 if ((unsigned int)bind >= array_size(in_adev)) {
838 printf("input: analog id %d out of range\n", bind);
841 in_adev[bind] = dev_id;
847 printf("input: parse error: %16s..\n", p);
851 get_line(key, sizeof(key), p);
852 act = strchr(key, '=');
854 printf("parse failed: %16s..\n", p);
862 bind = parse_bind_val(act, &bindtype);
863 if (bind != -1 && bind != 0) {
864 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
865 in_config_bind_key(dev_id, key, bind, bindtype);
868 lprintf("config: unhandled action \"%s\"\n", act);
874 static int key_config_loop_wrap(int id, int keys)
877 case MA_CTRL_PLAYER1:
878 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
880 case MA_CTRL_PLAYER2:
881 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
884 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
892 static const char *adevnames[IN_MAX_DEVS + 2];
893 static int stick_sel[2];
895 static menu_entry e_menu_keyconfig_analog[] =
897 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
898 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
899 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
900 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
901 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
902 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
906 static int key_config_analog(int id, int keys)
908 int i, d, count, sel = 0;
909 int sel2dev_map[IN_MAX_DEVS];
911 memset(adevnames, 0, sizeof(adevnames));
912 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
913 memset(stick_sel, 0, sizeof(stick_sel));
915 adevnames[0] = "None";
917 for (d = 0; d < IN_MAX_DEVS; d++)
919 const char *name = in_get_dev_name(d, 0, 1);
924 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
928 if (in_adev[0] == d) stick_sel[0] = i;
929 if (in_adev[1] == d) stick_sel[1] = i;
931 adevnames[i++] = name;
935 me_loop(e_menu_keyconfig_analog, &sel);
937 in_adev[0] = sel2dev_map[stick_sel[0]];
938 in_adev[1] = sel2dev_map[stick_sel[1]];
943 static const char *mgn_dev_name(int id, int *offs)
945 const char *name = NULL;
948 if (id == MA_CTRL_DEV_FIRST)
951 for (; it < IN_MAX_DEVS; it++) {
952 name = in_get_dev_name(it, 1, 1);
961 static const char *mgn_saveloadcfg(int id, int *offs)
966 static int mh_savecfg(int id, int keys)
968 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
969 me_update_msg("config saved");
971 me_update_msg("failed to write config");
976 static int mh_input_rescan(int id, int keys)
978 //menu_sync_config();
980 me_update_msg("rescan complete.");
985 static const char *men_in_type_sel[] = {
986 "Standard (SCPH-1080)",
987 "Analog (SCPH-1150)",
991 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
992 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
993 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
995 static menu_entry e_menu_keyconfig[] =
997 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
998 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
999 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1000 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1002 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1003 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1004 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1005 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1006 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1007 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1008 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1009 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1010 mee_handler ("Rescan devices:", mh_input_rescan),
1012 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1013 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1022 static int menu_loop_keyconfig(int id, int keys)
1026 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1027 me_loop(e_menu_keyconfig, &sel);
1031 // ------------ gfx options menu ------------
1033 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1034 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1035 "using d-pad or move it using R+d-pad";
1036 static const char *men_dummy[] = { NULL };
1038 static int menu_loop_cscaler(int id, int keys)
1042 g_scaler = SCALE_CUSTOM;
1044 plat_gvideo_open(Config.PsxType);
1049 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1050 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1051 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1054 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1055 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1056 if (inp & PBTN_UP) g_layer_y--;
1057 if (inp & PBTN_DOWN) g_layer_y++;
1058 if (inp & PBTN_LEFT) g_layer_x--;
1059 if (inp & PBTN_RIGHT) g_layer_x++;
1060 if (!(inp & PBTN_R)) {
1061 if (inp & PBTN_UP) g_layer_h += 2;
1062 if (inp & PBTN_DOWN) g_layer_h -= 2;
1063 if (inp & PBTN_LEFT) g_layer_w += 2;
1064 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1066 if (inp & (PBTN_MOK|PBTN_MBACK))
1069 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1070 if (g_layer_x < 0) g_layer_x = 0;
1071 if (g_layer_x > 640) g_layer_x = 640;
1072 if (g_layer_y < 0) g_layer_y = 0;
1073 if (g_layer_y > 420) g_layer_y = 420;
1074 if (g_layer_w < 160) g_layer_w = 160;
1075 if (g_layer_h < 60) g_layer_h = 60;
1076 if (g_layer_x + g_layer_w > 800)
1077 g_layer_w = 800 - g_layer_x;
1078 if (g_layer_y + g_layer_h > 480)
1079 g_layer_h = 480 - g_layer_y;
1081 plat_gvideo_open(Config.PsxType);
1085 plat_gvideo_close();
1090 static menu_entry e_menu_gfx_options[] =
1092 mee_enum ("Scaler", MA_OPT_SCALER, g_scaler, men_scaler),
1093 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1094 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1095 // mee_onoff ("Vsync", 0, vsync, 1),
1096 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1100 static int menu_loop_gfx_options(int id, int keys)
1104 me_loop(e_menu_gfx_options, &sel);
1110 void menu_set_filter_list(void *filters)
1114 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1115 e_menu_gfx_options[i].data = filters;
1116 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1119 // ------------ bios/plugins ------------
1123 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1124 static const char h_gpu_neon_enhanced[] = "Renders in double resolution at the cost of lower performance";
1125 static const char h_gpu_neon_enhanced_hack[] = "Speed hack for above option (glitches some games)";
1126 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1128 static menu_entry e_menu_plugin_gpu_neon[] =
1130 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1131 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1132 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1136 static int menu_loop_plugin_gpu_neon(int id, int keys)
1139 me_loop(e_menu_plugin_gpu_neon, &sel);
1145 static menu_entry e_menu_plugin_gpu_unai[] =
1147 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1148 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1149 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1150 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1154 static int menu_loop_plugin_gpu_unai(int id, int keys)
1157 me_loop(e_menu_plugin_gpu_unai, &sel);
1161 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1162 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1163 static const char h_gpu_1[] = "Capcom fighting games";
1164 static const char h_gpu_2[] = "Black screens in Lunar";
1165 static const char h_gpu_3[] = "Compatibility mode";
1166 static const char h_gpu_6[] = "Pandemonium 2";
1167 //static const char h_gpu_7[] = "Skip every second frame";
1168 static const char h_gpu_8[] = "Needed by Dark Forces";
1169 static const char h_gpu_9[] = "better g-colors, worse textures";
1170 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1172 static menu_entry e_menu_plugin_gpu_peops[] =
1174 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1175 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1176 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1177 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1178 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1179 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1180 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1181 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1182 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1183 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1187 static int menu_loop_plugin_gpu_peops(int id, int keys)
1190 me_loop(e_menu_plugin_gpu_peops, &sel);
1194 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1195 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1196 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1198 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1200 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1201 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1202 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1203 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1204 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1205 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1206 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1207 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1208 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1209 mee_label ("Fixes/hacks:"),
1210 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1211 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1212 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1213 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1214 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1215 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1216 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1217 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1218 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1219 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1220 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1224 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1227 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1231 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1232 static const char h_spu_volboost[] = "Large values cause distortion";
1234 static menu_entry e_menu_plugin_spu[] =
1236 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1237 mee_onoff ("Reverb", 0, iUseReverb, 2),
1238 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1239 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1243 static int menu_loop_plugin_spu(int id, int keys)
1246 me_loop(e_menu_plugin_spu, &sel);
1250 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1251 "savestates and can't be changed there. Must save\n"
1252 "config and reload the game for change to take effect";
1253 static const char h_plugin_gpu[] =
1255 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1257 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1258 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1259 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1260 "must save config and reload the game if changed";
1261 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1262 "must save config and reload the game if changed";
1263 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1264 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1265 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1266 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1268 static menu_entry e_menu_plugin_options[] =
1270 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1271 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1272 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1274 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1276 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1277 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1278 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1279 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1283 static menu_entry e_menu_main2[];
1285 static int menu_loop_plugin_options(int id, int keys)
1288 me_loop(e_menu_plugin_options, &sel);
1290 // sync BIOS/plugins
1291 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1292 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1293 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1294 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1299 // ------------ adv options menu ------------
1301 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1302 "(lower value - less work for the emu, may be faster)";
1303 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1304 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1305 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1307 static menu_entry e_menu_speed_hacks[] =
1309 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1310 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1311 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1312 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1316 static int menu_loop_speed_hacks(int id, int keys)
1319 me_loop(e_menu_speed_hacks, &sel);
1323 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1324 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1325 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1326 "(green: normal, red: fmod, blue: noise)";
1327 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1328 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1329 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1330 "(proper .cue/.bin dump is needed otherwise)";
1331 static const char h_cfg_sio[] = "You should not need this, breaks games";
1332 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1333 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1334 "(timing hack, breaks other games)";
1335 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1336 "(timing hack, breaks other games)";
1337 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1338 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1339 "Might be useful to overcome some dynarec bugs";
1340 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1341 "must reload game for any change to take effect";
1343 static menu_entry e_menu_adv_options[] =
1345 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1346 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1347 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1348 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1349 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1350 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1351 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1352 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1353 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1354 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1355 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1356 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1360 static int menu_loop_adv_options(int id, int keys)
1363 me_loop(e_menu_adv_options, &sel);
1367 // ------------ options menu ------------
1369 static int mh_restore_defaults(int id, int keys)
1371 menu_set_defconfig();
1372 me_update_msg("defaults restored");
1376 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1377 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1379 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1380 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1381 "loading state or both";
1383 static const char h_restore_def[] = "Switches back to default / recommended\n"
1385 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1387 static menu_entry e_menu_options[] =
1389 // mee_range ("Save slot", 0, state_slot, 0, 9),
1390 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1391 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1392 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1393 mee_enum ("Region", 0, region, men_region),
1394 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1395 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1396 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1397 mee_handler ("[Advanced]", menu_loop_adv_options),
1398 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1399 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1400 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1404 static int menu_loop_options(int id, int keys)
1409 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1410 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1411 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1413 me_loop(e_menu_options, &sel);
1418 // ------------ debug menu ------------
1420 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1422 int w = min(g_menuscreen_w, 1024);
1423 int h = min(g_menuscreen_h, 512);
1424 u16 *d = g_menuscreen_ptr;
1425 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1429 gpuf->ulFreezeVersion = 1;
1430 if (GPU_freeze != NULL)
1431 GPU_freeze(1, gpuf);
1433 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1434 bgr555_to_rgb565(d, s, w * 2);
1436 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1437 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1438 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1439 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1440 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1443 static void debug_menu_loop(void)
1445 int inp, df_x = 0, df_y = 0;
1448 gpuf = malloc(sizeof(*gpuf));
1455 draw_frame_debug(gpuf, df_x, df_y);
1458 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1459 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1460 if (inp & PBTN_MBACK) break;
1461 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1462 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1463 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1464 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1470 // --------- memcard manager ---------
1472 static void draw_mc_icon(int dx, int dy, const u16 *s)
1477 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1479 for (y = 0; y < 16; y++, s += 16) {
1480 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1481 for (x = 0; x < 16; x++) {
1483 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1484 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1490 static void draw_mc_bg(void)
1492 McdBlock *blocks1, *blocks2;
1496 blocks1 = malloc(15 * sizeof(blocks1[0]));
1497 blocks2 = malloc(15 * sizeof(blocks1[0]));
1498 if (blocks1 == NULL || blocks2 == NULL)
1501 for (i = 0; i < 15; i++) {
1502 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1503 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1508 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1510 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1514 maxicons = g_menuscreen_h / 32;
1517 row2 = g_menuscreen_w / 2;
1518 for (i = 0; i < maxicons; i++) {
1519 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1520 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1522 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1523 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1526 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1534 static void handle_memcard_sel(void)
1537 if (memcard1_sel != 0)
1538 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1540 if (memcard2_sel != 0)
1541 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1542 LoadMcds(Config.Mcd1, Config.Mcd2);
1546 static menu_entry e_memcard_options[] =
1548 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1549 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1553 static int menu_loop_memcards(int id, int keys)
1559 memcard1_sel = memcard2_sel = 0;
1560 p = strrchr(Config.Mcd1, '/');
1562 for (i = 0; memcards[i] != NULL; i++)
1563 if (strcmp(p + 1, memcards[i]) == 0)
1564 { memcard1_sel = i; break; }
1565 p = strrchr(Config.Mcd2, '/');
1567 for (i = 0; memcards[i] != NULL; i++)
1568 if (strcmp(p + 1, memcards[i]) == 0)
1569 { memcard2_sel = i; break; }
1571 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1573 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1578 // ------------ cheats menu ------------
1580 static void draw_cheatlist(int sel)
1582 int max_cnt, start, i, pos, active;
1584 max_cnt = g_menuscreen_h / me_sfont_h;
1585 start = max_cnt / 2 - sel;
1589 for (i = 0; i < NumCheats; i++) {
1591 if (pos < 0) continue;
1592 if (pos >= max_cnt) break;
1593 active = Cheats[i].Enabled;
1594 smalltext_out16(14, pos * me_sfont_h,
1595 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1596 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1597 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1601 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1603 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1607 static void menu_loop_cheats(void)
1609 static int menu_sel = 0;
1614 draw_cheatlist(menu_sel);
1615 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1616 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1617 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1618 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1619 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1620 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1621 if (inp & PBTN_MOK) { // action
1622 if (menu_sel < NumCheats)
1623 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1626 if (inp & PBTN_MBACK)
1631 // --------- main menu help ----------
1633 static void menu_bios_warn(void)
1636 static const char msg[] =
1637 "You don't seem to have copied any BIOS\n"
1639 #ifdef __ARM_ARCH_7A__ // XXX
1640 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1642 "pcsx_rearmed/bios/\n\n"
1644 "While many games work fine with fake\n"
1645 "(HLE) BIOS, others (like MGS and FF8)\n"
1646 "require BIOS to work.\n"
1647 "After copying the file, you'll also need\n"
1648 "to select it in the emu's menu:\n"
1649 "options->[BIOS/Plugins]\n\n"
1650 "The file is usually named SCPH1001.BIN,\n"
1651 "but other not compressed files can be\n"
1653 "Press %s or %s to continue";
1654 char tmp_msg[sizeof(msg) + 64];
1656 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1657 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1660 draw_menu_message(tmp_msg, NULL);
1662 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1663 if (inp & (PBTN_MBACK|PBTN_MOK))
1668 // ------------ main menu ------------
1670 static menu_entry e_menu_main[];
1673 static void draw_frame_main(void)
1682 if (CdromId[0] != 0) {
1683 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1684 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1685 Config.HLE ? "HLE" : "BIOS");
1686 smalltext_out16(4, 1, buff, 0x105f);
1690 capacity = plat_get_bat_capacity();
1692 tmp = localtime(<ime);
1693 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1694 if (capacity >= 0) {
1695 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1700 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1704 static void draw_frame_credits(void)
1706 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1709 static const char credits_text[] =
1711 "(C) 1999-2003 PCSX Team\n"
1712 "(C) 2005-2009 PCSX-df Team\n"
1713 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1714 "ARM recompiler (C) 2009-2011 Ari64\n"
1716 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1718 "PEOpS GPU and SPU by Pete Bernert\n"
1719 " and the P.E.Op.S. team\n"
1720 "PCSX4ALL plugin by PCSX4ALL team\n"
1721 " Chui, Franxis, Unai\n\n"
1722 "integration, optimization and\n"
1723 " frontend (C) 2010-2012 notaz\n";
1725 static int reset_game(void)
1728 if (bios_sel == 0 && !Config.HLE)
1734 if (CheckCdrom() != -1) {
1740 static int reload_plugins(const char *cdimg)
1746 set_cd_image(cdimg);
1748 pcnt_hook_plugins();
1750 if (OpenPlugins() == -1) {
1751 me_update_msg("failed to open plugins");
1754 plugin_call_rearmed_cbs();
1756 cdrIsoMultidiskCount = 1;
1758 CdromLabel[0] = '\0';
1763 static int run_bios(void)
1769 if (reload_plugins(NULL) != 0)
1777 static int run_exe(void)
1781 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1786 if (reload_plugins(NULL) != 0)
1790 if (Load(fname) != 0) {
1791 me_update_msg("exe load failed, bad file?");
1800 static int run_cd_image(const char *fname)
1803 reload_plugins(fname);
1805 // always autodetect, menu_sync_config will override as needed
1808 if (CheckCdrom() == -1) {
1809 // Only check the CD if we are starting the console with a CD
1811 me_update_msg("unsupported/invalid CD image");
1817 // Read main executable directly from CDRom and start it
1818 if (LoadCdrom() == -1) {
1820 me_update_msg("failed to load CD image");
1830 static int romsel_run(void)
1832 int prev_gpu, prev_spu;
1835 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1839 printf("selected file: %s\n", fname);
1841 new_dynarec_clear_full();
1843 if (run_cd_image(fname) != 0)
1846 prev_gpu = gpu_plugsel;
1847 prev_spu = spu_plugsel;
1848 if (menu_load_config(1) != 0)
1849 menu_load_config(0);
1851 // check for plugin changes, have to repeat
1852 // loading if game config changed plugins to reload them
1853 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1854 printf("plugin change detected, reloading plugins..\n");
1855 if (run_cd_image(fname) != 0)
1859 strcpy(last_selected_fname, rom_fname_reload);
1860 menu_do_last_cd_img(0);
1864 static int swap_cd_image(void)
1868 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1872 printf("selected file: %s\n", fname);
1875 CdromLabel[0] = '\0';
1877 set_cd_image(fname);
1878 if (ReloadCdromPlugin() < 0) {
1879 me_update_msg("failed to load cdr plugin");
1882 if (CDR_open() < 0) {
1883 me_update_msg("failed to open cdr plugin");
1887 SetCdOpenCaseTime(time(NULL) + 2);
1890 strcpy(last_selected_fname, rom_fname_reload);
1894 static int swap_cd_multidisk(void)
1896 cdrIsoMultidiskSelect++;
1898 CdromLabel[0] = '\0';
1901 if (CDR_open() < 0) {
1902 me_update_msg("failed to open cdr plugin");
1906 SetCdOpenCaseTime(time(NULL) + 2);
1912 static void load_pcsx_cht(void)
1918 fname = menu_loop_romsel(path, sizeof(path));
1922 printf("selected cheat file: %s\n", fname);
1925 if (NumCheats == 0 && NumCodes == 0)
1926 me_update_msg("failed to load cheats");
1928 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1929 me_update_msg(path);
1931 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1934 static int main_menu_handler(int id, int keys)
1938 case MA_MAIN_RESUME_GAME:
1942 case MA_MAIN_SAVE_STATE:
1944 return menu_loop_savestate(0);
1946 case MA_MAIN_LOAD_STATE:
1948 return menu_loop_savestate(1);
1950 case MA_MAIN_RESET_GAME:
1951 if (ready_to_go && reset_game() == 0)
1954 case MA_MAIN_LOAD_ROM:
1955 if (romsel_run() == 0)
1958 case MA_MAIN_SWAP_CD:
1959 if (swap_cd_image() == 0)
1962 case MA_MAIN_SWAP_CD_MULTI:
1963 if (swap_cd_multidisk() == 0)
1966 case MA_MAIN_RUN_BIOS:
1967 if (run_bios() == 0)
1970 case MA_MAIN_RUN_EXE:
1974 case MA_MAIN_CHEATS:
1977 case MA_MAIN_LOAD_CHEATS:
1980 case MA_MAIN_CREDITS:
1981 draw_menu_message(credits_text, draw_frame_credits);
1982 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1988 lprintf("%s: something unknown selected\n", __FUNCTION__);
1995 static menu_entry e_menu_main2[] =
1997 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1998 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1999 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2000 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2001 mee_handler ("Memcard manager", menu_loop_memcards),
2002 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2006 static int main_menu2_handler(int id, int keys)
2010 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2011 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2012 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2013 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2015 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2018 static const char h_extra[] = "Change CD, manage memcards..\n";
2020 static menu_entry e_menu_main[] =
2024 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2025 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2026 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2027 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2028 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2029 mee_handler ("Options", menu_loop_options),
2030 mee_handler ("Controls", menu_loop_keyconfig),
2031 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2032 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2033 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2034 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2038 // ----------------------------
2040 static void menu_leave_emu(void);
2042 void menu_loop(void)
2048 if (bioses[1] == NULL && !warned_about_bios) {
2050 warned_about_bios = 1;
2053 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2054 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2055 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2056 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2057 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2059 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2062 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2063 } while (!ready_to_go);
2065 /* wait until menu, ok, back is released */
2066 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2069 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2074 static int qsort_strcmp(const void *p1, const void *p2)
2076 char * const *s1 = (char * const *)p1;
2077 char * const *s2 = (char * const *)p2;
2078 return strcasecmp(*s1, *s2);
2081 static void scan_bios_plugins(void)
2083 char fname[MAXPATHLEN];
2085 int bios_i, gpu_i, spu_i, mc_i;
2090 gpu_plugins[0] = "builtin_gpu";
2091 spu_plugins[0] = "builtin_spu";
2092 memcards[0] = "(none)";
2093 bios_i = gpu_i = spu_i = mc_i = 1;
2095 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2096 dir = opendir(fname);
2098 perror("scan_bios_plugins bios opendir");
2113 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2116 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2117 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2118 printf("bad BIOS file: %s\n", ent->d_name);
2122 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2123 bioses[bios_i++] = strdup(ent->d_name);
2127 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2133 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2134 dir = opendir(fname);
2136 perror("scan_bios_plugins plugins opendir");
2150 p = strstr(ent->d_name, ".so");
2154 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2155 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2157 fprintf(stderr, "%s\n", dlerror());
2161 // now what do we have here?
2162 tmp = dlsym(h, "GPUinit");
2165 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2166 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2170 tmp = dlsym(h, "SPUinit");
2173 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2174 spu_plugins[spu_i++] = strdup(ent->d_name);
2178 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2185 dir = opendir("." MEMCARD_DIR);
2187 perror("scan_bios_plugins memcards opendir");
2202 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2205 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2206 if (stat(fname, &st) != 0) {
2207 printf("bad memcard file: %s\n", ent->d_name);
2211 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2212 memcards[mc_i++] = strdup(ent->d_name);
2216 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2220 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2225 void menu_init(void)
2227 char buff[MAXPATHLEN];
2229 strcpy(last_selected_fname, "/media");
2231 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2233 scan_bios_plugins();
2236 menu_set_defconfig();
2237 menu_load_config(0);
2238 menu_do_last_cd_img(1);
2243 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2244 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2245 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2246 fprintf(stderr, "OOM\n");
2250 emu_make_path(buff, "skin/background.png", sizeof(buff));
2251 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2253 #ifndef __ARM_ARCH_7A__ /* XXX */
2254 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2255 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2256 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2257 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2259 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2260 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2261 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2265 void menu_notify_mode_change(int w, int h, int bpp)
2269 last_vout_bpp = bpp;
2272 static void menu_leave_emu(void)
2274 if (GPU_close != NULL) {
2275 int ret = GPU_close();
2277 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2280 plat_video_menu_enter(ready_to_go);
2282 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2283 if (pl_vout_buf != NULL && ready_to_go) {
2284 int x = max(0, g_menuscreen_w - last_vout_w);
2285 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2286 int w = min(g_menuscreen_w, last_vout_w);
2287 int h = min(g_menuscreen_h, last_vout_h);
2288 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2289 char *s = pl_vout_buf;
2291 if (last_vout_bpp == 16) {
2292 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2293 menu_darken_bg(d, s, w, 0);
2296 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2297 rgb888_to_rgb565(d, s, w * 3);
2298 menu_darken_bg(d, d, w, 0);
2304 cpu_clock = plat_cpu_clock_get();
2307 void menu_prepare_emu(void)
2309 R3000Acpu *prev_cpu = psxCpu;
2311 plat_video_menu_leave();
2313 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2314 if (psxCpu != prev_cpu)
2315 // note that this does not really reset, just clears drc caches
2318 // core doesn't care about Config.Cdda changes,
2319 // so handle them manually here
2325 plat_cpu_clock_apply(cpu_clock);
2327 // push config to GPU plugin
2328 plugin_call_rearmed_cbs();
2330 if (GPU_open != NULL) {
2331 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2333 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2339 void me_update_msg(const char *msg)
2341 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2342 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2344 menu_error_time = plat_get_ticks_ms();
2345 lprintf("msg: %s\n", menu_error_msg);
2348 void menu_finish(void)
2350 plat_cpu_clock_apply(cpu_clock_st);