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),
281 // CE_CONFIG_VAL(Sio),
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),
291 CE_INTVAL_V(g_scaler, 2),
292 CE_INTVAL(g_layer_x),
293 CE_INTVAL(g_layer_y),
294 CE_INTVAL(g_layer_w),
295 CE_INTVAL(g_layer_h),
296 CE_INTVAL(soft_filter),
297 CE_INTVAL(plat_target.vout_method),
298 CE_INTVAL(plat_target.hwfilter),
299 CE_INTVAL(plat_target.vout_fullscreen),
300 CE_INTVAL(state_slot),
301 CE_INTVAL(cpu_clock),
303 CE_INTVAL(in_type_sel1),
304 CE_INTVAL(in_type_sel2),
305 CE_INTVAL(analog_deadzone),
306 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
307 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
308 CE_INTVAL_V(frameskip, 3),
309 CE_INTVAL_P(gpu_peops.iUseDither),
310 CE_INTVAL_P(gpu_peops.dwActFixes),
311 CE_INTVAL_P(gpu_unai.lineskip),
312 CE_INTVAL_P(gpu_unai.abe_hack),
313 CE_INTVAL_P(gpu_unai.no_light),
314 CE_INTVAL_P(gpu_unai.no_blend),
315 CE_INTVAL_P(gpu_neon.allow_interlace),
316 CE_INTVAL_P(gpu_neon.enhancement_enable),
317 CE_INTVAL_P(gpu_neon.enhancement_no_main),
318 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
319 CE_INTVAL_P(gpu_peopsgl.iFilterType),
320 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
321 CE_INTVAL_P(gpu_peopsgl.iUseMask),
322 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
323 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
324 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
325 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
326 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
327 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
328 CE_INTVAL_V(iUseReverb, 3),
329 CE_INTVAL_V(iXAPitch, 3),
330 CE_INTVAL_V(iUseInterpolation, 3),
331 CE_INTVAL(config_save_counter),
332 CE_INTVAL(in_evdev_allow_abs_only),
333 CE_INTVAL(volume_boost),
334 CE_INTVAL(psx_clock),
335 CE_INTVAL(new_dynarec_hacks),
336 CE_INTVAL(in_enable_vibration),
339 static char *get_cd_label(void)
341 static char trimlabel[33];
344 strncpy(trimlabel, CdromLabel, 32);
346 for (j = 31; j >= 0; j--)
347 if (trimlabel[j] == ' ')
353 static void make_cfg_fname(char *buf, size_t size, int is_game)
356 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
358 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
361 static void keys_write_all(FILE *f);
362 static char *mystrip(char *str);
364 static int menu_write_config(int is_game)
366 char cfgfile[MAXPATHLEN];
370 config_save_counter++;
372 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
373 f = fopen(cfgfile, "w");
375 printf("menu_write_config: failed to open: %s\n", cfgfile);
379 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
380 fprintf(f, "%s = ", config_data[i].name);
381 switch (config_data[i].len) {
383 fprintf(f, "%s\n", (char *)config_data[i].val);
386 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
389 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
392 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
395 printf("menu_write_config: unhandled len %d for %s\n",
396 (int)config_data[i].len, config_data[i].name);
407 static int menu_do_last_cd_img(int is_get)
413 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
414 f = fopen(path, is_get ? "r" : "w");
419 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
420 last_selected_fname[ret] = 0;
421 mystrip(last_selected_fname);
424 fprintf(f, "%s\n", last_selected_fname);
430 static void parse_str_val(char *cval, const char *src)
433 strncpy(cval, src, MAXPATHLEN);
434 cval[MAXPATHLEN - 1] = 0;
435 tmp = strchr(cval, '\n');
437 tmp = strchr(cval, '\r');
442 static void keys_load_all(const char *cfg);
444 static int menu_load_config(int is_game)
446 char cfgfile[MAXPATHLEN];
452 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
453 f = fopen(cfgfile, "r");
455 printf("menu_load_config: failed to open: %s\n", cfgfile);
459 fseek(f, 0, SEEK_END);
462 printf("bad size %ld: %s\n", size, cfgfile);
466 cfg = malloc(size + 1);
470 fseek(f, 0, SEEK_SET);
471 if (fread(cfg, 1, size, f) != size) {
472 printf("failed to read: %s\n", cfgfile);
477 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
481 tmp = strstr(cfg, config_data[i].name);
484 tmp += strlen(config_data[i].name);
485 if (strncmp(tmp, " = ", 3) != 0)
489 if (config_data[i].len == 0) {
490 parse_str_val(config_data[i].val, tmp);
495 val = strtoul(tmp, &tmp2, 16);
496 if (tmp2 == NULL || tmp == tmp2)
497 continue; // parse failed
499 switch (config_data[i].len) {
501 *(u8 *)config_data[i].val = val;
504 *(u16 *)config_data[i].val = val;
507 *(u32 *)config_data[i].val = val;
510 printf("menu_load_config: unhandled len %d for %s\n",
511 (int)config_data[i].len, config_data[i].name);
517 char *tmp = strstr(cfg, "lastcdimg = ");
520 parse_str_val(last_selected_fname, tmp);
535 for (i = bios_sel = 0; bioses[i] != NULL; i++)
536 if (strcmp(Config.Bios, bioses[i]) == 0)
537 { bios_sel = i; break; }
539 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
540 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
541 { gpu_plugsel = i; break; }
543 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
544 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
545 { spu_plugsel = i; break; }
550 // rrrr rggg gggb bbbb
551 static unsigned short fname2color(const char *fname)
553 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
554 ".bz", ".znx", ".pbp", ".cbn" };
555 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
556 ".table", ".index", ".sbi" };
557 const char *ext = strrchr(fname, '.');
562 for (i = 0; i < array_size(cdimg_exts); i++)
563 if (strcasecmp(ext, cdimg_exts[i]) == 0)
565 for (i = 0; i < array_size(other_exts); i++)
566 if (strcasecmp(ext, other_exts[i]) == 0)
571 static void draw_savestate_bg(int slot);
573 static const char *filter_exts[] = {
574 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
577 #define MENU_ALIGN_LEFT
578 #ifdef __ARM_ARCH_7A__ // assume hires device
584 #include "libpicofe/menu.c"
586 // a bit of black magic here
587 static void draw_savestate_bg(int slot)
589 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
591 char fname[MAXPATHLEN];
598 ret = get_state_filename(fname, sizeof(fname), slot);
602 f = gzopen(fname, "rb");
606 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
607 fprintf(stderr, "gzseek failed\n");
612 gpu = malloc(sizeof(*gpu));
618 ret = gzread(f, gpu, sizeof(*gpu));
620 if (ret != sizeof(*gpu)) {
621 fprintf(stderr, "gzread failed\n");
625 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
627 if (gpu->ulStatus & 0x800000)
628 goto out; // disabled
630 x = gpu->ulControl[5] & 0x3ff;
631 y = (gpu->ulControl[5] >> 10) & 0x1ff;
632 w = psx_widths[(gpu->ulStatus >> 16) & 7];
633 tmp = gpu->ulControl[7];
634 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
635 if (gpu->ulStatus & 0x80000) // doubleheight
637 if (h <= 0 || h > 512)
643 s = (u16 *)gpu->psxVRam + y * 1024 + x;
645 x = max(0, g_menuscreen_w - w) & ~3;
646 y = max(0, g_menuscreen_h / 2 - h / 2);
647 w = min(g_menuscreen_w, w);
648 h = min(g_menuscreen_h, h);
649 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
651 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
652 if (gpu->ulStatus & 0x200000)
653 bgr888_to_rgb565(d, s, w * 3);
655 bgr555_to_rgb565(d, s, w * 2);
657 // darken this so that menu text is visible
658 if (g_menuscreen_w - w < 320)
659 menu_darken_bg(d, d, w * 2, 0);
666 // -------------- key config --------------
668 me_bind_action me_ctrl_actions[] =
670 { "UP ", 1 << DKEY_UP},
671 { "DOWN ", 1 << DKEY_DOWN },
672 { "LEFT ", 1 << DKEY_LEFT },
673 { "RIGHT ", 1 << DKEY_RIGHT },
674 { "TRIANGLE", 1 << DKEY_TRIANGLE },
675 { "CIRCLE ", 1 << DKEY_CIRCLE },
676 { "CROSS ", 1 << DKEY_CROSS },
677 { "SQUARE ", 1 << DKEY_SQUARE },
678 { "L1 ", 1 << DKEY_L1 },
679 { "R1 ", 1 << DKEY_R1 },
680 { "L2 ", 1 << DKEY_L2 },
681 { "R2 ", 1 << DKEY_R2 },
682 { "L3 ", 1 << DKEY_L3 },
683 { "R3 ", 1 << DKEY_R3 },
684 { "START ", 1 << DKEY_START },
685 { "SELECT ", 1 << DKEY_SELECT },
689 me_bind_action emuctrl_actions[] =
691 { "Save State ", 1 << SACTION_SAVE_STATE },
692 { "Load State ", 1 << SACTION_LOAD_STATE },
693 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
694 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
695 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
696 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
697 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
698 #ifdef __ARM_ARCH_7A__
699 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
701 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
702 #if MENU_SHOW_MINIMIZE
703 { "Minimize ", 1 << SACTION_MINIMIZE },
705 #if MENU_SHOW_FULLSCREEN
706 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
708 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
709 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
710 { "Gun A button ", 1 << SACTION_GUN_A },
711 { "Gun B button ", 1 << SACTION_GUN_B },
712 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
714 { "Volume Up ", 1 << SACTION_VOLUME_UP },
715 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
720 static char *mystrip(char *str)
725 for (i = 0; i < len; i++)
726 if (str[i] != ' ') break;
727 if (i > 0) memmove(str, str + i, len - i + 1);
730 for (i = len - 1; i >= 0; i--)
731 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
737 static void get_line(char *d, size_t size, const char *s)
742 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
753 static void keys_write_all(FILE *f)
757 for (d = 0; d < IN_MAX_DEVS; d++)
759 const int *binds = in_get_dev_binds(d);
760 const char *name = in_get_dev_name(d, 0, 0);
763 if (binds == NULL || name == NULL)
766 fprintf(f, "binddev = %s\n", name);
767 in_get_config(d, IN_CFG_BIND_COUNT, &count);
769 for (k = 0; k < count; k++)
774 act[0] = act[31] = 0;
775 name = in_get_key_name(d, k);
777 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
778 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
779 mask = me_ctrl_actions[i].mask;
781 strncpy(act, me_ctrl_actions[i].name, 31);
782 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
785 mask = me_ctrl_actions[i].mask << 16;
787 strncpy(act, me_ctrl_actions[i].name, 31);
788 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
793 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
794 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
795 mask = emuctrl_actions[i].mask;
797 strncpy(act, emuctrl_actions[i].name, 31);
798 fprintf(f, "bind %s = %s\n", name, mystrip(act));
804 for (k = 0; k < array_size(in_adev); k++)
807 fprintf(f, "bind_analog = %d\n", k);
812 static int parse_bind_val(const char *val, int *type)
816 *type = IN_BINDTYPE_NONE;
820 if (strncasecmp(val, "player", 6) == 0)
822 int player, shift = 0;
823 player = atoi(val + 6) - 1;
825 if ((unsigned int)player > 1)
830 *type = IN_BINDTYPE_PLAYER12;
831 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
832 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
833 return me_ctrl_actions[i].mask << shift;
836 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
837 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
838 *type = IN_BINDTYPE_EMU;
839 return emuctrl_actions[i].mask;
846 static void keys_load_all(const char *cfg)
848 char dev[256], key[128], *act;
854 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
857 get_line(dev, sizeof(dev), p);
858 dev_id = in_config_parse_dev(dev);
860 printf("input: can't handle dev: %s\n", dev);
864 in_unbind_all(dev_id, -1, -1);
865 while ((p = strstr(p, "bind"))) {
866 if (strncmp(p, "binddev = ", 10) == 0)
869 if (strncmp(p, "bind_analog", 11) == 0) {
870 ret = sscanf(p, "bind_analog = %d", &bind);
873 printf("input: parse error: %16s..\n", p);
876 if ((unsigned int)bind >= array_size(in_adev)) {
877 printf("input: analog id %d out of range\n", bind);
880 in_adev[bind] = dev_id;
886 printf("input: parse error: %16s..\n", p);
890 get_line(key, sizeof(key), p);
891 act = strchr(key, '=');
893 printf("parse failed: %16s..\n", p);
901 bind = parse_bind_val(act, &bindtype);
902 if (bind != -1 && bind != 0) {
903 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
904 in_config_bind_key(dev_id, key, bind, bindtype);
907 lprintf("config: unhandled action \"%s\"\n", act);
913 static int key_config_loop_wrap(int id, int keys)
916 case MA_CTRL_PLAYER1:
917 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
919 case MA_CTRL_PLAYER2:
920 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
923 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
931 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
932 "Might cause problems with real analog sticks";
933 static const char *adevnames[IN_MAX_DEVS + 2];
934 static int stick_sel[2];
936 static menu_entry e_menu_keyconfig_analog[] =
938 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
939 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
940 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
941 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
942 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
943 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
944 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
945 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
949 static int key_config_analog(int id, int keys)
951 int i, d, count, sel = 0;
952 int sel2dev_map[IN_MAX_DEVS];
954 memset(adevnames, 0, sizeof(adevnames));
955 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
956 memset(stick_sel, 0, sizeof(stick_sel));
958 adevnames[0] = "None";
960 for (d = 0; d < IN_MAX_DEVS; d++)
962 const char *name = in_get_dev_name(d, 0, 1);
967 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
971 if (in_adev[0] == d) stick_sel[0] = i;
972 if (in_adev[1] == d) stick_sel[1] = i;
974 adevnames[i++] = name;
978 me_loop(e_menu_keyconfig_analog, &sel);
980 in_adev[0] = sel2dev_map[stick_sel[0]];
981 in_adev[1] = sel2dev_map[stick_sel[1]];
986 static const char *mgn_dev_name(int id, int *offs)
988 const char *name = NULL;
991 if (id == MA_CTRL_DEV_FIRST)
994 for (; it < IN_MAX_DEVS; it++) {
995 name = in_get_dev_name(it, 1, 1);
1004 static const char *mgn_saveloadcfg(int id, int *offs)
1009 static int mh_savecfg(int id, int keys)
1011 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1012 menu_update_msg("config saved");
1014 menu_update_msg("failed to write config");
1019 static int mh_input_rescan(int id, int keys)
1021 //menu_sync_config();
1023 menu_update_msg("rescan complete.");
1028 static const char *men_in_type_sel[] = {
1029 "Standard (SCPH-1080)",
1030 "Analog (SCPH-1150)",
1034 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1035 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1036 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1038 static menu_entry e_menu_keyconfig[] =
1040 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1041 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1042 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1043 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1045 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1046 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1047 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1048 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1049 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1050 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1051 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1052 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1053 mee_handler ("Rescan devices:", mh_input_rescan),
1055 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1056 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1065 static int menu_loop_keyconfig(int id, int keys)
1069 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1070 me_loop(e_menu_keyconfig, &sel);
1074 // ------------ gfx options menu ------------
1076 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1077 static const char *men_soft_filter[] = { "None",
1079 "scale2x", "eagle2x",
1082 static const char *men_dummy[] = { NULL };
1083 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1084 "using d-pad or move it using R+d-pad";
1085 static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
1086 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1087 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1089 static int menu_loop_cscaler(int id, int keys)
1093 g_scaler = SCALE_CUSTOM;
1095 plat_gvideo_open(Config.PsxType);
1099 menu_draw_begin(0, 1);
1100 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1101 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1102 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1105 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1106 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1107 if (inp & PBTN_UP) g_layer_y--;
1108 if (inp & PBTN_DOWN) g_layer_y++;
1109 if (inp & PBTN_LEFT) g_layer_x--;
1110 if (inp & PBTN_RIGHT) g_layer_x++;
1111 if (!(inp & PBTN_R)) {
1112 if (inp & PBTN_UP) g_layer_h += 2;
1113 if (inp & PBTN_DOWN) g_layer_h -= 2;
1114 if (inp & PBTN_LEFT) g_layer_w += 2;
1115 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1117 if (inp & (PBTN_MOK|PBTN_MBACK))
1120 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1121 if (g_layer_x < 0) g_layer_x = 0;
1122 if (g_layer_x > 640) g_layer_x = 640;
1123 if (g_layer_y < 0) g_layer_y = 0;
1124 if (g_layer_y > 420) g_layer_y = 420;
1125 if (g_layer_w < 160) g_layer_w = 160;
1126 if (g_layer_h < 60) g_layer_h = 60;
1127 if (g_layer_x + g_layer_w > 800)
1128 g_layer_w = 800 - g_layer_x;
1129 if (g_layer_y + g_layer_h > 480)
1130 g_layer_h = 480 - g_layer_y;
1132 plat_gvideo_open(Config.PsxType);
1136 plat_gvideo_close();
1141 static menu_entry e_menu_gfx_options[] =
1143 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1144 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1145 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1146 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1147 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1148 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1149 // mee_onoff ("Vsync", 0, vsync, 1),
1150 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1154 static int menu_loop_gfx_options(int id, int keys)
1158 me_loop(e_menu_gfx_options, &sel);
1163 // ------------ bios/plugins ------------
1167 static const char h_gpu_neon[] =
1168 "Configure built-in NEON GPU plugin";
1169 static const char h_gpu_neon_enhanced[] =
1170 "Renders in double resolution at the cost of lower performance\n"
1171 "(not available for high resolution games)";
1172 static const char h_gpu_neon_enhanced_hack[] =
1173 "Speed hack for above option (glitches some games)";
1174 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1176 static menu_entry e_menu_plugin_gpu_neon[] =
1178 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1179 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1180 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1184 static int menu_loop_plugin_gpu_neon(int id, int keys)
1187 me_loop(e_menu_plugin_gpu_neon, &sel);
1193 static menu_entry e_menu_plugin_gpu_unai[] =
1195 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1196 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1197 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1198 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1202 static int menu_loop_plugin_gpu_unai(int id, int keys)
1205 me_loop(e_menu_plugin_gpu_unai, &sel);
1209 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1210 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1211 static const char h_gpu_1[] = "Capcom fighting games";
1212 static const char h_gpu_2[] = "Black screens in Lunar";
1213 static const char h_gpu_3[] = "Compatibility mode";
1214 static const char h_gpu_6[] = "Pandemonium 2";
1215 //static const char h_gpu_7[] = "Skip every second frame";
1216 static const char h_gpu_8[] = "Needed by Dark Forces";
1217 static const char h_gpu_9[] = "better g-colors, worse textures";
1218 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1220 static menu_entry e_menu_plugin_gpu_peops[] =
1222 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1223 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1224 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1225 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1226 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1227 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1228 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1229 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1230 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1231 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1235 static int menu_loop_plugin_gpu_peops(int id, int keys)
1238 me_loop(e_menu_plugin_gpu_peops, &sel);
1242 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1243 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1244 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1246 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1248 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1249 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1250 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1251 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1252 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1253 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1254 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1255 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1256 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1257 mee_label ("Fixes/hacks:"),
1258 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1259 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1260 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1261 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1262 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1263 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1264 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1265 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1266 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1267 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1268 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1272 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1275 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1279 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1280 static const char h_spu_volboost[] = "Large values cause distortion";
1282 static menu_entry e_menu_plugin_spu[] =
1284 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1285 mee_onoff ("Reverb", 0, iUseReverb, 2),
1286 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1287 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1291 static int menu_loop_plugin_spu(int id, int keys)
1294 me_loop(e_menu_plugin_spu, &sel);
1298 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1299 "savestates and can't be changed there. Must save\n"
1300 "config and reload the game for change to take effect";
1301 static const char h_plugin_gpu[] =
1303 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1305 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1306 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1307 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1308 "must save config and reload the game if changed";
1309 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1310 "must save config and reload the game if changed";
1311 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1312 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1313 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1314 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1316 static menu_entry e_menu_plugin_options[] =
1318 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1319 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1320 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1322 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1324 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1325 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1326 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1327 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1331 static menu_entry e_menu_main2[];
1333 static int menu_loop_plugin_options(int id, int keys)
1336 me_loop(e_menu_plugin_options, &sel);
1338 // sync BIOS/plugins
1339 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1340 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1341 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1342 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1347 // ------------ adv options menu ------------
1349 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1350 "(lower value - less work for the emu, may be faster)";
1351 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1352 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1353 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1355 static menu_entry e_menu_speed_hacks[] =
1357 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1358 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1359 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1360 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1364 static int menu_loop_speed_hacks(int id, int keys)
1367 me_loop(e_menu_speed_hacks, &sel);
1371 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1372 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1373 "(green: normal, red: fmod, blue: noise)";
1374 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1375 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1376 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1377 "(proper .cue/.bin dump is needed otherwise)";
1378 static const char h_cfg_sio[] = "You should not need this, breaks games";
1379 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1380 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1381 "(timing hack, breaks other games)";
1382 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1383 "(timing hack, breaks other games)";
1384 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1385 "Might be useful to overcome some dynarec bugs";
1386 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1387 "must reload game for any change to take effect";
1389 static menu_entry e_menu_adv_options[] =
1391 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1392 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1393 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1394 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1395 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1396 //mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1397 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1398 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1399 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1400 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1401 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1405 static int menu_loop_adv_options(int id, int keys)
1408 me_loop(e_menu_adv_options, &sel);
1412 // ------------ options menu ------------
1414 static int mh_restore_defaults(int id, int keys)
1416 menu_set_defconfig();
1417 menu_update_msg("defaults restored");
1421 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1422 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1424 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1425 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1426 "loading state or both";
1428 static const char h_restore_def[] = "Switches back to default / recommended\n"
1430 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1432 static menu_entry e_menu_options[] =
1434 // mee_range ("Save slot", 0, state_slot, 0, 9),
1435 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1436 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1437 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1438 mee_enum ("Region", 0, region, men_region),
1439 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1440 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1441 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1442 mee_handler ("[Advanced]", menu_loop_adv_options),
1443 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1444 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1445 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1449 static int menu_loop_options(int id, int keys)
1454 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1455 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1456 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1458 me_loop(e_menu_options, &sel);
1463 // ------------ debug menu ------------
1465 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1467 int w = min(g_menuscreen_w, 1024);
1468 int h = min(g_menuscreen_h, 512);
1469 u16 *d = g_menuscreen_ptr;
1470 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1474 gpuf->ulFreezeVersion = 1;
1475 if (GPU_freeze != NULL)
1476 GPU_freeze(1, gpuf);
1478 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1479 bgr555_to_rgb565(d, s, w * 2);
1481 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1482 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1483 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1484 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1485 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1488 static void debug_menu_loop(void)
1490 int inp, df_x = 0, df_y = 0;
1493 gpuf = malloc(sizeof(*gpuf));
1499 menu_draw_begin(0, 1);
1500 draw_frame_debug(gpuf, df_x, df_y);
1503 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1504 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1505 if (inp & PBTN_MBACK) break;
1506 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1507 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1508 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1509 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1515 // --------- memcard manager ---------
1517 static void draw_mc_icon(int dx, int dy, const u16 *s)
1522 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1524 for (y = 0; y < 16; y++, s += 16) {
1525 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1526 for (x = 0; x < 16; x++) {
1528 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1529 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1535 static void draw_mc_bg(void)
1537 McdBlock *blocks1, *blocks2;
1541 blocks1 = malloc(15 * sizeof(blocks1[0]));
1542 blocks2 = malloc(15 * sizeof(blocks1[0]));
1543 if (blocks1 == NULL || blocks2 == NULL)
1546 for (i = 0; i < 15; i++) {
1547 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1548 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1551 menu_draw_begin(1, 1);
1553 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1555 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1559 maxicons = g_menuscreen_h / 32;
1562 row2 = g_menuscreen_w / 2;
1563 for (i = 0; i < maxicons; i++) {
1564 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1565 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1567 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1568 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1571 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1579 static void handle_memcard_sel(void)
1582 if (memcard1_sel != 0)
1583 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1585 if (memcard2_sel != 0)
1586 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1587 LoadMcds(Config.Mcd1, Config.Mcd2);
1591 static menu_entry e_memcard_options[] =
1593 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1594 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1598 static int menu_loop_memcards(int id, int keys)
1604 memcard1_sel = memcard2_sel = 0;
1605 p = strrchr(Config.Mcd1, '/');
1607 for (i = 0; memcards[i] != NULL; i++)
1608 if (strcmp(p + 1, memcards[i]) == 0)
1609 { memcard1_sel = i; break; }
1610 p = strrchr(Config.Mcd2, '/');
1612 for (i = 0; memcards[i] != NULL; i++)
1613 if (strcmp(p + 1, memcards[i]) == 0)
1614 { memcard2_sel = i; break; }
1616 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1618 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1623 // ------------ cheats menu ------------
1625 static void draw_cheatlist(int sel)
1627 int max_cnt, start, i, pos, active;
1629 max_cnt = g_menuscreen_h / me_sfont_h;
1630 start = max_cnt / 2 - sel;
1632 menu_draw_begin(1, 1);
1634 for (i = 0; i < NumCheats; i++) {
1636 if (pos < 0) continue;
1637 if (pos >= max_cnt) break;
1638 active = Cheats[i].Enabled;
1639 smalltext_out16(14, pos * me_sfont_h,
1640 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1641 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1642 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1646 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1648 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1652 static void menu_loop_cheats(void)
1654 static int menu_sel = 0;
1659 draw_cheatlist(menu_sel);
1660 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1661 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1662 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1663 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1664 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1665 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1666 if (inp & PBTN_MOK) { // action
1667 if (menu_sel < NumCheats)
1668 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1671 if (inp & PBTN_MBACK)
1676 // --------- main menu help ----------
1678 static void menu_bios_warn(void)
1681 static const char msg[] =
1682 "You don't seem to have copied any BIOS\n"
1684 MENU_BIOS_PATH "\n\n"
1686 "While many games work fine with fake\n"
1687 "(HLE) BIOS, others (like MGS and FF8)\n"
1688 "require BIOS to work.\n"
1689 "After copying the file, you'll also need\n"
1690 "to select it in the emu's menu:\n"
1691 "options->[BIOS/Plugins]\n\n"
1692 "The file is usually named SCPH1001.BIN,\n"
1693 "but other not compressed files can be\n"
1695 "Press %s or %s to continue";
1696 char tmp_msg[sizeof(msg) + 64];
1698 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1699 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1702 draw_menu_message(tmp_msg, NULL);
1704 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1705 if (inp & (PBTN_MBACK|PBTN_MOK))
1710 // ------------ main menu ------------
1712 static menu_entry e_menu_main[];
1715 static void draw_frame_main(void)
1724 if (CdromId[0] != 0) {
1725 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1726 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1727 Config.HLE ? "HLE" : "BIOS");
1728 smalltext_out16(4, 1, buff, 0x105f);
1732 capacity = plat_target_bat_capacity_get();
1734 tmp = localtime(<ime);
1735 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1736 if (capacity >= 0) {
1737 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1742 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1746 static void draw_frame_credits(void)
1748 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1751 static const char credits_text[] =
1753 "(C) 1999-2003 PCSX Team\n"
1754 "(C) 2005-2009 PCSX-df Team\n"
1755 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1756 "ARM recompiler (C) 2009-2011 Ari64\n"
1758 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1760 "PEOpS GPU and SPU by Pete Bernert\n"
1761 " and the P.E.Op.S. team\n"
1762 "PCSX4ALL plugin by PCSX4ALL team\n"
1763 " Chui, Franxis, Unai\n\n"
1764 "integration, optimization and\n"
1765 " frontend (C) 2010-2012 notaz\n";
1767 static int reset_game(void)
1770 if (bios_sel == 0 && !Config.HLE)
1776 if (CheckCdrom() != -1) {
1782 static int reload_plugins(const char *cdimg)
1788 set_cd_image(cdimg);
1790 pcnt_hook_plugins();
1792 if (OpenPlugins() == -1) {
1793 menu_update_msg("failed to open plugins");
1796 plugin_call_rearmed_cbs();
1798 cdrIsoMultidiskCount = 1;
1800 CdromLabel[0] = '\0';
1805 static int run_bios(void)
1811 if (reload_plugins(NULL) != 0)
1819 static int run_exe(void)
1823 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1828 if (reload_plugins(NULL) != 0)
1832 if (Load(fname) != 0) {
1833 menu_update_msg("exe load failed, bad file?");
1842 static int run_cd_image(const char *fname)
1845 reload_plugins(fname);
1847 // always autodetect, menu_sync_config will override as needed
1850 if (CheckCdrom() == -1) {
1851 // Only check the CD if we are starting the console with a CD
1853 menu_update_msg("unsupported/invalid CD image");
1859 // Read main executable directly from CDRom and start it
1860 if (LoadCdrom() == -1) {
1862 menu_update_msg("failed to load CD image");
1872 static int romsel_run(void)
1874 int prev_gpu, prev_spu;
1877 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1881 printf("selected file: %s\n", fname);
1883 new_dynarec_clear_full();
1885 if (run_cd_image(fname) != 0)
1888 prev_gpu = gpu_plugsel;
1889 prev_spu = spu_plugsel;
1890 if (menu_load_config(1) != 0)
1891 menu_load_config(0);
1893 // check for plugin changes, have to repeat
1894 // loading if game config changed plugins to reload them
1895 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1896 printf("plugin change detected, reloading plugins..\n");
1897 if (run_cd_image(fname) != 0)
1901 strcpy(last_selected_fname, rom_fname_reload);
1902 menu_do_last_cd_img(0);
1906 static int swap_cd_image(void)
1910 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1914 printf("selected file: %s\n", fname);
1917 CdromLabel[0] = '\0';
1919 set_cd_image(fname);
1920 if (ReloadCdromPlugin() < 0) {
1921 menu_update_msg("failed to load cdr plugin");
1924 if (CDR_open() < 0) {
1925 menu_update_msg("failed to open cdr plugin");
1929 SetCdOpenCaseTime(time(NULL) + 2);
1932 strcpy(last_selected_fname, rom_fname_reload);
1936 static int swap_cd_multidisk(void)
1938 cdrIsoMultidiskSelect++;
1940 CdromLabel[0] = '\0';
1943 if (CDR_open() < 0) {
1944 menu_update_msg("failed to open cdr plugin");
1948 SetCdOpenCaseTime(time(NULL) + 2);
1954 static void load_pcsx_cht(void)
1960 fname = menu_loop_romsel(path, sizeof(path));
1964 printf("selected cheat file: %s\n", fname);
1967 if (NumCheats == 0 && NumCodes == 0)
1968 menu_update_msg("failed to load cheats");
1970 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1971 menu_update_msg(path);
1973 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1976 static int main_menu_handler(int id, int keys)
1980 case MA_MAIN_RESUME_GAME:
1984 case MA_MAIN_SAVE_STATE:
1986 return menu_loop_savestate(0);
1988 case MA_MAIN_LOAD_STATE:
1990 return menu_loop_savestate(1);
1992 case MA_MAIN_RESET_GAME:
1993 if (ready_to_go && reset_game() == 0)
1996 case MA_MAIN_LOAD_ROM:
1997 if (romsel_run() == 0)
2000 case MA_MAIN_SWAP_CD:
2001 if (swap_cd_image() == 0)
2004 case MA_MAIN_SWAP_CD_MULTI:
2005 if (swap_cd_multidisk() == 0)
2008 case MA_MAIN_RUN_BIOS:
2009 if (run_bios() == 0)
2012 case MA_MAIN_RUN_EXE:
2016 case MA_MAIN_CHEATS:
2019 case MA_MAIN_LOAD_CHEATS:
2022 case MA_MAIN_CREDITS:
2023 draw_menu_message(credits_text, draw_frame_credits);
2024 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2030 lprintf("%s: something unknown selected\n", __FUNCTION__);
2037 static menu_entry e_menu_main2[] =
2039 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2040 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2041 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2042 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2043 mee_handler ("Memcard manager", menu_loop_memcards),
2044 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2048 static int main_menu2_handler(int id, int keys)
2052 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2053 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2054 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2055 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2057 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2060 static const char h_extra[] = "Change CD, manage memcards..\n";
2062 static menu_entry e_menu_main[] =
2066 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2067 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2068 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2069 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2070 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2071 mee_handler ("Options", menu_loop_options),
2072 mee_handler ("Controls", menu_loop_keyconfig),
2073 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2074 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2075 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2076 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2080 // ----------------------------
2082 static void menu_leave_emu(void);
2084 void menu_loop(void)
2086 static int warned_about_bios = 0;
2091 if (config_save_counter == 0) {
2093 if (bioses[1] != NULL) {
2094 // autoselect BIOS to make user's life easier
2095 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2098 else if (!warned_about_bios) {
2100 warned_about_bios = 1;
2104 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2105 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2106 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2107 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2108 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2110 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2113 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2114 } while (!ready_to_go);
2116 /* wait until menu, ok, back is released */
2117 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2120 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2125 static int qsort_strcmp(const void *p1, const void *p2)
2127 char * const *s1 = (char * const *)p1;
2128 char * const *s2 = (char * const *)p2;
2129 return strcasecmp(*s1, *s2);
2132 static void scan_bios_plugins(void)
2134 char fname[MAXPATHLEN];
2136 int bios_i, gpu_i, spu_i, mc_i;
2141 gpu_plugins[0] = "builtin_gpu";
2142 spu_plugins[0] = "builtin_spu";
2143 memcards[0] = "(none)";
2144 bios_i = gpu_i = spu_i = mc_i = 1;
2146 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2147 dir = opendir(fname);
2149 perror("scan_bios_plugins bios opendir");
2164 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2167 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2168 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2169 printf("bad BIOS file: %s\n", ent->d_name);
2173 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2174 bioses[bios_i++] = strdup(ent->d_name);
2178 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2184 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2185 dir = opendir(fname);
2187 perror("scan_bios_plugins plugins opendir");
2201 p = strstr(ent->d_name, ".so");
2205 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2206 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2208 fprintf(stderr, "%s\n", dlerror());
2212 // now what do we have here?
2213 tmp = dlsym(h, "GPUinit");
2216 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2217 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2221 tmp = dlsym(h, "SPUinit");
2224 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2225 spu_plugins[spu_i++] = strdup(ent->d_name);
2229 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2236 dir = opendir("." MEMCARD_DIR);
2238 perror("scan_bios_plugins memcards opendir");
2253 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2256 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2257 if (stat(fname, &st) != 0) {
2258 printf("bad memcard file: %s\n", ent->d_name);
2262 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2263 memcards[mc_i++] = strdup(ent->d_name);
2267 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2271 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2276 void menu_init(void)
2278 char buff[MAXPATHLEN];
2281 strcpy(last_selected_fname, "/media");
2283 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2285 scan_bios_plugins();
2288 menu_set_defconfig();
2289 menu_load_config(0);
2290 menu_do_last_cd_img(1);
2295 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2296 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2297 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2298 fprintf(stderr, "OOM\n");
2302 emu_make_path(buff, "skin/background.png", sizeof(buff));
2303 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2305 i = plat_target.cpu_clock_set != NULL
2306 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2307 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2309 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2310 e_menu_gfx_options[i].data = plat_target.vout_methods;
2311 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2312 plat_target.vout_methods != NULL);
2314 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2315 e_menu_gfx_options[i].data = plat_target.hwfilters;
2316 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2317 plat_target.hwfilters != NULL);
2319 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2320 plat_target.gamma_set != NULL);
2322 #ifndef __ARM_ARCH_7A__
2323 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2325 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2326 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2327 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2328 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2329 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2330 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2331 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2334 void menu_notify_mode_change(int w, int h, int bpp)
2338 last_vout_bpp = bpp;
2341 static void menu_leave_emu(void)
2343 if (GPU_close != NULL) {
2344 int ret = GPU_close();
2346 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2349 plat_video_menu_enter(ready_to_go);
2351 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2352 if (pl_vout_buf != NULL && ready_to_go) {
2353 int x = max(0, g_menuscreen_w - last_vout_w);
2354 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2355 int w = min(g_menuscreen_w, last_vout_w);
2356 int h = min(g_menuscreen_h, last_vout_h);
2357 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2358 char *s = pl_vout_buf;
2360 if (last_vout_bpp == 16) {
2361 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2362 menu_darken_bg(d, s, w, 0);
2365 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2366 rgb888_to_rgb565(d, s, w * 3);
2367 menu_darken_bg(d, d, w, 0);
2373 cpu_clock = plat_target_cpu_clock_get();
2376 void menu_prepare_emu(void)
2378 R3000Acpu *prev_cpu = psxCpu;
2380 plat_video_menu_leave();
2382 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2383 if (psxCpu != prev_cpu)
2384 // note that this does not really reset, just clears drc caches
2387 // core doesn't care about Config.Cdda changes,
2388 // so handle them manually here
2394 plat_target_cpu_clock_set(cpu_clock);
2396 // push config to GPU plugin
2397 plugin_call_rearmed_cbs();
2399 if (GPU_open != NULL) {
2400 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2402 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2408 void menu_update_msg(const char *msg)
2410 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2411 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2413 menu_error_time = plat_get_ticks_ms();
2414 lprintf("msg: %s\n", menu_error_msg);
2417 void menu_finish(void)
2419 if (cpu_clock_st > 0)
2420 plat_target_cpu_clock_set(cpu_clock_st);