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/new_dynarec/new_dynarec.h"
36 #include "../plugins/dfinput/externals.h"
37 #include "../plugins/gpulib/cspace.h"
38 #include "psemu_plugin_defs.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,
85 static int last_vout_w, last_vout_h, last_vout_bpp;
86 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
87 static char rom_fname_reload[MAXPATHLEN];
88 static char last_selected_fname[MAXPATHLEN];
89 static int config_save_counter, region, in_type_sel1, in_type_sel2;
91 static int memcard1_sel, memcard2_sel;
92 int g_opts, g_scaler, g_gamma = 100;
93 int soft_scaling, analog_deadzone; // for Caanoo
94 int g_use_overlay, g_fullscreen;
95 int filter, soft_filter;
97 #ifdef __ARM_ARCH_7A__
98 #define DEFAULT_PSX_CLOCK 57
99 #define DEFAULT_PSX_CLOCK_S "57"
101 #define DEFAULT_PSX_CLOCK 50
102 #define DEFAULT_PSX_CLOCK_S "50"
106 extern int iUseReverb;
107 extern int iUseInterpolation;
111 static const char *bioses[24];
112 static const char *gpu_plugins[16];
113 static const char *spu_plugins[16];
114 static const char *memcards[32];
115 static int bios_sel, gpu_plugsel, spu_plugsel;
117 #ifndef UI_FEATURES_H
118 #define MENU_BIOS_PATH "bios/"
119 #define MENU_SHOW_VARSCALER 0
120 #define MENU_SHOW_VIDOVERLAY 1
121 #define MENU_SHOW_SCALER2 0
122 #define MENU_SHOW_NUBS_BTNS 0
123 #define MENU_SHOW_VIBRATION 0
124 #define MENU_SHOW_DEADZONE 0
125 #define MENU_SHOW_MINIMIZE 0
126 #define MENU_SHOW_FULLSCREEN 1
127 #define MENU_SHOW_VOLUME 0
130 static int min(int x, int y) { return x < y ? x : y; }
131 static int max(int x, int y) { return x > y ? x : y; }
133 void emu_make_path(char *buff, const char *end, int size)
137 end_len = strlen(end);
138 pos = plat_get_root_dir(buff, size);
139 strncpy(buff + pos, end, size - pos);
141 if (pos + end_len > size - 1)
142 printf("Warning: path truncated: %s\n", buff);
145 static int emu_check_save_file(int slot, int *time)
147 char fname[MAXPATHLEN];
151 ret = emu_check_state(slot);
152 if (ret != 0 || time == NULL)
153 return ret == 0 ? 1 : 0;
155 ret = get_state_filename(fname, sizeof(fname), slot);
159 ret = stat(fname, &status);
163 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
164 return 1; // probably bad rtc like on some Caanoos
166 *time = status.st_mtime;
171 static int emu_save_load_game(int load, int unused)
176 ret = emu_load_state(state_slot);
178 // reflect hle/bios mode from savestate
181 else if (bios_sel == 0 && bioses[1] != NULL)
182 // XXX: maybe find the right bios instead
186 ret = emu_save_state(state_slot);
191 // propagate menu settings to the emu vars
192 static void menu_sync_config(void)
194 static int allow_abs_only_old;
199 Config.PsxType = region - 1;
201 cycle_multiplier = 10000 / psx_clock;
203 switch (in_type_sel1) {
204 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
205 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
206 default: in_type1 = PSE_PAD_TYPE_STANDARD;
208 switch (in_type_sel2) {
209 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
210 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
211 default: in_type2 = PSE_PAD_TYPE_STANDARD;
213 if (in_evdev_allow_abs_only != allow_abs_only_old) {
215 allow_abs_only_old = in_evdev_allow_abs_only;
218 iVolume = 768 + 128 * volume_boost;
219 pl_rearmed_cbs.frameskip = frameskip - 1;
220 pl_timing_prepare(Config.PsxType);
223 static void menu_set_defconfig(void)
225 emu_set_default_config();
228 g_scaler = SCALE_4_3;
231 analog_deadzone = 50;
236 psx_clock = DEFAULT_PSX_CLOCK;
239 in_type_sel1 = in_type_sel2 = 0;
240 in_evdev_allow_abs_only = 0;
245 #define CE_CONFIG_STR(val) \
246 { #val, 0, Config.val }
248 #define CE_CONFIG_VAL(val) \
249 { #val, sizeof(Config.val), &Config.val }
251 #define CE_STR(val) \
254 #define CE_INTVAL(val) \
255 { #val, sizeof(val), &val }
257 #define CE_INTVAL_N(name, val) \
258 { name, sizeof(val), &val }
260 #define CE_INTVAL_P(val) \
261 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
263 // 'versioned' var, used when defaults change
264 #define CE_CONFIG_STR_V(val, ver) \
265 { #val #ver, 0, Config.val }
267 #define CE_INTVAL_V(val, ver) \
268 { #val #ver, sizeof(val), &val }
270 #define CE_INTVAL_PV(val, ver) \
271 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
273 static const struct {
279 CE_CONFIG_STR_V(Gpu, 3),
281 // CE_CONFIG_STR(Cdr),
286 CE_CONFIG_VAL(Debug),
287 CE_CONFIG_VAL(PsxOut),
288 CE_CONFIG_VAL(SpuIrq),
289 CE_CONFIG_VAL(RCntFix),
290 CE_CONFIG_VAL(VSyncWA),
292 CE_CONFIG_VAL(CdrReschedule),
294 CE_INTVAL_V(g_scaler, 2),
295 CE_INTVAL(g_layer_x),
296 CE_INTVAL(g_layer_y),
297 CE_INTVAL(g_layer_w),
298 CE_INTVAL(g_layer_h),
300 CE_INTVAL(soft_filter),
301 CE_INTVAL(g_use_overlay),
302 CE_INTVAL(g_fullscreen),
303 CE_INTVAL(state_slot),
304 CE_INTVAL(cpu_clock),
306 CE_INTVAL(in_type_sel1),
307 CE_INTVAL(in_type_sel2),
308 CE_INTVAL(analog_deadzone),
309 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
310 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
311 CE_INTVAL_V(frameskip, 3),
312 CE_INTVAL_P(gpu_peops.iUseDither),
313 CE_INTVAL_P(gpu_peops.dwActFixes),
314 CE_INTVAL_P(gpu_unai.lineskip),
315 CE_INTVAL_P(gpu_unai.abe_hack),
316 CE_INTVAL_P(gpu_unai.no_light),
317 CE_INTVAL_P(gpu_unai.no_blend),
318 CE_INTVAL_P(gpu_neon.allow_interlace),
319 CE_INTVAL_P(gpu_neon.enhancement_enable),
320 CE_INTVAL_P(gpu_neon.enhancement_no_main),
321 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
322 CE_INTVAL_P(gpu_peopsgl.iFilterType),
323 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
324 CE_INTVAL_P(gpu_peopsgl.iUseMask),
325 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
326 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
327 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
328 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
329 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
330 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
331 CE_INTVAL_V(iUseReverb, 3),
332 CE_INTVAL_V(iXAPitch, 3),
333 CE_INTVAL_V(iUseInterpolation, 3),
334 CE_INTVAL(config_save_counter),
335 CE_INTVAL(in_evdev_allow_abs_only),
336 CE_INTVAL(volume_boost),
337 CE_INTVAL(psx_clock),
338 CE_INTVAL(new_dynarec_hacks),
339 CE_INTVAL(in_enable_vibration),
342 static char *get_cd_label(void)
344 static char trimlabel[33];
347 strncpy(trimlabel, CdromLabel, 32);
349 for (j = 31; j >= 0; j--)
350 if (trimlabel[j] == ' ')
356 static void make_cfg_fname(char *buf, size_t size, int is_game)
359 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
361 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
364 static void keys_write_all(FILE *f);
365 static char *mystrip(char *str);
367 static int menu_write_config(int is_game)
369 char cfgfile[MAXPATHLEN];
373 config_save_counter++;
375 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
376 f = fopen(cfgfile, "w");
378 printf("menu_write_config: failed to open: %s\n", cfgfile);
382 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
383 fprintf(f, "%s = ", config_data[i].name);
384 switch (config_data[i].len) {
386 fprintf(f, "%s\n", (char *)config_data[i].val);
389 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
392 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
395 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
398 printf("menu_write_config: unhandled len %d for %s\n",
399 (int)config_data[i].len, config_data[i].name);
410 static int menu_do_last_cd_img(int is_get)
416 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
417 f = fopen(path, is_get ? "r" : "w");
422 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
423 last_selected_fname[ret] = 0;
424 mystrip(last_selected_fname);
427 fprintf(f, "%s\n", last_selected_fname);
433 static void parse_str_val(char *cval, const char *src)
436 strncpy(cval, src, MAXPATHLEN);
437 cval[MAXPATHLEN - 1] = 0;
438 tmp = strchr(cval, '\n');
440 tmp = strchr(cval, '\r');
445 static void keys_load_all(const char *cfg);
447 static int menu_load_config(int is_game)
449 char cfgfile[MAXPATHLEN];
455 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
456 f = fopen(cfgfile, "r");
458 printf("menu_load_config: failed to open: %s\n", cfgfile);
462 fseek(f, 0, SEEK_END);
465 printf("bad size %ld: %s\n", size, cfgfile);
469 cfg = malloc(size + 1);
473 fseek(f, 0, SEEK_SET);
474 if (fread(cfg, 1, size, f) != size) {
475 printf("failed to read: %s\n", cfgfile);
480 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
484 tmp = strstr(cfg, config_data[i].name);
487 tmp += strlen(config_data[i].name);
488 if (strncmp(tmp, " = ", 3) != 0)
492 if (config_data[i].len == 0) {
493 parse_str_val(config_data[i].val, tmp);
498 val = strtoul(tmp, &tmp2, 16);
499 if (tmp2 == NULL || tmp == tmp2)
500 continue; // parse failed
502 switch (config_data[i].len) {
504 *(u8 *)config_data[i].val = val;
507 *(u16 *)config_data[i].val = val;
510 *(u32 *)config_data[i].val = val;
513 printf("menu_load_config: unhandled len %d for %s\n",
514 (int)config_data[i].len, config_data[i].name);
520 char *tmp = strstr(cfg, "lastcdimg = ");
523 parse_str_val(last_selected_fname, tmp);
538 for (i = bios_sel = 0; bioses[i] != NULL; i++)
539 if (strcmp(Config.Bios, bioses[i]) == 0)
540 { bios_sel = i; break; }
542 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
543 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
544 { gpu_plugsel = i; break; }
546 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
547 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
548 { spu_plugsel = i; break; }
553 // rrrr rggg gggb bbbb
554 static unsigned short fname2color(const char *fname)
556 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
557 ".bz", ".znx", ".pbp", ".cbn" };
558 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
559 ".table", ".index", ".sbi" };
560 const char *ext = strrchr(fname, '.');
565 for (i = 0; i < array_size(cdimg_exts); i++)
566 if (strcasecmp(ext, cdimg_exts[i]) == 0)
568 for (i = 0; i < array_size(other_exts); i++)
569 if (strcasecmp(ext, other_exts[i]) == 0)
574 static void draw_savestate_bg(int slot);
576 static const char *filter_exts[] = {
577 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
580 #define MENU_ALIGN_LEFT
581 #ifdef __ARM_ARCH_7A__ // assume hires device
587 #include "libpicofe/menu.c"
589 // a bit of black magic here
590 static void draw_savestate_bg(int slot)
592 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
594 char fname[MAXPATHLEN];
601 ret = get_state_filename(fname, sizeof(fname), slot);
605 f = gzopen(fname, "rb");
609 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
610 fprintf(stderr, "gzseek failed\n");
615 gpu = malloc(sizeof(*gpu));
621 ret = gzread(f, gpu, sizeof(*gpu));
623 if (ret != sizeof(*gpu)) {
624 fprintf(stderr, "gzread failed\n");
628 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
630 if (gpu->ulStatus & 0x800000)
631 goto out; // disabled
633 x = gpu->ulControl[5] & 0x3ff;
634 y = (gpu->ulControl[5] >> 10) & 0x1ff;
635 w = psx_widths[(gpu->ulStatus >> 16) & 7];
636 tmp = gpu->ulControl[7];
637 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
638 if (gpu->ulStatus & 0x80000) // doubleheight
640 if (h <= 0 || h > 512)
646 s = (u16 *)gpu->psxVRam + y * 1024 + x;
648 x = max(0, g_menuscreen_w - w) & ~3;
649 y = max(0, g_menuscreen_h / 2 - h / 2);
650 w = min(g_menuscreen_w, w);
651 h = min(g_menuscreen_h, h);
652 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
654 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
655 if (gpu->ulStatus & 0x200000)
656 bgr888_to_rgb565(d, s, w * 3);
658 bgr555_to_rgb565(d, s, w * 2);
660 // darken this so that menu text is visible
661 if (g_menuscreen_w - w < 320)
662 menu_darken_bg(d, d, w * 2, 0);
669 // -------------- key config --------------
671 me_bind_action me_ctrl_actions[] =
673 { "UP ", 1 << DKEY_UP},
674 { "DOWN ", 1 << DKEY_DOWN },
675 { "LEFT ", 1 << DKEY_LEFT },
676 { "RIGHT ", 1 << DKEY_RIGHT },
677 { "TRIANGLE", 1 << DKEY_TRIANGLE },
678 { "CIRCLE ", 1 << DKEY_CIRCLE },
679 { "CROSS ", 1 << DKEY_CROSS },
680 { "SQUARE ", 1 << DKEY_SQUARE },
681 { "L1 ", 1 << DKEY_L1 },
682 { "R1 ", 1 << DKEY_R1 },
683 { "L2 ", 1 << DKEY_L2 },
684 { "R2 ", 1 << DKEY_R2 },
685 { "L3 ", 1 << DKEY_L3 },
686 { "R3 ", 1 << DKEY_R3 },
687 { "START ", 1 << DKEY_START },
688 { "SELECT ", 1 << DKEY_SELECT },
692 me_bind_action emuctrl_actions[] =
694 { "Save State ", 1 << SACTION_SAVE_STATE },
695 { "Load State ", 1 << SACTION_LOAD_STATE },
696 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
697 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
698 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
699 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
700 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
701 #ifdef __ARM_ARCH_7A__
702 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
704 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
705 #if MENU_SHOW_MINIMIZE
706 { "Minimize ", 1 << SACTION_MINIMIZE },
708 #if MENU_SHOW_FULLSCREEN
709 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
711 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
712 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
713 { "Gun A button ", 1 << SACTION_GUN_A },
714 { "Gun B button ", 1 << SACTION_GUN_B },
715 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
717 { "Volume Up ", 1 << SACTION_VOLUME_UP },
718 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
723 static char *mystrip(char *str)
728 for (i = 0; i < len; i++)
729 if (str[i] != ' ') break;
730 if (i > 0) memmove(str, str + i, len - i + 1);
733 for (i = len - 1; i >= 0; i--)
734 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
740 static void get_line(char *d, size_t size, const char *s)
745 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
756 static void keys_write_all(FILE *f)
760 for (d = 0; d < IN_MAX_DEVS; d++)
762 const int *binds = in_get_dev_binds(d);
763 const char *name = in_get_dev_name(d, 0, 0);
766 if (binds == NULL || name == NULL)
769 fprintf(f, "binddev = %s\n", name);
770 in_get_config(d, IN_CFG_BIND_COUNT, &count);
772 for (k = 0; k < count; k++)
777 act[0] = act[31] = 0;
778 name = in_get_key_name(d, k);
780 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
781 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
782 mask = me_ctrl_actions[i].mask;
784 strncpy(act, me_ctrl_actions[i].name, 31);
785 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
788 mask = me_ctrl_actions[i].mask << 16;
790 strncpy(act, me_ctrl_actions[i].name, 31);
791 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
796 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
797 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
798 mask = emuctrl_actions[i].mask;
800 strncpy(act, emuctrl_actions[i].name, 31);
801 fprintf(f, "bind %s = %s\n", name, mystrip(act));
807 for (k = 0; k < array_size(in_adev); k++)
810 fprintf(f, "bind_analog = %d\n", k);
815 static int parse_bind_val(const char *val, int *type)
819 *type = IN_BINDTYPE_NONE;
823 if (strncasecmp(val, "player", 6) == 0)
825 int player, shift = 0;
826 player = atoi(val + 6) - 1;
828 if ((unsigned int)player > 1)
833 *type = IN_BINDTYPE_PLAYER12;
834 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
835 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
836 return me_ctrl_actions[i].mask << shift;
839 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
840 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
841 *type = IN_BINDTYPE_EMU;
842 return emuctrl_actions[i].mask;
849 static void keys_load_all(const char *cfg)
851 char dev[256], key[128], *act;
857 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
860 get_line(dev, sizeof(dev), p);
861 dev_id = in_config_parse_dev(dev);
863 printf("input: can't handle dev: %s\n", dev);
867 in_unbind_all(dev_id, -1, -1);
868 while ((p = strstr(p, "bind"))) {
869 if (strncmp(p, "binddev = ", 10) == 0)
872 if (strncmp(p, "bind_analog", 11) == 0) {
873 ret = sscanf(p, "bind_analog = %d", &bind);
876 printf("input: parse error: %16s..\n", p);
879 if ((unsigned int)bind >= array_size(in_adev)) {
880 printf("input: analog id %d out of range\n", bind);
883 in_adev[bind] = dev_id;
889 printf("input: parse error: %16s..\n", p);
893 get_line(key, sizeof(key), p);
894 act = strchr(key, '=');
896 printf("parse failed: %16s..\n", p);
904 bind = parse_bind_val(act, &bindtype);
905 if (bind != -1 && bind != 0) {
906 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
907 in_config_bind_key(dev_id, key, bind, bindtype);
910 lprintf("config: unhandled action \"%s\"\n", act);
916 static int key_config_loop_wrap(int id, int keys)
919 case MA_CTRL_PLAYER1:
920 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
922 case MA_CTRL_PLAYER2:
923 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
926 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
934 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
935 "Might cause problems with real analog sticks";
936 static const char *adevnames[IN_MAX_DEVS + 2];
937 static int stick_sel[2];
939 static menu_entry e_menu_keyconfig_analog[] =
941 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
942 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
943 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
944 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
945 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
946 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
947 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
948 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
952 static int key_config_analog(int id, int keys)
954 int i, d, count, sel = 0;
955 int sel2dev_map[IN_MAX_DEVS];
957 memset(adevnames, 0, sizeof(adevnames));
958 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
959 memset(stick_sel, 0, sizeof(stick_sel));
961 adevnames[0] = "None";
963 for (d = 0; d < IN_MAX_DEVS; d++)
965 const char *name = in_get_dev_name(d, 0, 1);
970 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
974 if (in_adev[0] == d) stick_sel[0] = i;
975 if (in_adev[1] == d) stick_sel[1] = i;
977 adevnames[i++] = name;
981 me_loop(e_menu_keyconfig_analog, &sel);
983 in_adev[0] = sel2dev_map[stick_sel[0]];
984 in_adev[1] = sel2dev_map[stick_sel[1]];
989 static const char *mgn_dev_name(int id, int *offs)
991 const char *name = NULL;
994 if (id == MA_CTRL_DEV_FIRST)
997 for (; it < IN_MAX_DEVS; it++) {
998 name = in_get_dev_name(it, 1, 1);
1007 static const char *mgn_saveloadcfg(int id, int *offs)
1012 static int mh_savecfg(int id, int keys)
1014 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1015 menu_update_msg("config saved");
1017 menu_update_msg("failed to write config");
1022 static int mh_input_rescan(int id, int keys)
1024 //menu_sync_config();
1026 menu_update_msg("rescan complete.");
1031 static const char *men_in_type_sel[] = {
1032 "Standard (SCPH-1080)",
1033 "Analog (SCPH-1150)",
1037 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1038 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1039 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1041 static menu_entry e_menu_keyconfig[] =
1043 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1044 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1045 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1046 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1048 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1049 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1050 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1051 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1052 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1053 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1054 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1055 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1056 mee_handler ("Rescan devices:", mh_input_rescan),
1058 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1059 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1060 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1061 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1062 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1063 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1064 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1068 static int menu_loop_keyconfig(int id, int keys)
1072 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1073 me_loop(e_menu_keyconfig, &sel);
1077 // ------------ gfx options menu ------------
1079 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1080 static const char *men_soft_filter[] = { "None",
1082 "scale2x", "eagle2x",
1085 static const char *men_dummy[] = { NULL };
1086 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1087 "using d-pad or move it using R+d-pad";
1088 static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
1089 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1090 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1092 static int menu_loop_cscaler(int id, int keys)
1096 g_scaler = SCALE_CUSTOM;
1098 plat_gvideo_open(Config.PsxType);
1102 menu_draw_begin(0, 1);
1103 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1104 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1105 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1108 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1109 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1110 if (inp & PBTN_UP) g_layer_y--;
1111 if (inp & PBTN_DOWN) g_layer_y++;
1112 if (inp & PBTN_LEFT) g_layer_x--;
1113 if (inp & PBTN_RIGHT) g_layer_x++;
1114 if (!(inp & PBTN_R)) {
1115 if (inp & PBTN_UP) g_layer_h += 2;
1116 if (inp & PBTN_DOWN) g_layer_h -= 2;
1117 if (inp & PBTN_LEFT) g_layer_w += 2;
1118 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1120 if (inp & (PBTN_MOK|PBTN_MBACK))
1123 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1124 if (g_layer_x < 0) g_layer_x = 0;
1125 if (g_layer_x > 640) g_layer_x = 640;
1126 if (g_layer_y < 0) g_layer_y = 0;
1127 if (g_layer_y > 420) g_layer_y = 420;
1128 if (g_layer_w < 160) g_layer_w = 160;
1129 if (g_layer_h < 60) g_layer_h = 60;
1130 if (g_layer_x + g_layer_w > 800)
1131 g_layer_w = 800 - g_layer_x;
1132 if (g_layer_y + g_layer_h > 480)
1133 g_layer_h = 480 - g_layer_y;
1135 plat_gvideo_open(Config.PsxType);
1139 plat_gvideo_close();
1144 static menu_entry e_menu_gfx_options[] =
1146 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1147 mee_onoff_h ("Use video overlay", MA_OPT_VIDOVERLAY, g_use_overlay, 1, h_overlay),
1148 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1149 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, filter, men_dummy),
1150 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1151 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1152 // mee_onoff ("Vsync", 0, vsync, 1),
1153 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1157 static int menu_loop_gfx_options(int id, int keys)
1161 me_loop(e_menu_gfx_options, &sel);
1166 // ------------ bios/plugins ------------
1170 static const char h_gpu_neon[] =
1171 "Configure built-in NEON GPU plugin";
1172 static const char h_gpu_neon_enhanced[] =
1173 "Renders in double resolution at the cost of lower performance\n"
1174 "(not available for high resolution games)";
1175 static const char h_gpu_neon_enhanced_hack[] =
1176 "Speed hack for above option (glitches some games)";
1177 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1179 static menu_entry e_menu_plugin_gpu_neon[] =
1181 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1182 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1183 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1187 static int menu_loop_plugin_gpu_neon(int id, int keys)
1190 me_loop(e_menu_plugin_gpu_neon, &sel);
1196 static menu_entry e_menu_plugin_gpu_unai[] =
1198 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1199 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1200 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1201 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1205 static int menu_loop_plugin_gpu_unai(int id, int keys)
1208 me_loop(e_menu_plugin_gpu_unai, &sel);
1212 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1213 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1214 static const char h_gpu_1[] = "Capcom fighting games";
1215 static const char h_gpu_2[] = "Black screens in Lunar";
1216 static const char h_gpu_3[] = "Compatibility mode";
1217 static const char h_gpu_6[] = "Pandemonium 2";
1218 //static const char h_gpu_7[] = "Skip every second frame";
1219 static const char h_gpu_8[] = "Needed by Dark Forces";
1220 static const char h_gpu_9[] = "better g-colors, worse textures";
1221 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1223 static menu_entry e_menu_plugin_gpu_peops[] =
1225 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1226 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1227 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1228 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1229 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1230 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1231 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1232 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1233 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1234 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1238 static int menu_loop_plugin_gpu_peops(int id, int keys)
1241 me_loop(e_menu_plugin_gpu_peops, &sel);
1245 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1246 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1247 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1249 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1251 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1252 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1253 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1254 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1255 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1256 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1257 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1258 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1259 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1260 mee_label ("Fixes/hacks:"),
1261 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1262 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1263 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1264 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1265 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1266 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1267 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1268 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1269 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1270 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1271 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1275 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1278 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1282 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1283 static const char h_spu_volboost[] = "Large values cause distortion";
1285 static menu_entry e_menu_plugin_spu[] =
1287 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1288 mee_onoff ("Reverb", 0, iUseReverb, 2),
1289 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1290 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1294 static int menu_loop_plugin_spu(int id, int keys)
1297 me_loop(e_menu_plugin_spu, &sel);
1301 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1302 "savestates and can't be changed there. Must save\n"
1303 "config and reload the game for change to take effect";
1304 static const char h_plugin_gpu[] =
1306 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1308 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1309 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1310 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1311 "must save config and reload the game if changed";
1312 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1313 "must save config and reload the game if changed";
1314 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1315 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1316 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1317 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1319 static menu_entry e_menu_plugin_options[] =
1321 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1322 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1323 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1325 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1327 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1328 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1329 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1330 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1334 static menu_entry e_menu_main2[];
1336 static int menu_loop_plugin_options(int id, int keys)
1339 me_loop(e_menu_plugin_options, &sel);
1341 // sync BIOS/plugins
1342 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1343 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1344 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1345 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1350 // ------------ adv options menu ------------
1352 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1353 "(lower value - less work for the emu, may be faster)";
1354 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1355 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1356 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1358 static menu_entry e_menu_speed_hacks[] =
1360 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1361 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1362 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1363 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1367 static int menu_loop_speed_hacks(int id, int keys)
1370 me_loop(e_menu_speed_hacks, &sel);
1374 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1375 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1376 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1377 "(green: normal, red: fmod, blue: noise)";
1378 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1379 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1380 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1381 "(proper .cue/.bin dump is needed otherwise)";
1382 static const char h_cfg_sio[] = "You should not need this, breaks games";
1383 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1384 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1385 "(timing hack, breaks other games)";
1386 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1387 "(timing hack, breaks other games)";
1388 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1389 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1390 "Might be useful to overcome some dynarec bugs";
1391 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1392 "must reload game for any change to take effect";
1394 static menu_entry e_menu_adv_options[] =
1396 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1397 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1398 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1399 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1400 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1401 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1402 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1403 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1404 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1405 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1406 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1407 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1411 static int menu_loop_adv_options(int id, int keys)
1414 me_loop(e_menu_adv_options, &sel);
1418 // ------------ options menu ------------
1420 static int mh_restore_defaults(int id, int keys)
1422 menu_set_defconfig();
1423 menu_update_msg("defaults restored");
1427 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1428 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1430 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1431 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1432 "loading state or both";
1434 static const char h_restore_def[] = "Switches back to default / recommended\n"
1436 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1438 static menu_entry e_menu_options[] =
1440 // mee_range ("Save slot", 0, state_slot, 0, 9),
1441 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1442 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1443 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1444 mee_enum ("Region", 0, region, men_region),
1445 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1446 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1447 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1448 mee_handler ("[Advanced]", menu_loop_adv_options),
1449 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1450 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1451 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1455 static int menu_loop_options(int id, int keys)
1460 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1461 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1462 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1464 me_loop(e_menu_options, &sel);
1469 // ------------ debug menu ------------
1471 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1473 int w = min(g_menuscreen_w, 1024);
1474 int h = min(g_menuscreen_h, 512);
1475 u16 *d = g_menuscreen_ptr;
1476 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1480 gpuf->ulFreezeVersion = 1;
1481 if (GPU_freeze != NULL)
1482 GPU_freeze(1, gpuf);
1484 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1485 bgr555_to_rgb565(d, s, w * 2);
1487 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1488 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1489 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1490 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1491 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1494 static void debug_menu_loop(void)
1496 int inp, df_x = 0, df_y = 0;
1499 gpuf = malloc(sizeof(*gpuf));
1505 menu_draw_begin(0, 1);
1506 draw_frame_debug(gpuf, df_x, df_y);
1509 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1510 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1511 if (inp & PBTN_MBACK) break;
1512 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1513 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1514 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1515 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1521 // --------- memcard manager ---------
1523 static void draw_mc_icon(int dx, int dy, const u16 *s)
1528 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1530 for (y = 0; y < 16; y++, s += 16) {
1531 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1532 for (x = 0; x < 16; x++) {
1534 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1535 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1541 static void draw_mc_bg(void)
1543 McdBlock *blocks1, *blocks2;
1547 blocks1 = malloc(15 * sizeof(blocks1[0]));
1548 blocks2 = malloc(15 * sizeof(blocks1[0]));
1549 if (blocks1 == NULL || blocks2 == NULL)
1552 for (i = 0; i < 15; i++) {
1553 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1554 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1557 menu_draw_begin(1, 1);
1559 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1561 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1565 maxicons = g_menuscreen_h / 32;
1568 row2 = g_menuscreen_w / 2;
1569 for (i = 0; i < maxicons; i++) {
1570 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1571 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1573 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1574 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1577 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1585 static void handle_memcard_sel(void)
1588 if (memcard1_sel != 0)
1589 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1591 if (memcard2_sel != 0)
1592 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1593 LoadMcds(Config.Mcd1, Config.Mcd2);
1597 static menu_entry e_memcard_options[] =
1599 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1600 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1604 static int menu_loop_memcards(int id, int keys)
1610 memcard1_sel = memcard2_sel = 0;
1611 p = strrchr(Config.Mcd1, '/');
1613 for (i = 0; memcards[i] != NULL; i++)
1614 if (strcmp(p + 1, memcards[i]) == 0)
1615 { memcard1_sel = i; break; }
1616 p = strrchr(Config.Mcd2, '/');
1618 for (i = 0; memcards[i] != NULL; i++)
1619 if (strcmp(p + 1, memcards[i]) == 0)
1620 { memcard2_sel = i; break; }
1622 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1624 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1629 // ------------ cheats menu ------------
1631 static void draw_cheatlist(int sel)
1633 int max_cnt, start, i, pos, active;
1635 max_cnt = g_menuscreen_h / me_sfont_h;
1636 start = max_cnt / 2 - sel;
1638 menu_draw_begin(1, 1);
1640 for (i = 0; i < NumCheats; i++) {
1642 if (pos < 0) continue;
1643 if (pos >= max_cnt) break;
1644 active = Cheats[i].Enabled;
1645 smalltext_out16(14, pos * me_sfont_h,
1646 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1647 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1648 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1652 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1654 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1658 static void menu_loop_cheats(void)
1660 static int menu_sel = 0;
1665 draw_cheatlist(menu_sel);
1666 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1667 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1668 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1669 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1670 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1671 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1672 if (inp & PBTN_MOK) { // action
1673 if (menu_sel < NumCheats)
1674 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1677 if (inp & PBTN_MBACK)
1682 // --------- main menu help ----------
1684 static void menu_bios_warn(void)
1687 static const char msg[] =
1688 "You don't seem to have copied any BIOS\n"
1690 MENU_BIOS_PATH "\n\n"
1692 "While many games work fine with fake\n"
1693 "(HLE) BIOS, others (like MGS and FF8)\n"
1694 "require BIOS to work.\n"
1695 "After copying the file, you'll also need\n"
1696 "to select it in the emu's menu:\n"
1697 "options->[BIOS/Plugins]\n\n"
1698 "The file is usually named SCPH1001.BIN,\n"
1699 "but other not compressed files can be\n"
1701 "Press %s or %s to continue";
1702 char tmp_msg[sizeof(msg) + 64];
1704 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1705 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1708 draw_menu_message(tmp_msg, NULL);
1710 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1711 if (inp & (PBTN_MBACK|PBTN_MOK))
1716 // ------------ main menu ------------
1718 static menu_entry e_menu_main[];
1721 static void draw_frame_main(void)
1730 if (CdromId[0] != 0) {
1731 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1732 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1733 Config.HLE ? "HLE" : "BIOS");
1734 smalltext_out16(4, 1, buff, 0x105f);
1738 capacity = plat_target_bat_capacity_get();
1740 tmp = localtime(<ime);
1741 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1742 if (capacity >= 0) {
1743 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1748 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1752 static void draw_frame_credits(void)
1754 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1757 static const char credits_text[] =
1759 "(C) 1999-2003 PCSX Team\n"
1760 "(C) 2005-2009 PCSX-df Team\n"
1761 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1762 "ARM recompiler (C) 2009-2011 Ari64\n"
1764 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1766 "PEOpS GPU and SPU by Pete Bernert\n"
1767 " and the P.E.Op.S. team\n"
1768 "PCSX4ALL plugin by PCSX4ALL team\n"
1769 " Chui, Franxis, Unai\n\n"
1770 "integration, optimization and\n"
1771 " frontend (C) 2010-2012 notaz\n";
1773 static int reset_game(void)
1776 if (bios_sel == 0 && !Config.HLE)
1782 if (CheckCdrom() != -1) {
1788 static int reload_plugins(const char *cdimg)
1794 set_cd_image(cdimg);
1796 pcnt_hook_plugins();
1798 if (OpenPlugins() == -1) {
1799 menu_update_msg("failed to open plugins");
1802 plugin_call_rearmed_cbs();
1804 cdrIsoMultidiskCount = 1;
1806 CdromLabel[0] = '\0';
1811 static int run_bios(void)
1817 if (reload_plugins(NULL) != 0)
1825 static int run_exe(void)
1829 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1834 if (reload_plugins(NULL) != 0)
1838 if (Load(fname) != 0) {
1839 menu_update_msg("exe load failed, bad file?");
1848 static int run_cd_image(const char *fname)
1851 reload_plugins(fname);
1853 // always autodetect, menu_sync_config will override as needed
1856 if (CheckCdrom() == -1) {
1857 // Only check the CD if we are starting the console with a CD
1859 menu_update_msg("unsupported/invalid CD image");
1865 // Read main executable directly from CDRom and start it
1866 if (LoadCdrom() == -1) {
1868 menu_update_msg("failed to load CD image");
1878 static int romsel_run(void)
1880 int prev_gpu, prev_spu;
1883 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1887 printf("selected file: %s\n", fname);
1889 new_dynarec_clear_full();
1891 if (run_cd_image(fname) != 0)
1894 prev_gpu = gpu_plugsel;
1895 prev_spu = spu_plugsel;
1896 if (menu_load_config(1) != 0)
1897 menu_load_config(0);
1899 // check for plugin changes, have to repeat
1900 // loading if game config changed plugins to reload them
1901 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1902 printf("plugin change detected, reloading plugins..\n");
1903 if (run_cd_image(fname) != 0)
1907 strcpy(last_selected_fname, rom_fname_reload);
1908 menu_do_last_cd_img(0);
1912 static int swap_cd_image(void)
1916 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1920 printf("selected file: %s\n", fname);
1923 CdromLabel[0] = '\0';
1925 set_cd_image(fname);
1926 if (ReloadCdromPlugin() < 0) {
1927 menu_update_msg("failed to load cdr plugin");
1930 if (CDR_open() < 0) {
1931 menu_update_msg("failed to open cdr plugin");
1935 SetCdOpenCaseTime(time(NULL) + 2);
1938 strcpy(last_selected_fname, rom_fname_reload);
1942 static int swap_cd_multidisk(void)
1944 cdrIsoMultidiskSelect++;
1946 CdromLabel[0] = '\0';
1949 if (CDR_open() < 0) {
1950 menu_update_msg("failed to open cdr plugin");
1954 SetCdOpenCaseTime(time(NULL) + 2);
1960 static void load_pcsx_cht(void)
1966 fname = menu_loop_romsel(path, sizeof(path));
1970 printf("selected cheat file: %s\n", fname);
1973 if (NumCheats == 0 && NumCodes == 0)
1974 menu_update_msg("failed to load cheats");
1976 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1977 menu_update_msg(path);
1979 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1982 static int main_menu_handler(int id, int keys)
1986 case MA_MAIN_RESUME_GAME:
1990 case MA_MAIN_SAVE_STATE:
1992 return menu_loop_savestate(0);
1994 case MA_MAIN_LOAD_STATE:
1996 return menu_loop_savestate(1);
1998 case MA_MAIN_RESET_GAME:
1999 if (ready_to_go && reset_game() == 0)
2002 case MA_MAIN_LOAD_ROM:
2003 if (romsel_run() == 0)
2006 case MA_MAIN_SWAP_CD:
2007 if (swap_cd_image() == 0)
2010 case MA_MAIN_SWAP_CD_MULTI:
2011 if (swap_cd_multidisk() == 0)
2014 case MA_MAIN_RUN_BIOS:
2015 if (run_bios() == 0)
2018 case MA_MAIN_RUN_EXE:
2022 case MA_MAIN_CHEATS:
2025 case MA_MAIN_LOAD_CHEATS:
2028 case MA_MAIN_CREDITS:
2029 draw_menu_message(credits_text, draw_frame_credits);
2030 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2036 lprintf("%s: something unknown selected\n", __FUNCTION__);
2043 static menu_entry e_menu_main2[] =
2045 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2046 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2047 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2048 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2049 mee_handler ("Memcard manager", menu_loop_memcards),
2050 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2054 static int main_menu2_handler(int id, int keys)
2058 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2059 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2060 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2061 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2063 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2066 static const char h_extra[] = "Change CD, manage memcards..\n";
2068 static menu_entry e_menu_main[] =
2072 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2073 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2074 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2075 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2076 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2077 mee_handler ("Options", menu_loop_options),
2078 mee_handler ("Controls", menu_loop_keyconfig),
2079 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2080 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2081 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2082 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2086 // ----------------------------
2088 static void menu_leave_emu(void);
2090 void menu_loop(void)
2092 static int warned_about_bios = 0;
2097 if (config_save_counter == 0) {
2099 if (bioses[1] != NULL) {
2100 // autoselect BIOS to make user's life easier
2101 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2104 else if (!warned_about_bios) {
2106 warned_about_bios = 1;
2110 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2111 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2112 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2113 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2114 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2116 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2119 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2120 } while (!ready_to_go);
2122 /* wait until menu, ok, back is released */
2123 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2126 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2131 static int qsort_strcmp(const void *p1, const void *p2)
2133 char * const *s1 = (char * const *)p1;
2134 char * const *s2 = (char * const *)p2;
2135 return strcasecmp(*s1, *s2);
2138 static void scan_bios_plugins(void)
2140 char fname[MAXPATHLEN];
2142 int bios_i, gpu_i, spu_i, mc_i;
2147 gpu_plugins[0] = "builtin_gpu";
2148 spu_plugins[0] = "builtin_spu";
2149 memcards[0] = "(none)";
2150 bios_i = gpu_i = spu_i = mc_i = 1;
2152 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2153 dir = opendir(fname);
2155 perror("scan_bios_plugins bios opendir");
2170 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2173 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2174 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2175 printf("bad BIOS file: %s\n", ent->d_name);
2179 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2180 bioses[bios_i++] = strdup(ent->d_name);
2184 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2190 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2191 dir = opendir(fname);
2193 perror("scan_bios_plugins plugins opendir");
2207 p = strstr(ent->d_name, ".so");
2211 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2212 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2214 fprintf(stderr, "%s\n", dlerror());
2218 // now what do we have here?
2219 tmp = dlsym(h, "GPUinit");
2222 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2223 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2227 tmp = dlsym(h, "SPUinit");
2230 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2231 spu_plugins[spu_i++] = strdup(ent->d_name);
2235 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2242 dir = opendir("." MEMCARD_DIR);
2244 perror("scan_bios_plugins memcards opendir");
2259 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2262 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2263 if (stat(fname, &st) != 0) {
2264 printf("bad memcard file: %s\n", ent->d_name);
2268 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2269 memcards[mc_i++] = strdup(ent->d_name);
2273 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2277 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2282 void menu_init(void)
2284 char buff[MAXPATHLEN];
2287 strcpy(last_selected_fname, "/media");
2289 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2291 scan_bios_plugins();
2294 menu_set_defconfig();
2295 menu_load_config(0);
2296 menu_do_last_cd_img(1);
2301 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2302 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2303 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2304 fprintf(stderr, "OOM\n");
2308 emu_make_path(buff, "skin/background.png", sizeof(buff));
2309 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2311 i = plat_target.cpu_clock_set != NULL
2312 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2313 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2315 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2316 e_menu_gfx_options[i].data = plat_target.hwfilters;
2317 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2318 plat_target.hwfilters != NULL);
2320 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2321 plat_target.gamma_set != NULL);
2323 #ifndef __ARM_ARCH_7A__
2324 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2326 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2327 me_enable(e_menu_gfx_options, MA_OPT_VIDOVERLAY, MENU_SHOW_VIDOVERLAY);
2328 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2329 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2330 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2331 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2332 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2335 void menu_notify_mode_change(int w, int h, int bpp)
2339 last_vout_bpp = bpp;
2342 static void menu_leave_emu(void)
2344 if (GPU_close != NULL) {
2345 int ret = GPU_close();
2347 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2350 plat_video_menu_enter(ready_to_go);
2352 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2353 if (pl_vout_buf != NULL && ready_to_go) {
2354 int x = max(0, g_menuscreen_w - last_vout_w);
2355 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2356 int w = min(g_menuscreen_w, last_vout_w);
2357 int h = min(g_menuscreen_h, last_vout_h);
2358 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2359 char *s = pl_vout_buf;
2361 if (last_vout_bpp == 16) {
2362 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2363 menu_darken_bg(d, s, w, 0);
2366 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2367 rgb888_to_rgb565(d, s, w * 3);
2368 menu_darken_bg(d, d, w, 0);
2374 cpu_clock = plat_target_cpu_clock_get();
2377 void menu_prepare_emu(void)
2379 R3000Acpu *prev_cpu = psxCpu;
2381 plat_video_menu_leave();
2383 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2384 if (psxCpu != prev_cpu)
2385 // note that this does not really reset, just clears drc caches
2388 // core doesn't care about Config.Cdda changes,
2389 // so handle them manually here
2395 plat_target_cpu_clock_set(cpu_clock);
2397 // push config to GPU plugin
2398 plugin_call_rearmed_cbs();
2400 if (GPU_open != NULL) {
2401 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2403 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2409 void menu_update_msg(const char *msg)
2411 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2412 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2414 menu_error_time = plat_get_ticks_ms();
2415 lprintf("msg: %s\n", menu_error_msg);
2418 void menu_finish(void)
2420 if (cpu_clock_st > 0)
2421 plat_target_cpu_clock_set(cpu_clock_st);