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/externals.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_N(name, val) \
252 { name, sizeof(val), &val }
254 #define CE_INTVAL_P(val) \
255 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
257 // 'versioned' var, used when defaults change
258 #define CE_CONFIG_STR_V(val, ver) \
259 { #val #ver, 0, Config.val }
261 #define CE_INTVAL_V(val, ver) \
262 { #val #ver, sizeof(val), &val }
264 #define CE_INTVAL_PV(val, ver) \
265 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
267 static const struct {
273 CE_CONFIG_STR_V(Gpu, 3),
275 // CE_CONFIG_STR(Cdr),
280 CE_CONFIG_VAL(Debug),
281 CE_CONFIG_VAL(PsxOut),
282 CE_CONFIG_VAL(SpuIrq),
283 CE_CONFIG_VAL(RCntFix),
284 CE_CONFIG_VAL(VSyncWA),
286 CE_CONFIG_VAL(CdrReschedule),
288 CE_INTVAL_V(g_scaler, 2),
289 CE_INTVAL(g_layer_x),
290 CE_INTVAL(g_layer_y),
291 CE_INTVAL(g_layer_w),
292 CE_INTVAL(g_layer_h),
294 CE_INTVAL(soft_filter),
295 CE_INTVAL(state_slot),
296 CE_INTVAL(cpu_clock),
298 CE_INTVAL(in_type_sel1),
299 CE_INTVAL(in_type_sel2),
300 CE_INTVAL(analog_deadzone),
301 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
302 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
303 CE_INTVAL_V(frameskip, 3),
304 CE_INTVAL_P(gpu_peops.iUseDither),
305 CE_INTVAL_P(gpu_peops.dwActFixes),
306 CE_INTVAL_P(gpu_unai.lineskip),
307 CE_INTVAL_P(gpu_unai.abe_hack),
308 CE_INTVAL_P(gpu_unai.no_light),
309 CE_INTVAL_P(gpu_unai.no_blend),
310 CE_INTVAL_P(gpu_neon.allow_interlace),
311 CE_INTVAL_P(gpu_neon.enhancement_enable),
312 CE_INTVAL_P(gpu_neon.enhancement_no_main),
313 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
314 CE_INTVAL_P(gpu_peopsgl.iFilterType),
315 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
316 CE_INTVAL_P(gpu_peopsgl.iUseMask),
317 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
318 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
319 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
320 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
321 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
322 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
323 CE_INTVAL_V(iUseReverb, 3),
324 CE_INTVAL_V(iXAPitch, 3),
325 CE_INTVAL_V(iUseInterpolation, 3),
326 CE_INTVAL(config_save_counter),
327 CE_INTVAL(in_evdev_allow_abs_only),
328 CE_INTVAL(volume_boost),
329 CE_INTVAL(psx_clock),
330 CE_INTVAL(new_dynarec_hacks),
331 CE_INTVAL(in_enable_vibration),
334 static char *get_cd_label(void)
336 static char trimlabel[33];
339 strncpy(trimlabel, CdromLabel, 32);
341 for (j = 31; j >= 0; j--)
342 if (trimlabel[j] == ' ')
348 static void make_cfg_fname(char *buf, size_t size, int is_game)
351 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
353 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
356 static void keys_write_all(FILE *f);
357 static char *mystrip(char *str);
359 static int menu_write_config(int is_game)
361 char cfgfile[MAXPATHLEN];
365 config_save_counter++;
367 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
368 f = fopen(cfgfile, "w");
370 printf("menu_write_config: failed to open: %s\n", cfgfile);
374 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
375 fprintf(f, "%s = ", config_data[i].name);
376 switch (config_data[i].len) {
378 fprintf(f, "%s\n", (char *)config_data[i].val);
381 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
384 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
387 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
390 printf("menu_write_config: unhandled len %d for %s\n",
391 (int)config_data[i].len, config_data[i].name);
402 static int menu_do_last_cd_img(int is_get)
408 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
409 f = fopen(path, is_get ? "r" : "w");
414 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
415 last_selected_fname[ret] = 0;
416 mystrip(last_selected_fname);
419 fprintf(f, "%s\n", last_selected_fname);
425 static void parse_str_val(char *cval, const char *src)
428 strncpy(cval, src, MAXPATHLEN);
429 cval[MAXPATHLEN - 1] = 0;
430 tmp = strchr(cval, '\n');
432 tmp = strchr(cval, '\r');
437 static void keys_load_all(const char *cfg);
439 static int menu_load_config(int is_game)
441 char cfgfile[MAXPATHLEN];
447 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
448 f = fopen(cfgfile, "r");
450 printf("menu_load_config: failed to open: %s\n", cfgfile);
454 fseek(f, 0, SEEK_END);
457 printf("bad size %ld: %s\n", size, cfgfile);
461 cfg = malloc(size + 1);
465 fseek(f, 0, SEEK_SET);
466 if (fread(cfg, 1, size, f) != size) {
467 printf("failed to read: %s\n", cfgfile);
472 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
476 tmp = strstr(cfg, config_data[i].name);
479 tmp += strlen(config_data[i].name);
480 if (strncmp(tmp, " = ", 3) != 0)
484 if (config_data[i].len == 0) {
485 parse_str_val(config_data[i].val, tmp);
490 val = strtoul(tmp, &tmp2, 16);
491 if (tmp2 == NULL || tmp == tmp2)
492 continue; // parse failed
494 switch (config_data[i].len) {
496 *(u8 *)config_data[i].val = val;
499 *(u16 *)config_data[i].val = val;
502 *(u32 *)config_data[i].val = val;
505 printf("menu_load_config: unhandled len %d for %s\n",
506 (int)config_data[i].len, config_data[i].name);
512 char *tmp = strstr(cfg, "lastcdimg = ");
515 parse_str_val(last_selected_fname, tmp);
530 for (i = bios_sel = 0; bioses[i] != NULL; i++)
531 if (strcmp(Config.Bios, bioses[i]) == 0)
532 { bios_sel = i; break; }
534 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
535 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
536 { gpu_plugsel = i; break; }
538 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
539 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
540 { spu_plugsel = i; break; }
545 // rrrr rggg gggb bbbb
546 static unsigned short fname2color(const char *fname)
548 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
549 ".bz", ".znx", ".pbp", ".cbn" };
550 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
551 ".table", ".index", ".sbi" };
552 const char *ext = strrchr(fname, '.');
557 for (i = 0; i < array_size(cdimg_exts); i++)
558 if (strcasecmp(ext, cdimg_exts[i]) == 0)
560 for (i = 0; i < array_size(other_exts); i++)
561 if (strcasecmp(ext, other_exts[i]) == 0)
566 static void draw_savestate_bg(int slot);
568 static const char *filter_exts[] = {
569 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
572 #define MENU_ALIGN_LEFT
573 #ifdef __ARM_ARCH_7A__ // assume hires device
579 #include "libpicofe/menu.c"
581 // a bit of black magic here
582 static void draw_savestate_bg(int slot)
584 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
586 char fname[MAXPATHLEN];
593 ret = get_state_filename(fname, sizeof(fname), slot);
597 f = gzopen(fname, "rb");
601 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
602 fprintf(stderr, "gzseek failed\n");
607 gpu = malloc(sizeof(*gpu));
613 ret = gzread(f, gpu, sizeof(*gpu));
615 if (ret != sizeof(*gpu)) {
616 fprintf(stderr, "gzread failed\n");
620 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
622 if (gpu->ulStatus & 0x800000)
623 goto out; // disabled
625 x = gpu->ulControl[5] & 0x3ff;
626 y = (gpu->ulControl[5] >> 10) & 0x1ff;
627 w = psx_widths[(gpu->ulStatus >> 16) & 7];
628 tmp = gpu->ulControl[7];
629 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
630 if (gpu->ulStatus & 0x80000) // doubleheight
632 if (h <= 0 || h > 512)
638 s = (u16 *)gpu->psxVRam + y * 1024 + x;
640 x = max(0, g_menuscreen_w - w) & ~3;
641 y = max(0, g_menuscreen_h / 2 - h / 2);
642 w = min(g_menuscreen_w, w);
643 h = min(g_menuscreen_h, h);
644 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
646 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
647 if (gpu->ulStatus & 0x200000)
648 bgr888_to_rgb565(d, s, w * 3);
650 bgr555_to_rgb565(d, s, w * 2);
652 // darken this so that menu text is visible
653 if (g_menuscreen_w - w < 320)
654 menu_darken_bg(d, d, w * 2, 0);
661 // -------------- key config --------------
663 me_bind_action me_ctrl_actions[] =
665 { "UP ", 1 << DKEY_UP},
666 { "DOWN ", 1 << DKEY_DOWN },
667 { "LEFT ", 1 << DKEY_LEFT },
668 { "RIGHT ", 1 << DKEY_RIGHT },
669 { "TRIANGLE", 1 << DKEY_TRIANGLE },
670 { "CIRCLE ", 1 << DKEY_CIRCLE },
671 { "CROSS ", 1 << DKEY_CROSS },
672 { "SQUARE ", 1 << DKEY_SQUARE },
673 { "L1 ", 1 << DKEY_L1 },
674 { "R1 ", 1 << DKEY_R1 },
675 { "L2 ", 1 << DKEY_L2 },
676 { "R2 ", 1 << DKEY_R2 },
677 { "L3 ", 1 << DKEY_L3 },
678 { "R3 ", 1 << DKEY_R3 },
679 { "START ", 1 << DKEY_START },
680 { "SELECT ", 1 << DKEY_SELECT },
684 me_bind_action emuctrl_actions[] =
686 { "Save State ", 1 << SACTION_SAVE_STATE },
687 { "Load State ", 1 << SACTION_LOAD_STATE },
688 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
689 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
690 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
691 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
692 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
693 #ifdef __ARM_ARCH_7A__
694 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
696 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
697 #if MENU_SHOW_MINIMIZE
698 { "Minimize ", 1 << SACTION_MINIMIZE },
700 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
701 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
702 { "Gun A button ", 1 << SACTION_GUN_A },
703 { "Gun B button ", 1 << SACTION_GUN_B },
704 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
706 { "Volume Up ", 1 << SACTION_VOLUME_UP },
707 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
712 static char *mystrip(char *str)
717 for (i = 0; i < len; i++)
718 if (str[i] != ' ') break;
719 if (i > 0) memmove(str, str + i, len - i + 1);
722 for (i = len - 1; i >= 0; i--)
723 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
729 static void get_line(char *d, size_t size, const char *s)
734 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
745 static void keys_write_all(FILE *f)
749 for (d = 0; d < IN_MAX_DEVS; d++)
751 const int *binds = in_get_dev_binds(d);
752 const char *name = in_get_dev_name(d, 0, 0);
755 if (binds == NULL || name == NULL)
758 fprintf(f, "binddev = %s\n", name);
759 in_get_config(d, IN_CFG_BIND_COUNT, &count);
761 for (k = 0; k < count; k++)
766 act[0] = act[31] = 0;
767 name = in_get_key_name(d, k);
769 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
770 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
771 mask = me_ctrl_actions[i].mask;
773 strncpy(act, me_ctrl_actions[i].name, 31);
774 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
777 mask = me_ctrl_actions[i].mask << 16;
779 strncpy(act, me_ctrl_actions[i].name, 31);
780 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
785 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
786 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
787 mask = emuctrl_actions[i].mask;
789 strncpy(act, emuctrl_actions[i].name, 31);
790 fprintf(f, "bind %s = %s\n", name, mystrip(act));
796 for (k = 0; k < array_size(in_adev); k++)
799 fprintf(f, "bind_analog = %d\n", k);
804 static int parse_bind_val(const char *val, int *type)
808 *type = IN_BINDTYPE_NONE;
812 if (strncasecmp(val, "player", 6) == 0)
814 int player, shift = 0;
815 player = atoi(val + 6) - 1;
817 if ((unsigned int)player > 1)
822 *type = IN_BINDTYPE_PLAYER12;
823 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
824 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
825 return me_ctrl_actions[i].mask << shift;
828 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
829 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
830 *type = IN_BINDTYPE_EMU;
831 return emuctrl_actions[i].mask;
838 static void keys_load_all(const char *cfg)
840 char dev[256], key[128], *act;
846 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
849 get_line(dev, sizeof(dev), p);
850 dev_id = in_config_parse_dev(dev);
852 printf("input: can't handle dev: %s\n", dev);
856 in_unbind_all(dev_id, -1, -1);
857 while ((p = strstr(p, "bind"))) {
858 if (strncmp(p, "binddev = ", 10) == 0)
861 if (strncmp(p, "bind_analog", 11) == 0) {
862 ret = sscanf(p, "bind_analog = %d", &bind);
865 printf("input: parse error: %16s..\n", p);
868 if ((unsigned int)bind >= array_size(in_adev)) {
869 printf("input: analog id %d out of range\n", bind);
872 in_adev[bind] = dev_id;
878 printf("input: parse error: %16s..\n", p);
882 get_line(key, sizeof(key), p);
883 act = strchr(key, '=');
885 printf("parse failed: %16s..\n", p);
893 bind = parse_bind_val(act, &bindtype);
894 if (bind != -1 && bind != 0) {
895 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
896 in_config_bind_key(dev_id, key, bind, bindtype);
899 lprintf("config: unhandled action \"%s\"\n", act);
905 static int key_config_loop_wrap(int id, int keys)
908 case MA_CTRL_PLAYER1:
909 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
911 case MA_CTRL_PLAYER2:
912 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
915 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
923 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
924 "Might cause problems with real analog sticks";
925 static const char *adevnames[IN_MAX_DEVS + 2];
926 static int stick_sel[2];
928 static menu_entry e_menu_keyconfig_analog[] =
930 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
931 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
932 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
933 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
934 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
935 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
936 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
937 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
941 static int key_config_analog(int id, int keys)
943 int i, d, count, sel = 0;
944 int sel2dev_map[IN_MAX_DEVS];
946 memset(adevnames, 0, sizeof(adevnames));
947 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
948 memset(stick_sel, 0, sizeof(stick_sel));
950 adevnames[0] = "None";
952 for (d = 0; d < IN_MAX_DEVS; d++)
954 const char *name = in_get_dev_name(d, 0, 1);
959 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
963 if (in_adev[0] == d) stick_sel[0] = i;
964 if (in_adev[1] == d) stick_sel[1] = i;
966 adevnames[i++] = name;
970 me_loop(e_menu_keyconfig_analog, &sel);
972 in_adev[0] = sel2dev_map[stick_sel[0]];
973 in_adev[1] = sel2dev_map[stick_sel[1]];
978 static const char *mgn_dev_name(int id, int *offs)
980 const char *name = NULL;
983 if (id == MA_CTRL_DEV_FIRST)
986 for (; it < IN_MAX_DEVS; it++) {
987 name = in_get_dev_name(it, 1, 1);
996 static const char *mgn_saveloadcfg(int id, int *offs)
1001 static int mh_savecfg(int id, int keys)
1003 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1004 menu_update_msg("config saved");
1006 menu_update_msg("failed to write config");
1011 static int mh_input_rescan(int id, int keys)
1013 //menu_sync_config();
1015 menu_update_msg("rescan complete.");
1020 static const char *men_in_type_sel[] = {
1021 "Standard (SCPH-1080)",
1022 "Analog (SCPH-1150)",
1026 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1027 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1028 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1030 static menu_entry e_menu_keyconfig[] =
1032 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1033 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1034 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1035 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1037 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1038 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1039 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1040 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1041 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1042 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1043 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1044 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1045 mee_handler ("Rescan devices:", mh_input_rescan),
1047 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1048 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1049 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1050 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1051 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1052 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1053 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1057 static int menu_loop_keyconfig(int id, int keys)
1061 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1062 me_loop(e_menu_keyconfig, &sel);
1066 // ------------ gfx options menu ------------
1068 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1069 static const char *men_soft_filter[] = { "None",
1071 "scale2x", "eagle2x",
1074 static const char *men_dummy[] = { NULL };
1075 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1076 "using d-pad or move it using R+d-pad";
1077 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1078 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1080 static int menu_loop_cscaler(int id, int keys)
1084 g_scaler = SCALE_CUSTOM;
1086 plat_gvideo_open(Config.PsxType);
1090 menu_draw_begin(0, 1);
1091 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1092 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1093 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1096 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1097 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1098 if (inp & PBTN_UP) g_layer_y--;
1099 if (inp & PBTN_DOWN) g_layer_y++;
1100 if (inp & PBTN_LEFT) g_layer_x--;
1101 if (inp & PBTN_RIGHT) g_layer_x++;
1102 if (!(inp & PBTN_R)) {
1103 if (inp & PBTN_UP) g_layer_h += 2;
1104 if (inp & PBTN_DOWN) g_layer_h -= 2;
1105 if (inp & PBTN_LEFT) g_layer_w += 2;
1106 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1108 if (inp & (PBTN_MOK|PBTN_MBACK))
1111 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1112 if (g_layer_x < 0) g_layer_x = 0;
1113 if (g_layer_x > 640) g_layer_x = 640;
1114 if (g_layer_y < 0) g_layer_y = 0;
1115 if (g_layer_y > 420) g_layer_y = 420;
1116 if (g_layer_w < 160) g_layer_w = 160;
1117 if (g_layer_h < 60) g_layer_h = 60;
1118 if (g_layer_x + g_layer_w > 800)
1119 g_layer_w = 800 - g_layer_x;
1120 if (g_layer_y + g_layer_h > 480)
1121 g_layer_h = 480 - g_layer_y;
1123 plat_gvideo_open(Config.PsxType);
1127 plat_gvideo_close();
1132 static menu_entry e_menu_gfx_options[] =
1134 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1135 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1136 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, filter, men_dummy),
1137 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1138 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1139 // mee_onoff ("Vsync", 0, vsync, 1),
1140 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1144 static int menu_loop_gfx_options(int id, int keys)
1148 me_loop(e_menu_gfx_options, &sel);
1153 // ------------ bios/plugins ------------
1157 static const char h_gpu_neon[] =
1158 "Configure built-in NEON GPU plugin";
1159 static const char h_gpu_neon_enhanced[] =
1160 "Renders in double resolution at the cost of lower performance\n"
1161 "(not available for high resolution games)";
1162 static const char h_gpu_neon_enhanced_hack[] =
1163 "Speed hack for above option (glitches some games)";
1164 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1166 static menu_entry e_menu_plugin_gpu_neon[] =
1168 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1169 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1170 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1174 static int menu_loop_plugin_gpu_neon(int id, int keys)
1177 me_loop(e_menu_plugin_gpu_neon, &sel);
1183 static menu_entry e_menu_plugin_gpu_unai[] =
1185 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1186 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1187 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1188 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1192 static int menu_loop_plugin_gpu_unai(int id, int keys)
1195 me_loop(e_menu_plugin_gpu_unai, &sel);
1199 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1200 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1201 static const char h_gpu_1[] = "Capcom fighting games";
1202 static const char h_gpu_2[] = "Black screens in Lunar";
1203 static const char h_gpu_3[] = "Compatibility mode";
1204 static const char h_gpu_6[] = "Pandemonium 2";
1205 //static const char h_gpu_7[] = "Skip every second frame";
1206 static const char h_gpu_8[] = "Needed by Dark Forces";
1207 static const char h_gpu_9[] = "better g-colors, worse textures";
1208 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1210 static menu_entry e_menu_plugin_gpu_peops[] =
1212 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1213 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1214 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1215 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1216 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1217 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1218 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1219 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1220 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1221 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1225 static int menu_loop_plugin_gpu_peops(int id, int keys)
1228 me_loop(e_menu_plugin_gpu_peops, &sel);
1232 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1233 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1234 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1236 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1238 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1239 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1240 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1241 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1242 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1243 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1244 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1245 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1246 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1247 mee_label ("Fixes/hacks:"),
1248 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1249 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1250 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1251 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1252 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1253 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1254 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1255 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1256 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1257 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1258 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1262 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1265 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1269 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1270 static const char h_spu_volboost[] = "Large values cause distortion";
1272 static menu_entry e_menu_plugin_spu[] =
1274 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1275 mee_onoff ("Reverb", 0, iUseReverb, 2),
1276 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1277 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1281 static int menu_loop_plugin_spu(int id, int keys)
1284 me_loop(e_menu_plugin_spu, &sel);
1288 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1289 "savestates and can't be changed there. Must save\n"
1290 "config and reload the game for change to take effect";
1291 static const char h_plugin_gpu[] =
1293 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1295 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1296 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1297 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1298 "must save config and reload the game if changed";
1299 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1300 "must save config and reload the game if changed";
1301 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1302 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1303 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1304 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1306 static menu_entry e_menu_plugin_options[] =
1308 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1309 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1310 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1312 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1314 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1315 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1316 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1317 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1321 static menu_entry e_menu_main2[];
1323 static int menu_loop_plugin_options(int id, int keys)
1326 me_loop(e_menu_plugin_options, &sel);
1328 // sync BIOS/plugins
1329 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1330 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1331 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1332 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1337 // ------------ adv options menu ------------
1339 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1340 "(lower value - less work for the emu, may be faster)";
1341 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1342 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1343 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1345 static menu_entry e_menu_speed_hacks[] =
1347 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1348 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1349 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1350 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1354 static int menu_loop_speed_hacks(int id, int keys)
1357 me_loop(e_menu_speed_hacks, &sel);
1361 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1362 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1363 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1364 "(green: normal, red: fmod, blue: noise)";
1365 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1366 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1367 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1368 "(proper .cue/.bin dump is needed otherwise)";
1369 static const char h_cfg_sio[] = "You should not need this, breaks games";
1370 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1371 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1372 "(timing hack, breaks other games)";
1373 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1374 "(timing hack, breaks other games)";
1375 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1376 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1377 "Might be useful to overcome some dynarec bugs";
1378 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1379 "must reload game for any change to take effect";
1381 static menu_entry e_menu_adv_options[] =
1383 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1384 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1385 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1386 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1387 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1388 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1389 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1390 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1391 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1392 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1393 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1394 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1398 static int menu_loop_adv_options(int id, int keys)
1401 me_loop(e_menu_adv_options, &sel);
1405 // ------------ options menu ------------
1407 static int mh_restore_defaults(int id, int keys)
1409 menu_set_defconfig();
1410 menu_update_msg("defaults restored");
1414 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1415 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1417 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1418 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1419 "loading state or both";
1421 static const char h_restore_def[] = "Switches back to default / recommended\n"
1423 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1425 static menu_entry e_menu_options[] =
1427 // mee_range ("Save slot", 0, state_slot, 0, 9),
1428 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1429 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1430 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1431 mee_enum ("Region", 0, region, men_region),
1432 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1433 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1434 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1435 mee_handler ("[Advanced]", menu_loop_adv_options),
1436 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1437 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1438 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1442 static int menu_loop_options(int id, int keys)
1447 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1448 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1449 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1451 me_loop(e_menu_options, &sel);
1456 // ------------ debug menu ------------
1458 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1460 int w = min(g_menuscreen_w, 1024);
1461 int h = min(g_menuscreen_h, 512);
1462 u16 *d = g_menuscreen_ptr;
1463 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1467 gpuf->ulFreezeVersion = 1;
1468 if (GPU_freeze != NULL)
1469 GPU_freeze(1, gpuf);
1471 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1472 bgr555_to_rgb565(d, s, w * 2);
1474 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1475 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1476 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1477 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1478 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1481 static void debug_menu_loop(void)
1483 int inp, df_x = 0, df_y = 0;
1486 gpuf = malloc(sizeof(*gpuf));
1492 menu_draw_begin(0, 1);
1493 draw_frame_debug(gpuf, df_x, df_y);
1496 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1497 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1498 if (inp & PBTN_MBACK) break;
1499 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1500 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1501 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1502 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1508 // --------- memcard manager ---------
1510 static void draw_mc_icon(int dx, int dy, const u16 *s)
1515 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1517 for (y = 0; y < 16; y++, s += 16) {
1518 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1519 for (x = 0; x < 16; x++) {
1521 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1522 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1528 static void draw_mc_bg(void)
1530 McdBlock *blocks1, *blocks2;
1534 blocks1 = malloc(15 * sizeof(blocks1[0]));
1535 blocks2 = malloc(15 * sizeof(blocks1[0]));
1536 if (blocks1 == NULL || blocks2 == NULL)
1539 for (i = 0; i < 15; i++) {
1540 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1541 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1544 menu_draw_begin(1, 1);
1546 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1548 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1552 maxicons = g_menuscreen_h / 32;
1555 row2 = g_menuscreen_w / 2;
1556 for (i = 0; i < maxicons; i++) {
1557 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1558 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1560 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1561 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1564 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1572 static void handle_memcard_sel(void)
1575 if (memcard1_sel != 0)
1576 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1578 if (memcard2_sel != 0)
1579 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1580 LoadMcds(Config.Mcd1, Config.Mcd2);
1584 static menu_entry e_memcard_options[] =
1586 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1587 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1591 static int menu_loop_memcards(int id, int keys)
1597 memcard1_sel = memcard2_sel = 0;
1598 p = strrchr(Config.Mcd1, '/');
1600 for (i = 0; memcards[i] != NULL; i++)
1601 if (strcmp(p + 1, memcards[i]) == 0)
1602 { memcard1_sel = i; break; }
1603 p = strrchr(Config.Mcd2, '/');
1605 for (i = 0; memcards[i] != NULL; i++)
1606 if (strcmp(p + 1, memcards[i]) == 0)
1607 { memcard2_sel = i; break; }
1609 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1611 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1616 // ------------ cheats menu ------------
1618 static void draw_cheatlist(int sel)
1620 int max_cnt, start, i, pos, active;
1622 max_cnt = g_menuscreen_h / me_sfont_h;
1623 start = max_cnt / 2 - sel;
1625 menu_draw_begin(1, 1);
1627 for (i = 0; i < NumCheats; i++) {
1629 if (pos < 0) continue;
1630 if (pos >= max_cnt) break;
1631 active = Cheats[i].Enabled;
1632 smalltext_out16(14, pos * me_sfont_h,
1633 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1634 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1635 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1639 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1641 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1645 static void menu_loop_cheats(void)
1647 static int menu_sel = 0;
1652 draw_cheatlist(menu_sel);
1653 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1654 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1655 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1656 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1657 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1658 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1659 if (inp & PBTN_MOK) { // action
1660 if (menu_sel < NumCheats)
1661 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1664 if (inp & PBTN_MBACK)
1669 // --------- main menu help ----------
1671 static void menu_bios_warn(void)
1674 static const char msg[] =
1675 "You don't seem to have copied any BIOS\n"
1677 MENU_BIOS_PATH "\n\n"
1679 "While many games work fine with fake\n"
1680 "(HLE) BIOS, others (like MGS and FF8)\n"
1681 "require BIOS to work.\n"
1682 "After copying the file, you'll also need\n"
1683 "to select it in the emu's menu:\n"
1684 "options->[BIOS/Plugins]\n\n"
1685 "The file is usually named SCPH1001.BIN,\n"
1686 "but other not compressed files can be\n"
1688 "Press %s or %s to continue";
1689 char tmp_msg[sizeof(msg) + 64];
1691 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1692 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1695 draw_menu_message(tmp_msg, NULL);
1697 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1698 if (inp & (PBTN_MBACK|PBTN_MOK))
1703 // ------------ main menu ------------
1705 static menu_entry e_menu_main[];
1708 static void draw_frame_main(void)
1717 if (CdromId[0] != 0) {
1718 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1719 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1720 Config.HLE ? "HLE" : "BIOS");
1721 smalltext_out16(4, 1, buff, 0x105f);
1725 capacity = plat_target_bat_capacity_get();
1727 tmp = localtime(<ime);
1728 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1729 if (capacity >= 0) {
1730 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1735 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1739 static void draw_frame_credits(void)
1741 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1744 static const char credits_text[] =
1746 "(C) 1999-2003 PCSX Team\n"
1747 "(C) 2005-2009 PCSX-df Team\n"
1748 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1749 "ARM recompiler (C) 2009-2011 Ari64\n"
1751 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1753 "PEOpS GPU and SPU by Pete Bernert\n"
1754 " and the P.E.Op.S. team\n"
1755 "PCSX4ALL plugin by PCSX4ALL team\n"
1756 " Chui, Franxis, Unai\n\n"
1757 "integration, optimization and\n"
1758 " frontend (C) 2010-2012 notaz\n";
1760 static int reset_game(void)
1763 if (bios_sel == 0 && !Config.HLE)
1769 if (CheckCdrom() != -1) {
1775 static int reload_plugins(const char *cdimg)
1781 set_cd_image(cdimg);
1783 pcnt_hook_plugins();
1785 if (OpenPlugins() == -1) {
1786 menu_update_msg("failed to open plugins");
1789 plugin_call_rearmed_cbs();
1791 cdrIsoMultidiskCount = 1;
1793 CdromLabel[0] = '\0';
1798 static int run_bios(void)
1804 if (reload_plugins(NULL) != 0)
1812 static int run_exe(void)
1816 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1821 if (reload_plugins(NULL) != 0)
1825 if (Load(fname) != 0) {
1826 menu_update_msg("exe load failed, bad file?");
1835 static int run_cd_image(const char *fname)
1838 reload_plugins(fname);
1840 // always autodetect, menu_sync_config will override as needed
1843 if (CheckCdrom() == -1) {
1844 // Only check the CD if we are starting the console with a CD
1846 menu_update_msg("unsupported/invalid CD image");
1852 // Read main executable directly from CDRom and start it
1853 if (LoadCdrom() == -1) {
1855 menu_update_msg("failed to load CD image");
1865 static int romsel_run(void)
1867 int prev_gpu, prev_spu;
1870 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1874 printf("selected file: %s\n", fname);
1876 new_dynarec_clear_full();
1878 if (run_cd_image(fname) != 0)
1881 prev_gpu = gpu_plugsel;
1882 prev_spu = spu_plugsel;
1883 if (menu_load_config(1) != 0)
1884 menu_load_config(0);
1886 // check for plugin changes, have to repeat
1887 // loading if game config changed plugins to reload them
1888 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1889 printf("plugin change detected, reloading plugins..\n");
1890 if (run_cd_image(fname) != 0)
1894 strcpy(last_selected_fname, rom_fname_reload);
1895 menu_do_last_cd_img(0);
1899 static int swap_cd_image(void)
1903 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1907 printf("selected file: %s\n", fname);
1910 CdromLabel[0] = '\0';
1912 set_cd_image(fname);
1913 if (ReloadCdromPlugin() < 0) {
1914 menu_update_msg("failed to load cdr plugin");
1917 if (CDR_open() < 0) {
1918 menu_update_msg("failed to open cdr plugin");
1922 SetCdOpenCaseTime(time(NULL) + 2);
1925 strcpy(last_selected_fname, rom_fname_reload);
1929 static int swap_cd_multidisk(void)
1931 cdrIsoMultidiskSelect++;
1933 CdromLabel[0] = '\0';
1936 if (CDR_open() < 0) {
1937 menu_update_msg("failed to open cdr plugin");
1941 SetCdOpenCaseTime(time(NULL) + 2);
1947 static void load_pcsx_cht(void)
1953 fname = menu_loop_romsel(path, sizeof(path));
1957 printf("selected cheat file: %s\n", fname);
1960 if (NumCheats == 0 && NumCodes == 0)
1961 menu_update_msg("failed to load cheats");
1963 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1964 menu_update_msg(path);
1966 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1969 static int main_menu_handler(int id, int keys)
1973 case MA_MAIN_RESUME_GAME:
1977 case MA_MAIN_SAVE_STATE:
1979 return menu_loop_savestate(0);
1981 case MA_MAIN_LOAD_STATE:
1983 return menu_loop_savestate(1);
1985 case MA_MAIN_RESET_GAME:
1986 if (ready_to_go && reset_game() == 0)
1989 case MA_MAIN_LOAD_ROM:
1990 if (romsel_run() == 0)
1993 case MA_MAIN_SWAP_CD:
1994 if (swap_cd_image() == 0)
1997 case MA_MAIN_SWAP_CD_MULTI:
1998 if (swap_cd_multidisk() == 0)
2001 case MA_MAIN_RUN_BIOS:
2002 if (run_bios() == 0)
2005 case MA_MAIN_RUN_EXE:
2009 case MA_MAIN_CHEATS:
2012 case MA_MAIN_LOAD_CHEATS:
2015 case MA_MAIN_CREDITS:
2016 draw_menu_message(credits_text, draw_frame_credits);
2017 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2023 lprintf("%s: something unknown selected\n", __FUNCTION__);
2030 static menu_entry e_menu_main2[] =
2032 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2033 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2034 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2035 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2036 mee_handler ("Memcard manager", menu_loop_memcards),
2037 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2041 static int main_menu2_handler(int id, int keys)
2045 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2046 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2047 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2048 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2050 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2053 static const char h_extra[] = "Change CD, manage memcards..\n";
2055 static menu_entry e_menu_main[] =
2059 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2060 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2061 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2062 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2063 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2064 mee_handler ("Options", menu_loop_options),
2065 mee_handler ("Controls", menu_loop_keyconfig),
2066 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2067 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2068 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2069 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2073 // ----------------------------
2075 static void menu_leave_emu(void);
2077 void menu_loop(void)
2079 static int warned_about_bios = 0;
2084 if (config_save_counter == 0) {
2086 if (bioses[1] != NULL) {
2087 // autoselect BIOS to make user's life easier
2088 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2091 else if (!warned_about_bios) {
2093 warned_about_bios = 1;
2097 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2098 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2099 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2100 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2101 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2103 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2106 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2107 } while (!ready_to_go);
2109 /* wait until menu, ok, back is released */
2110 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2113 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2118 static int qsort_strcmp(const void *p1, const void *p2)
2120 char * const *s1 = (char * const *)p1;
2121 char * const *s2 = (char * const *)p2;
2122 return strcasecmp(*s1, *s2);
2125 static void scan_bios_plugins(void)
2127 char fname[MAXPATHLEN];
2129 int bios_i, gpu_i, spu_i, mc_i;
2134 gpu_plugins[0] = "builtin_gpu";
2135 spu_plugins[0] = "builtin_spu";
2136 memcards[0] = "(none)";
2137 bios_i = gpu_i = spu_i = mc_i = 1;
2139 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2140 dir = opendir(fname);
2142 perror("scan_bios_plugins bios opendir");
2157 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2160 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2161 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2162 printf("bad BIOS file: %s\n", ent->d_name);
2166 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2167 bioses[bios_i++] = strdup(ent->d_name);
2171 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2177 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2178 dir = opendir(fname);
2180 perror("scan_bios_plugins plugins opendir");
2194 p = strstr(ent->d_name, ".so");
2198 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2199 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2201 fprintf(stderr, "%s\n", dlerror());
2205 // now what do we have here?
2206 tmp = dlsym(h, "GPUinit");
2209 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2210 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2214 tmp = dlsym(h, "SPUinit");
2217 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2218 spu_plugins[spu_i++] = strdup(ent->d_name);
2222 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2229 dir = opendir("." MEMCARD_DIR);
2231 perror("scan_bios_plugins memcards opendir");
2246 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2249 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2250 if (stat(fname, &st) != 0) {
2251 printf("bad memcard file: %s\n", ent->d_name);
2255 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2256 memcards[mc_i++] = strdup(ent->d_name);
2260 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2264 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2269 void menu_init(void)
2271 char buff[MAXPATHLEN];
2274 strcpy(last_selected_fname, "/media");
2276 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2278 scan_bios_plugins();
2281 menu_set_defconfig();
2282 menu_load_config(0);
2283 menu_do_last_cd_img(1);
2288 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2289 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2290 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2291 fprintf(stderr, "OOM\n");
2295 emu_make_path(buff, "skin/background.png", sizeof(buff));
2296 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2298 i = plat_target.cpu_clock_set != NULL
2299 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2300 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2302 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2303 e_menu_gfx_options[i].data = plat_target.hwfilters;
2304 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2305 plat_target.hwfilters != NULL);
2307 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2308 plat_target.gamma_set != NULL);
2310 #ifndef __ARM_ARCH_7A__
2311 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2313 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2314 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2315 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2316 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2317 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2318 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2321 void menu_notify_mode_change(int w, int h, int bpp)
2325 last_vout_bpp = bpp;
2328 static void menu_leave_emu(void)
2330 if (GPU_close != NULL) {
2331 int ret = GPU_close();
2333 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2336 plat_video_menu_enter(ready_to_go);
2338 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2339 if (pl_vout_buf != NULL && ready_to_go) {
2340 int x = max(0, g_menuscreen_w - last_vout_w);
2341 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2342 int w = min(g_menuscreen_w, last_vout_w);
2343 int h = min(g_menuscreen_h, last_vout_h);
2344 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2345 char *s = pl_vout_buf;
2347 if (last_vout_bpp == 16) {
2348 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2349 menu_darken_bg(d, s, w, 0);
2352 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2353 rgb888_to_rgb565(d, s, w * 3);
2354 menu_darken_bg(d, d, w, 0);
2360 cpu_clock = plat_target_cpu_clock_get();
2363 void menu_prepare_emu(void)
2365 R3000Acpu *prev_cpu = psxCpu;
2367 plat_video_menu_leave();
2369 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2370 if (psxCpu != prev_cpu)
2371 // note that this does not really reset, just clears drc caches
2374 // core doesn't care about Config.Cdda changes,
2375 // so handle them manually here
2381 plat_target_cpu_clock_set(cpu_clock);
2383 // push config to GPU plugin
2384 plugin_call_rearmed_cbs();
2386 if (GPU_open != NULL) {
2387 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2389 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2395 void menu_update_msg(const char *msg)
2397 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2398 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2400 menu_error_time = plat_get_ticks_ms();
2401 lprintf("msg: %s\n", menu_error_msg);
2404 void menu_finish(void)
2406 if (cpu_clock_st > 0)
2407 plat_target_cpu_clock_set(cpu_clock_st);