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
96 #ifdef __ARM_ARCH_7A__
97 #define DEFAULT_PSX_CLOCK 57
98 #define DEFAULT_PSX_CLOCK_S "57"
100 #define DEFAULT_PSX_CLOCK 50
101 #define DEFAULT_PSX_CLOCK_S "50"
105 extern int iUseReverb;
106 extern int iUseInterpolation;
110 static const char *bioses[24];
111 static const char *gpu_plugins[16];
112 static const char *spu_plugins[16];
113 static const char *memcards[32];
114 static int bios_sel, gpu_plugsel, spu_plugsel;
116 #ifndef UI_FEATURES_H
117 #define MENU_BIOS_PATH "bios/"
118 #define MENU_SHOW_VARSCALER 0
119 #define MENU_SHOW_VOUTMODE 1
120 #define MENU_SHOW_SCALER2 0
121 #define MENU_SHOW_NUBS_BTNS 0
122 #define MENU_SHOW_VIBRATION 0
123 #define MENU_SHOW_DEADZONE 0
124 #define MENU_SHOW_MINIMIZE 0
125 #define MENU_SHOW_FULLSCREEN 1
126 #define MENU_SHOW_VOLUME 0
129 static int min(int x, int y) { return x < y ? x : y; }
130 static int max(int x, int y) { return x > y ? x : y; }
132 void emu_make_path(char *buff, const char *end, int size)
136 end_len = strlen(end);
137 pos = plat_get_root_dir(buff, size);
138 strncpy(buff + pos, end, size - pos);
140 if (pos + end_len > size - 1)
141 printf("Warning: path truncated: %s\n", buff);
144 static int emu_check_save_file(int slot, int *time)
146 char fname[MAXPATHLEN];
150 ret = emu_check_state(slot);
151 if (ret != 0 || time == NULL)
152 return ret == 0 ? 1 : 0;
154 ret = get_state_filename(fname, sizeof(fname), slot);
158 ret = stat(fname, &status);
162 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
163 return 1; // probably bad rtc like on some Caanoos
165 *time = status.st_mtime;
170 static int emu_save_load_game(int load, int unused)
175 ret = emu_load_state(state_slot);
177 // reflect hle/bios mode from savestate
180 else if (bios_sel == 0 && bioses[1] != NULL)
181 // XXX: maybe find the right bios instead
185 ret = emu_save_state(state_slot);
190 // propagate menu settings to the emu vars
191 static void menu_sync_config(void)
193 static int allow_abs_only_old;
198 Config.PsxType = region - 1;
200 cycle_multiplier = 10000 / psx_clock;
202 switch (in_type_sel1) {
203 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
204 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
205 default: in_type1 = PSE_PAD_TYPE_STANDARD;
207 switch (in_type_sel2) {
208 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
209 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
210 default: in_type2 = PSE_PAD_TYPE_STANDARD;
212 if (in_evdev_allow_abs_only != allow_abs_only_old) {
214 allow_abs_only_old = in_evdev_allow_abs_only;
217 iVolume = 768 + 128 * volume_boost;
218 pl_rearmed_cbs.frameskip = frameskip - 1;
219 pl_timing_prepare(Config.PsxType);
222 static void menu_set_defconfig(void)
224 emu_set_default_config();
227 g_scaler = SCALE_4_3;
230 analog_deadzone = 50;
233 plat_target.vout_fullscreen = 0;
234 psx_clock = DEFAULT_PSX_CLOCK;
237 in_type_sel1 = in_type_sel2 = 0;
238 in_evdev_allow_abs_only = 0;
243 #define CE_CONFIG_STR(val) \
244 { #val, 0, Config.val }
246 #define CE_CONFIG_VAL(val) \
247 { #val, sizeof(Config.val), &Config.val }
249 #define CE_STR(val) \
252 #define CE_INTVAL(val) \
253 { #val, sizeof(val), &val }
255 #define CE_INTVAL_N(name, val) \
256 { name, sizeof(val), &val }
258 #define CE_INTVAL_P(val) \
259 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
261 // 'versioned' var, used when defaults change
262 #define CE_CONFIG_STR_V(val, ver) \
263 { #val #ver, 0, Config.val }
265 #define CE_INTVAL_V(val, ver) \
266 { #val #ver, sizeof(val), &val }
268 #define CE_INTVAL_PV(val, ver) \
269 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
271 static const struct {
277 CE_CONFIG_STR_V(Gpu, 3),
279 // CE_CONFIG_STR(Cdr),
284 CE_CONFIG_VAL(Debug),
285 CE_CONFIG_VAL(PsxOut),
286 CE_CONFIG_VAL(SpuIrq),
287 CE_CONFIG_VAL(RCntFix),
288 CE_CONFIG_VAL(VSyncWA),
290 CE_CONFIG_VAL(CdrReschedule),
292 CE_INTVAL_V(g_scaler, 2),
293 CE_INTVAL(g_layer_x),
294 CE_INTVAL(g_layer_y),
295 CE_INTVAL(g_layer_w),
296 CE_INTVAL(g_layer_h),
297 CE_INTVAL(soft_filter),
298 CE_INTVAL(plat_target.vout_method),
299 CE_INTVAL(plat_target.hwfilter),
300 CE_INTVAL(plat_target.vout_fullscreen),
301 CE_INTVAL(state_slot),
302 CE_INTVAL(cpu_clock),
304 CE_INTVAL(in_type_sel1),
305 CE_INTVAL(in_type_sel2),
306 CE_INTVAL(analog_deadzone),
307 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
308 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
309 CE_INTVAL_V(frameskip, 3),
310 CE_INTVAL_P(gpu_peops.iUseDither),
311 CE_INTVAL_P(gpu_peops.dwActFixes),
312 CE_INTVAL_P(gpu_unai.lineskip),
313 CE_INTVAL_P(gpu_unai.abe_hack),
314 CE_INTVAL_P(gpu_unai.no_light),
315 CE_INTVAL_P(gpu_unai.no_blend),
316 CE_INTVAL_P(gpu_neon.allow_interlace),
317 CE_INTVAL_P(gpu_neon.enhancement_enable),
318 CE_INTVAL_P(gpu_neon.enhancement_no_main),
319 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
320 CE_INTVAL_P(gpu_peopsgl.iFilterType),
321 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
322 CE_INTVAL_P(gpu_peopsgl.iUseMask),
323 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
324 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
325 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
326 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
327 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
328 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
329 CE_INTVAL_V(iUseReverb, 3),
330 CE_INTVAL_V(iXAPitch, 3),
331 CE_INTVAL_V(iUseInterpolation, 3),
332 CE_INTVAL(config_save_counter),
333 CE_INTVAL(in_evdev_allow_abs_only),
334 CE_INTVAL(volume_boost),
335 CE_INTVAL(psx_clock),
336 CE_INTVAL(new_dynarec_hacks),
337 CE_INTVAL(in_enable_vibration),
340 static char *get_cd_label(void)
342 static char trimlabel[33];
345 strncpy(trimlabel, CdromLabel, 32);
347 for (j = 31; j >= 0; j--)
348 if (trimlabel[j] == ' ')
354 static void make_cfg_fname(char *buf, size_t size, int is_game)
357 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
359 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
362 static void keys_write_all(FILE *f);
363 static char *mystrip(char *str);
365 static int menu_write_config(int is_game)
367 char cfgfile[MAXPATHLEN];
371 config_save_counter++;
373 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
374 f = fopen(cfgfile, "w");
376 printf("menu_write_config: failed to open: %s\n", cfgfile);
380 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
381 fprintf(f, "%s = ", config_data[i].name);
382 switch (config_data[i].len) {
384 fprintf(f, "%s\n", (char *)config_data[i].val);
387 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
390 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
393 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
396 printf("menu_write_config: unhandled len %d for %s\n",
397 (int)config_data[i].len, config_data[i].name);
408 static int menu_do_last_cd_img(int is_get)
414 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
415 f = fopen(path, is_get ? "r" : "w");
420 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
421 last_selected_fname[ret] = 0;
422 mystrip(last_selected_fname);
425 fprintf(f, "%s\n", last_selected_fname);
431 static void parse_str_val(char *cval, const char *src)
434 strncpy(cval, src, MAXPATHLEN);
435 cval[MAXPATHLEN - 1] = 0;
436 tmp = strchr(cval, '\n');
438 tmp = strchr(cval, '\r');
443 static void keys_load_all(const char *cfg);
445 static int menu_load_config(int is_game)
447 char cfgfile[MAXPATHLEN];
453 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
454 f = fopen(cfgfile, "r");
456 printf("menu_load_config: failed to open: %s\n", cfgfile);
460 fseek(f, 0, SEEK_END);
463 printf("bad size %ld: %s\n", size, cfgfile);
467 cfg = malloc(size + 1);
471 fseek(f, 0, SEEK_SET);
472 if (fread(cfg, 1, size, f) != size) {
473 printf("failed to read: %s\n", cfgfile);
478 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
482 tmp = strstr(cfg, config_data[i].name);
485 tmp += strlen(config_data[i].name);
486 if (strncmp(tmp, " = ", 3) != 0)
490 if (config_data[i].len == 0) {
491 parse_str_val(config_data[i].val, tmp);
496 val = strtoul(tmp, &tmp2, 16);
497 if (tmp2 == NULL || tmp == tmp2)
498 continue; // parse failed
500 switch (config_data[i].len) {
502 *(u8 *)config_data[i].val = val;
505 *(u16 *)config_data[i].val = val;
508 *(u32 *)config_data[i].val = val;
511 printf("menu_load_config: unhandled len %d for %s\n",
512 (int)config_data[i].len, config_data[i].name);
518 char *tmp = strstr(cfg, "lastcdimg = ");
521 parse_str_val(last_selected_fname, tmp);
536 for (i = bios_sel = 0; bioses[i] != NULL; i++)
537 if (strcmp(Config.Bios, bioses[i]) == 0)
538 { bios_sel = i; break; }
540 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
541 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
542 { gpu_plugsel = i; break; }
544 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
545 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
546 { spu_plugsel = i; break; }
551 // rrrr rggg gggb bbbb
552 static unsigned short fname2color(const char *fname)
554 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
555 ".bz", ".znx", ".pbp", ".cbn" };
556 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
557 ".table", ".index", ".sbi" };
558 const char *ext = strrchr(fname, '.');
563 for (i = 0; i < array_size(cdimg_exts); i++)
564 if (strcasecmp(ext, cdimg_exts[i]) == 0)
566 for (i = 0; i < array_size(other_exts); i++)
567 if (strcasecmp(ext, other_exts[i]) == 0)
572 static void draw_savestate_bg(int slot);
574 static const char *filter_exts[] = {
575 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
578 #define MENU_ALIGN_LEFT
579 #ifdef __ARM_ARCH_7A__ // assume hires device
585 #include "libpicofe/menu.c"
587 // a bit of black magic here
588 static void draw_savestate_bg(int slot)
590 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
592 char fname[MAXPATHLEN];
599 ret = get_state_filename(fname, sizeof(fname), slot);
603 f = gzopen(fname, "rb");
607 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
608 fprintf(stderr, "gzseek failed\n");
613 gpu = malloc(sizeof(*gpu));
619 ret = gzread(f, gpu, sizeof(*gpu));
621 if (ret != sizeof(*gpu)) {
622 fprintf(stderr, "gzread failed\n");
626 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
628 if (gpu->ulStatus & 0x800000)
629 goto out; // disabled
631 x = gpu->ulControl[5] & 0x3ff;
632 y = (gpu->ulControl[5] >> 10) & 0x1ff;
633 w = psx_widths[(gpu->ulStatus >> 16) & 7];
634 tmp = gpu->ulControl[7];
635 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
636 if (gpu->ulStatus & 0x80000) // doubleheight
638 if (h <= 0 || h > 512)
644 s = (u16 *)gpu->psxVRam + y * 1024 + x;
646 x = max(0, g_menuscreen_w - w) & ~3;
647 y = max(0, g_menuscreen_h / 2 - h / 2);
648 w = min(g_menuscreen_w, w);
649 h = min(g_menuscreen_h, h);
650 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
652 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
653 if (gpu->ulStatus & 0x200000)
654 bgr888_to_rgb565(d, s, w * 3);
656 bgr555_to_rgb565(d, s, w * 2);
658 // darken this so that menu text is visible
659 if (g_menuscreen_w - w < 320)
660 menu_darken_bg(d, d, w * 2, 0);
667 // -------------- key config --------------
669 me_bind_action me_ctrl_actions[] =
671 { "UP ", 1 << DKEY_UP},
672 { "DOWN ", 1 << DKEY_DOWN },
673 { "LEFT ", 1 << DKEY_LEFT },
674 { "RIGHT ", 1 << DKEY_RIGHT },
675 { "TRIANGLE", 1 << DKEY_TRIANGLE },
676 { "CIRCLE ", 1 << DKEY_CIRCLE },
677 { "CROSS ", 1 << DKEY_CROSS },
678 { "SQUARE ", 1 << DKEY_SQUARE },
679 { "L1 ", 1 << DKEY_L1 },
680 { "R1 ", 1 << DKEY_R1 },
681 { "L2 ", 1 << DKEY_L2 },
682 { "R2 ", 1 << DKEY_R2 },
683 { "L3 ", 1 << DKEY_L3 },
684 { "R3 ", 1 << DKEY_R3 },
685 { "START ", 1 << DKEY_START },
686 { "SELECT ", 1 << DKEY_SELECT },
690 me_bind_action emuctrl_actions[] =
692 { "Save State ", 1 << SACTION_SAVE_STATE },
693 { "Load State ", 1 << SACTION_LOAD_STATE },
694 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
695 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
696 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
697 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
698 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
699 #ifdef __ARM_ARCH_7A__
700 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
702 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
703 #if MENU_SHOW_MINIMIZE
704 { "Minimize ", 1 << SACTION_MINIMIZE },
706 #if MENU_SHOW_FULLSCREEN
707 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
709 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
710 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
711 { "Gun A button ", 1 << SACTION_GUN_A },
712 { "Gun B button ", 1 << SACTION_GUN_B },
713 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
715 { "Volume Up ", 1 << SACTION_VOLUME_UP },
716 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
721 static char *mystrip(char *str)
726 for (i = 0; i < len; i++)
727 if (str[i] != ' ') break;
728 if (i > 0) memmove(str, str + i, len - i + 1);
731 for (i = len - 1; i >= 0; i--)
732 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
738 static void get_line(char *d, size_t size, const char *s)
743 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
754 static void keys_write_all(FILE *f)
758 for (d = 0; d < IN_MAX_DEVS; d++)
760 const int *binds = in_get_dev_binds(d);
761 const char *name = in_get_dev_name(d, 0, 0);
764 if (binds == NULL || name == NULL)
767 fprintf(f, "binddev = %s\n", name);
768 in_get_config(d, IN_CFG_BIND_COUNT, &count);
770 for (k = 0; k < count; k++)
775 act[0] = act[31] = 0;
776 name = in_get_key_name(d, k);
778 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
779 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
780 mask = me_ctrl_actions[i].mask;
782 strncpy(act, me_ctrl_actions[i].name, 31);
783 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
786 mask = me_ctrl_actions[i].mask << 16;
788 strncpy(act, me_ctrl_actions[i].name, 31);
789 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
794 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
795 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
796 mask = emuctrl_actions[i].mask;
798 strncpy(act, emuctrl_actions[i].name, 31);
799 fprintf(f, "bind %s = %s\n", name, mystrip(act));
805 for (k = 0; k < array_size(in_adev); k++)
808 fprintf(f, "bind_analog = %d\n", k);
813 static int parse_bind_val(const char *val, int *type)
817 *type = IN_BINDTYPE_NONE;
821 if (strncasecmp(val, "player", 6) == 0)
823 int player, shift = 0;
824 player = atoi(val + 6) - 1;
826 if ((unsigned int)player > 1)
831 *type = IN_BINDTYPE_PLAYER12;
832 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
833 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
834 return me_ctrl_actions[i].mask << shift;
837 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
838 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
839 *type = IN_BINDTYPE_EMU;
840 return emuctrl_actions[i].mask;
847 static void keys_load_all(const char *cfg)
849 char dev[256], key[128], *act;
855 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
858 get_line(dev, sizeof(dev), p);
859 dev_id = in_config_parse_dev(dev);
861 printf("input: can't handle dev: %s\n", dev);
865 in_unbind_all(dev_id, -1, -1);
866 while ((p = strstr(p, "bind"))) {
867 if (strncmp(p, "binddev = ", 10) == 0)
870 if (strncmp(p, "bind_analog", 11) == 0) {
871 ret = sscanf(p, "bind_analog = %d", &bind);
874 printf("input: parse error: %16s..\n", p);
877 if ((unsigned int)bind >= array_size(in_adev)) {
878 printf("input: analog id %d out of range\n", bind);
881 in_adev[bind] = dev_id;
887 printf("input: parse error: %16s..\n", p);
891 get_line(key, sizeof(key), p);
892 act = strchr(key, '=');
894 printf("parse failed: %16s..\n", p);
902 bind = parse_bind_val(act, &bindtype);
903 if (bind != -1 && bind != 0) {
904 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
905 in_config_bind_key(dev_id, key, bind, bindtype);
908 lprintf("config: unhandled action \"%s\"\n", act);
914 static int key_config_loop_wrap(int id, int keys)
917 case MA_CTRL_PLAYER1:
918 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
920 case MA_CTRL_PLAYER2:
921 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
924 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
932 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
933 "Might cause problems with real analog sticks";
934 static const char *adevnames[IN_MAX_DEVS + 2];
935 static int stick_sel[2];
937 static menu_entry e_menu_keyconfig_analog[] =
939 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
940 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
941 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
942 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
943 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
944 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
945 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
946 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
950 static int key_config_analog(int id, int keys)
952 int i, d, count, sel = 0;
953 int sel2dev_map[IN_MAX_DEVS];
955 memset(adevnames, 0, sizeof(adevnames));
956 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
957 memset(stick_sel, 0, sizeof(stick_sel));
959 adevnames[0] = "None";
961 for (d = 0; d < IN_MAX_DEVS; d++)
963 const char *name = in_get_dev_name(d, 0, 1);
968 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
972 if (in_adev[0] == d) stick_sel[0] = i;
973 if (in_adev[1] == d) stick_sel[1] = i;
975 adevnames[i++] = name;
979 me_loop(e_menu_keyconfig_analog, &sel);
981 in_adev[0] = sel2dev_map[stick_sel[0]];
982 in_adev[1] = sel2dev_map[stick_sel[1]];
987 static const char *mgn_dev_name(int id, int *offs)
989 const char *name = NULL;
992 if (id == MA_CTRL_DEV_FIRST)
995 for (; it < IN_MAX_DEVS; it++) {
996 name = in_get_dev_name(it, 1, 1);
1005 static const char *mgn_saveloadcfg(int id, int *offs)
1010 static int mh_savecfg(int id, int keys)
1012 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1013 menu_update_msg("config saved");
1015 menu_update_msg("failed to write config");
1020 static int mh_input_rescan(int id, int keys)
1022 //menu_sync_config();
1024 menu_update_msg("rescan complete.");
1029 static const char *men_in_type_sel[] = {
1030 "Standard (SCPH-1080)",
1031 "Analog (SCPH-1150)",
1035 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1036 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1037 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1039 static menu_entry e_menu_keyconfig[] =
1041 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1042 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1043 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1044 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1046 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1047 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1048 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1049 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1050 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1051 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1052 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1053 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1054 mee_handler ("Rescan devices:", mh_input_rescan),
1056 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1057 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1058 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1066 static int menu_loop_keyconfig(int id, int keys)
1070 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1071 me_loop(e_menu_keyconfig, &sel);
1075 // ------------ gfx options menu ------------
1077 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1078 static const char *men_soft_filter[] = { "None",
1080 "scale2x", "eagle2x",
1083 static const char *men_dummy[] = { NULL };
1084 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1085 "using d-pad or move it using R+d-pad";
1086 static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
1087 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1088 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1090 static int menu_loop_cscaler(int id, int keys)
1094 g_scaler = SCALE_CUSTOM;
1096 plat_gvideo_open(Config.PsxType);
1100 menu_draw_begin(0, 1);
1101 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1102 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1103 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1106 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1107 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1108 if (inp & PBTN_UP) g_layer_y--;
1109 if (inp & PBTN_DOWN) g_layer_y++;
1110 if (inp & PBTN_LEFT) g_layer_x--;
1111 if (inp & PBTN_RIGHT) g_layer_x++;
1112 if (!(inp & PBTN_R)) {
1113 if (inp & PBTN_UP) g_layer_h += 2;
1114 if (inp & PBTN_DOWN) g_layer_h -= 2;
1115 if (inp & PBTN_LEFT) g_layer_w += 2;
1116 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1118 if (inp & (PBTN_MOK|PBTN_MBACK))
1121 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1122 if (g_layer_x < 0) g_layer_x = 0;
1123 if (g_layer_x > 640) g_layer_x = 640;
1124 if (g_layer_y < 0) g_layer_y = 0;
1125 if (g_layer_y > 420) g_layer_y = 420;
1126 if (g_layer_w < 160) g_layer_w = 160;
1127 if (g_layer_h < 60) g_layer_h = 60;
1128 if (g_layer_x + g_layer_w > 800)
1129 g_layer_w = 800 - g_layer_x;
1130 if (g_layer_y + g_layer_h > 480)
1131 g_layer_h = 480 - g_layer_y;
1133 plat_gvideo_open(Config.PsxType);
1137 plat_gvideo_close();
1142 static menu_entry e_menu_gfx_options[] =
1144 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1145 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1146 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1147 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1148 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1149 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1150 // mee_onoff ("Vsync", 0, vsync, 1),
1151 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1155 static int menu_loop_gfx_options(int id, int keys)
1159 me_loop(e_menu_gfx_options, &sel);
1164 // ------------ bios/plugins ------------
1168 static const char h_gpu_neon[] =
1169 "Configure built-in NEON GPU plugin";
1170 static const char h_gpu_neon_enhanced[] =
1171 "Renders in double resolution at the cost of lower performance\n"
1172 "(not available for high resolution games)";
1173 static const char h_gpu_neon_enhanced_hack[] =
1174 "Speed hack for above option (glitches some games)";
1175 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1177 static menu_entry e_menu_plugin_gpu_neon[] =
1179 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1180 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1181 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1185 static int menu_loop_plugin_gpu_neon(int id, int keys)
1188 me_loop(e_menu_plugin_gpu_neon, &sel);
1194 static menu_entry e_menu_plugin_gpu_unai[] =
1196 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1197 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1198 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1199 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1203 static int menu_loop_plugin_gpu_unai(int id, int keys)
1206 me_loop(e_menu_plugin_gpu_unai, &sel);
1210 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1211 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1212 static const char h_gpu_1[] = "Capcom fighting games";
1213 static const char h_gpu_2[] = "Black screens in Lunar";
1214 static const char h_gpu_3[] = "Compatibility mode";
1215 static const char h_gpu_6[] = "Pandemonium 2";
1216 //static const char h_gpu_7[] = "Skip every second frame";
1217 static const char h_gpu_8[] = "Needed by Dark Forces";
1218 static const char h_gpu_9[] = "better g-colors, worse textures";
1219 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1221 static menu_entry e_menu_plugin_gpu_peops[] =
1223 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1224 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1225 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1226 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1227 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1228 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1229 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1230 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1231 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1232 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1236 static int menu_loop_plugin_gpu_peops(int id, int keys)
1239 me_loop(e_menu_plugin_gpu_peops, &sel);
1243 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1244 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1245 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1247 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1249 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1250 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1251 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1252 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1253 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1254 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1255 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1256 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1257 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1258 mee_label ("Fixes/hacks:"),
1259 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1260 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1261 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1262 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1263 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1264 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1265 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1266 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1267 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1268 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1269 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1273 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1276 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1280 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1281 static const char h_spu_volboost[] = "Large values cause distortion";
1283 static menu_entry e_menu_plugin_spu[] =
1285 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1286 mee_onoff ("Reverb", 0, iUseReverb, 2),
1287 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1288 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1292 static int menu_loop_plugin_spu(int id, int keys)
1295 me_loop(e_menu_plugin_spu, &sel);
1299 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1300 "savestates and can't be changed there. Must save\n"
1301 "config and reload the game for change to take effect";
1302 static const char h_plugin_gpu[] =
1304 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1306 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1307 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1308 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1309 "must save config and reload the game if changed";
1310 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1311 "must save config and reload the game if changed";
1312 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1313 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1314 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1315 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1317 static menu_entry e_menu_plugin_options[] =
1319 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1320 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1321 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1323 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1325 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1326 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1327 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1328 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1332 static menu_entry e_menu_main2[];
1334 static int menu_loop_plugin_options(int id, int keys)
1337 me_loop(e_menu_plugin_options, &sel);
1339 // sync BIOS/plugins
1340 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1341 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1342 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1343 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1348 // ------------ adv options menu ------------
1350 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1351 "(lower value - less work for the emu, may be faster)";
1352 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1353 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1354 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1356 static menu_entry e_menu_speed_hacks[] =
1358 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1359 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1360 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1361 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1365 static int menu_loop_speed_hacks(int id, int keys)
1368 me_loop(e_menu_speed_hacks, &sel);
1372 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1373 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1374 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1375 "(green: normal, red: fmod, blue: noise)";
1376 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1377 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1378 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1379 "(proper .cue/.bin dump is needed otherwise)";
1380 static const char h_cfg_sio[] = "You should not need this, breaks games";
1381 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1382 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1383 "(timing hack, breaks other games)";
1384 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1385 "(timing hack, breaks other games)";
1386 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1387 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1388 "Might be useful to overcome some dynarec bugs";
1389 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1390 "must reload game for any change to take effect";
1392 static menu_entry e_menu_adv_options[] =
1394 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1395 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1396 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1397 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1398 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1399 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1400 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1401 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1402 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1403 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1404 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1405 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1409 static int menu_loop_adv_options(int id, int keys)
1412 me_loop(e_menu_adv_options, &sel);
1416 // ------------ options menu ------------
1418 static int mh_restore_defaults(int id, int keys)
1420 menu_set_defconfig();
1421 menu_update_msg("defaults restored");
1425 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1426 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1428 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1429 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1430 "loading state or both";
1432 static const char h_restore_def[] = "Switches back to default / recommended\n"
1434 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1436 static menu_entry e_menu_options[] =
1438 // mee_range ("Save slot", 0, state_slot, 0, 9),
1439 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1440 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1441 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1442 mee_enum ("Region", 0, region, men_region),
1443 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1444 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1445 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1446 mee_handler ("[Advanced]", menu_loop_adv_options),
1447 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1448 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1449 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1453 static int menu_loop_options(int id, int keys)
1458 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1459 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1460 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1462 me_loop(e_menu_options, &sel);
1467 // ------------ debug menu ------------
1469 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1471 int w = min(g_menuscreen_w, 1024);
1472 int h = min(g_menuscreen_h, 512);
1473 u16 *d = g_menuscreen_ptr;
1474 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1478 gpuf->ulFreezeVersion = 1;
1479 if (GPU_freeze != NULL)
1480 GPU_freeze(1, gpuf);
1482 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1483 bgr555_to_rgb565(d, s, w * 2);
1485 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1486 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1487 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1488 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1489 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1492 static void debug_menu_loop(void)
1494 int inp, df_x = 0, df_y = 0;
1497 gpuf = malloc(sizeof(*gpuf));
1503 menu_draw_begin(0, 1);
1504 draw_frame_debug(gpuf, df_x, df_y);
1507 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1508 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1509 if (inp & PBTN_MBACK) break;
1510 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1511 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1512 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1513 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1519 // --------- memcard manager ---------
1521 static void draw_mc_icon(int dx, int dy, const u16 *s)
1526 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1528 for (y = 0; y < 16; y++, s += 16) {
1529 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1530 for (x = 0; x < 16; x++) {
1532 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1533 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1539 static void draw_mc_bg(void)
1541 McdBlock *blocks1, *blocks2;
1545 blocks1 = malloc(15 * sizeof(blocks1[0]));
1546 blocks2 = malloc(15 * sizeof(blocks1[0]));
1547 if (blocks1 == NULL || blocks2 == NULL)
1550 for (i = 0; i < 15; i++) {
1551 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1552 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1555 menu_draw_begin(1, 1);
1557 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1559 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1563 maxicons = g_menuscreen_h / 32;
1566 row2 = g_menuscreen_w / 2;
1567 for (i = 0; i < maxicons; i++) {
1568 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1569 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1571 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1572 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1575 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1583 static void handle_memcard_sel(void)
1586 if (memcard1_sel != 0)
1587 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1589 if (memcard2_sel != 0)
1590 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1591 LoadMcds(Config.Mcd1, Config.Mcd2);
1595 static menu_entry e_memcard_options[] =
1597 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1598 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1602 static int menu_loop_memcards(int id, int keys)
1608 memcard1_sel = memcard2_sel = 0;
1609 p = strrchr(Config.Mcd1, '/');
1611 for (i = 0; memcards[i] != NULL; i++)
1612 if (strcmp(p + 1, memcards[i]) == 0)
1613 { memcard1_sel = i; break; }
1614 p = strrchr(Config.Mcd2, '/');
1616 for (i = 0; memcards[i] != NULL; i++)
1617 if (strcmp(p + 1, memcards[i]) == 0)
1618 { memcard2_sel = i; break; }
1620 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1622 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1627 // ------------ cheats menu ------------
1629 static void draw_cheatlist(int sel)
1631 int max_cnt, start, i, pos, active;
1633 max_cnt = g_menuscreen_h / me_sfont_h;
1634 start = max_cnt / 2 - sel;
1636 menu_draw_begin(1, 1);
1638 for (i = 0; i < NumCheats; i++) {
1640 if (pos < 0) continue;
1641 if (pos >= max_cnt) break;
1642 active = Cheats[i].Enabled;
1643 smalltext_out16(14, pos * me_sfont_h,
1644 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1645 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1646 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1650 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1652 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1656 static void menu_loop_cheats(void)
1658 static int menu_sel = 0;
1663 draw_cheatlist(menu_sel);
1664 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1665 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1666 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1667 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1668 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1669 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1670 if (inp & PBTN_MOK) { // action
1671 if (menu_sel < NumCheats)
1672 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1675 if (inp & PBTN_MBACK)
1680 // --------- main menu help ----------
1682 static void menu_bios_warn(void)
1685 static const char msg[] =
1686 "You don't seem to have copied any BIOS\n"
1688 MENU_BIOS_PATH "\n\n"
1690 "While many games work fine with fake\n"
1691 "(HLE) BIOS, others (like MGS and FF8)\n"
1692 "require BIOS to work.\n"
1693 "After copying the file, you'll also need\n"
1694 "to select it in the emu's menu:\n"
1695 "options->[BIOS/Plugins]\n\n"
1696 "The file is usually named SCPH1001.BIN,\n"
1697 "but other not compressed files can be\n"
1699 "Press %s or %s to continue";
1700 char tmp_msg[sizeof(msg) + 64];
1702 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1703 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1706 draw_menu_message(tmp_msg, NULL);
1708 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1709 if (inp & (PBTN_MBACK|PBTN_MOK))
1714 // ------------ main menu ------------
1716 static menu_entry e_menu_main[];
1719 static void draw_frame_main(void)
1728 if (CdromId[0] != 0) {
1729 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1730 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1731 Config.HLE ? "HLE" : "BIOS");
1732 smalltext_out16(4, 1, buff, 0x105f);
1736 capacity = plat_target_bat_capacity_get();
1738 tmp = localtime(<ime);
1739 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1740 if (capacity >= 0) {
1741 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1746 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1750 static void draw_frame_credits(void)
1752 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1755 static const char credits_text[] =
1757 "(C) 1999-2003 PCSX Team\n"
1758 "(C) 2005-2009 PCSX-df Team\n"
1759 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1760 "ARM recompiler (C) 2009-2011 Ari64\n"
1762 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1764 "PEOpS GPU and SPU by Pete Bernert\n"
1765 " and the P.E.Op.S. team\n"
1766 "PCSX4ALL plugin by PCSX4ALL team\n"
1767 " Chui, Franxis, Unai\n\n"
1768 "integration, optimization and\n"
1769 " frontend (C) 2010-2012 notaz\n";
1771 static int reset_game(void)
1774 if (bios_sel == 0 && !Config.HLE)
1780 if (CheckCdrom() != -1) {
1786 static int reload_plugins(const char *cdimg)
1792 set_cd_image(cdimg);
1794 pcnt_hook_plugins();
1796 if (OpenPlugins() == -1) {
1797 menu_update_msg("failed to open plugins");
1800 plugin_call_rearmed_cbs();
1802 cdrIsoMultidiskCount = 1;
1804 CdromLabel[0] = '\0';
1809 static int run_bios(void)
1815 if (reload_plugins(NULL) != 0)
1823 static int run_exe(void)
1827 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1832 if (reload_plugins(NULL) != 0)
1836 if (Load(fname) != 0) {
1837 menu_update_msg("exe load failed, bad file?");
1846 static int run_cd_image(const char *fname)
1849 reload_plugins(fname);
1851 // always autodetect, menu_sync_config will override as needed
1854 if (CheckCdrom() == -1) {
1855 // Only check the CD if we are starting the console with a CD
1857 menu_update_msg("unsupported/invalid CD image");
1863 // Read main executable directly from CDRom and start it
1864 if (LoadCdrom() == -1) {
1866 menu_update_msg("failed to load CD image");
1876 static int romsel_run(void)
1878 int prev_gpu, prev_spu;
1881 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1885 printf("selected file: %s\n", fname);
1887 new_dynarec_clear_full();
1889 if (run_cd_image(fname) != 0)
1892 prev_gpu = gpu_plugsel;
1893 prev_spu = spu_plugsel;
1894 if (menu_load_config(1) != 0)
1895 menu_load_config(0);
1897 // check for plugin changes, have to repeat
1898 // loading if game config changed plugins to reload them
1899 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1900 printf("plugin change detected, reloading plugins..\n");
1901 if (run_cd_image(fname) != 0)
1905 strcpy(last_selected_fname, rom_fname_reload);
1906 menu_do_last_cd_img(0);
1910 static int swap_cd_image(void)
1914 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1918 printf("selected file: %s\n", fname);
1921 CdromLabel[0] = '\0';
1923 set_cd_image(fname);
1924 if (ReloadCdromPlugin() < 0) {
1925 menu_update_msg("failed to load cdr plugin");
1928 if (CDR_open() < 0) {
1929 menu_update_msg("failed to open cdr plugin");
1933 SetCdOpenCaseTime(time(NULL) + 2);
1936 strcpy(last_selected_fname, rom_fname_reload);
1940 static int swap_cd_multidisk(void)
1942 cdrIsoMultidiskSelect++;
1944 CdromLabel[0] = '\0';
1947 if (CDR_open() < 0) {
1948 menu_update_msg("failed to open cdr plugin");
1952 SetCdOpenCaseTime(time(NULL) + 2);
1958 static void load_pcsx_cht(void)
1964 fname = menu_loop_romsel(path, sizeof(path));
1968 printf("selected cheat file: %s\n", fname);
1971 if (NumCheats == 0 && NumCodes == 0)
1972 menu_update_msg("failed to load cheats");
1974 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1975 menu_update_msg(path);
1977 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1980 static int main_menu_handler(int id, int keys)
1984 case MA_MAIN_RESUME_GAME:
1988 case MA_MAIN_SAVE_STATE:
1990 return menu_loop_savestate(0);
1992 case MA_MAIN_LOAD_STATE:
1994 return menu_loop_savestate(1);
1996 case MA_MAIN_RESET_GAME:
1997 if (ready_to_go && reset_game() == 0)
2000 case MA_MAIN_LOAD_ROM:
2001 if (romsel_run() == 0)
2004 case MA_MAIN_SWAP_CD:
2005 if (swap_cd_image() == 0)
2008 case MA_MAIN_SWAP_CD_MULTI:
2009 if (swap_cd_multidisk() == 0)
2012 case MA_MAIN_RUN_BIOS:
2013 if (run_bios() == 0)
2016 case MA_MAIN_RUN_EXE:
2020 case MA_MAIN_CHEATS:
2023 case MA_MAIN_LOAD_CHEATS:
2026 case MA_MAIN_CREDITS:
2027 draw_menu_message(credits_text, draw_frame_credits);
2028 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2034 lprintf("%s: something unknown selected\n", __FUNCTION__);
2041 static menu_entry e_menu_main2[] =
2043 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2044 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2045 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2046 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2047 mee_handler ("Memcard manager", menu_loop_memcards),
2048 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2052 static int main_menu2_handler(int id, int keys)
2056 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2057 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2058 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2059 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2061 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2064 static const char h_extra[] = "Change CD, manage memcards..\n";
2066 static menu_entry e_menu_main[] =
2070 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2071 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2072 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2073 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2074 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2075 mee_handler ("Options", menu_loop_options),
2076 mee_handler ("Controls", menu_loop_keyconfig),
2077 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2078 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2079 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2080 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2084 // ----------------------------
2086 static void menu_leave_emu(void);
2088 void menu_loop(void)
2090 static int warned_about_bios = 0;
2095 if (config_save_counter == 0) {
2097 if (bioses[1] != NULL) {
2098 // autoselect BIOS to make user's life easier
2099 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2102 else if (!warned_about_bios) {
2104 warned_about_bios = 1;
2108 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2109 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2110 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2111 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2112 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2114 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2117 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2118 } while (!ready_to_go);
2120 /* wait until menu, ok, back is released */
2121 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2124 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2129 static int qsort_strcmp(const void *p1, const void *p2)
2131 char * const *s1 = (char * const *)p1;
2132 char * const *s2 = (char * const *)p2;
2133 return strcasecmp(*s1, *s2);
2136 static void scan_bios_plugins(void)
2138 char fname[MAXPATHLEN];
2140 int bios_i, gpu_i, spu_i, mc_i;
2145 gpu_plugins[0] = "builtin_gpu";
2146 spu_plugins[0] = "builtin_spu";
2147 memcards[0] = "(none)";
2148 bios_i = gpu_i = spu_i = mc_i = 1;
2150 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2151 dir = opendir(fname);
2153 perror("scan_bios_plugins bios opendir");
2168 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2171 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2172 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2173 printf("bad BIOS file: %s\n", ent->d_name);
2177 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2178 bioses[bios_i++] = strdup(ent->d_name);
2182 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2188 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2189 dir = opendir(fname);
2191 perror("scan_bios_plugins plugins opendir");
2205 p = strstr(ent->d_name, ".so");
2209 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2210 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2212 fprintf(stderr, "%s\n", dlerror());
2216 // now what do we have here?
2217 tmp = dlsym(h, "GPUinit");
2220 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2221 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2225 tmp = dlsym(h, "SPUinit");
2228 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2229 spu_plugins[spu_i++] = strdup(ent->d_name);
2233 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2240 dir = opendir("." MEMCARD_DIR);
2242 perror("scan_bios_plugins memcards opendir");
2257 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2260 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2261 if (stat(fname, &st) != 0) {
2262 printf("bad memcard file: %s\n", ent->d_name);
2266 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2267 memcards[mc_i++] = strdup(ent->d_name);
2271 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2275 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2280 void menu_init(void)
2282 char buff[MAXPATHLEN];
2285 strcpy(last_selected_fname, "/media");
2287 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2289 scan_bios_plugins();
2292 menu_set_defconfig();
2293 menu_load_config(0);
2294 menu_do_last_cd_img(1);
2299 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2300 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2301 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2302 fprintf(stderr, "OOM\n");
2306 emu_make_path(buff, "skin/background.png", sizeof(buff));
2307 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2309 i = plat_target.cpu_clock_set != NULL
2310 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2311 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2313 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2314 e_menu_gfx_options[i].data = plat_target.vout_methods;
2315 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2316 plat_target.vout_methods != NULL);
2318 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2319 e_menu_gfx_options[i].data = plat_target.hwfilters;
2320 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2321 plat_target.hwfilters != NULL);
2323 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2324 plat_target.gamma_set != NULL);
2326 #ifndef __ARM_ARCH_7A__
2327 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2329 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2330 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2331 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2332 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2333 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2334 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2335 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2338 void menu_notify_mode_change(int w, int h, int bpp)
2342 last_vout_bpp = bpp;
2345 static void menu_leave_emu(void)
2347 if (GPU_close != NULL) {
2348 int ret = GPU_close();
2350 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2353 plat_video_menu_enter(ready_to_go);
2355 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2356 if (pl_vout_buf != NULL && ready_to_go) {
2357 int x = max(0, g_menuscreen_w - last_vout_w);
2358 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2359 int w = min(g_menuscreen_w, last_vout_w);
2360 int h = min(g_menuscreen_h, last_vout_h);
2361 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2362 char *s = pl_vout_buf;
2364 if (last_vout_bpp == 16) {
2365 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2366 menu_darken_bg(d, s, w, 0);
2369 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2370 rgb888_to_rgb565(d, s, w * 3);
2371 menu_darken_bg(d, d, w, 0);
2377 cpu_clock = plat_target_cpu_clock_get();
2380 void menu_prepare_emu(void)
2382 R3000Acpu *prev_cpu = psxCpu;
2384 plat_video_menu_leave();
2386 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2387 if (psxCpu != prev_cpu)
2388 // note that this does not really reset, just clears drc caches
2391 // core doesn't care about Config.Cdda changes,
2392 // so handle them manually here
2398 plat_target_cpu_clock_set(cpu_clock);
2400 // push config to GPU plugin
2401 plugin_call_rearmed_cbs();
2403 if (GPU_open != NULL) {
2404 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2406 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2412 void menu_update_msg(const char *msg)
2414 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2415 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2417 menu_error_time = plat_get_ticks_ms();
2418 lprintf("msg: %s\n", menu_error_msg);
2421 void menu_finish(void)
2423 if (cpu_clock_st > 0)
2424 plat_target_cpu_clock_set(cpu_clock_st);