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 "libpicofe/plat.h"
28 #include "libpicofe/input.h"
29 #include "libpicofe/linux/in_evdev.h"
30 #include "libpicofe/plat.h"
31 #include "../libpcsxcore/misc.h"
32 #include "../libpcsxcore/cdrom.h"
33 #include "../libpcsxcore/cdriso.h"
34 #include "../libpcsxcore/cheat.h"
35 #include "../libpcsxcore/psemu_plugin_defs.h"
36 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
37 #include "../plugins/dfinput/main.h"
38 #include "../plugins/gpulib/cspace.h"
41 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
43 #define array_size(x) (sizeof(x) / sizeof(x[0]))
54 MA_MAIN_SWAP_CD_MULTI,
84 static int last_vout_w, last_vout_h, last_vout_bpp;
85 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
86 static char rom_fname_reload[MAXPATHLEN];
87 static char last_selected_fname[MAXPATHLEN];
88 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
90 static int memcard1_sel, memcard2_sel;
91 int g_opts, g_scaler, g_gamma = 100;
92 int soft_scaling, analog_deadzone; // for Caanoo
93 int filter, soft_filter;
95 #ifdef __ARM_ARCH_7A__
96 #define DEFAULT_PSX_CLOCK 57
97 #define DEFAULT_PSX_CLOCK_S "57"
99 #define DEFAULT_PSX_CLOCK 50
100 #define DEFAULT_PSX_CLOCK_S "50"
104 extern int iUseReverb;
105 extern int iUseInterpolation;
109 static const char *bioses[24];
110 static const char *gpu_plugins[16];
111 static const char *spu_plugins[16];
112 static const char *memcards[32];
113 static int bios_sel, gpu_plugsel, spu_plugsel;
116 static int min(int x, int y) { return x < y ? x : y; }
117 static int max(int x, int y) { return x > y ? x : y; }
119 void emu_make_path(char *buff, const char *end, int size)
123 end_len = strlen(end);
124 pos = plat_get_root_dir(buff, size);
125 strncpy(buff + pos, end, size - pos);
127 if (pos + end_len > size - 1)
128 printf("Warning: path truncated: %s\n", buff);
131 static int emu_check_save_file(int slot, int *time)
133 char fname[MAXPATHLEN];
137 ret = emu_check_state(slot);
138 if (ret != 0 || time == NULL)
139 return ret == 0 ? 1 : 0;
141 ret = get_state_filename(fname, sizeof(fname), slot);
145 ret = stat(fname, &status);
149 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
150 return 1; // probably bad rtc like on some Caanoos
152 *time = status.st_mtime;
157 static int emu_save_load_game(int load, int unused)
162 ret = emu_load_state(state_slot);
164 // reflect hle/bios mode from savestate
167 else if (bios_sel == 0 && bioses[1] != NULL)
168 // XXX: maybe find the right bios instead
172 ret = emu_save_state(state_slot);
177 // propagate menu settings to the emu vars
178 static void menu_sync_config(void)
180 static int allow_abs_only_old;
185 Config.PsxType = region - 1;
187 cycle_multiplier = 10000 / psx_clock;
189 switch (in_type_sel1) {
190 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
191 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
192 default: in_type1 = PSE_PAD_TYPE_STANDARD;
194 switch (in_type_sel2) {
195 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
196 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
197 default: in_type2 = PSE_PAD_TYPE_STANDARD;
199 if (in_evdev_allow_abs_only != allow_abs_only_old) {
201 allow_abs_only_old = in_evdev_allow_abs_only;
204 iVolume = 768 + 128 * volume_boost;
205 pl_rearmed_cbs.frameskip = frameskip - 1;
206 pl_timing_prepare(Config.PsxType);
209 static void menu_set_defconfig(void)
211 emu_set_default_config();
214 g_scaler = SCALE_4_3;
217 analog_deadzone = 50;
220 psx_clock = DEFAULT_PSX_CLOCK;
223 in_type_sel1 = in_type_sel2 = 0;
224 in_evdev_allow_abs_only = 0;
229 #define CE_CONFIG_STR(val) \
230 { #val, 0, Config.val }
232 #define CE_CONFIG_VAL(val) \
233 { #val, sizeof(Config.val), &Config.val }
235 #define CE_STR(val) \
238 #define CE_INTVAL(val) \
239 { #val, sizeof(val), &val }
241 #define CE_INTVAL_P(val) \
242 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
244 // 'versioned' var, used when defaults change
245 #define CE_CONFIG_STR_V(val, ver) \
246 { #val #ver, 0, Config.val }
248 #define CE_INTVAL_V(val, ver) \
249 { #val #ver, sizeof(val), &val }
251 #define CE_INTVAL_PV(val, ver) \
252 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
254 static const struct {
260 CE_CONFIG_STR_V(Gpu, 3),
262 // CE_CONFIG_STR(Cdr),
267 CE_CONFIG_VAL(Debug),
268 CE_CONFIG_VAL(PsxOut),
269 CE_CONFIG_VAL(SpuIrq),
270 CE_CONFIG_VAL(RCntFix),
271 CE_CONFIG_VAL(VSyncWA),
273 CE_CONFIG_VAL(CdrReschedule),
275 CE_INTVAL_V(g_scaler, 2),
276 CE_INTVAL(g_layer_x),
277 CE_INTVAL(g_layer_y),
278 CE_INTVAL(g_layer_w),
279 CE_INTVAL(g_layer_h),
281 CE_INTVAL(soft_filter),
282 CE_INTVAL(state_slot),
283 CE_INTVAL(cpu_clock),
285 CE_INTVAL(in_type_sel1),
286 CE_INTVAL(in_type_sel2),
287 CE_INTVAL(analog_deadzone),
288 CE_INTVAL_V(frameskip, 3),
289 CE_INTVAL_P(gpu_peops.iUseDither),
290 CE_INTVAL_P(gpu_peops.dwActFixes),
291 CE_INTVAL_P(gpu_unai.lineskip),
292 CE_INTVAL_P(gpu_unai.abe_hack),
293 CE_INTVAL_P(gpu_unai.no_light),
294 CE_INTVAL_P(gpu_unai.no_blend),
295 CE_INTVAL_P(gpu_neon.allow_interlace),
296 CE_INTVAL_P(gpu_neon.enhancement_enable),
297 CE_INTVAL_P(gpu_neon.enhancement_no_main),
298 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
299 CE_INTVAL_P(gpu_peopsgl.iFilterType),
300 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
301 CE_INTVAL_P(gpu_peopsgl.iUseMask),
302 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
303 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
304 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
305 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
306 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
307 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
308 CE_INTVAL_V(iUseReverb, 3),
309 CE_INTVAL_V(iXAPitch, 3),
310 CE_INTVAL_V(iUseInterpolation, 3),
311 CE_INTVAL(warned_about_bios),
312 CE_INTVAL(in_evdev_allow_abs_only),
313 CE_INTVAL(volume_boost),
314 CE_INTVAL(psx_clock),
315 CE_INTVAL(new_dynarec_hacks),
316 CE_INTVAL(in_enable_vibration),
319 static char *get_cd_label(void)
321 static char trimlabel[33];
324 strncpy(trimlabel, CdromLabel, 32);
326 for (j = 31; j >= 0; j--)
327 if (trimlabel[j] == ' ')
333 static void make_cfg_fname(char *buf, size_t size, int is_game)
336 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
338 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
341 static void keys_write_all(FILE *f);
342 static char *mystrip(char *str);
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 (int)config_data[i].len, config_data[i].name);
385 static int menu_do_last_cd_img(int is_get)
391 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
392 f = fopen(path, is_get ? "r" : "w");
397 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
398 last_selected_fname[ret] = 0;
399 mystrip(last_selected_fname);
402 fprintf(f, "%s\n", last_selected_fname);
408 static void parse_str_val(char *cval, const char *src)
411 strncpy(cval, src, MAXPATHLEN);
412 cval[MAXPATHLEN - 1] = 0;
413 tmp = strchr(cval, '\n');
415 tmp = strchr(cval, '\r');
420 static void keys_load_all(const char *cfg);
422 static int menu_load_config(int is_game)
424 char cfgfile[MAXPATHLEN];
430 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
431 f = fopen(cfgfile, "r");
433 printf("menu_load_config: failed to open: %s\n", cfgfile);
437 fseek(f, 0, SEEK_END);
440 printf("bad size %ld: %s\n", size, cfgfile);
444 cfg = malloc(size + 1);
448 fseek(f, 0, SEEK_SET);
449 if (fread(cfg, 1, size, f) != size) {
450 printf("failed to read: %s\n", cfgfile);
455 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
459 tmp = strstr(cfg, config_data[i].name);
462 tmp += strlen(config_data[i].name);
463 if (strncmp(tmp, " = ", 3) != 0)
467 if (config_data[i].len == 0) {
468 parse_str_val(config_data[i].val, tmp);
473 val = strtoul(tmp, &tmp2, 16);
474 if (tmp2 == NULL || tmp == tmp2)
475 continue; // parse failed
477 switch (config_data[i].len) {
479 *(u8 *)config_data[i].val = val;
482 *(u16 *)config_data[i].val = val;
485 *(u32 *)config_data[i].val = val;
488 printf("menu_load_config: unhandled len %d for %s\n",
489 (int)config_data[i].len, config_data[i].name);
495 char *tmp = strstr(cfg, "lastcdimg = ");
498 parse_str_val(last_selected_fname, tmp);
513 for (i = bios_sel = 0; bioses[i] != NULL; i++)
514 if (strcmp(Config.Bios, bioses[i]) == 0)
515 { bios_sel = i; break; }
517 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
518 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
519 { gpu_plugsel = i; break; }
521 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
522 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
523 { spu_plugsel = i; break; }
528 // rrrr rggg gggb bbbb
529 static unsigned short fname2color(const char *fname)
531 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
532 ".bz", ".znx", ".pbp", ".cbn" };
533 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
534 ".table", ".index", ".sbi" };
535 const char *ext = strrchr(fname, '.');
540 for (i = 0; i < array_size(cdimg_exts); i++)
541 if (strcasecmp(ext, cdimg_exts[i]) == 0)
543 for (i = 0; i < array_size(other_exts); i++)
544 if (strcasecmp(ext, other_exts[i]) == 0)
549 static void draw_savestate_bg(int slot);
551 static const char *filter_exts[] = {
552 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
555 #define MENU_ALIGN_LEFT
556 #ifdef __ARM_ARCH_7A__ // assume hires device
562 #include "libpicofe/menu.c"
564 // a bit of black magic here
565 static void draw_savestate_bg(int slot)
567 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
569 char fname[MAXPATHLEN];
576 ret = get_state_filename(fname, sizeof(fname), slot);
580 f = gzopen(fname, "rb");
584 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
585 fprintf(stderr, "gzseek failed\n");
590 gpu = malloc(sizeof(*gpu));
596 ret = gzread(f, gpu, sizeof(*gpu));
598 if (ret != sizeof(*gpu)) {
599 fprintf(stderr, "gzread failed\n");
603 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
605 if (gpu->ulStatus & 0x800000)
606 goto out; // disabled
608 x = gpu->ulControl[5] & 0x3ff;
609 y = (gpu->ulControl[5] >> 10) & 0x1ff;
610 s = (u16 *)gpu->psxVRam + y * 1024 + x;
611 w = psx_widths[(gpu->ulStatus >> 16) & 7];
612 tmp = gpu->ulControl[7];
613 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
614 if (gpu->ulStatus & 0x80000) // doubleheight
617 x = max(0, g_menuscreen_w - w) & ~3;
618 y = max(0, g_menuscreen_h / 2 - h / 2);
619 w = min(g_menuscreen_w, w);
620 h = min(g_menuscreen_h, h);
621 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
623 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
624 if (gpu->ulStatus & 0x200000)
625 bgr888_to_rgb565(d, s, w * 3);
627 bgr555_to_rgb565(d, s, w * 2);
629 // darken this so that menu text is visible
630 if (g_menuscreen_w - w < 320)
631 menu_darken_bg(d, d, w * 2, 0);
638 // -------------- key config --------------
640 me_bind_action me_ctrl_actions[] =
642 { "UP ", 1 << DKEY_UP},
643 { "DOWN ", 1 << DKEY_DOWN },
644 { "LEFT ", 1 << DKEY_LEFT },
645 { "RIGHT ", 1 << DKEY_RIGHT },
646 { "TRIANGLE", 1 << DKEY_TRIANGLE },
647 { "CIRCLE ", 1 << DKEY_CIRCLE },
648 { "CROSS ", 1 << DKEY_CROSS },
649 { "SQUARE ", 1 << DKEY_SQUARE },
650 { "L1 ", 1 << DKEY_L1 },
651 { "R1 ", 1 << DKEY_R1 },
652 { "L2 ", 1 << DKEY_L2 },
653 { "R2 ", 1 << DKEY_R2 },
654 { "L3 ", 1 << DKEY_L3 },
655 { "R3 ", 1 << DKEY_R3 },
656 { "START ", 1 << DKEY_START },
657 { "SELECT ", 1 << DKEY_SELECT },
661 me_bind_action emuctrl_actions[] =
663 { "Save State ", 1 << SACTION_SAVE_STATE },
664 { "Load State ", 1 << SACTION_LOAD_STATE },
665 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
666 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
667 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
668 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
669 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
670 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
671 #ifdef __ARM_ARCH_7A__ /* XXX */
672 { "Minimize ", 1 << SACTION_MINIMIZE },
674 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
675 { "Gun A button ", 1 << SACTION_GUN_A },
676 { "Gun B button ", 1 << SACTION_GUN_B },
677 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
678 #ifndef __ARM_ARCH_7A__ /* XXX */
679 { "Volume Up ", 1 << SACTION_VOLUME_UP },
680 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
685 static char *mystrip(char *str)
690 for (i = 0; i < len; i++)
691 if (str[i] != ' ') break;
692 if (i > 0) memmove(str, str + i, len - i + 1);
695 for (i = len - 1; i >= 0; i--)
696 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
702 static void get_line(char *d, size_t size, const char *s)
707 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
718 static void keys_write_all(FILE *f)
722 for (d = 0; d < IN_MAX_DEVS; d++)
724 const int *binds = in_get_dev_binds(d);
725 const char *name = in_get_dev_name(d, 0, 0);
728 if (binds == NULL || name == NULL)
731 fprintf(f, "binddev = %s\n", name);
732 in_get_config(d, IN_CFG_BIND_COUNT, &count);
734 for (k = 0; k < count; k++)
739 act[0] = act[31] = 0;
740 name = in_get_key_name(d, k);
742 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
743 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
744 mask = me_ctrl_actions[i].mask;
746 strncpy(act, me_ctrl_actions[i].name, 31);
747 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
750 mask = me_ctrl_actions[i].mask << 16;
752 strncpy(act, me_ctrl_actions[i].name, 31);
753 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
758 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
759 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
760 mask = emuctrl_actions[i].mask;
762 strncpy(act, emuctrl_actions[i].name, 31);
763 fprintf(f, "bind %s = %s\n", name, mystrip(act));
769 for (k = 0; k < array_size(in_adev); k++)
772 fprintf(f, "bind_analog = %d\n", k);
777 static int parse_bind_val(const char *val, int *type)
781 *type = IN_BINDTYPE_NONE;
785 if (strncasecmp(val, "player", 6) == 0)
787 int player, shift = 0;
788 player = atoi(val + 6) - 1;
790 if ((unsigned int)player > 1)
795 *type = IN_BINDTYPE_PLAYER12;
796 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
797 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
798 return me_ctrl_actions[i].mask << shift;
801 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
802 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
803 *type = IN_BINDTYPE_EMU;
804 return emuctrl_actions[i].mask;
811 static void keys_load_all(const char *cfg)
813 char dev[256], key[128], *act;
819 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
822 get_line(dev, sizeof(dev), p);
823 dev_id = in_config_parse_dev(dev);
825 printf("input: can't handle dev: %s\n", dev);
829 in_unbind_all(dev_id, -1, -1);
830 while ((p = strstr(p, "bind"))) {
831 if (strncmp(p, "binddev = ", 10) == 0)
834 if (strncmp(p, "bind_analog", 11) == 0) {
835 ret = sscanf(p, "bind_analog = %d", &bind);
838 printf("input: parse error: %16s..\n", p);
841 if ((unsigned int)bind >= array_size(in_adev)) {
842 printf("input: analog id %d out of range\n", bind);
845 in_adev[bind] = dev_id;
851 printf("input: parse error: %16s..\n", p);
855 get_line(key, sizeof(key), p);
856 act = strchr(key, '=');
858 printf("parse failed: %16s..\n", p);
866 bind = parse_bind_val(act, &bindtype);
867 if (bind != -1 && bind != 0) {
868 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
869 in_config_bind_key(dev_id, key, bind, bindtype);
872 lprintf("config: unhandled action \"%s\"\n", act);
878 static int key_config_loop_wrap(int id, int keys)
881 case MA_CTRL_PLAYER1:
882 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
884 case MA_CTRL_PLAYER2:
885 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
888 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
896 static const char *adevnames[IN_MAX_DEVS + 2];
897 static int stick_sel[2];
899 static menu_entry e_menu_keyconfig_analog[] =
901 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
902 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
903 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
904 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
905 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
906 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
910 static int key_config_analog(int id, int keys)
912 int i, d, count, sel = 0;
913 int sel2dev_map[IN_MAX_DEVS];
915 memset(adevnames, 0, sizeof(adevnames));
916 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
917 memset(stick_sel, 0, sizeof(stick_sel));
919 adevnames[0] = "None";
921 for (d = 0; d < IN_MAX_DEVS; d++)
923 const char *name = in_get_dev_name(d, 0, 1);
928 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
932 if (in_adev[0] == d) stick_sel[0] = i;
933 if (in_adev[1] == d) stick_sel[1] = i;
935 adevnames[i++] = name;
939 me_loop(e_menu_keyconfig_analog, &sel);
941 in_adev[0] = sel2dev_map[stick_sel[0]];
942 in_adev[1] = sel2dev_map[stick_sel[1]];
947 static const char *mgn_dev_name(int id, int *offs)
949 const char *name = NULL;
952 if (id == MA_CTRL_DEV_FIRST)
955 for (; it < IN_MAX_DEVS; it++) {
956 name = in_get_dev_name(it, 1, 1);
965 static const char *mgn_saveloadcfg(int id, int *offs)
970 static int mh_savecfg(int id, int keys)
972 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
973 menu_update_msg("config saved");
975 menu_update_msg("failed to write config");
980 static int mh_input_rescan(int id, int keys)
982 //menu_sync_config();
984 menu_update_msg("rescan complete.");
989 static const char *men_in_type_sel[] = {
990 "Standard (SCPH-1080)",
991 "Analog (SCPH-1150)",
995 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
996 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
997 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
999 static menu_entry e_menu_keyconfig[] =
1001 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1002 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1003 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1004 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1006 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1007 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1008 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1009 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1010 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1011 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1012 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1013 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1014 mee_handler ("Rescan devices:", mh_input_rescan),
1016 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1017 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1018 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1019 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1020 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1021 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1022 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1026 static int menu_loop_keyconfig(int id, int keys)
1030 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1031 me_loop(e_menu_keyconfig, &sel);
1035 // ------------ gfx options menu ------------
1037 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1038 static const char *men_soft_filter[] = { "None",
1040 "scale2x", "eagle2x",
1043 static const char *men_dummy[] = { NULL };
1044 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1045 "using d-pad or move it using R+d-pad";
1046 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1047 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1049 static int menu_loop_cscaler(int id, int keys)
1053 g_scaler = SCALE_CUSTOM;
1055 plat_gvideo_open(Config.PsxType);
1059 menu_draw_begin(0, 1);
1060 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1061 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1062 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1065 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1066 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1067 if (inp & PBTN_UP) g_layer_y--;
1068 if (inp & PBTN_DOWN) g_layer_y++;
1069 if (inp & PBTN_LEFT) g_layer_x--;
1070 if (inp & PBTN_RIGHT) g_layer_x++;
1071 if (!(inp & PBTN_R)) {
1072 if (inp & PBTN_UP) g_layer_h += 2;
1073 if (inp & PBTN_DOWN) g_layer_h -= 2;
1074 if (inp & PBTN_LEFT) g_layer_w += 2;
1075 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1077 if (inp & (PBTN_MOK|PBTN_MBACK))
1080 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1081 if (g_layer_x < 0) g_layer_x = 0;
1082 if (g_layer_x > 640) g_layer_x = 640;
1083 if (g_layer_y < 0) g_layer_y = 0;
1084 if (g_layer_y > 420) g_layer_y = 420;
1085 if (g_layer_w < 160) g_layer_w = 160;
1086 if (g_layer_h < 60) g_layer_h = 60;
1087 if (g_layer_x + g_layer_w > 800)
1088 g_layer_w = 800 - g_layer_x;
1089 if (g_layer_y + g_layer_h > 480)
1090 g_layer_h = 480 - g_layer_y;
1092 plat_gvideo_open(Config.PsxType);
1096 plat_gvideo_close();
1101 static menu_entry e_menu_gfx_options[] =
1103 mee_enum ("Scaler", MA_OPT_SCALER, g_scaler, men_scaler),
1104 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1105 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, filter, men_dummy),
1106 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1107 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1108 // mee_onoff ("Vsync", 0, vsync, 1),
1109 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1113 static int menu_loop_gfx_options(int id, int keys)
1117 me_loop(e_menu_gfx_options, &sel);
1122 // ------------ bios/plugins ------------
1126 static const char h_gpu_neon[] =
1127 "Configure built-in NEON GPU plugin";
1128 static const char h_gpu_neon_enhanced[] =
1129 "Renders in double resolution at the cost of lower performance\n"
1130 "(not available for high resolution games)";
1131 static const char h_gpu_neon_enhanced_hack[] =
1132 "Speed hack for above option (glitches some games)";
1133 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1135 static menu_entry e_menu_plugin_gpu_neon[] =
1137 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1138 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1139 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1143 static int menu_loop_plugin_gpu_neon(int id, int keys)
1146 me_loop(e_menu_plugin_gpu_neon, &sel);
1152 static menu_entry e_menu_plugin_gpu_unai[] =
1154 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1155 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1156 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1157 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1161 static int menu_loop_plugin_gpu_unai(int id, int keys)
1164 me_loop(e_menu_plugin_gpu_unai, &sel);
1168 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1169 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1170 static const char h_gpu_1[] = "Capcom fighting games";
1171 static const char h_gpu_2[] = "Black screens in Lunar";
1172 static const char h_gpu_3[] = "Compatibility mode";
1173 static const char h_gpu_6[] = "Pandemonium 2";
1174 //static const char h_gpu_7[] = "Skip every second frame";
1175 static const char h_gpu_8[] = "Needed by Dark Forces";
1176 static const char h_gpu_9[] = "better g-colors, worse textures";
1177 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1179 static menu_entry e_menu_plugin_gpu_peops[] =
1181 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1182 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1183 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1184 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1185 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1186 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1187 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1188 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1189 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1190 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1194 static int menu_loop_plugin_gpu_peops(int id, int keys)
1197 me_loop(e_menu_plugin_gpu_peops, &sel);
1201 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1202 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1203 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1205 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1207 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1208 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1209 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1210 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1211 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1212 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1213 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1214 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1215 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1216 mee_label ("Fixes/hacks:"),
1217 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1218 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1219 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1220 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1221 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1222 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1223 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1224 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1225 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1226 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1227 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1231 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1234 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1238 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1239 static const char h_spu_volboost[] = "Large values cause distortion";
1241 static menu_entry e_menu_plugin_spu[] =
1243 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1244 mee_onoff ("Reverb", 0, iUseReverb, 2),
1245 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1246 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1250 static int menu_loop_plugin_spu(int id, int keys)
1253 me_loop(e_menu_plugin_spu, &sel);
1257 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1258 "savestates and can't be changed there. Must save\n"
1259 "config and reload the game for change to take effect";
1260 static const char h_plugin_gpu[] =
1262 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1264 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1265 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1266 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1267 "must save config and reload the game if changed";
1268 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1269 "must save config and reload the game if changed";
1270 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1271 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1272 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1273 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1275 static menu_entry e_menu_plugin_options[] =
1277 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1278 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1279 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1281 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1283 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1284 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1285 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1286 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1290 static menu_entry e_menu_main2[];
1292 static int menu_loop_plugin_options(int id, int keys)
1295 me_loop(e_menu_plugin_options, &sel);
1297 // sync BIOS/plugins
1298 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1299 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1300 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1301 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1306 // ------------ adv options menu ------------
1308 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1309 "(lower value - less work for the emu, may be faster)";
1310 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1311 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1312 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1314 static menu_entry e_menu_speed_hacks[] =
1316 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1317 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1318 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1319 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1323 static int menu_loop_speed_hacks(int id, int keys)
1326 me_loop(e_menu_speed_hacks, &sel);
1330 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1331 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1332 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1333 "(green: normal, red: fmod, blue: noise)";
1334 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1335 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1336 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1337 "(proper .cue/.bin dump is needed otherwise)";
1338 static const char h_cfg_sio[] = "You should not need this, breaks games";
1339 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1340 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1341 "(timing hack, breaks other games)";
1342 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1343 "(timing hack, breaks other games)";
1344 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1345 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1346 "Might be useful to overcome some dynarec bugs";
1347 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1348 "must reload game for any change to take effect";
1350 static menu_entry e_menu_adv_options[] =
1352 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1353 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1354 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1355 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1356 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1357 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1358 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1359 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1360 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1361 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1362 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1363 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1367 static int menu_loop_adv_options(int id, int keys)
1370 me_loop(e_menu_adv_options, &sel);
1374 // ------------ options menu ------------
1376 static int mh_restore_defaults(int id, int keys)
1378 menu_set_defconfig();
1379 menu_update_msg("defaults restored");
1383 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1384 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1386 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1387 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1388 "loading state or both";
1390 static const char h_restore_def[] = "Switches back to default / recommended\n"
1392 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1394 static menu_entry e_menu_options[] =
1396 // mee_range ("Save slot", 0, state_slot, 0, 9),
1397 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1398 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1399 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1400 mee_enum ("Region", 0, region, men_region),
1401 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1402 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1403 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1404 mee_handler ("[Advanced]", menu_loop_adv_options),
1405 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1406 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1407 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1411 static int menu_loop_options(int id, int keys)
1416 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1417 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1418 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1420 me_loop(e_menu_options, &sel);
1425 // ------------ debug menu ------------
1427 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1429 int w = min(g_menuscreen_w, 1024);
1430 int h = min(g_menuscreen_h, 512);
1431 u16 *d = g_menuscreen_ptr;
1432 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1436 gpuf->ulFreezeVersion = 1;
1437 if (GPU_freeze != NULL)
1438 GPU_freeze(1, gpuf);
1440 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1441 bgr555_to_rgb565(d, s, w * 2);
1443 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1444 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1445 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1446 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1447 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1450 static void debug_menu_loop(void)
1452 int inp, df_x = 0, df_y = 0;
1455 gpuf = malloc(sizeof(*gpuf));
1461 menu_draw_begin(0, 1);
1462 draw_frame_debug(gpuf, df_x, df_y);
1465 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1466 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1467 if (inp & PBTN_MBACK) break;
1468 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1469 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1470 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1471 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1477 // --------- memcard manager ---------
1479 static void draw_mc_icon(int dx, int dy, const u16 *s)
1484 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1486 for (y = 0; y < 16; y++, s += 16) {
1487 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1488 for (x = 0; x < 16; x++) {
1490 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1491 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1497 static void draw_mc_bg(void)
1499 McdBlock *blocks1, *blocks2;
1503 blocks1 = malloc(15 * sizeof(blocks1[0]));
1504 blocks2 = malloc(15 * sizeof(blocks1[0]));
1505 if (blocks1 == NULL || blocks2 == NULL)
1508 for (i = 0; i < 15; i++) {
1509 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1510 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1513 menu_draw_begin(1, 1);
1515 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1517 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1521 maxicons = g_menuscreen_h / 32;
1524 row2 = g_menuscreen_w / 2;
1525 for (i = 0; i < maxicons; i++) {
1526 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1527 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1529 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1530 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1533 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1541 static void handle_memcard_sel(void)
1544 if (memcard1_sel != 0)
1545 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1547 if (memcard2_sel != 0)
1548 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1549 LoadMcds(Config.Mcd1, Config.Mcd2);
1553 static menu_entry e_memcard_options[] =
1555 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1556 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1560 static int menu_loop_memcards(int id, int keys)
1566 memcard1_sel = memcard2_sel = 0;
1567 p = strrchr(Config.Mcd1, '/');
1569 for (i = 0; memcards[i] != NULL; i++)
1570 if (strcmp(p + 1, memcards[i]) == 0)
1571 { memcard1_sel = i; break; }
1572 p = strrchr(Config.Mcd2, '/');
1574 for (i = 0; memcards[i] != NULL; i++)
1575 if (strcmp(p + 1, memcards[i]) == 0)
1576 { memcard2_sel = i; break; }
1578 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1580 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1585 // ------------ cheats menu ------------
1587 static void draw_cheatlist(int sel)
1589 int max_cnt, start, i, pos, active;
1591 max_cnt = g_menuscreen_h / me_sfont_h;
1592 start = max_cnt / 2 - sel;
1594 menu_draw_begin(1, 1);
1596 for (i = 0; i < NumCheats; i++) {
1598 if (pos < 0) continue;
1599 if (pos >= max_cnt) break;
1600 active = Cheats[i].Enabled;
1601 smalltext_out16(14, pos * me_sfont_h,
1602 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1603 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1604 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1608 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1610 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1614 static void menu_loop_cheats(void)
1616 static int menu_sel = 0;
1621 draw_cheatlist(menu_sel);
1622 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1623 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1624 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1625 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1626 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1627 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1628 if (inp & PBTN_MOK) { // action
1629 if (menu_sel < NumCheats)
1630 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1633 if (inp & PBTN_MBACK)
1638 // --------- main menu help ----------
1640 static void menu_bios_warn(void)
1643 static const char msg[] =
1644 "You don't seem to have copied any BIOS\n"
1646 #ifdef __ARM_ARCH_7A__ // XXX
1647 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1649 "pcsx_rearmed/bios/\n\n"
1651 "While many games work fine with fake\n"
1652 "(HLE) BIOS, others (like MGS and FF8)\n"
1653 "require BIOS to work.\n"
1654 "After copying the file, you'll also need\n"
1655 "to select it in the emu's menu:\n"
1656 "options->[BIOS/Plugins]\n\n"
1657 "The file is usually named SCPH1001.BIN,\n"
1658 "but other not compressed files can be\n"
1660 "Press %s or %s to continue";
1661 char tmp_msg[sizeof(msg) + 64];
1663 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1664 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1667 draw_menu_message(tmp_msg, NULL);
1669 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1670 if (inp & (PBTN_MBACK|PBTN_MOK))
1675 // ------------ main menu ------------
1677 static menu_entry e_menu_main[];
1680 static void draw_frame_main(void)
1689 if (CdromId[0] != 0) {
1690 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1691 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1692 Config.HLE ? "HLE" : "BIOS");
1693 smalltext_out16(4, 1, buff, 0x105f);
1697 capacity = plat_target_bat_capacity_get();
1699 tmp = localtime(<ime);
1700 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1701 if (capacity >= 0) {
1702 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1707 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1711 static void draw_frame_credits(void)
1713 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1716 static const char credits_text[] =
1718 "(C) 1999-2003 PCSX Team\n"
1719 "(C) 2005-2009 PCSX-df Team\n"
1720 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1721 "ARM recompiler (C) 2009-2011 Ari64\n"
1723 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1725 "PEOpS GPU and SPU by Pete Bernert\n"
1726 " and the P.E.Op.S. team\n"
1727 "PCSX4ALL plugin by PCSX4ALL team\n"
1728 " Chui, Franxis, Unai\n\n"
1729 "integration, optimization and\n"
1730 " frontend (C) 2010-2012 notaz\n";
1732 static int reset_game(void)
1735 if (bios_sel == 0 && !Config.HLE)
1741 if (CheckCdrom() != -1) {
1747 static int reload_plugins(const char *cdimg)
1753 set_cd_image(cdimg);
1755 pcnt_hook_plugins();
1757 if (OpenPlugins() == -1) {
1758 menu_update_msg("failed to open plugins");
1761 plugin_call_rearmed_cbs();
1763 cdrIsoMultidiskCount = 1;
1765 CdromLabel[0] = '\0';
1770 static int run_bios(void)
1776 if (reload_plugins(NULL) != 0)
1784 static int run_exe(void)
1788 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1793 if (reload_plugins(NULL) != 0)
1797 if (Load(fname) != 0) {
1798 menu_update_msg("exe load failed, bad file?");
1807 static int run_cd_image(const char *fname)
1810 reload_plugins(fname);
1812 // always autodetect, menu_sync_config will override as needed
1815 if (CheckCdrom() == -1) {
1816 // Only check the CD if we are starting the console with a CD
1818 menu_update_msg("unsupported/invalid CD image");
1824 // Read main executable directly from CDRom and start it
1825 if (LoadCdrom() == -1) {
1827 menu_update_msg("failed to load CD image");
1837 static int romsel_run(void)
1839 int prev_gpu, prev_spu;
1842 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1846 printf("selected file: %s\n", fname);
1848 new_dynarec_clear_full();
1850 if (run_cd_image(fname) != 0)
1853 prev_gpu = gpu_plugsel;
1854 prev_spu = spu_plugsel;
1855 if (menu_load_config(1) != 0)
1856 menu_load_config(0);
1858 // check for plugin changes, have to repeat
1859 // loading if game config changed plugins to reload them
1860 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1861 printf("plugin change detected, reloading plugins..\n");
1862 if (run_cd_image(fname) != 0)
1866 strcpy(last_selected_fname, rom_fname_reload);
1867 menu_do_last_cd_img(0);
1871 static int swap_cd_image(void)
1875 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1879 printf("selected file: %s\n", fname);
1882 CdromLabel[0] = '\0';
1884 set_cd_image(fname);
1885 if (ReloadCdromPlugin() < 0) {
1886 menu_update_msg("failed to load cdr plugin");
1889 if (CDR_open() < 0) {
1890 menu_update_msg("failed to open cdr plugin");
1894 SetCdOpenCaseTime(time(NULL) + 2);
1897 strcpy(last_selected_fname, rom_fname_reload);
1901 static int swap_cd_multidisk(void)
1903 cdrIsoMultidiskSelect++;
1905 CdromLabel[0] = '\0';
1908 if (CDR_open() < 0) {
1909 menu_update_msg("failed to open cdr plugin");
1913 SetCdOpenCaseTime(time(NULL) + 2);
1919 static void load_pcsx_cht(void)
1925 fname = menu_loop_romsel(path, sizeof(path));
1929 printf("selected cheat file: %s\n", fname);
1932 if (NumCheats == 0 && NumCodes == 0)
1933 menu_update_msg("failed to load cheats");
1935 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1936 menu_update_msg(path);
1938 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1941 static int main_menu_handler(int id, int keys)
1945 case MA_MAIN_RESUME_GAME:
1949 case MA_MAIN_SAVE_STATE:
1951 return menu_loop_savestate(0);
1953 case MA_MAIN_LOAD_STATE:
1955 return menu_loop_savestate(1);
1957 case MA_MAIN_RESET_GAME:
1958 if (ready_to_go && reset_game() == 0)
1961 case MA_MAIN_LOAD_ROM:
1962 if (romsel_run() == 0)
1965 case MA_MAIN_SWAP_CD:
1966 if (swap_cd_image() == 0)
1969 case MA_MAIN_SWAP_CD_MULTI:
1970 if (swap_cd_multidisk() == 0)
1973 case MA_MAIN_RUN_BIOS:
1974 if (run_bios() == 0)
1977 case MA_MAIN_RUN_EXE:
1981 case MA_MAIN_CHEATS:
1984 case MA_MAIN_LOAD_CHEATS:
1987 case MA_MAIN_CREDITS:
1988 draw_menu_message(credits_text, draw_frame_credits);
1989 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1995 lprintf("%s: something unknown selected\n", __FUNCTION__);
2002 static menu_entry e_menu_main2[] =
2004 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2005 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2006 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2007 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2008 mee_handler ("Memcard manager", menu_loop_memcards),
2009 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2013 static int main_menu2_handler(int id, int keys)
2017 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2018 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2019 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2020 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2022 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2025 static const char h_extra[] = "Change CD, manage memcards..\n";
2027 static menu_entry e_menu_main[] =
2031 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2032 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2033 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2034 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2035 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2036 mee_handler ("Options", menu_loop_options),
2037 mee_handler ("Controls", menu_loop_keyconfig),
2038 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2039 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2040 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2041 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2045 // ----------------------------
2047 static void menu_leave_emu(void);
2049 void menu_loop(void)
2055 if (bioses[1] == NULL && !warned_about_bios) {
2057 warned_about_bios = 1;
2060 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2061 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2062 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2063 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2064 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2066 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2069 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2070 } while (!ready_to_go);
2072 /* wait until menu, ok, back is released */
2073 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2076 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2081 static int qsort_strcmp(const void *p1, const void *p2)
2083 char * const *s1 = (char * const *)p1;
2084 char * const *s2 = (char * const *)p2;
2085 return strcasecmp(*s1, *s2);
2088 static void scan_bios_plugins(void)
2090 char fname[MAXPATHLEN];
2092 int bios_i, gpu_i, spu_i, mc_i;
2097 gpu_plugins[0] = "builtin_gpu";
2098 spu_plugins[0] = "builtin_spu";
2099 memcards[0] = "(none)";
2100 bios_i = gpu_i = spu_i = mc_i = 1;
2102 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2103 dir = opendir(fname);
2105 perror("scan_bios_plugins bios opendir");
2120 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2123 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2124 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2125 printf("bad BIOS file: %s\n", ent->d_name);
2129 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2130 bioses[bios_i++] = strdup(ent->d_name);
2134 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2140 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2141 dir = opendir(fname);
2143 perror("scan_bios_plugins plugins opendir");
2157 p = strstr(ent->d_name, ".so");
2161 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2162 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2164 fprintf(stderr, "%s\n", dlerror());
2168 // now what do we have here?
2169 tmp = dlsym(h, "GPUinit");
2172 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2173 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2177 tmp = dlsym(h, "SPUinit");
2180 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2181 spu_plugins[spu_i++] = strdup(ent->d_name);
2185 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2192 dir = opendir("." MEMCARD_DIR);
2194 perror("scan_bios_plugins memcards opendir");
2209 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2212 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2213 if (stat(fname, &st) != 0) {
2214 printf("bad memcard file: %s\n", ent->d_name);
2218 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2219 memcards[mc_i++] = strdup(ent->d_name);
2223 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2227 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2232 void menu_init(void)
2234 char buff[MAXPATHLEN];
2237 strcpy(last_selected_fname, "/media");
2239 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2241 scan_bios_plugins();
2244 menu_set_defconfig();
2245 menu_load_config(0);
2246 menu_do_last_cd_img(1);
2251 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2252 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2253 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2254 fprintf(stderr, "OOM\n");
2258 emu_make_path(buff, "skin/background.png", sizeof(buff));
2259 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2261 i = plat_target.cpu_clock_set != NULL
2262 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2263 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2265 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2266 e_menu_gfx_options[i].data = plat_target.hwfilters;
2267 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2268 plat_target.hwfilters != NULL);
2270 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2271 plat_target.gamma_set != NULL);
2273 #ifndef __ARM_ARCH_7A__ /* XXX */
2274 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2275 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
2276 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2277 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2279 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
2280 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2281 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2285 void menu_notify_mode_change(int w, int h, int bpp)
2289 last_vout_bpp = bpp;
2292 static void menu_leave_emu(void)
2294 if (GPU_close != NULL) {
2295 int ret = GPU_close();
2297 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2300 plat_video_menu_enter(ready_to_go);
2302 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2303 if (pl_vout_buf != NULL && ready_to_go) {
2304 int x = max(0, g_menuscreen_w - last_vout_w);
2305 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2306 int w = min(g_menuscreen_w, last_vout_w);
2307 int h = min(g_menuscreen_h, last_vout_h);
2308 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2309 char *s = pl_vout_buf;
2311 if (last_vout_bpp == 16) {
2312 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2313 menu_darken_bg(d, s, w, 0);
2316 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2317 rgb888_to_rgb565(d, s, w * 3);
2318 menu_darken_bg(d, d, w, 0);
2324 cpu_clock = plat_target_cpu_clock_get();
2327 void menu_prepare_emu(void)
2329 R3000Acpu *prev_cpu = psxCpu;
2331 plat_video_menu_leave();
2333 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2334 if (psxCpu != prev_cpu)
2335 // note that this does not really reset, just clears drc caches
2338 // core doesn't care about Config.Cdda changes,
2339 // so handle them manually here
2345 plat_target_cpu_clock_set(cpu_clock);
2347 // push config to GPU plugin
2348 plugin_call_rearmed_cbs();
2350 if (GPU_open != NULL) {
2351 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2353 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2359 void menu_update_msg(const char *msg)
2361 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2362 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2364 menu_error_time = plat_get_ticks_ms();
2365 lprintf("msg: %s\n", menu_error_msg);
2368 void menu_finish(void)
2370 if (cpu_clock_st > 0)
2371 plat_target_cpu_clock_set(cpu_clock_st);