2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
16 #include <sys/types.h>
24 #include "plugin_lib.h"
27 #include "common/plat.h"
28 #include "common/input.h"
29 #include "linux/in_evdev.h"
30 #include "../libpcsxcore/misc.h"
31 #include "../libpcsxcore/cdrom.h"
32 #include "../libpcsxcore/cdriso.h"
33 #include "../libpcsxcore/cheat.h"
34 #include "../libpcsxcore/psemu_plugin_defs.h"
35 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
36 #include "../plugins/dfinput/main.h"
37 #include "../plugins/gpulib/cspace.h"
40 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
42 #define array_size(x) (sizeof(x) / sizeof(x[0]))
53 MA_MAIN_SWAP_CD_MULTI,
89 static int last_psx_w, last_psx_h, last_psx_bpp;
90 static int scaling, cpu_clock, cpu_clock_st, volume_boost, frameskip;
91 static char rom_fname_reload[MAXPATHLEN];
92 static char last_selected_fname[MAXPATHLEN];
93 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
95 static int memcard1_sel, memcard2_sel;
97 int soft_scaling, analog_deadzone; // for Caanoo
100 #ifdef __ARM_ARCH_7A__
101 #define DEFAULT_PSX_CLOCK 57
102 #define DEFAULT_PSX_CLOCK_S "57"
104 #define DEFAULT_PSX_CLOCK 50
105 #define DEFAULT_PSX_CLOCK_S "50"
109 extern int iUseReverb;
110 extern int iUseInterpolation;
114 static const char *bioses[24];
115 static const char *gpu_plugins[16];
116 static const char *spu_plugins[16];
117 static const char *memcards[32];
118 static int bios_sel, gpu_plugsel, spu_plugsel;
121 static int min(int x, int y) { return x < y ? x : y; }
122 static int max(int x, int y) { return x > y ? x : y; }
124 void emu_make_path(char *buff, const char *end, int size)
128 end_len = strlen(end);
129 pos = plat_get_root_dir(buff, size);
130 strncpy(buff + pos, end, size - pos);
132 if (pos + end_len > size - 1)
133 printf("Warning: path truncated: %s\n", buff);
136 static int emu_check_save_file(int slot, int *time)
138 char fname[MAXPATHLEN];
142 ret = emu_check_state(slot);
143 if (ret != 0 || time == NULL)
144 return ret == 0 ? 1 : 0;
146 ret = get_state_filename(fname, sizeof(fname), slot);
150 ret = stat(fname, &status);
154 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
155 return 1; // probably bad rtc like on some Caanoos
157 *time = status.st_mtime;
162 static int emu_save_load_game(int load, int unused)
167 ret = emu_load_state(state_slot);
169 // reflect hle/bios mode from savestate
172 else if (bios_sel == 0 && bioses[1] != NULL)
173 // XXX: maybe find the right bios instead
177 ret = emu_save_state(state_slot);
182 // propagate menu settings to the emu vars
183 static void menu_sync_config(void)
185 static int allow_abs_only_old;
190 Config.PsxType = region - 1;
192 cycle_multiplier = 10000 / psx_clock;
194 switch (in_type_sel1) {
195 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
196 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
197 default: in_type1 = PSE_PAD_TYPE_STANDARD;
199 switch (in_type_sel2) {
200 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
201 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
202 default: in_type2 = PSE_PAD_TYPE_STANDARD;
204 if (in_evdev_allow_abs_only != allow_abs_only_old) {
206 allow_abs_only_old = in_evdev_allow_abs_only;
209 iVolume = 768 + 128 * volume_boost;
210 pl_rearmed_cbs.frameskip = frameskip - 1;
211 pl_timing_prepare(Config.PsxType);
214 static void menu_set_defconfig(void)
216 emu_set_default_config();
222 analog_deadzone = 50;
224 psx_clock = DEFAULT_PSX_CLOCK;
227 in_type_sel1 = in_type_sel2 = 0;
228 in_evdev_allow_abs_only = 0;
233 #define CE_CONFIG_STR(val) \
234 { #val, 0, Config.val }
236 #define CE_CONFIG_VAL(val) \
237 { #val, sizeof(Config.val), &Config.val }
239 #define CE_STR(val) \
242 #define CE_INTVAL(val) \
243 { #val, sizeof(val), &val }
245 #define CE_INTVAL_P(val) \
246 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
248 // 'versioned' var, used when defaults change
249 #define CE_CONFIG_STR_V(val, ver) \
250 { #val #ver, 0, Config.val }
252 #define CE_INTVAL_V(val, ver) \
253 { #val #ver, sizeof(val), &val }
255 #define CE_INTVAL_PV(val, ver) \
256 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
258 static const struct {
264 CE_CONFIG_STR_V(Gpu, 2),
266 // CE_CONFIG_STR(Cdr),
271 CE_CONFIG_VAL(Debug),
272 CE_CONFIG_VAL(PsxOut),
273 CE_CONFIG_VAL(SpuIrq),
274 CE_CONFIG_VAL(RCntFix),
275 CE_CONFIG_VAL(VSyncWA),
277 CE_CONFIG_VAL(CdrReschedule),
279 CE_INTVAL_V(scaling, 2),
280 CE_INTVAL(g_layer_x),
281 CE_INTVAL(g_layer_y),
282 CE_INTVAL(g_layer_w),
283 CE_INTVAL(g_layer_h),
285 CE_INTVAL(state_slot),
286 CE_INTVAL(cpu_clock),
288 CE_INTVAL(in_type_sel1),
289 CE_INTVAL(in_type_sel2),
290 CE_INTVAL(analog_deadzone),
291 CE_INTVAL_V(frameskip, 3),
292 CE_INTVAL_P(gpu_peops.iUseDither),
293 CE_INTVAL_P(gpu_peops.dwActFixes),
294 CE_INTVAL_P(gpu_unai.lineskip),
295 CE_INTVAL_P(gpu_unai.abe_hack),
296 CE_INTVAL_P(gpu_unai.no_light),
297 CE_INTVAL_P(gpu_unai.no_blend),
298 CE_INTVAL_P(gpu_neon.allow_interlace),
299 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
300 CE_INTVAL_P(gpu_peopsgl.iFilterType),
301 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
302 CE_INTVAL_P(gpu_peopsgl.iUseMask),
303 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
304 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
305 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
306 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
307 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
308 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
309 CE_INTVAL_V(iUseReverb, 3),
310 CE_INTVAL_V(iXAPitch, 3),
311 CE_INTVAL_V(iUseInterpolation, 3),
312 CE_INTVAL(warned_about_bios),
313 CE_INTVAL(in_evdev_allow_abs_only),
314 CE_INTVAL(volume_boost),
315 CE_INTVAL(psx_clock),
316 CE_INTVAL(new_dynarec_hacks),
317 CE_INTVAL(in_enable_vibration),
320 static char *get_cd_label(void)
322 static char trimlabel[33];
325 strncpy(trimlabel, CdromLabel, 32);
327 for (j = 31; j >= 0; j--)
328 if (trimlabel[j] == ' ')
334 static void make_cfg_fname(char *buf, size_t size, int is_game)
337 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
339 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
342 static void keys_write_all(FILE *f);
344 static int menu_write_config(int is_game)
346 char cfgfile[MAXPATHLEN];
350 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
351 f = fopen(cfgfile, "w");
353 printf("menu_write_config: failed to open: %s\n", cfgfile);
357 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
358 fprintf(f, "%s = ", config_data[i].name);
359 switch (config_data[i].len) {
361 fprintf(f, "%s\n", (char *)config_data[i].val);
364 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
367 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
370 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
373 printf("menu_write_config: unhandled len %d for %s\n",
374 config_data[i].len, config_data[i].name);
380 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
388 static void parse_str_val(char *cval, const char *src)
391 strncpy(cval, src, MAXPATHLEN);
392 cval[MAXPATHLEN - 1] = 0;
393 tmp = strchr(cval, '\n');
395 tmp = strchr(cval, '\r');
400 static void keys_load_all(const char *cfg);
402 static int menu_load_config(int is_game)
404 char cfgfile[MAXPATHLEN];
410 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
411 f = fopen(cfgfile, "r");
413 printf("menu_load_config: failed to open: %s\n", cfgfile);
417 fseek(f, 0, SEEK_END);
420 printf("bad size %ld: %s\n", size, cfgfile);
424 cfg = malloc(size + 1);
428 fseek(f, 0, SEEK_SET);
429 if (fread(cfg, 1, size, f) != size) {
430 printf("failed to read: %s\n", cfgfile);
435 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
439 tmp = strstr(cfg, config_data[i].name);
442 tmp += strlen(config_data[i].name);
443 if (strncmp(tmp, " = ", 3) != 0)
447 if (config_data[i].len == 0) {
448 parse_str_val(config_data[i].val, tmp);
453 val = strtoul(tmp, &tmp2, 16);
454 if (tmp2 == NULL || tmp == tmp2)
455 continue; // parse failed
457 switch (config_data[i].len) {
459 *(u8 *)config_data[i].val = val;
462 *(u16 *)config_data[i].val = val;
465 *(u32 *)config_data[i].val = val;
468 printf("menu_load_config: unhandled len %d for %s\n",
469 config_data[i].len, config_data[i].name);
475 char *tmp = strstr(cfg, "lastcdimg = ");
478 parse_str_val(last_selected_fname, tmp);
492 // caanoo old config compat hack
493 if (strcmp(Config.Gpu, "gpuPCSX4ALL.so") == 0)
494 strcpy(Config.Gpu, "gpu_unai.so");
497 for (i = bios_sel = 0; bioses[i] != NULL; i++)
498 if (strcmp(Config.Bios, bioses[i]) == 0)
499 { bios_sel = i; break; }
501 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
502 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
503 { gpu_plugsel = i; break; }
505 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
506 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
507 { spu_plugsel = i; break; }
512 // rrrr rggg gggb bbbb
513 static unsigned short fname2color(const char *fname)
515 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
516 ".bz", ".znx", ".pbp", ".cbn" };
517 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
518 ".table", ".index", ".sbi" };
519 const char *ext = strrchr(fname, '.');
524 for (i = 0; i < array_size(cdimg_exts); i++)
525 if (strcasecmp(ext, cdimg_exts[i]) == 0)
527 for (i = 0; i < array_size(other_exts); i++)
528 if (strcasecmp(ext, other_exts[i]) == 0)
533 static void draw_savestate_bg(int slot);
535 static const char *filter_exts[] = {
536 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
539 #define MENU_ALIGN_LEFT
540 #ifdef __ARM_ARCH_7A__ // assume hires device
546 #define menu_init menu_init_common
547 #include "common/menu.c"
550 // a bit of black magic here
551 static void draw_savestate_bg(int slot)
553 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
555 char fname[MAXPATHLEN];
562 ret = get_state_filename(fname, sizeof(fname), slot);
566 f = gzopen(fname, "rb");
570 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
571 fprintf(stderr, "gzseek failed\n");
576 gpu = malloc(sizeof(*gpu));
582 ret = gzread(f, gpu, sizeof(*gpu));
584 if (ret != sizeof(*gpu)) {
585 fprintf(stderr, "gzread failed\n");
589 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
591 if (gpu->ulStatus & 0x800000)
592 goto out; // disabled
594 x = gpu->ulControl[5] & 0x3ff;
595 y = (gpu->ulControl[5] >> 10) & 0x1ff;
596 s = (u16 *)gpu->psxVRam + y * 1024 + x;
597 w = psx_widths[(gpu->ulStatus >> 16) & 7];
598 tmp = gpu->ulControl[7];
599 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
600 if (gpu->ulStatus & 0x80000) // doubleheight
603 x = max(0, g_menuscreen_w - w) & ~3;
604 y = max(0, g_menuscreen_h / 2 - h / 2);
605 w = min(g_menuscreen_w, w);
606 h = min(g_menuscreen_h, h);
607 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
609 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
610 if (gpu->ulStatus & 0x200000)
611 bgr888_to_rgb565(d, s, w * 3);
613 bgr555_to_rgb565(d, s, w * 2);
615 // darken this so that menu text is visible
616 if (g_menuscreen_w - w < 320)
617 menu_darken_bg(d, d, w * 2, 0);
624 // -------------- key config --------------
626 me_bind_action me_ctrl_actions[] =
628 { "UP ", 1 << DKEY_UP},
629 { "DOWN ", 1 << DKEY_DOWN },
630 { "LEFT ", 1 << DKEY_LEFT },
631 { "RIGHT ", 1 << DKEY_RIGHT },
632 { "TRIANGLE", 1 << DKEY_TRIANGLE },
633 { "CIRCLE ", 1 << DKEY_CIRCLE },
634 { "CROSS ", 1 << DKEY_CROSS },
635 { "SQUARE ", 1 << DKEY_SQUARE },
636 { "L1 ", 1 << DKEY_L1 },
637 { "R1 ", 1 << DKEY_R1 },
638 { "L2 ", 1 << DKEY_L2 },
639 { "R2 ", 1 << DKEY_R2 },
640 { "L3 ", 1 << DKEY_L3 },
641 { "R3 ", 1 << DKEY_R3 },
642 { "START ", 1 << DKEY_START },
643 { "SELECT ", 1 << DKEY_SELECT },
647 me_bind_action emuctrl_actions[] =
649 { "Save State ", 1 << SACTION_SAVE_STATE },
650 { "Load State ", 1 << SACTION_LOAD_STATE },
651 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
652 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
653 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
654 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
655 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
656 #ifdef __ARM_ARCH_7A__ /* XXX */
657 { "Minimize ", 1 << SACTION_MINIMIZE },
659 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
660 { "Gun A button ", 1 << SACTION_GUN_A },
661 { "Gun B button ", 1 << SACTION_GUN_B },
662 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
663 #ifndef __ARM_ARCH_7A__ /* XXX */
664 { "Volume Up ", 1 << SACTION_VOLUME_UP },
665 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
670 static char *mystrip(char *str)
675 for (i = 0; i < len; i++)
676 if (str[i] != ' ') break;
677 if (i > 0) memmove(str, str + i, len - i + 1);
680 for (i = len - 1; i >= 0; i--)
681 if (str[i] != ' ') break;
687 static void get_line(char *d, size_t size, const char *s)
692 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
703 static void keys_write_all(FILE *f)
707 for (d = 0; d < IN_MAX_DEVS; d++)
709 const int *binds = in_get_dev_binds(d);
710 const char *name = in_get_dev_name(d, 0, 0);
713 if (binds == NULL || name == NULL)
716 fprintf(f, "binddev = %s\n", name);
717 in_get_config(d, IN_CFG_BIND_COUNT, &count);
719 for (k = 0; k < count; k++)
724 act[0] = act[31] = 0;
725 name = in_get_key_name(d, k);
727 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
728 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
729 mask = me_ctrl_actions[i].mask;
731 strncpy(act, me_ctrl_actions[i].name, 31);
732 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
735 mask = me_ctrl_actions[i].mask << 16;
737 strncpy(act, me_ctrl_actions[i].name, 31);
738 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
743 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
744 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
745 mask = emuctrl_actions[i].mask;
747 strncpy(act, emuctrl_actions[i].name, 31);
748 fprintf(f, "bind %s = %s\n", name, mystrip(act));
754 for (k = 0; k < array_size(in_adev); k++)
757 fprintf(f, "bind_analog = %d\n", k);
762 static int parse_bind_val(const char *val, int *type)
766 *type = IN_BINDTYPE_NONE;
770 if (strncasecmp(val, "player", 6) == 0)
772 int player, shift = 0;
773 player = atoi(val + 6) - 1;
775 if ((unsigned int)player > 1)
780 *type = IN_BINDTYPE_PLAYER12;
781 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
782 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
783 return me_ctrl_actions[i].mask << shift;
786 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
787 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
788 *type = IN_BINDTYPE_EMU;
789 return emuctrl_actions[i].mask;
796 static void keys_load_all(const char *cfg)
798 char dev[256], key[128], *act;
804 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
807 get_line(dev, sizeof(dev), p);
808 dev_id = in_config_parse_dev(dev);
810 printf("input: can't handle dev: %s\n", dev);
814 in_unbind_all(dev_id, -1, -1);
815 while ((p = strstr(p, "bind"))) {
816 if (strncmp(p, "binddev = ", 10) == 0)
819 if (strncmp(p, "bind_analog", 11) == 0) {
820 ret = sscanf(p, "bind_analog = %d", &bind);
823 printf("input: parse error: %16s..\n", p);
826 if ((unsigned int)bind >= array_size(in_adev)) {
827 printf("input: analog id %d out of range\n", bind);
830 in_adev[bind] = dev_id;
836 printf("input: parse error: %16s..\n", p);
840 get_line(key, sizeof(key), p);
841 act = strchr(key, '=');
843 printf("parse failed: %16s..\n", p);
851 bind = parse_bind_val(act, &bindtype);
852 if (bind != -1 && bind != 0) {
853 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
854 in_config_bind_key(dev_id, key, bind, bindtype);
857 lprintf("config: unhandled action \"%s\"\n", act);
863 static int key_config_loop_wrap(int id, int keys)
866 case MA_CTRL_PLAYER1:
867 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
869 case MA_CTRL_PLAYER2:
870 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
873 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
881 static const char *adevnames[IN_MAX_DEVS + 2];
882 static int stick_sel[2];
884 static menu_entry e_menu_keyconfig_analog[] =
886 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
887 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
888 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
889 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
890 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
891 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
895 static int key_config_analog(int id, int keys)
897 int i, d, count, sel = 0;
898 int sel2dev_map[IN_MAX_DEVS];
900 memset(adevnames, 0, sizeof(adevnames));
901 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
902 memset(stick_sel, 0, sizeof(stick_sel));
904 adevnames[0] = "None";
906 for (d = 0; d < IN_MAX_DEVS; d++)
908 const char *name = in_get_dev_name(d, 0, 1);
913 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
917 if (in_adev[0] == d) stick_sel[0] = i;
918 if (in_adev[1] == d) stick_sel[1] = i;
920 adevnames[i++] = name;
924 me_loop(e_menu_keyconfig_analog, &sel);
926 in_adev[0] = sel2dev_map[stick_sel[0]];
927 in_adev[1] = sel2dev_map[stick_sel[1]];
932 static const char *mgn_dev_name(int id, int *offs)
934 const char *name = NULL;
937 if (id == MA_CTRL_DEV_FIRST)
940 for (; it < IN_MAX_DEVS; it++) {
941 name = in_get_dev_name(it, 1, 1);
950 static const char *mgn_saveloadcfg(int id, int *offs)
955 static int mh_savecfg(int id, int keys)
957 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
958 me_update_msg("config saved");
960 me_update_msg("failed to write config");
965 static int mh_input_rescan(int id, int keys)
967 //menu_sync_config();
969 me_update_msg("rescan complete.");
974 static const char *men_in_type_sel[] = {
975 "Standard (SCPH-1080)",
976 "Analog (SCPH-1150)",
980 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
981 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
982 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
984 static menu_entry e_menu_keyconfig[] =
986 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
987 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
988 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
989 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
991 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
992 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
993 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
994 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
995 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
996 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
997 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
998 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
999 mee_handler ("Rescan devices:", mh_input_rescan),
1001 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1002 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1003 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1004 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1005 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1006 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1007 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1011 static int menu_loop_keyconfig(int id, int keys)
1015 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1016 me_loop(e_menu_keyconfig, &sel);
1020 // ------------ gfx options menu ------------
1022 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1023 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1024 "using d-pad or move it using R+d-pad";
1025 static const char *men_dummy[] = { NULL };
1027 static int menu_loop_cscaler(int id, int keys)
1031 scaling = SCALE_CUSTOM;
1033 plat_gvideo_open(Config.PsxType);
1038 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1039 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1040 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1043 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1044 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1045 if (inp & PBTN_UP) g_layer_y--;
1046 if (inp & PBTN_DOWN) g_layer_y++;
1047 if (inp & PBTN_LEFT) g_layer_x--;
1048 if (inp & PBTN_RIGHT) g_layer_x++;
1049 if (!(inp & PBTN_R)) {
1050 if (inp & PBTN_UP) g_layer_h += 2;
1051 if (inp & PBTN_DOWN) g_layer_h -= 2;
1052 if (inp & PBTN_LEFT) g_layer_w += 2;
1053 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1055 if (inp & (PBTN_MOK|PBTN_MBACK))
1058 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1059 if (g_layer_x < 0) g_layer_x = 0;
1060 if (g_layer_x > 640) g_layer_x = 640;
1061 if (g_layer_y < 0) g_layer_y = 0;
1062 if (g_layer_y > 420) g_layer_y = 420;
1063 if (g_layer_w < 160) g_layer_w = 160;
1064 if (g_layer_h < 60) g_layer_h = 60;
1065 if (g_layer_x + g_layer_w > 800)
1066 g_layer_w = 800 - g_layer_x;
1067 if (g_layer_y + g_layer_h > 480)
1068 g_layer_h = 480 - g_layer_y;
1070 plat_gvideo_open(Config.PsxType);
1074 plat_gvideo_close();
1079 static menu_entry e_menu_gfx_options[] =
1081 mee_enum ("Scaler", MA_OPT_SCALER, scaling, men_scaler),
1082 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1083 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1084 // mee_onoff ("Vsync", 0, vsync, 1),
1085 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1089 static int menu_loop_gfx_options(int id, int keys)
1093 me_loop(e_menu_gfx_options, &sel);
1099 void menu_set_filter_list(void *filters)
1103 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1104 e_menu_gfx_options[i].data = filters;
1105 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1108 // ------------ bios/plugins ------------
1112 static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
1113 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1115 static menu_entry e_menu_plugin_gpu_neon[] =
1117 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1121 static int menu_loop_plugin_gpu_neon(int id, int keys)
1124 me_loop(e_menu_plugin_gpu_neon, &sel);
1130 static menu_entry e_menu_plugin_gpu_unai[] =
1132 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1133 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1134 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1135 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1139 static int menu_loop_plugin_gpu_unai(int id, int keys)
1142 me_loop(e_menu_plugin_gpu_unai, &sel);
1146 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1147 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1148 static const char h_gpu_1[] = "Capcom fighting games";
1149 static const char h_gpu_2[] = "Black screens in Lunar";
1150 static const char h_gpu_3[] = "Compatibility mode";
1151 static const char h_gpu_6[] = "Pandemonium 2";
1152 //static const char h_gpu_7[] = "Skip every second frame";
1153 static const char h_gpu_8[] = "Needed by Dark Forces";
1154 static const char h_gpu_9[] = "better g-colors, worse textures";
1155 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1157 static menu_entry e_menu_plugin_gpu_peops[] =
1159 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1160 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1161 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1162 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1163 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1164 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1165 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1166 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1167 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1168 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1172 static int menu_loop_plugin_gpu_peops(int id, int keys)
1175 me_loop(e_menu_plugin_gpu_peops, &sel);
1179 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1180 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1181 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1183 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1185 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1186 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1187 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1188 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1189 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1190 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1191 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1192 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1193 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1194 mee_label ("Fixes/hacks:"),
1195 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1196 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1197 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1198 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1199 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1200 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1201 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1202 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1203 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1204 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1205 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1209 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1212 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1216 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1217 static const char h_spu_volboost[] = "Large values cause distortion";
1219 static menu_entry e_menu_plugin_spu[] =
1221 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1222 mee_onoff ("Reverb", 0, iUseReverb, 2),
1223 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1224 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1228 static int menu_loop_plugin_spu(int id, int keys)
1231 me_loop(e_menu_plugin_spu, &sel);
1235 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1236 "savestates and can't be changed there. Must save\n"
1237 "config and reload the game for change to take effect";
1238 static const char h_plugin_gpu[] =
1240 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1245 "is Pete's soft GPU, slow but accurate\n"
1246 "gpuPCSX4ALL is GPU from PCSX4ALL, fast but glitchy\n"
1247 "gpuGLES Pete's hw GPU, uses 3D chip but is glitchy\n"
1248 "must save config and reload the game if changed";
1249 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1250 "must save config and reload the game if changed";
1251 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1252 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1253 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1254 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1256 static menu_entry e_menu_plugin_options[] =
1258 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1259 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1260 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1262 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1264 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1265 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1266 mee_handler_h ("Configure GLES GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1267 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1271 static menu_entry e_menu_main2[];
1273 static int menu_loop_plugin_options(int id, int keys)
1276 me_loop(e_menu_plugin_options, &sel);
1278 // sync BIOS/plugins
1279 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1280 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1281 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1282 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1287 // ------------ adv options menu ------------
1289 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1290 "(lower value - less work for the emu, may be faster)";
1291 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1292 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1293 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1295 static menu_entry e_menu_speed_hacks[] =
1297 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1298 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1299 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1300 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1304 static int menu_loop_speed_hacks(int id, int keys)
1307 me_loop(e_menu_speed_hacks, &sel);
1311 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1312 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1313 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1314 "(green: normal, red: fmod, blue: noise)";
1315 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1316 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1317 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1318 "(proper .cue/.bin dump is needed otherwise)";
1319 static const char h_cfg_sio[] = "You should not need this, breaks games";
1320 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1321 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1322 "(timing hack, breaks other games)";
1323 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1324 "(timing hack, breaks other games)";
1325 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1326 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1327 "Might be useful to overcome some dynarec bugs";
1328 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1329 "must reload game for any change to take effect";
1331 static menu_entry e_menu_adv_options[] =
1333 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1334 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1335 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1336 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1337 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1338 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1339 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1340 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1341 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1342 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1343 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1344 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1348 static int menu_loop_adv_options(int id, int keys)
1351 me_loop(e_menu_adv_options, &sel);
1355 // ------------ options menu ------------
1357 static int mh_restore_defaults(int id, int keys)
1359 menu_set_defconfig();
1360 me_update_msg("defaults restored");
1364 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1365 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1367 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1368 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1369 "loading state or both";
1371 static const char h_restore_def[] = "Switches back to default / recommended\n"
1373 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1375 static menu_entry e_menu_options[] =
1377 // mee_range ("Save slot", 0, state_slot, 0, 9),
1378 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1379 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1380 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1381 mee_enum ("Region", 0, region, men_region),
1382 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1383 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1384 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1385 mee_handler ("[Advanced]", menu_loop_adv_options),
1386 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1387 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1388 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1392 static int menu_loop_options(int id, int keys)
1397 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1398 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1399 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1401 me_loop(e_menu_options, &sel);
1406 // ------------ debug menu ------------
1408 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1410 int w = min(g_menuscreen_w, 1024);
1411 int h = min(g_menuscreen_h, 512);
1412 u16 *d = g_menuscreen_ptr;
1413 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1417 gpuf->ulFreezeVersion = 1;
1418 if (GPU_freeze != NULL)
1419 GPU_freeze(1, gpuf);
1421 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1422 bgr555_to_rgb565(d, s, w * 2);
1424 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1425 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1426 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1427 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1428 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1431 static void debug_menu_loop(void)
1433 int inp, df_x = 0, df_y = 0;
1436 gpuf = malloc(sizeof(*gpuf));
1443 draw_frame_debug(gpuf, df_x, df_y);
1446 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1447 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1448 if (inp & PBTN_MBACK) break;
1449 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1450 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1451 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1452 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1458 // --------- memcard manager ---------
1460 static void draw_mc_icon(int dx, int dy, const u16 *s)
1465 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1467 for (y = 0; y < 16; y++, s += 16) {
1468 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1469 for (x = 0; x < 16; x++) {
1471 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1472 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1478 static void draw_mc_bg(void)
1480 McdBlock *blocks1, *blocks2;
1484 blocks1 = malloc(15 * sizeof(blocks1[0]));
1485 blocks2 = malloc(15 * sizeof(blocks1[0]));
1486 if (blocks1 == NULL || blocks2 == NULL)
1489 for (i = 0; i < 15; i++) {
1490 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1491 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1496 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1498 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1502 maxicons = g_menuscreen_h / 32;
1505 row2 = g_menuscreen_w / 2;
1506 for (i = 0; i < maxicons; i++) {
1507 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1508 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1510 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1511 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1514 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1522 static void handle_memcard_sel(void)
1525 if (memcard1_sel != 0)
1526 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1528 if (memcard2_sel != 0)
1529 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1530 LoadMcds(Config.Mcd1, Config.Mcd2);
1534 static menu_entry e_memcard_options[] =
1536 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1537 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1541 static int menu_loop_memcards(int id, int keys)
1547 memcard1_sel = memcard2_sel = 0;
1548 p = strrchr(Config.Mcd1, '/');
1550 for (i = 0; memcards[i] != NULL; i++)
1551 if (strcmp(p + 1, memcards[i]) == 0)
1552 { memcard1_sel = i; break; }
1553 p = strrchr(Config.Mcd2, '/');
1555 for (i = 0; memcards[i] != NULL; i++)
1556 if (strcmp(p + 1, memcards[i]) == 0)
1557 { memcard2_sel = i; break; }
1559 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1561 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1566 // ------------ cheats menu ------------
1568 static void draw_cheatlist(int sel)
1570 int max_cnt, start, i, pos, active;
1572 max_cnt = g_menuscreen_h / me_sfont_h;
1573 start = max_cnt / 2 - sel;
1577 for (i = 0; i < NumCheats; i++) {
1579 if (pos < 0) continue;
1580 if (pos >= max_cnt) break;
1581 active = Cheats[i].Enabled;
1582 smalltext_out16(14, pos * me_sfont_h,
1583 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1584 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1585 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1589 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1591 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1595 static void menu_loop_cheats(void)
1597 static int menu_sel = 0;
1602 draw_cheatlist(menu_sel);
1603 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1604 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1605 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1606 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1607 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1608 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1609 if (inp & PBTN_MOK) { // action
1610 if (menu_sel < NumCheats)
1611 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1614 if (inp & PBTN_MBACK)
1619 // --------- main menu help ----------
1621 static void menu_bios_warn(void)
1624 static const char msg[] =
1625 "You don't seem to have copied any BIOS\n"
1627 #ifdef __ARM_ARCH_7A__ // XXX
1628 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1630 "pcsx_rearmed/bios/\n\n"
1632 "While many games work fine with fake\n"
1633 "(HLE) BIOS, others (like MGS and FF8)\n"
1634 "require BIOS to work.\n"
1635 "After copying the file, you'll also need\n"
1636 "to select it in the emu's menu:\n"
1637 "options->[BIOS/Plugins]\n\n"
1638 "The file is usually named SCPH1001.BIN,\n"
1639 "but other not compressed files can be\n"
1641 "Press %s or %s to continue";
1642 char tmp_msg[sizeof(msg) + 64];
1644 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1645 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1648 draw_menu_message(tmp_msg, NULL);
1650 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1651 if (inp & (PBTN_MBACK|PBTN_MOK))
1656 // ------------ main menu ------------
1658 static menu_entry e_menu_main[];
1661 static void draw_frame_main(void)
1670 if (CdromId[0] != 0) {
1671 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1672 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1673 Config.HLE ? "HLE" : "BIOS");
1674 smalltext_out16(4, 1, buff, 0x105f);
1678 capacity = plat_get_bat_capacity();
1680 tmp = localtime(<ime);
1681 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1682 if (capacity >= 0) {
1683 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1688 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1692 static void draw_frame_credits(void)
1694 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1697 static const char credits_text[] =
1699 "(C) 1999-2003 PCSX Team\n"
1700 "(C) 2005-2009 PCSX-df Team\n"
1701 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1702 "ARM recompiler (C) 2009-2011 Ari64\n"
1704 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1706 "PEOpS GPU and SPU by Pete Bernert\n"
1707 " and the P.E.Op.S. team\n"
1708 "PCSX4ALL plugin by PCSX4ALL team\n"
1709 " Chui, Franxis, Unai\n\n"
1710 "integration, optimization and\n"
1711 " frontend (C) 2010-2012 notaz\n";
1713 static int reset_game(void)
1716 if (bios_sel == 0 && !Config.HLE)
1722 if (CheckCdrom() != -1) {
1728 static int reload_plugins(const char *cdimg)
1734 set_cd_image(cdimg);
1736 pcnt_hook_plugins();
1738 if (OpenPlugins() == -1) {
1739 me_update_msg("failed to open plugins");
1742 plugin_call_rearmed_cbs();
1744 cdrIsoMultidiskCount = 1;
1746 CdromLabel[0] = '\0';
1751 static int run_bios(void)
1757 if (reload_plugins(NULL) != 0)
1765 static int run_exe(void)
1769 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1774 if (reload_plugins(NULL) != 0)
1778 if (Load(fname) != 0) {
1779 me_update_msg("exe load failed, bad file?");
1788 static int run_cd_image(const char *fname)
1791 reload_plugins(fname);
1793 // always autodetect, menu_sync_config will override as needed
1796 if (CheckCdrom() == -1) {
1797 // Only check the CD if we are starting the console with a CD
1799 me_update_msg("unsupported/invalid CD image");
1805 // Read main executable directly from CDRom and start it
1806 if (LoadCdrom() == -1) {
1808 me_update_msg("failed to load CD image");
1818 static int romsel_run(void)
1820 int prev_gpu, prev_spu;
1823 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1827 printf("selected file: %s\n", fname);
1829 new_dynarec_clear_full();
1831 if (run_cd_image(fname) != 0)
1834 prev_gpu = gpu_plugsel;
1835 prev_spu = spu_plugsel;
1836 if (menu_load_config(1) != 0)
1837 menu_load_config(0);
1839 // check for plugin changes, have to repeat
1840 // loading if game config changed plugins to reload them
1841 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1842 printf("plugin change detected, reloading plugins..\n");
1843 if (run_cd_image(fname) != 0)
1847 strcpy(last_selected_fname, rom_fname_reload);
1851 static int swap_cd_image(void)
1855 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1859 printf("selected file: %s\n", fname);
1862 CdromLabel[0] = '\0';
1864 set_cd_image(fname);
1865 if (ReloadCdromPlugin() < 0) {
1866 me_update_msg("failed to load cdr plugin");
1869 if (CDR_open() < 0) {
1870 me_update_msg("failed to open cdr plugin");
1874 SetCdOpenCaseTime(time(NULL) + 2);
1877 strcpy(last_selected_fname, rom_fname_reload);
1881 static int swap_cd_multidisk(void)
1883 cdrIsoMultidiskSelect++;
1885 CdromLabel[0] = '\0';
1888 if (CDR_open() < 0) {
1889 me_update_msg("failed to open cdr plugin");
1893 SetCdOpenCaseTime(time(NULL) + 2);
1899 static void load_pcsx_cht(void)
1905 fname = menu_loop_romsel(path, sizeof(path));
1909 printf("selected cheat file: %s\n", fname);
1912 if (NumCheats == 0 && NumCodes == 0)
1913 me_update_msg("failed to load cheats");
1915 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1916 me_update_msg(path);
1918 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1921 static int main_menu_handler(int id, int keys)
1925 case MA_MAIN_RESUME_GAME:
1929 case MA_MAIN_SAVE_STATE:
1931 return menu_loop_savestate(0);
1933 case MA_MAIN_LOAD_STATE:
1935 return menu_loop_savestate(1);
1937 case MA_MAIN_RESET_GAME:
1938 if (ready_to_go && reset_game() == 0)
1941 case MA_MAIN_LOAD_ROM:
1942 if (romsel_run() == 0)
1945 case MA_MAIN_SWAP_CD:
1946 if (swap_cd_image() == 0)
1949 case MA_MAIN_SWAP_CD_MULTI:
1950 if (swap_cd_multidisk() == 0)
1953 case MA_MAIN_RUN_BIOS:
1954 if (run_bios() == 0)
1957 case MA_MAIN_RUN_EXE:
1961 case MA_MAIN_CHEATS:
1964 case MA_MAIN_LOAD_CHEATS:
1967 case MA_MAIN_CREDITS:
1968 draw_menu_message(credits_text, draw_frame_credits);
1969 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1975 lprintf("%s: something unknown selected\n", __FUNCTION__);
1982 static menu_entry e_menu_main2[] =
1984 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1985 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1986 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1987 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1988 mee_handler ("Memcard manager", menu_loop_memcards),
1989 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
1993 static int main_menu2_handler(int id, int keys)
1997 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1998 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1999 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2000 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2002 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2005 static const char h_extra[] = "Change CD, manage memcards..\n";
2007 static menu_entry e_menu_main[] =
2011 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2012 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2013 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2014 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2015 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2016 mee_handler ("Options", menu_loop_options),
2017 mee_handler ("Controls", menu_loop_keyconfig),
2018 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2019 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2020 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2021 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2025 // ----------------------------
2027 static void menu_leave_emu(void);
2029 void menu_loop(void)
2035 if (bioses[1] == NULL && !warned_about_bios) {
2037 warned_about_bios = 1;
2040 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2041 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2042 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2043 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2044 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2046 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2049 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2050 } while (!ready_to_go);
2052 /* wait until menu, ok, back is released */
2053 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2056 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2061 static int qsort_strcmp(const void *p1, const void *p2)
2063 char * const *s1 = (char * const *)p1;
2064 char * const *s2 = (char * const *)p2;
2065 return strcasecmp(*s1, *s2);
2068 static void scan_bios_plugins(void)
2070 char fname[MAXPATHLEN];
2072 int bios_i, gpu_i, spu_i, mc_i;
2077 gpu_plugins[0] = "builtin_gpu";
2078 spu_plugins[0] = "builtin_spu";
2079 memcards[0] = "(none)";
2080 bios_i = gpu_i = spu_i = mc_i = 1;
2082 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2083 dir = opendir(fname);
2085 perror("scan_bios_plugins bios opendir");
2100 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2103 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2104 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2105 printf("bad BIOS file: %s\n", ent->d_name);
2109 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2110 bioses[bios_i++] = strdup(ent->d_name);
2114 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2120 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2121 dir = opendir(fname);
2123 perror("scan_bios_plugins plugins opendir");
2137 p = strstr(ent->d_name, ".so");
2141 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2142 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2144 fprintf(stderr, "%s\n", dlerror());
2148 // now what do we have here?
2149 tmp = dlsym(h, "GPUinit");
2152 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2153 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2157 tmp = dlsym(h, "SPUinit");
2160 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2161 spu_plugins[spu_i++] = strdup(ent->d_name);
2165 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2172 dir = opendir("." MEMCARD_DIR);
2174 perror("scan_bios_plugins memcards opendir");
2189 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2192 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2193 if (stat(fname, &st) != 0) {
2194 printf("bad memcard file: %s\n", ent->d_name);
2198 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2199 memcards[mc_i++] = strdup(ent->d_name);
2203 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2207 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2212 void menu_init(void)
2214 char buff[MAXPATHLEN];
2216 strcpy(last_selected_fname, "/media");
2218 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2220 scan_bios_plugins();
2223 menu_set_defconfig();
2224 menu_load_config(0);
2229 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2230 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2231 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2232 fprintf(stderr, "OOM\n");
2236 emu_make_path(buff, "skin/background.png", sizeof(buff));
2237 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2239 #ifndef __ARM_ARCH_7A__ /* XXX */
2240 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2241 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2242 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2243 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2245 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2246 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2247 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2251 void menu_notify_mode_change(int w, int h, int bpp)
2260 // XXX: should really menu code cotrol the layer size?
2263 g_layer_w = w; g_layer_h = h;
2267 if (h > g_menuscreen_h || (240 < h && h <= 360))
2268 goto fractional_4_3;
2270 // 4:3 that prefers integer scaling
2271 imult = g_menuscreen_h / h;
2272 g_layer_w = w * imult;
2273 g_layer_h = h * imult;
2274 mult = (float)g_layer_w / (float)g_layer_h;
2275 if (mult < 1.25f || mult > 1.666f)
2276 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2277 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2282 mult = 240.0f / (float)h * 4.0f / 3.0f;
2285 g_layer_w = mult * (float)g_menuscreen_h;
2286 g_layer_h = g_menuscreen_h;
2287 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2290 case SCALE_FULLSCREEN:
2291 g_layer_w = g_menuscreen_w;
2292 g_layer_h = g_menuscreen_h;
2299 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2300 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2301 if (g_layer_x < 0) g_layer_x = 0;
2302 if (g_layer_y < 0) g_layer_y = 0;
2303 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2304 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2307 static void menu_leave_emu(void)
2309 if (GPU_close != NULL) {
2310 int ret = GPU_close();
2312 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2315 plat_video_menu_enter(ready_to_go);
2317 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2318 if (pl_vout_buf != NULL && ready_to_go) {
2319 int x = max(0, g_menuscreen_w - last_psx_w);
2320 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2321 int w = min(g_menuscreen_w, last_psx_w);
2322 int h = min(g_menuscreen_h, last_psx_h);
2323 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2324 char *s = pl_vout_buf;
2326 if (last_psx_bpp == 16) {
2327 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 2)
2328 menu_darken_bg(d, s, w, 0);
2331 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 3) {
2332 rgb888_to_rgb565(d, s, w * 3);
2333 menu_darken_bg(d, d, w, 0);
2339 cpu_clock = plat_cpu_clock_get();
2342 void menu_prepare_emu(void)
2344 R3000Acpu *prev_cpu = psxCpu;
2346 plat_video_menu_leave();
2348 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2350 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2351 if (psxCpu != prev_cpu)
2352 // note that this does not really reset, just clears drc caches
2355 // core doesn't care about Config.Cdda changes,
2356 // so handle them manually here
2362 plat_cpu_clock_apply(cpu_clock);
2364 // push config to GPU plugin
2365 plugin_call_rearmed_cbs();
2367 if (GPU_open != NULL) {
2368 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2370 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2376 void me_update_msg(const char *msg)
2378 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2379 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2381 menu_error_time = plat_get_ticks_ms();
2382 lprintf("msg: %s\n", menu_error_msg);
2385 void menu_finish(void)
2387 plat_cpu_clock_apply(cpu_clock_st);