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 config_save_counter, 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;
115 #ifndef UI_FEATURES_H
116 #define MENU_BIOS_PATH "bios/"
117 #define MENU_SHOW_VARSCALER 0
118 #define MENU_SHOW_SCALER2 0
119 #define MENU_SHOW_NUBS_BTNS 0
120 #define MENU_SHOW_VIBRATION 0
121 #define MENU_SHOW_DEADZONE 0
122 #define MENU_SHOW_MINIMIZE 0
123 #define MENU_SHOW_VOLUME 0
126 static int min(int x, int y) { return x < y ? x : y; }
127 static int max(int x, int y) { return x > y ? x : y; }
129 void emu_make_path(char *buff, const char *end, int size)
133 end_len = strlen(end);
134 pos = plat_get_root_dir(buff, size);
135 strncpy(buff + pos, end, size - pos);
137 if (pos + end_len > size - 1)
138 printf("Warning: path truncated: %s\n", buff);
141 static int emu_check_save_file(int slot, int *time)
143 char fname[MAXPATHLEN];
147 ret = emu_check_state(slot);
148 if (ret != 0 || time == NULL)
149 return ret == 0 ? 1 : 0;
151 ret = get_state_filename(fname, sizeof(fname), slot);
155 ret = stat(fname, &status);
159 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
160 return 1; // probably bad rtc like on some Caanoos
162 *time = status.st_mtime;
167 static int emu_save_load_game(int load, int unused)
172 ret = emu_load_state(state_slot);
174 // reflect hle/bios mode from savestate
177 else if (bios_sel == 0 && bioses[1] != NULL)
178 // XXX: maybe find the right bios instead
182 ret = emu_save_state(state_slot);
187 // propagate menu settings to the emu vars
188 static void menu_sync_config(void)
190 static int allow_abs_only_old;
195 Config.PsxType = region - 1;
197 cycle_multiplier = 10000 / psx_clock;
199 switch (in_type_sel1) {
200 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
201 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
202 default: in_type1 = PSE_PAD_TYPE_STANDARD;
204 switch (in_type_sel2) {
205 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
206 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
207 default: in_type2 = PSE_PAD_TYPE_STANDARD;
209 if (in_evdev_allow_abs_only != allow_abs_only_old) {
211 allow_abs_only_old = in_evdev_allow_abs_only;
214 iVolume = 768 + 128 * volume_boost;
215 pl_rearmed_cbs.frameskip = frameskip - 1;
216 pl_timing_prepare(Config.PsxType);
219 static void menu_set_defconfig(void)
221 emu_set_default_config();
224 g_scaler = SCALE_4_3;
227 analog_deadzone = 50;
230 psx_clock = DEFAULT_PSX_CLOCK;
233 in_type_sel1 = in_type_sel2 = 0;
234 in_evdev_allow_abs_only = 0;
239 #define CE_CONFIG_STR(val) \
240 { #val, 0, Config.val }
242 #define CE_CONFIG_VAL(val) \
243 { #val, sizeof(Config.val), &Config.val }
245 #define CE_STR(val) \
248 #define CE_INTVAL(val) \
249 { #val, sizeof(val), &val }
251 #define CE_INTVAL_P(val) \
252 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
254 // 'versioned' var, used when defaults change
255 #define CE_CONFIG_STR_V(val, ver) \
256 { #val #ver, 0, Config.val }
258 #define CE_INTVAL_V(val, ver) \
259 { #val #ver, sizeof(val), &val }
261 #define CE_INTVAL_PV(val, ver) \
262 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
264 static const struct {
270 CE_CONFIG_STR_V(Gpu, 3),
272 // CE_CONFIG_STR(Cdr),
277 CE_CONFIG_VAL(Debug),
278 CE_CONFIG_VAL(PsxOut),
279 CE_CONFIG_VAL(SpuIrq),
280 CE_CONFIG_VAL(RCntFix),
281 CE_CONFIG_VAL(VSyncWA),
283 CE_CONFIG_VAL(CdrReschedule),
285 CE_INTVAL_V(g_scaler, 2),
286 CE_INTVAL(g_layer_x),
287 CE_INTVAL(g_layer_y),
288 CE_INTVAL(g_layer_w),
289 CE_INTVAL(g_layer_h),
291 CE_INTVAL(soft_filter),
292 CE_INTVAL(state_slot),
293 CE_INTVAL(cpu_clock),
295 CE_INTVAL(in_type_sel1),
296 CE_INTVAL(in_type_sel2),
297 CE_INTVAL(analog_deadzone),
298 CE_INTVAL_V(frameskip, 3),
299 CE_INTVAL_P(gpu_peops.iUseDither),
300 CE_INTVAL_P(gpu_peops.dwActFixes),
301 CE_INTVAL_P(gpu_unai.lineskip),
302 CE_INTVAL_P(gpu_unai.abe_hack),
303 CE_INTVAL_P(gpu_unai.no_light),
304 CE_INTVAL_P(gpu_unai.no_blend),
305 CE_INTVAL_P(gpu_neon.allow_interlace),
306 CE_INTVAL_P(gpu_neon.enhancement_enable),
307 CE_INTVAL_P(gpu_neon.enhancement_no_main),
308 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
309 CE_INTVAL_P(gpu_peopsgl.iFilterType),
310 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
311 CE_INTVAL_P(gpu_peopsgl.iUseMask),
312 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
313 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
314 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
315 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
316 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
317 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
318 CE_INTVAL_V(iUseReverb, 3),
319 CE_INTVAL_V(iXAPitch, 3),
320 CE_INTVAL_V(iUseInterpolation, 3),
321 CE_INTVAL(config_save_counter),
322 CE_INTVAL(in_evdev_allow_abs_only),
323 CE_INTVAL(volume_boost),
324 CE_INTVAL(psx_clock),
325 CE_INTVAL(new_dynarec_hacks),
326 CE_INTVAL(in_enable_vibration),
329 static char *get_cd_label(void)
331 static char trimlabel[33];
334 strncpy(trimlabel, CdromLabel, 32);
336 for (j = 31; j >= 0; j--)
337 if (trimlabel[j] == ' ')
343 static void make_cfg_fname(char *buf, size_t size, int is_game)
346 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
348 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
351 static void keys_write_all(FILE *f);
352 static char *mystrip(char *str);
354 static int menu_write_config(int is_game)
356 char cfgfile[MAXPATHLEN];
360 config_save_counter++;
362 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
363 f = fopen(cfgfile, "w");
365 printf("menu_write_config: failed to open: %s\n", cfgfile);
369 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
370 fprintf(f, "%s = ", config_data[i].name);
371 switch (config_data[i].len) {
373 fprintf(f, "%s\n", (char *)config_data[i].val);
376 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
379 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
382 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
385 printf("menu_write_config: unhandled len %d for %s\n",
386 (int)config_data[i].len, config_data[i].name);
397 static int menu_do_last_cd_img(int is_get)
403 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
404 f = fopen(path, is_get ? "r" : "w");
409 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
410 last_selected_fname[ret] = 0;
411 mystrip(last_selected_fname);
414 fprintf(f, "%s\n", last_selected_fname);
420 static void parse_str_val(char *cval, const char *src)
423 strncpy(cval, src, MAXPATHLEN);
424 cval[MAXPATHLEN - 1] = 0;
425 tmp = strchr(cval, '\n');
427 tmp = strchr(cval, '\r');
432 static void keys_load_all(const char *cfg);
434 static int menu_load_config(int is_game)
436 char cfgfile[MAXPATHLEN];
442 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
443 f = fopen(cfgfile, "r");
445 printf("menu_load_config: failed to open: %s\n", cfgfile);
449 fseek(f, 0, SEEK_END);
452 printf("bad size %ld: %s\n", size, cfgfile);
456 cfg = malloc(size + 1);
460 fseek(f, 0, SEEK_SET);
461 if (fread(cfg, 1, size, f) != size) {
462 printf("failed to read: %s\n", cfgfile);
467 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
471 tmp = strstr(cfg, config_data[i].name);
474 tmp += strlen(config_data[i].name);
475 if (strncmp(tmp, " = ", 3) != 0)
479 if (config_data[i].len == 0) {
480 parse_str_val(config_data[i].val, tmp);
485 val = strtoul(tmp, &tmp2, 16);
486 if (tmp2 == NULL || tmp == tmp2)
487 continue; // parse failed
489 switch (config_data[i].len) {
491 *(u8 *)config_data[i].val = val;
494 *(u16 *)config_data[i].val = val;
497 *(u32 *)config_data[i].val = val;
500 printf("menu_load_config: unhandled len %d for %s\n",
501 (int)config_data[i].len, config_data[i].name);
507 char *tmp = strstr(cfg, "lastcdimg = ");
510 parse_str_val(last_selected_fname, tmp);
525 for (i = bios_sel = 0; bioses[i] != NULL; i++)
526 if (strcmp(Config.Bios, bioses[i]) == 0)
527 { bios_sel = i; break; }
529 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
530 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
531 { gpu_plugsel = i; break; }
533 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
534 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
535 { spu_plugsel = i; break; }
540 // rrrr rggg gggb bbbb
541 static unsigned short fname2color(const char *fname)
543 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
544 ".bz", ".znx", ".pbp", ".cbn" };
545 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
546 ".table", ".index", ".sbi" };
547 const char *ext = strrchr(fname, '.');
552 for (i = 0; i < array_size(cdimg_exts); i++)
553 if (strcasecmp(ext, cdimg_exts[i]) == 0)
555 for (i = 0; i < array_size(other_exts); i++)
556 if (strcasecmp(ext, other_exts[i]) == 0)
561 static void draw_savestate_bg(int slot);
563 static const char *filter_exts[] = {
564 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
567 #define MENU_ALIGN_LEFT
568 #ifdef __ARM_ARCH_7A__ // assume hires device
574 #include "libpicofe/menu.c"
576 // a bit of black magic here
577 static void draw_savestate_bg(int slot)
579 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
581 char fname[MAXPATHLEN];
588 ret = get_state_filename(fname, sizeof(fname), slot);
592 f = gzopen(fname, "rb");
596 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
597 fprintf(stderr, "gzseek failed\n");
602 gpu = malloc(sizeof(*gpu));
608 ret = gzread(f, gpu, sizeof(*gpu));
610 if (ret != sizeof(*gpu)) {
611 fprintf(stderr, "gzread failed\n");
615 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
617 if (gpu->ulStatus & 0x800000)
618 goto out; // disabled
620 x = gpu->ulControl[5] & 0x3ff;
621 y = (gpu->ulControl[5] >> 10) & 0x1ff;
622 s = (u16 *)gpu->psxVRam + y * 1024 + x;
623 w = psx_widths[(gpu->ulStatus >> 16) & 7];
624 tmp = gpu->ulControl[7];
625 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
626 if (gpu->ulStatus & 0x80000) // doubleheight
629 x = max(0, g_menuscreen_w - w) & ~3;
630 y = max(0, g_menuscreen_h / 2 - h / 2);
631 w = min(g_menuscreen_w, w);
632 h = min(g_menuscreen_h, h);
633 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
635 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
636 if (gpu->ulStatus & 0x200000)
637 bgr888_to_rgb565(d, s, w * 3);
639 bgr555_to_rgb565(d, s, w * 2);
641 // darken this so that menu text is visible
642 if (g_menuscreen_w - w < 320)
643 menu_darken_bg(d, d, w * 2, 0);
650 // -------------- key config --------------
652 me_bind_action me_ctrl_actions[] =
654 { "UP ", 1 << DKEY_UP},
655 { "DOWN ", 1 << DKEY_DOWN },
656 { "LEFT ", 1 << DKEY_LEFT },
657 { "RIGHT ", 1 << DKEY_RIGHT },
658 { "TRIANGLE", 1 << DKEY_TRIANGLE },
659 { "CIRCLE ", 1 << DKEY_CIRCLE },
660 { "CROSS ", 1 << DKEY_CROSS },
661 { "SQUARE ", 1 << DKEY_SQUARE },
662 { "L1 ", 1 << DKEY_L1 },
663 { "R1 ", 1 << DKEY_R1 },
664 { "L2 ", 1 << DKEY_L2 },
665 { "R2 ", 1 << DKEY_R2 },
666 { "L3 ", 1 << DKEY_L3 },
667 { "R3 ", 1 << DKEY_R3 },
668 { "START ", 1 << DKEY_START },
669 { "SELECT ", 1 << DKEY_SELECT },
673 me_bind_action emuctrl_actions[] =
675 { "Save State ", 1 << SACTION_SAVE_STATE },
676 { "Load State ", 1 << SACTION_LOAD_STATE },
677 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
678 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
679 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
680 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
681 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
682 #ifdef __ARM_ARCH_7A__
683 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
685 #if MENU_SHOW_MINIMIZE
686 { "Minimize ", 1 << SACTION_MINIMIZE },
688 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
689 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
690 { "Gun A button ", 1 << SACTION_GUN_A },
691 { "Gun B button ", 1 << SACTION_GUN_B },
692 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
694 { "Volume Up ", 1 << SACTION_VOLUME_UP },
695 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
700 static char *mystrip(char *str)
705 for (i = 0; i < len; i++)
706 if (str[i] != ' ') break;
707 if (i > 0) memmove(str, str + i, len - i + 1);
710 for (i = len - 1; i >= 0; i--)
711 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
717 static void get_line(char *d, size_t size, const char *s)
722 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
733 static void keys_write_all(FILE *f)
737 for (d = 0; d < IN_MAX_DEVS; d++)
739 const int *binds = in_get_dev_binds(d);
740 const char *name = in_get_dev_name(d, 0, 0);
743 if (binds == NULL || name == NULL)
746 fprintf(f, "binddev = %s\n", name);
747 in_get_config(d, IN_CFG_BIND_COUNT, &count);
749 for (k = 0; k < count; k++)
754 act[0] = act[31] = 0;
755 name = in_get_key_name(d, k);
757 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
758 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
759 mask = me_ctrl_actions[i].mask;
761 strncpy(act, me_ctrl_actions[i].name, 31);
762 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
765 mask = me_ctrl_actions[i].mask << 16;
767 strncpy(act, me_ctrl_actions[i].name, 31);
768 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
773 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
774 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
775 mask = emuctrl_actions[i].mask;
777 strncpy(act, emuctrl_actions[i].name, 31);
778 fprintf(f, "bind %s = %s\n", name, mystrip(act));
784 for (k = 0; k < array_size(in_adev); k++)
787 fprintf(f, "bind_analog = %d\n", k);
792 static int parse_bind_val(const char *val, int *type)
796 *type = IN_BINDTYPE_NONE;
800 if (strncasecmp(val, "player", 6) == 0)
802 int player, shift = 0;
803 player = atoi(val + 6) - 1;
805 if ((unsigned int)player > 1)
810 *type = IN_BINDTYPE_PLAYER12;
811 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
812 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
813 return me_ctrl_actions[i].mask << shift;
816 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
817 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
818 *type = IN_BINDTYPE_EMU;
819 return emuctrl_actions[i].mask;
826 static void keys_load_all(const char *cfg)
828 char dev[256], key[128], *act;
834 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
837 get_line(dev, sizeof(dev), p);
838 dev_id = in_config_parse_dev(dev);
840 printf("input: can't handle dev: %s\n", dev);
844 in_unbind_all(dev_id, -1, -1);
845 while ((p = strstr(p, "bind"))) {
846 if (strncmp(p, "binddev = ", 10) == 0)
849 if (strncmp(p, "bind_analog", 11) == 0) {
850 ret = sscanf(p, "bind_analog = %d", &bind);
853 printf("input: parse error: %16s..\n", p);
856 if ((unsigned int)bind >= array_size(in_adev)) {
857 printf("input: analog id %d out of range\n", bind);
860 in_adev[bind] = dev_id;
866 printf("input: parse error: %16s..\n", p);
870 get_line(key, sizeof(key), p);
871 act = strchr(key, '=');
873 printf("parse failed: %16s..\n", p);
881 bind = parse_bind_val(act, &bindtype);
882 if (bind != -1 && bind != 0) {
883 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
884 in_config_bind_key(dev_id, key, bind, bindtype);
887 lprintf("config: unhandled action \"%s\"\n", act);
893 static int key_config_loop_wrap(int id, int keys)
896 case MA_CTRL_PLAYER1:
897 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
899 case MA_CTRL_PLAYER2:
900 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
903 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
911 static const char *adevnames[IN_MAX_DEVS + 2];
912 static int stick_sel[2];
914 static menu_entry e_menu_keyconfig_analog[] =
916 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
917 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
918 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
919 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
920 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
921 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
925 static int key_config_analog(int id, int keys)
927 int i, d, count, sel = 0;
928 int sel2dev_map[IN_MAX_DEVS];
930 memset(adevnames, 0, sizeof(adevnames));
931 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
932 memset(stick_sel, 0, sizeof(stick_sel));
934 adevnames[0] = "None";
936 for (d = 0; d < IN_MAX_DEVS; d++)
938 const char *name = in_get_dev_name(d, 0, 1);
943 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
947 if (in_adev[0] == d) stick_sel[0] = i;
948 if (in_adev[1] == d) stick_sel[1] = i;
950 adevnames[i++] = name;
954 me_loop(e_menu_keyconfig_analog, &sel);
956 in_adev[0] = sel2dev_map[stick_sel[0]];
957 in_adev[1] = sel2dev_map[stick_sel[1]];
962 static const char *mgn_dev_name(int id, int *offs)
964 const char *name = NULL;
967 if (id == MA_CTRL_DEV_FIRST)
970 for (; it < IN_MAX_DEVS; it++) {
971 name = in_get_dev_name(it, 1, 1);
980 static const char *mgn_saveloadcfg(int id, int *offs)
985 static int mh_savecfg(int id, int keys)
987 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
988 menu_update_msg("config saved");
990 menu_update_msg("failed to write config");
995 static int mh_input_rescan(int id, int keys)
997 //menu_sync_config();
999 menu_update_msg("rescan complete.");
1004 static const char *men_in_type_sel[] = {
1005 "Standard (SCPH-1080)",
1006 "Analog (SCPH-1150)",
1010 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1011 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1012 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1014 static menu_entry e_menu_keyconfig[] =
1016 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1017 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1018 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1019 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1021 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1022 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1023 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1024 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1025 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1026 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1027 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1028 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1029 mee_handler ("Rescan devices:", mh_input_rescan),
1031 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1032 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1033 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1034 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1035 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1036 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1037 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1041 static int menu_loop_keyconfig(int id, int keys)
1045 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1046 me_loop(e_menu_keyconfig, &sel);
1050 // ------------ gfx options menu ------------
1052 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1053 static const char *men_soft_filter[] = { "None",
1055 "scale2x", "eagle2x",
1058 static const char *men_dummy[] = { NULL };
1059 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1060 "using d-pad or move it using R+d-pad";
1061 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1062 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1064 static int menu_loop_cscaler(int id, int keys)
1068 g_scaler = SCALE_CUSTOM;
1070 plat_gvideo_open(Config.PsxType);
1074 menu_draw_begin(0, 1);
1075 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1076 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1077 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1080 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1081 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1082 if (inp & PBTN_UP) g_layer_y--;
1083 if (inp & PBTN_DOWN) g_layer_y++;
1084 if (inp & PBTN_LEFT) g_layer_x--;
1085 if (inp & PBTN_RIGHT) g_layer_x++;
1086 if (!(inp & PBTN_R)) {
1087 if (inp & PBTN_UP) g_layer_h += 2;
1088 if (inp & PBTN_DOWN) g_layer_h -= 2;
1089 if (inp & PBTN_LEFT) g_layer_w += 2;
1090 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1092 if (inp & (PBTN_MOK|PBTN_MBACK))
1095 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1096 if (g_layer_x < 0) g_layer_x = 0;
1097 if (g_layer_x > 640) g_layer_x = 640;
1098 if (g_layer_y < 0) g_layer_y = 0;
1099 if (g_layer_y > 420) g_layer_y = 420;
1100 if (g_layer_w < 160) g_layer_w = 160;
1101 if (g_layer_h < 60) g_layer_h = 60;
1102 if (g_layer_x + g_layer_w > 800)
1103 g_layer_w = 800 - g_layer_x;
1104 if (g_layer_y + g_layer_h > 480)
1105 g_layer_h = 480 - g_layer_y;
1107 plat_gvideo_open(Config.PsxType);
1111 plat_gvideo_close();
1116 static menu_entry e_menu_gfx_options[] =
1118 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1119 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1120 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, filter, men_dummy),
1121 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1122 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1123 // mee_onoff ("Vsync", 0, vsync, 1),
1124 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1128 static int menu_loop_gfx_options(int id, int keys)
1132 me_loop(e_menu_gfx_options, &sel);
1137 // ------------ bios/plugins ------------
1141 static const char h_gpu_neon[] =
1142 "Configure built-in NEON GPU plugin";
1143 static const char h_gpu_neon_enhanced[] =
1144 "Renders in double resolution at the cost of lower performance\n"
1145 "(not available for high resolution games)";
1146 static const char h_gpu_neon_enhanced_hack[] =
1147 "Speed hack for above option (glitches some games)";
1148 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1150 static menu_entry e_menu_plugin_gpu_neon[] =
1152 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1153 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1154 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1158 static int menu_loop_plugin_gpu_neon(int id, int keys)
1161 me_loop(e_menu_plugin_gpu_neon, &sel);
1167 static menu_entry e_menu_plugin_gpu_unai[] =
1169 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1170 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1171 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1172 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1176 static int menu_loop_plugin_gpu_unai(int id, int keys)
1179 me_loop(e_menu_plugin_gpu_unai, &sel);
1183 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1184 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1185 static const char h_gpu_1[] = "Capcom fighting games";
1186 static const char h_gpu_2[] = "Black screens in Lunar";
1187 static const char h_gpu_3[] = "Compatibility mode";
1188 static const char h_gpu_6[] = "Pandemonium 2";
1189 //static const char h_gpu_7[] = "Skip every second frame";
1190 static const char h_gpu_8[] = "Needed by Dark Forces";
1191 static const char h_gpu_9[] = "better g-colors, worse textures";
1192 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1194 static menu_entry e_menu_plugin_gpu_peops[] =
1196 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1197 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1198 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1199 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1200 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1201 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1202 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1203 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1204 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1205 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1209 static int menu_loop_plugin_gpu_peops(int id, int keys)
1212 me_loop(e_menu_plugin_gpu_peops, &sel);
1216 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1217 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1218 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1220 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1222 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1223 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1224 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1225 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1226 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1227 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1228 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1229 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1230 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1231 mee_label ("Fixes/hacks:"),
1232 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1233 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1234 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1235 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1236 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1237 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1238 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1239 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1240 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1241 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1242 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1246 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1249 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1253 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1254 static const char h_spu_volboost[] = "Large values cause distortion";
1256 static menu_entry e_menu_plugin_spu[] =
1258 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1259 mee_onoff ("Reverb", 0, iUseReverb, 2),
1260 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1261 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1265 static int menu_loop_plugin_spu(int id, int keys)
1268 me_loop(e_menu_plugin_spu, &sel);
1272 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1273 "savestates and can't be changed there. Must save\n"
1274 "config and reload the game for change to take effect";
1275 static const char h_plugin_gpu[] =
1277 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1279 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1280 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1281 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1282 "must save config and reload the game if changed";
1283 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1284 "must save config and reload the game if changed";
1285 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1286 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1287 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1288 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1290 static menu_entry e_menu_plugin_options[] =
1292 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1293 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1294 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1296 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1298 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1299 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1300 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1301 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1305 static menu_entry e_menu_main2[];
1307 static int menu_loop_plugin_options(int id, int keys)
1310 me_loop(e_menu_plugin_options, &sel);
1312 // sync BIOS/plugins
1313 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1314 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1315 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1316 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1321 // ------------ adv options menu ------------
1323 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1324 "(lower value - less work for the emu, may be faster)";
1325 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1326 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1327 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1329 static menu_entry e_menu_speed_hacks[] =
1331 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1332 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1333 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1334 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1338 static int menu_loop_speed_hacks(int id, int keys)
1341 me_loop(e_menu_speed_hacks, &sel);
1345 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1346 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1347 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1348 "(green: normal, red: fmod, blue: noise)";
1349 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1350 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1351 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1352 "(proper .cue/.bin dump is needed otherwise)";
1353 static const char h_cfg_sio[] = "You should not need this, breaks games";
1354 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1355 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1356 "(timing hack, breaks other games)";
1357 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1358 "(timing hack, breaks other games)";
1359 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1360 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1361 "Might be useful to overcome some dynarec bugs";
1362 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1363 "must reload game for any change to take effect";
1365 static menu_entry e_menu_adv_options[] =
1367 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1368 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1369 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1370 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1371 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1372 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1373 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1374 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1375 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1376 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1377 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1378 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1382 static int menu_loop_adv_options(int id, int keys)
1385 me_loop(e_menu_adv_options, &sel);
1389 // ------------ options menu ------------
1391 static int mh_restore_defaults(int id, int keys)
1393 menu_set_defconfig();
1394 menu_update_msg("defaults restored");
1398 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1399 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1401 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1402 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1403 "loading state or both";
1405 static const char h_restore_def[] = "Switches back to default / recommended\n"
1407 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1409 static menu_entry e_menu_options[] =
1411 // mee_range ("Save slot", 0, state_slot, 0, 9),
1412 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1413 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1414 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1415 mee_enum ("Region", 0, region, men_region),
1416 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1417 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1418 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1419 mee_handler ("[Advanced]", menu_loop_adv_options),
1420 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1421 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1422 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1426 static int menu_loop_options(int id, int keys)
1431 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1432 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1433 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1435 me_loop(e_menu_options, &sel);
1440 // ------------ debug menu ------------
1442 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1444 int w = min(g_menuscreen_w, 1024);
1445 int h = min(g_menuscreen_h, 512);
1446 u16 *d = g_menuscreen_ptr;
1447 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1451 gpuf->ulFreezeVersion = 1;
1452 if (GPU_freeze != NULL)
1453 GPU_freeze(1, gpuf);
1455 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1456 bgr555_to_rgb565(d, s, w * 2);
1458 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1459 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1460 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1461 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1462 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1465 static void debug_menu_loop(void)
1467 int inp, df_x = 0, df_y = 0;
1470 gpuf = malloc(sizeof(*gpuf));
1476 menu_draw_begin(0, 1);
1477 draw_frame_debug(gpuf, df_x, df_y);
1480 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1481 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1482 if (inp & PBTN_MBACK) break;
1483 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1484 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1485 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1486 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1492 // --------- memcard manager ---------
1494 static void draw_mc_icon(int dx, int dy, const u16 *s)
1499 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1501 for (y = 0; y < 16; y++, s += 16) {
1502 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1503 for (x = 0; x < 16; x++) {
1505 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1506 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1512 static void draw_mc_bg(void)
1514 McdBlock *blocks1, *blocks2;
1518 blocks1 = malloc(15 * sizeof(blocks1[0]));
1519 blocks2 = malloc(15 * sizeof(blocks1[0]));
1520 if (blocks1 == NULL || blocks2 == NULL)
1523 for (i = 0; i < 15; i++) {
1524 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1525 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1528 menu_draw_begin(1, 1);
1530 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1532 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1536 maxicons = g_menuscreen_h / 32;
1539 row2 = g_menuscreen_w / 2;
1540 for (i = 0; i < maxicons; i++) {
1541 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1542 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1544 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1545 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1548 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1556 static void handle_memcard_sel(void)
1559 if (memcard1_sel != 0)
1560 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1562 if (memcard2_sel != 0)
1563 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1564 LoadMcds(Config.Mcd1, Config.Mcd2);
1568 static menu_entry e_memcard_options[] =
1570 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1571 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1575 static int menu_loop_memcards(int id, int keys)
1581 memcard1_sel = memcard2_sel = 0;
1582 p = strrchr(Config.Mcd1, '/');
1584 for (i = 0; memcards[i] != NULL; i++)
1585 if (strcmp(p + 1, memcards[i]) == 0)
1586 { memcard1_sel = i; break; }
1587 p = strrchr(Config.Mcd2, '/');
1589 for (i = 0; memcards[i] != NULL; i++)
1590 if (strcmp(p + 1, memcards[i]) == 0)
1591 { memcard2_sel = i; break; }
1593 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1595 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1600 // ------------ cheats menu ------------
1602 static void draw_cheatlist(int sel)
1604 int max_cnt, start, i, pos, active;
1606 max_cnt = g_menuscreen_h / me_sfont_h;
1607 start = max_cnt / 2 - sel;
1609 menu_draw_begin(1, 1);
1611 for (i = 0; i < NumCheats; i++) {
1613 if (pos < 0) continue;
1614 if (pos >= max_cnt) break;
1615 active = Cheats[i].Enabled;
1616 smalltext_out16(14, pos * me_sfont_h,
1617 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1618 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1619 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1623 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1625 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1629 static void menu_loop_cheats(void)
1631 static int menu_sel = 0;
1636 draw_cheatlist(menu_sel);
1637 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1638 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1639 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1640 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1641 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1642 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1643 if (inp & PBTN_MOK) { // action
1644 if (menu_sel < NumCheats)
1645 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1648 if (inp & PBTN_MBACK)
1653 // --------- main menu help ----------
1655 static void menu_bios_warn(void)
1658 static const char msg[] =
1659 "You don't seem to have copied any BIOS\n"
1661 MENU_BIOS_PATH "\n\n"
1663 "While many games work fine with fake\n"
1664 "(HLE) BIOS, others (like MGS and FF8)\n"
1665 "require BIOS to work.\n"
1666 "After copying the file, you'll also need\n"
1667 "to select it in the emu's menu:\n"
1668 "options->[BIOS/Plugins]\n\n"
1669 "The file is usually named SCPH1001.BIN,\n"
1670 "but other not compressed files can be\n"
1672 "Press %s or %s to continue";
1673 char tmp_msg[sizeof(msg) + 64];
1675 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1676 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1679 draw_menu_message(tmp_msg, NULL);
1681 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1682 if (inp & (PBTN_MBACK|PBTN_MOK))
1687 // ------------ main menu ------------
1689 static menu_entry e_menu_main[];
1692 static void draw_frame_main(void)
1701 if (CdromId[0] != 0) {
1702 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1703 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1704 Config.HLE ? "HLE" : "BIOS");
1705 smalltext_out16(4, 1, buff, 0x105f);
1709 capacity = plat_target_bat_capacity_get();
1711 tmp = localtime(<ime);
1712 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1713 if (capacity >= 0) {
1714 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1719 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1723 static void draw_frame_credits(void)
1725 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1728 static const char credits_text[] =
1730 "(C) 1999-2003 PCSX Team\n"
1731 "(C) 2005-2009 PCSX-df Team\n"
1732 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1733 "ARM recompiler (C) 2009-2011 Ari64\n"
1735 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1737 "PEOpS GPU and SPU by Pete Bernert\n"
1738 " and the P.E.Op.S. team\n"
1739 "PCSX4ALL plugin by PCSX4ALL team\n"
1740 " Chui, Franxis, Unai\n\n"
1741 "integration, optimization and\n"
1742 " frontend (C) 2010-2012 notaz\n";
1744 static int reset_game(void)
1747 if (bios_sel == 0 && !Config.HLE)
1753 if (CheckCdrom() != -1) {
1759 static int reload_plugins(const char *cdimg)
1765 set_cd_image(cdimg);
1767 pcnt_hook_plugins();
1769 if (OpenPlugins() == -1) {
1770 menu_update_msg("failed to open plugins");
1773 plugin_call_rearmed_cbs();
1775 cdrIsoMultidiskCount = 1;
1777 CdromLabel[0] = '\0';
1782 static int run_bios(void)
1788 if (reload_plugins(NULL) != 0)
1796 static int run_exe(void)
1800 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1805 if (reload_plugins(NULL) != 0)
1809 if (Load(fname) != 0) {
1810 menu_update_msg("exe load failed, bad file?");
1819 static int run_cd_image(const char *fname)
1822 reload_plugins(fname);
1824 // always autodetect, menu_sync_config will override as needed
1827 if (CheckCdrom() == -1) {
1828 // Only check the CD if we are starting the console with a CD
1830 menu_update_msg("unsupported/invalid CD image");
1836 // Read main executable directly from CDRom and start it
1837 if (LoadCdrom() == -1) {
1839 menu_update_msg("failed to load CD image");
1849 static int romsel_run(void)
1851 int prev_gpu, prev_spu;
1854 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1858 printf("selected file: %s\n", fname);
1860 new_dynarec_clear_full();
1862 if (run_cd_image(fname) != 0)
1865 prev_gpu = gpu_plugsel;
1866 prev_spu = spu_plugsel;
1867 if (menu_load_config(1) != 0)
1868 menu_load_config(0);
1870 // check for plugin changes, have to repeat
1871 // loading if game config changed plugins to reload them
1872 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1873 printf("plugin change detected, reloading plugins..\n");
1874 if (run_cd_image(fname) != 0)
1878 strcpy(last_selected_fname, rom_fname_reload);
1879 menu_do_last_cd_img(0);
1883 static int swap_cd_image(void)
1887 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1891 printf("selected file: %s\n", fname);
1894 CdromLabel[0] = '\0';
1896 set_cd_image(fname);
1897 if (ReloadCdromPlugin() < 0) {
1898 menu_update_msg("failed to load cdr plugin");
1901 if (CDR_open() < 0) {
1902 menu_update_msg("failed to open cdr plugin");
1906 SetCdOpenCaseTime(time(NULL) + 2);
1909 strcpy(last_selected_fname, rom_fname_reload);
1913 static int swap_cd_multidisk(void)
1915 cdrIsoMultidiskSelect++;
1917 CdromLabel[0] = '\0';
1920 if (CDR_open() < 0) {
1921 menu_update_msg("failed to open cdr plugin");
1925 SetCdOpenCaseTime(time(NULL) + 2);
1931 static void load_pcsx_cht(void)
1937 fname = menu_loop_romsel(path, sizeof(path));
1941 printf("selected cheat file: %s\n", fname);
1944 if (NumCheats == 0 && NumCodes == 0)
1945 menu_update_msg("failed to load cheats");
1947 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1948 menu_update_msg(path);
1950 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1953 static int main_menu_handler(int id, int keys)
1957 case MA_MAIN_RESUME_GAME:
1961 case MA_MAIN_SAVE_STATE:
1963 return menu_loop_savestate(0);
1965 case MA_MAIN_LOAD_STATE:
1967 return menu_loop_savestate(1);
1969 case MA_MAIN_RESET_GAME:
1970 if (ready_to_go && reset_game() == 0)
1973 case MA_MAIN_LOAD_ROM:
1974 if (romsel_run() == 0)
1977 case MA_MAIN_SWAP_CD:
1978 if (swap_cd_image() == 0)
1981 case MA_MAIN_SWAP_CD_MULTI:
1982 if (swap_cd_multidisk() == 0)
1985 case MA_MAIN_RUN_BIOS:
1986 if (run_bios() == 0)
1989 case MA_MAIN_RUN_EXE:
1993 case MA_MAIN_CHEATS:
1996 case MA_MAIN_LOAD_CHEATS:
1999 case MA_MAIN_CREDITS:
2000 draw_menu_message(credits_text, draw_frame_credits);
2001 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2007 lprintf("%s: something unknown selected\n", __FUNCTION__);
2014 static menu_entry e_menu_main2[] =
2016 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2017 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2018 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2019 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2020 mee_handler ("Memcard manager", menu_loop_memcards),
2021 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2025 static int main_menu2_handler(int id, int keys)
2029 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2030 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2031 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2032 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2034 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2037 static const char h_extra[] = "Change CD, manage memcards..\n";
2039 static menu_entry e_menu_main[] =
2043 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2044 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2045 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2046 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2047 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2048 mee_handler ("Options", menu_loop_options),
2049 mee_handler ("Controls", menu_loop_keyconfig),
2050 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2051 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2052 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2053 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2057 // ----------------------------
2059 static void menu_leave_emu(void);
2061 void menu_loop(void)
2063 static int warned_about_bios = 0;
2068 if (config_save_counter == 0) {
2070 if (bioses[1] != NULL) {
2071 // autoselect BIOS to make user's life easier
2072 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2075 else if (!warned_about_bios) {
2077 warned_about_bios = 1;
2081 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2082 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2083 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2084 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2085 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2087 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2090 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2091 } while (!ready_to_go);
2093 /* wait until menu, ok, back is released */
2094 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2097 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2102 static int qsort_strcmp(const void *p1, const void *p2)
2104 char * const *s1 = (char * const *)p1;
2105 char * const *s2 = (char * const *)p2;
2106 return strcasecmp(*s1, *s2);
2109 static void scan_bios_plugins(void)
2111 char fname[MAXPATHLEN];
2113 int bios_i, gpu_i, spu_i, mc_i;
2118 gpu_plugins[0] = "builtin_gpu";
2119 spu_plugins[0] = "builtin_spu";
2120 memcards[0] = "(none)";
2121 bios_i = gpu_i = spu_i = mc_i = 1;
2123 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2124 dir = opendir(fname);
2126 perror("scan_bios_plugins bios opendir");
2141 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2144 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2145 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2146 printf("bad BIOS file: %s\n", ent->d_name);
2150 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2151 bioses[bios_i++] = strdup(ent->d_name);
2155 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2161 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2162 dir = opendir(fname);
2164 perror("scan_bios_plugins plugins opendir");
2178 p = strstr(ent->d_name, ".so");
2182 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2183 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2185 fprintf(stderr, "%s\n", dlerror());
2189 // now what do we have here?
2190 tmp = dlsym(h, "GPUinit");
2193 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2194 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2198 tmp = dlsym(h, "SPUinit");
2201 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2202 spu_plugins[spu_i++] = strdup(ent->d_name);
2206 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2213 dir = opendir("." MEMCARD_DIR);
2215 perror("scan_bios_plugins memcards opendir");
2230 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2233 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2234 if (stat(fname, &st) != 0) {
2235 printf("bad memcard file: %s\n", ent->d_name);
2239 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2240 memcards[mc_i++] = strdup(ent->d_name);
2244 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2248 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2253 void menu_init(void)
2255 char buff[MAXPATHLEN];
2258 strcpy(last_selected_fname, "/media");
2260 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2262 scan_bios_plugins();
2265 menu_set_defconfig();
2266 menu_load_config(0);
2267 menu_do_last_cd_img(1);
2272 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2273 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2274 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2275 fprintf(stderr, "OOM\n");
2279 emu_make_path(buff, "skin/background.png", sizeof(buff));
2280 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2282 i = plat_target.cpu_clock_set != NULL
2283 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2284 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2286 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2287 e_menu_gfx_options[i].data = plat_target.hwfilters;
2288 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2289 plat_target.hwfilters != NULL);
2291 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2292 plat_target.gamma_set != NULL);
2294 #ifndef __ARM_ARCH_7A__
2295 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2297 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2298 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2299 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2300 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2301 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2302 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2305 void menu_notify_mode_change(int w, int h, int bpp)
2309 last_vout_bpp = bpp;
2312 static void menu_leave_emu(void)
2314 if (GPU_close != NULL) {
2315 int ret = GPU_close();
2317 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2320 plat_video_menu_enter(ready_to_go);
2322 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2323 if (pl_vout_buf != NULL && ready_to_go) {
2324 int x = max(0, g_menuscreen_w - last_vout_w);
2325 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2326 int w = min(g_menuscreen_w, last_vout_w);
2327 int h = min(g_menuscreen_h, last_vout_h);
2328 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2329 char *s = pl_vout_buf;
2331 if (last_vout_bpp == 16) {
2332 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2333 menu_darken_bg(d, s, w, 0);
2336 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2337 rgb888_to_rgb565(d, s, w * 3);
2338 menu_darken_bg(d, d, w, 0);
2344 cpu_clock = plat_target_cpu_clock_get();
2347 void menu_prepare_emu(void)
2349 R3000Acpu *prev_cpu = psxCpu;
2351 plat_video_menu_leave();
2353 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2354 if (psxCpu != prev_cpu)
2355 // note that this does not really reset, just clears drc caches
2358 // core doesn't care about Config.Cdda changes,
2359 // so handle them manually here
2365 plat_target_cpu_clock_set(cpu_clock);
2367 // push config to GPU plugin
2368 plugin_call_rearmed_cbs();
2370 if (GPU_open != NULL) {
2371 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2373 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2379 void menu_update_msg(const char *msg)
2381 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2382 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2384 menu_error_time = plat_get_ticks_ms();
2385 lprintf("msg: %s\n", menu_error_msg);
2388 void menu_finish(void)
2390 if (cpu_clock_st > 0)
2391 plat_target_cpu_clock_set(cpu_clock_st);