2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2013
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.
17 #include <sys/types.h>
26 #include "plugin_lib.h"
29 #include "libpicofe/plat.h"
30 #include "libpicofe/input.h"
31 #include "libpicofe/linux/in_evdev.h"
32 #include "libpicofe/plat.h"
33 #include "../libpcsxcore/misc.h"
34 #include "../libpcsxcore/cdrom.h"
35 #include "../libpcsxcore/cdriso.h"
36 #include "../libpcsxcore/cheat.h"
37 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
38 #include "../plugins/dfinput/externals.h"
39 #include "../plugins/gpulib/cspace.h"
40 #include "psemu_plugin_defs.h"
43 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
45 #define array_size(x) (sizeof(x) / sizeof(x[0]))
56 MA_MAIN_SWAP_CD_MULTI,
87 static int last_vout_w, last_vout_h, last_vout_bpp;
88 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
89 static char last_selected_fname[MAXPATHLEN];
90 static int config_save_counter, region, in_type_sel1, in_type_sel2;
92 static int memcard1_sel, memcard2_sel;
93 int g_opts, g_scaler, g_gamma = 100;
94 int soft_scaling, analog_deadzone; // for Caanoo
97 #ifdef __ARM_ARCH_7A__
98 #define DEFAULT_PSX_CLOCK 57
99 #define DEFAULT_PSX_CLOCK_S "57"
101 #define DEFAULT_PSX_CLOCK 50
102 #define DEFAULT_PSX_CLOCK_S "50"
106 extern int iUseReverb;
107 extern int iUseInterpolation;
111 static const char *bioses[24];
112 static const char *gpu_plugins[16];
113 static const char *spu_plugins[16];
114 static const char *memcards[32];
115 static int bios_sel, gpu_plugsel, spu_plugsel;
117 #ifndef UI_FEATURES_H
118 #define MENU_BIOS_PATH "bios/"
119 #define MENU_SHOW_VARSCALER 0
120 #define MENU_SHOW_VOUTMODE 1
121 #define MENU_SHOW_SCALER2 0
122 #define MENU_SHOW_NUBS_BTNS 0
123 #define MENU_SHOW_VIBRATION 0
124 #define MENU_SHOW_DEADZONE 0
125 #define MENU_SHOW_MINIMIZE 0
126 #define MENU_SHOW_FULLSCREEN 1
127 #define MENU_SHOW_VOLUME 0
130 static int min(int x, int y) { return x < y ? x : y; }
131 static int max(int x, int y) { return x > y ? x : y; }
133 void emu_make_path(char *buff, const char *end, int size)
137 end_len = strlen(end);
138 pos = plat_get_root_dir(buff, size);
139 strncpy(buff + pos, end, size - pos);
141 if (pos + end_len > size - 1)
142 printf("Warning: path truncated: %s\n", buff);
145 static int emu_check_save_file(int slot, int *time)
147 char fname[MAXPATHLEN];
151 ret = emu_check_state(slot);
152 if (ret != 0 || time == NULL)
153 return ret == 0 ? 1 : 0;
155 ret = get_state_filename(fname, sizeof(fname), slot);
159 ret = stat(fname, &status);
163 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
164 return 1; // probably bad rtc like on some Caanoos
166 *time = status.st_mtime;
171 static int emu_save_load_game(int load, int unused)
176 ret = emu_load_state(state_slot);
178 // reflect hle/bios mode from savestate
181 else if (bios_sel == 0 && bioses[1] != NULL)
182 // XXX: maybe find the right bios instead
186 ret = emu_save_state(state_slot);
191 static void rm_namelist_entry(struct dirent **namelist,
192 int count, const char *name)
196 for (i = 1; i < count; i++) {
197 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
200 if (strcmp(name, namelist[i]->d_name) == 0) {
208 static int optional_cdimg_filter(struct dirent **namelist, int count,
212 char buf[256], buf2[256];
213 int i, d, ret, good_cue;
217 for (i = 1; i < count; i++) {
218 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
221 ext = strrchr(namelist[i]->d_name, '.');
223 // should not happen but whatever
230 // first find .cue files and remove files they reference
231 if (strcasecmp(ext, "cue") == 0)
233 snprintf(buf, sizeof(buf), "%s/%s", basedir,
234 namelist[i]->d_name);
244 while (fgets(buf, sizeof(buf), f)) {
245 ret = sscanf(buf, " FILE \"%256[^\"]\"", buf2);
247 ret = sscanf(buf, " FILE %256s", buf2);
251 p = strrchr(buf2, '/');
253 p = strrchr(buf2, '\\');
259 snprintf(buf, sizeof(buf), "%s/%s", basedir, p);
260 ret = stat64(buf, &statf);
262 rm_namelist_entry(namelist, count, p);
275 p = strcasestr(namelist[i]->d_name, "track");
277 ret = strtoul(p + 5, NULL, 10);
287 for (i = d = 1; i < count; i++)
288 if (namelist[i] != NULL)
289 namelist[d++] = namelist[i];
294 // propagate menu settings to the emu vars
295 static void menu_sync_config(void)
297 static int allow_abs_only_old;
302 Config.PsxType = region - 1;
304 cycle_multiplier = 10000 / psx_clock;
306 switch (in_type_sel1) {
307 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
308 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
309 default: in_type1 = PSE_PAD_TYPE_STANDARD;
311 switch (in_type_sel2) {
312 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
313 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
314 default: in_type2 = PSE_PAD_TYPE_STANDARD;
316 if (in_evdev_allow_abs_only != allow_abs_only_old) {
318 allow_abs_only_old = in_evdev_allow_abs_only;
321 iVolume = 768 + 128 * volume_boost;
322 pl_rearmed_cbs.frameskip = frameskip - 1;
323 pl_timing_prepare(Config.PsxType);
326 static void menu_set_defconfig(void)
328 emu_set_default_config();
331 g_scaler = SCALE_4_3;
335 analog_deadzone = 50;
338 plat_target.vout_fullscreen = 0;
339 psx_clock = DEFAULT_PSX_CLOCK;
342 in_type_sel1 = in_type_sel2 = 0;
343 in_evdev_allow_abs_only = 0;
348 #define CE_CONFIG_STR(val) \
349 { #val, 0, Config.val }
351 #define CE_CONFIG_VAL(val) \
352 { #val, sizeof(Config.val), &Config.val }
354 #define CE_STR(val) \
357 #define CE_INTVAL(val) \
358 { #val, sizeof(val), &val }
360 #define CE_INTVAL_N(name, val) \
361 { name, sizeof(val), &val }
363 #define CE_INTVAL_P(val) \
364 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
366 // 'versioned' var, used when defaults change
367 #define CE_CONFIG_STR_V(val, ver) \
368 { #val #ver, 0, Config.val }
370 #define CE_INTVAL_V(val, ver) \
371 { #val #ver, sizeof(val), &val }
373 #define CE_INTVAL_PV(val, ver) \
374 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
376 static const struct {
382 CE_CONFIG_STR_V(Gpu, 3),
384 // CE_CONFIG_STR(Cdr),
386 // CE_CONFIG_VAL(Sio),
389 CE_CONFIG_VAL(Debug),
390 CE_CONFIG_VAL(PsxOut),
391 CE_CONFIG_VAL(SpuIrq),
392 CE_CONFIG_VAL(RCntFix),
393 CE_CONFIG_VAL(VSyncWA),
396 CE_INTVAL_V(g_scaler, 2),
398 CE_INTVAL(g_layer_x),
399 CE_INTVAL(g_layer_y),
400 CE_INTVAL(g_layer_w),
401 CE_INTVAL(g_layer_h),
402 CE_INTVAL(soft_filter),
403 CE_INTVAL(plat_target.vout_method),
404 CE_INTVAL(plat_target.hwfilter),
405 CE_INTVAL(plat_target.vout_fullscreen),
406 CE_INTVAL(state_slot),
407 CE_INTVAL(cpu_clock),
409 CE_INTVAL(in_type_sel1),
410 CE_INTVAL(in_type_sel2),
411 CE_INTVAL(analog_deadzone),
412 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
413 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
414 CE_INTVAL_V(frameskip, 3),
415 CE_INTVAL_P(gpu_peops.iUseDither),
416 CE_INTVAL_P(gpu_peops.dwActFixes),
417 CE_INTVAL_P(gpu_unai.lineskip),
418 CE_INTVAL_P(gpu_unai.abe_hack),
419 CE_INTVAL_P(gpu_unai.no_light),
420 CE_INTVAL_P(gpu_unai.no_blend),
421 CE_INTVAL_P(gpu_neon.allow_interlace),
422 CE_INTVAL_P(gpu_neon.enhancement_enable),
423 CE_INTVAL_P(gpu_neon.enhancement_no_main),
424 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
425 CE_INTVAL_P(gpu_peopsgl.iFilterType),
426 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
427 CE_INTVAL_P(gpu_peopsgl.iUseMask),
428 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
429 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
430 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
431 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
432 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
433 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
434 CE_INTVAL_V(iUseReverb, 3),
435 CE_INTVAL_V(iXAPitch, 3),
436 CE_INTVAL_V(iUseInterpolation, 3),
437 CE_INTVAL(config_save_counter),
438 CE_INTVAL(in_evdev_allow_abs_only),
439 CE_INTVAL(volume_boost),
440 CE_INTVAL(psx_clock),
441 CE_INTVAL(new_dynarec_hacks),
442 CE_INTVAL(in_enable_vibration),
445 static char *get_cd_label(void)
447 static char trimlabel[33];
450 strncpy(trimlabel, CdromLabel, 32);
452 for (j = 31; j >= 0; j--)
453 if (trimlabel[j] == ' ')
459 static void make_cfg_fname(char *buf, size_t size, int is_game)
462 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
464 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
467 static void keys_write_all(FILE *f);
468 static char *mystrip(char *str);
470 static int menu_write_config(int is_game)
472 char cfgfile[MAXPATHLEN];
476 config_save_counter++;
478 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
479 f = fopen(cfgfile, "w");
481 printf("menu_write_config: failed to open: %s\n", cfgfile);
485 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
486 fprintf(f, "%s = ", config_data[i].name);
487 switch (config_data[i].len) {
489 fprintf(f, "%s\n", (char *)config_data[i].val);
492 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
495 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
498 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
501 printf("menu_write_config: unhandled len %d for %s\n",
502 (int)config_data[i].len, config_data[i].name);
513 static int menu_do_last_cd_img(int is_get)
515 static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
521 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
522 f = fopen(path, is_get ? "r" : "w");
529 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
530 last_selected_fname[ret] = 0;
531 mystrip(last_selected_fname);
534 fprintf(f, "%s\n", last_selected_fname);
539 for (i = 0; last_selected_fname[0] == 0
540 || stat64(last_selected_fname, &st) != 0; i++)
542 if (i >= ARRAY_SIZE(defaults))
544 strcpy(last_selected_fname, defaults[i]);
551 static void parse_str_val(char *cval, const char *src)
554 strncpy(cval, src, MAXPATHLEN);
555 cval[MAXPATHLEN - 1] = 0;
556 tmp = strchr(cval, '\n');
558 tmp = strchr(cval, '\r');
563 static void keys_load_all(const char *cfg);
565 static int menu_load_config(int is_game)
567 char cfgfile[MAXPATHLEN];
573 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
574 f = fopen(cfgfile, "r");
576 printf("menu_load_config: failed to open: %s\n", cfgfile);
580 fseek(f, 0, SEEK_END);
583 printf("bad size %ld: %s\n", size, cfgfile);
587 cfg = malloc(size + 1);
591 fseek(f, 0, SEEK_SET);
592 if (fread(cfg, 1, size, f) != size) {
593 printf("failed to read: %s\n", cfgfile);
598 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
602 tmp = strstr(cfg, config_data[i].name);
605 tmp += strlen(config_data[i].name);
606 if (strncmp(tmp, " = ", 3) != 0)
610 if (config_data[i].len == 0) {
611 parse_str_val(config_data[i].val, tmp);
616 val = strtoul(tmp, &tmp2, 16);
617 if (tmp2 == NULL || tmp == tmp2)
618 continue; // parse failed
620 switch (config_data[i].len) {
622 *(u8 *)config_data[i].val = val;
625 *(u16 *)config_data[i].val = val;
628 *(u32 *)config_data[i].val = val;
631 printf("menu_load_config: unhandled len %d for %s\n",
632 (int)config_data[i].len, config_data[i].name);
638 char *tmp = strstr(cfg, "lastcdimg = ");
641 parse_str_val(last_selected_fname, tmp);
656 for (i = bios_sel = 0; bioses[i] != NULL; i++)
657 if (strcmp(Config.Bios, bioses[i]) == 0)
658 { bios_sel = i; break; }
660 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
661 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
662 { gpu_plugsel = i; break; }
664 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
665 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
666 { spu_plugsel = i; break; }
671 static const char *filter_exts[] = {
672 "bin", "img", "mdf", "iso", "cue", "z",
673 "bz", "znx", "pbp", "cbn", NULL
676 // rrrr rggg gggb bbbb
677 static unsigned short fname2color(const char *fname)
679 static const char *other_exts[] = {
680 "ccd", "toc", "mds", "sub", "table", "index", "sbi"
682 const char *ext = strrchr(fname, '.');
688 for (i = 0; filter_exts[i] != NULL; i++)
689 if (strcasecmp(ext, filter_exts[i]) == 0)
691 for (i = 0; i < array_size(other_exts); i++)
692 if (strcasecmp(ext, other_exts[i]) == 0)
697 static void draw_savestate_bg(int slot);
699 #define MENU_ALIGN_LEFT
700 #ifdef __ARM_ARCH_7A__ // assume hires device
706 #include "libpicofe/menu.c"
708 // a bit of black magic here
709 static void draw_savestate_bg(int slot)
711 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
713 char fname[MAXPATHLEN];
720 ret = get_state_filename(fname, sizeof(fname), slot);
724 f = gzopen(fname, "rb");
728 if ((ret = (int)gzseek(f, 0x29933d, SEEK_SET)) != 0x29933d) {
729 fprintf(stderr, "gzseek failed: %d\n", ret);
734 gpu = malloc(sizeof(*gpu));
740 ret = gzread(f, gpu, sizeof(*gpu));
742 if (ret != sizeof(*gpu)) {
743 fprintf(stderr, "gzread failed\n");
747 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
749 if (gpu->ulStatus & 0x800000)
750 goto out; // disabled
752 x = gpu->ulControl[5] & 0x3ff;
753 y = (gpu->ulControl[5] >> 10) & 0x1ff;
754 w = psx_widths[(gpu->ulStatus >> 16) & 7];
755 tmp = gpu->ulControl[7];
756 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
757 if (gpu->ulStatus & 0x80000) // doubleheight
759 if (h <= 0 || h > 512)
765 s = (u16 *)gpu->psxVRam + y * 1024 + x;
767 x = max(0, g_menuscreen_w - w) & ~3;
768 y = max(0, g_menuscreen_h / 2 - h / 2);
769 w = min(g_menuscreen_w, w);
770 h = min(g_menuscreen_h, h);
771 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
773 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
774 if (gpu->ulStatus & 0x200000)
775 bgr888_to_rgb565(d, s, w * 3);
777 bgr555_to_rgb565(d, s, w * 2);
779 // darken this so that menu text is visible
780 if (g_menuscreen_w - w < 320)
781 menu_darken_bg(d, d, w * 2, 0);
788 // -------------- key config --------------
790 me_bind_action me_ctrl_actions[] =
792 { "UP ", 1 << DKEY_UP},
793 { "DOWN ", 1 << DKEY_DOWN },
794 { "LEFT ", 1 << DKEY_LEFT },
795 { "RIGHT ", 1 << DKEY_RIGHT },
796 { "TRIANGLE", 1 << DKEY_TRIANGLE },
797 { "CIRCLE ", 1 << DKEY_CIRCLE },
798 { "CROSS ", 1 << DKEY_CROSS },
799 { "SQUARE ", 1 << DKEY_SQUARE },
800 { "L1 ", 1 << DKEY_L1 },
801 { "R1 ", 1 << DKEY_R1 },
802 { "L2 ", 1 << DKEY_L2 },
803 { "R2 ", 1 << DKEY_R2 },
804 { "L3 ", 1 << DKEY_L3 },
805 { "R3 ", 1 << DKEY_R3 },
806 { "START ", 1 << DKEY_START },
807 { "SELECT ", 1 << DKEY_SELECT },
811 me_bind_action emuctrl_actions[] =
813 { "Save State ", 1 << SACTION_SAVE_STATE },
814 { "Load State ", 1 << SACTION_LOAD_STATE },
815 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
816 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
817 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
818 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
819 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
820 #ifdef __ARM_ARCH_7A__
821 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
823 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
824 #if MENU_SHOW_MINIMIZE
825 { "Minimize ", 1 << SACTION_MINIMIZE },
827 #if MENU_SHOW_FULLSCREEN
828 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
830 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
831 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
832 { "Gun A button ", 1 << SACTION_GUN_A },
833 { "Gun B button ", 1 << SACTION_GUN_B },
834 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
836 { "Volume Up ", 1 << SACTION_VOLUME_UP },
837 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
842 static char *mystrip(char *str)
847 for (i = 0; i < len; i++)
848 if (str[i] != ' ') break;
849 if (i > 0) memmove(str, str + i, len - i + 1);
852 for (i = len - 1; i >= 0; i--)
853 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
859 static void get_line(char *d, size_t size, const char *s)
864 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
875 static void keys_write_all(FILE *f)
879 for (d = 0; d < IN_MAX_DEVS; d++)
881 const int *binds = in_get_dev_binds(d);
882 const char *name = in_get_dev_name(d, 0, 0);
885 if (binds == NULL || name == NULL)
888 fprintf(f, "binddev = %s\n", name);
889 in_get_config(d, IN_CFG_BIND_COUNT, &count);
891 for (k = 0; k < count; k++)
896 act[0] = act[31] = 0;
897 name = in_get_key_name(d, k);
899 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
900 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
901 mask = me_ctrl_actions[i].mask;
903 strncpy(act, me_ctrl_actions[i].name, 31);
904 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
907 mask = me_ctrl_actions[i].mask << 16;
909 strncpy(act, me_ctrl_actions[i].name, 31);
910 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
915 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
916 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
917 mask = emuctrl_actions[i].mask;
919 strncpy(act, emuctrl_actions[i].name, 31);
920 fprintf(f, "bind %s = %s\n", name, mystrip(act));
926 for (k = 0; k < array_size(in_adev); k++)
929 fprintf(f, "bind_analog = %d\n", k);
934 static int parse_bind_val(const char *val, int *type)
938 *type = IN_BINDTYPE_NONE;
942 if (strncasecmp(val, "player", 6) == 0)
944 int player, shift = 0;
945 player = atoi(val + 6) - 1;
947 if ((unsigned int)player > 1)
952 *type = IN_BINDTYPE_PLAYER12;
953 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
954 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
955 return me_ctrl_actions[i].mask << shift;
958 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
959 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
960 *type = IN_BINDTYPE_EMU;
961 return emuctrl_actions[i].mask;
968 static void keys_load_all(const char *cfg)
970 char dev[256], key[128], *act;
976 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
979 get_line(dev, sizeof(dev), p);
980 dev_id = in_config_parse_dev(dev);
982 printf("input: can't handle dev: %s\n", dev);
986 in_unbind_all(dev_id, -1, -1);
987 while ((p = strstr(p, "bind"))) {
988 if (strncmp(p, "binddev = ", 10) == 0)
991 if (strncmp(p, "bind_analog", 11) == 0) {
992 ret = sscanf(p, "bind_analog = %d", &bind);
995 printf("input: parse error: %16s..\n", p);
998 if ((unsigned int)bind >= array_size(in_adev)) {
999 printf("input: analog id %d out of range\n", bind);
1002 in_adev[bind] = dev_id;
1008 printf("input: parse error: %16s..\n", p);
1012 get_line(key, sizeof(key), p);
1013 act = strchr(key, '=');
1015 printf("parse failed: %16s..\n", p);
1023 bind = parse_bind_val(act, &bindtype);
1024 if (bind != -1 && bind != 0) {
1025 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
1026 in_config_bind_key(dev_id, key, bind, bindtype);
1029 lprintf("config: unhandled action \"%s\"\n", act);
1035 static int key_config_loop_wrap(int id, int keys)
1038 case MA_CTRL_PLAYER1:
1039 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
1041 case MA_CTRL_PLAYER2:
1042 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
1045 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
1053 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
1054 "Might cause problems with real analog sticks";
1055 static const char *adevnames[IN_MAX_DEVS + 2];
1056 static int stick_sel[2];
1058 static menu_entry e_menu_keyconfig_analog[] =
1060 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
1061 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
1062 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
1063 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
1064 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
1065 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
1066 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
1067 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
1071 static int key_config_analog(int id, int keys)
1073 int i, d, count, sel = 0;
1074 int sel2dev_map[IN_MAX_DEVS];
1076 memset(adevnames, 0, sizeof(adevnames));
1077 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1078 memset(stick_sel, 0, sizeof(stick_sel));
1080 adevnames[0] = "None";
1082 for (d = 0; d < IN_MAX_DEVS; d++)
1084 const char *name = in_get_dev_name(d, 0, 1);
1089 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1093 if (in_adev[0] == d) stick_sel[0] = i;
1094 if (in_adev[1] == d) stick_sel[1] = i;
1096 adevnames[i++] = name;
1098 adevnames[i] = NULL;
1100 me_loop(e_menu_keyconfig_analog, &sel);
1102 in_adev[0] = sel2dev_map[stick_sel[0]];
1103 in_adev[1] = sel2dev_map[stick_sel[1]];
1108 static const char *mgn_dev_name(int id, int *offs)
1110 const char *name = NULL;
1113 if (id == MA_CTRL_DEV_FIRST)
1116 for (; it < IN_MAX_DEVS; it++) {
1117 name = in_get_dev_name(it, 1, 1);
1126 static const char *mgn_saveloadcfg(int id, int *offs)
1131 static int mh_savecfg(int id, int keys)
1133 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1134 menu_update_msg("config saved");
1136 menu_update_msg("failed to write config");
1141 static int mh_input_rescan(int id, int keys)
1143 //menu_sync_config();
1145 menu_update_msg("rescan complete.");
1150 static const char *men_in_type_sel[] = {
1151 "Standard (SCPH-1080)",
1152 "Analog (SCPH-1150)",
1156 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1157 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1158 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1160 static menu_entry e_menu_keyconfig[] =
1162 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1163 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1164 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1165 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1167 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1168 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1169 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1170 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1171 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1172 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1173 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1174 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1175 mee_handler ("Rescan devices:", mh_input_rescan),
1177 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1178 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1179 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1180 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1181 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1182 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1183 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1187 static int menu_loop_keyconfig(int id, int keys)
1191 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1192 me_loop(e_menu_keyconfig, &sel);
1196 // ------------ gfx options menu ------------
1198 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1199 static const char *men_soft_filter[] = { "None",
1201 "scale2x", "eagle2x",
1204 static const char *men_dummy[] = { NULL };
1205 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1206 "using d-pad or move it using R+d-pad";
1207 static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
1208 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1209 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1211 static int menu_loop_cscaler(int id, int keys)
1215 g_scaler = SCALE_CUSTOM;
1217 plat_gvideo_open(Config.PsxType);
1221 menu_draw_begin(0, 1);
1222 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1223 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1224 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1227 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1228 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1229 if (inp & PBTN_UP) g_layer_y--;
1230 if (inp & PBTN_DOWN) g_layer_y++;
1231 if (inp & PBTN_LEFT) g_layer_x--;
1232 if (inp & PBTN_RIGHT) g_layer_x++;
1233 if (!(inp & PBTN_R)) {
1234 if (inp & PBTN_UP) g_layer_h += 2;
1235 if (inp & PBTN_DOWN) g_layer_h -= 2;
1236 if (inp & PBTN_LEFT) g_layer_w += 2;
1237 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1239 if (inp & (PBTN_MOK|PBTN_MBACK))
1242 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1243 if (g_layer_x < 0) g_layer_x = 0;
1244 if (g_layer_x > 640) g_layer_x = 640;
1245 if (g_layer_y < 0) g_layer_y = 0;
1246 if (g_layer_y > 420) g_layer_y = 420;
1247 if (g_layer_w < 160) g_layer_w = 160;
1248 if (g_layer_h < 60) g_layer_h = 60;
1249 if (g_layer_x + g_layer_w > 800)
1250 g_layer_w = 800 - g_layer_x;
1251 if (g_layer_y + g_layer_h > 480)
1252 g_layer_h = 480 - g_layer_y;
1254 plat_gvideo_open(Config.PsxType);
1258 plat_gvideo_close();
1263 static menu_entry e_menu_gfx_options[] =
1265 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1266 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1267 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1268 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1269 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1270 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1271 // mee_onoff ("Vsync", 0, vsync, 1),
1272 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1276 static int menu_loop_gfx_options(int id, int keys)
1280 me_loop(e_menu_gfx_options, &sel);
1285 // ------------ bios/plugins ------------
1289 static const char h_gpu_neon[] =
1290 "Configure built-in NEON GPU plugin";
1291 static const char h_gpu_neon_enhanced[] =
1292 "Renders in double resolution at the cost of lower performance\n"
1293 "(not available for high resolution games)";
1294 static const char h_gpu_neon_enhanced_hack[] =
1295 "Speed hack for above option (glitches some games)";
1296 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1298 static menu_entry e_menu_plugin_gpu_neon[] =
1300 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1301 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1302 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1306 static int menu_loop_plugin_gpu_neon(int id, int keys)
1309 me_loop(e_menu_plugin_gpu_neon, &sel);
1315 static menu_entry e_menu_plugin_gpu_unai[] =
1317 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1318 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1319 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1320 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1324 static int menu_loop_plugin_gpu_unai(int id, int keys)
1327 me_loop(e_menu_plugin_gpu_unai, &sel);
1331 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1332 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1333 static const char h_gpu_1[] = "Capcom fighting games";
1334 static const char h_gpu_2[] = "Black screens in Lunar";
1335 static const char h_gpu_3[] = "Compatibility mode";
1336 static const char h_gpu_6[] = "Pandemonium 2";
1337 //static const char h_gpu_7[] = "Skip every second frame";
1338 static const char h_gpu_8[] = "Needed by Dark Forces";
1339 static const char h_gpu_9[] = "better g-colors, worse textures";
1340 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1342 static menu_entry e_menu_plugin_gpu_peops[] =
1344 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1345 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1346 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1347 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1348 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1349 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1350 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1351 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1352 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1353 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1357 static int menu_loop_plugin_gpu_peops(int id, int keys)
1360 me_loop(e_menu_plugin_gpu_peops, &sel);
1364 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1365 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1366 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1368 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1370 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1371 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1372 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1373 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1374 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1375 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1376 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1377 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1378 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1379 mee_label ("Fixes/hacks:"),
1380 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1381 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1382 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1383 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1384 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1385 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1386 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1387 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1388 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1389 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1390 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1394 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1397 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1401 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1402 static const char h_spu_volboost[] = "Large values cause distortion";
1404 static menu_entry e_menu_plugin_spu[] =
1406 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1407 mee_onoff ("Reverb", 0, iUseReverb, 2),
1408 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1409 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1413 static int menu_loop_plugin_spu(int id, int keys)
1416 me_loop(e_menu_plugin_spu, &sel);
1420 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1421 "savestates and can't be changed there. Must save\n"
1422 "config and reload the game for change to take effect";
1423 static const char h_plugin_gpu[] =
1425 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1427 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1428 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1429 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1430 "must save config and reload the game if changed";
1431 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1432 "must save config and reload the game if changed";
1433 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1434 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1435 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1436 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1438 static menu_entry e_menu_plugin_options[] =
1440 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1441 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1442 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1444 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1446 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1447 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1448 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1449 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1453 static menu_entry e_menu_main2[];
1455 static int menu_loop_plugin_options(int id, int keys)
1458 me_loop(e_menu_plugin_options, &sel);
1460 // sync BIOS/plugins
1461 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1462 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1463 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1464 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1469 // ------------ adv options menu ------------
1471 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1472 "(lower value - less work for the emu, may be faster)";
1473 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1474 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1475 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1477 static menu_entry e_menu_speed_hacks[] =
1479 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1480 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1481 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1482 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1486 static int menu_loop_speed_hacks(int id, int keys)
1489 me_loop(e_menu_speed_hacks, &sel);
1493 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1494 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1495 "(green: normal, red: fmod, blue: noise)";
1496 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1497 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1498 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1499 "(proper .cue/.bin dump is needed otherwise)";
1500 static const char h_cfg_sio[] = "You should not need this, breaks games";
1501 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1502 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1503 "(timing hack, breaks other games)";
1504 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1505 "(timing hack, breaks other games)";
1506 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1507 "Might be useful to overcome some dynarec bugs";
1508 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1509 "must reload game for any change to take effect";
1511 static menu_entry e_menu_adv_options[] =
1513 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1514 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1515 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1516 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1517 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1518 //mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1519 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1520 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1521 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1522 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1523 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1527 static int menu_loop_adv_options(int id, int keys)
1530 me_loop(e_menu_adv_options, &sel);
1534 // ------------ options menu ------------
1536 static int mh_restore_defaults(int id, int keys)
1538 menu_set_defconfig();
1539 menu_update_msg("defaults restored");
1543 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1544 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1546 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1547 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1548 "loading state or both";
1550 static const char h_restore_def[] = "Switches back to default / recommended\n"
1552 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1554 static menu_entry e_menu_options[] =
1556 // mee_range ("Save slot", 0, state_slot, 0, 9),
1557 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1558 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1559 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1560 mee_enum ("Region", 0, region, men_region),
1561 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1562 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1563 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1564 mee_handler ("[Advanced]", menu_loop_adv_options),
1565 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1566 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1567 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1571 static int menu_loop_options(int id, int keys)
1576 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1577 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1578 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1580 me_loop(e_menu_options, &sel);
1585 // ------------ debug menu ------------
1587 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1589 int w = min(g_menuscreen_w, 1024);
1590 int h = min(g_menuscreen_h, 512);
1591 u16 *d = g_menuscreen_ptr;
1592 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1596 gpuf->ulFreezeVersion = 1;
1597 if (GPU_freeze != NULL)
1598 GPU_freeze(1, gpuf);
1600 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1601 bgr555_to_rgb565(d, s, w * 2);
1603 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1604 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1605 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1606 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1607 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1610 static void debug_menu_loop(void)
1612 int inp, df_x = 0, df_y = 0;
1615 gpuf = malloc(sizeof(*gpuf));
1621 menu_draw_begin(0, 1);
1622 draw_frame_debug(gpuf, df_x, df_y);
1625 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1626 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1627 if (inp & PBTN_MBACK) break;
1628 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1629 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1630 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1631 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1637 // --------- memcard manager ---------
1639 static void draw_mc_icon(int dx, int dy, const u16 *s)
1644 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1646 for (y = 0; y < 16; y++, s += 16) {
1647 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1648 for (x = 0; x < 16; x++) {
1650 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1651 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1657 static void draw_mc_bg(void)
1659 McdBlock *blocks1, *blocks2;
1663 blocks1 = malloc(15 * sizeof(blocks1[0]));
1664 blocks2 = malloc(15 * sizeof(blocks1[0]));
1665 if (blocks1 == NULL || blocks2 == NULL)
1668 for (i = 0; i < 15; i++) {
1669 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1670 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1673 menu_draw_begin(1, 1);
1675 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1677 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1681 maxicons = g_menuscreen_h / 32;
1684 row2 = g_menuscreen_w / 2;
1685 for (i = 0; i < maxicons; i++) {
1686 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1687 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1689 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1690 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1693 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1701 static void handle_memcard_sel(void)
1703 strcpy(Config.Mcd1, "none");
1704 if (memcard1_sel != 0)
1705 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1706 strcpy(Config.Mcd2, "none");
1707 if (memcard2_sel != 0)
1708 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1709 LoadMcds(Config.Mcd1, Config.Mcd2);
1713 static menu_entry e_memcard_options[] =
1715 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1716 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1720 static int menu_loop_memcards(int id, int keys)
1726 memcard1_sel = memcard2_sel = 0;
1727 p = strrchr(Config.Mcd1, '/');
1729 for (i = 0; memcards[i] != NULL; i++)
1730 if (strcmp(p + 1, memcards[i]) == 0)
1731 { memcard1_sel = i; break; }
1732 p = strrchr(Config.Mcd2, '/');
1734 for (i = 0; memcards[i] != NULL; i++)
1735 if (strcmp(p + 1, memcards[i]) == 0)
1736 { memcard2_sel = i; break; }
1738 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1740 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1745 // ------------ cheats menu ------------
1747 static void draw_cheatlist(int sel)
1749 int max_cnt, start, i, pos, active;
1751 max_cnt = g_menuscreen_h / me_sfont_h;
1752 start = max_cnt / 2 - sel;
1754 menu_draw_begin(1, 1);
1756 for (i = 0; i < NumCheats; i++) {
1758 if (pos < 0) continue;
1759 if (pos >= max_cnt) break;
1760 active = Cheats[i].Enabled;
1761 smalltext_out16(14, pos * me_sfont_h,
1762 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1763 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1764 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1768 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1770 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1774 static void menu_loop_cheats(void)
1776 static int menu_sel = 0;
1781 draw_cheatlist(menu_sel);
1782 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1783 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1784 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1785 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1786 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1787 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1788 if (inp & PBTN_MOK) { // action
1789 if (menu_sel < NumCheats)
1790 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1793 if (inp & PBTN_MBACK)
1798 // --------- main menu help ----------
1800 static void menu_bios_warn(void)
1803 static const char msg[] =
1804 "You don't seem to have copied any BIOS\n"
1806 MENU_BIOS_PATH "\n\n"
1808 "While many games work fine with fake\n"
1809 "(HLE) BIOS, others (like MGS and FF8)\n"
1810 "require BIOS to work.\n"
1811 "After copying the file, you'll also need\n"
1812 "to select it in the emu's menu:\n"
1813 "options->[BIOS/Plugins]\n\n"
1814 "The file is usually named SCPH1001.BIN,\n"
1815 "but other not compressed files can be\n"
1817 "Press %s or %s to continue";
1818 char tmp_msg[sizeof(msg) + 64];
1820 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1821 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1824 draw_menu_message(tmp_msg, NULL);
1826 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1827 if (inp & (PBTN_MBACK|PBTN_MOK))
1832 // ------------ main menu ------------
1834 static menu_entry e_menu_main[];
1836 static void draw_frame_main(void)
1845 if (CdromId[0] != 0) {
1846 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1847 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1848 Config.HLE ? "HLE" : "BIOS");
1849 smalltext_out16(4, 1, buff, 0x105f);
1853 capacity = plat_target_bat_capacity_get();
1855 tmp = localtime(<ime);
1856 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1857 if (capacity >= 0) {
1858 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1863 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1867 static void draw_frame_credits(void)
1869 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1872 static const char credits_text[] =
1874 "(C) 1999-2003 PCSX Team\n"
1875 "(C) 2005-2009 PCSX-df Team\n"
1876 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1877 "ARM recompiler (C) 2009-2011 Ari64\n"
1879 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1881 "PEOpS GPU and SPU by Pete Bernert\n"
1882 " and the P.E.Op.S. team\n"
1883 "PCSX4ALL plugin by PCSX4ALL team\n"
1884 " Chui, Franxis, Unai\n\n"
1885 "integration, optimization and\n"
1886 " frontend (C) 2010-2012 notaz\n";
1888 static int reset_game(void)
1891 if (bios_sel == 0 && !Config.HLE)
1897 if (CheckCdrom() != -1) {
1903 static int reload_plugins(const char *cdimg)
1909 set_cd_image(cdimg);
1911 pcnt_hook_plugins();
1913 if (OpenPlugins() == -1) {
1914 menu_update_msg("failed to open plugins");
1917 plugin_call_rearmed_cbs();
1919 cdrIsoMultidiskCount = 1;
1921 CdromLabel[0] = '\0';
1926 static int run_bios(void)
1932 if (reload_plugins(NULL) != 0)
1940 static int run_exe(void)
1942 const char *exts[] = { "exe", NULL };
1945 fname = menu_loop_romsel(last_selected_fname,
1946 sizeof(last_selected_fname), exts, NULL);
1951 if (reload_plugins(NULL) != 0)
1955 if (Load(fname) != 0) {
1956 menu_update_msg("exe load failed, bad file?");
1965 static int run_cd_image(const char *fname)
1968 reload_plugins(fname);
1970 // always autodetect, menu_sync_config will override as needed
1973 if (CheckCdrom() == -1) {
1974 // Only check the CD if we are starting the console with a CD
1976 menu_update_msg("unsupported/invalid CD image");
1982 // Read main executable directly from CDRom and start it
1983 if (LoadCdrom() == -1) {
1985 menu_update_msg("failed to load CD image");
1995 static int romsel_run(void)
1997 int prev_gpu, prev_spu;
2000 fname = menu_loop_romsel(last_selected_fname,
2001 sizeof(last_selected_fname), filter_exts,
2002 optional_cdimg_filter);
2006 printf("selected file: %s\n", fname);
2008 new_dynarec_clear_full();
2010 if (run_cd_image(fname) != 0)
2013 prev_gpu = gpu_plugsel;
2014 prev_spu = spu_plugsel;
2015 if (menu_load_config(1) != 0)
2016 menu_load_config(0);
2018 // check for plugin changes, have to repeat
2019 // loading if game config changed plugins to reload them
2020 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
2021 printf("plugin change detected, reloading plugins..\n");
2022 if (run_cd_image(fname) != 0)
2026 strcpy(last_selected_fname, fname);
2027 menu_do_last_cd_img(0);
2031 static int swap_cd_image(void)
2035 fname = menu_loop_romsel(last_selected_fname,
2036 sizeof(last_selected_fname), filter_exts,
2037 optional_cdimg_filter);
2041 printf("selected file: %s\n", fname);
2044 CdromLabel[0] = '\0';
2046 set_cd_image(fname);
2047 if (ReloadCdromPlugin() < 0) {
2048 menu_update_msg("failed to load cdr plugin");
2051 if (CDR_open() < 0) {
2052 menu_update_msg("failed to open cdr plugin");
2056 SetCdOpenCaseTime(time(NULL) + 2);
2059 strcpy(last_selected_fname, fname);
2063 static int swap_cd_multidisk(void)
2065 cdrIsoMultidiskSelect++;
2067 CdromLabel[0] = '\0';
2070 if (CDR_open() < 0) {
2071 menu_update_msg("failed to open cdr plugin");
2075 SetCdOpenCaseTime(time(NULL) + 2);
2081 static void load_pcsx_cht(void)
2083 const char *exts[] = { "cht", NULL };
2088 fname = menu_loop_romsel(path, sizeof(path), exts, NULL);
2092 printf("selected cheat file: %s\n", fname);
2095 if (NumCheats == 0 && NumCodes == 0)
2096 menu_update_msg("failed to load cheats");
2098 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
2099 menu_update_msg(path);
2101 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2104 static int main_menu_handler(int id, int keys)
2108 case MA_MAIN_RESUME_GAME:
2112 case MA_MAIN_SAVE_STATE:
2114 return menu_loop_savestate(0);
2116 case MA_MAIN_LOAD_STATE:
2118 return menu_loop_savestate(1);
2120 case MA_MAIN_RESET_GAME:
2121 if (ready_to_go && reset_game() == 0)
2124 case MA_MAIN_LOAD_ROM:
2125 if (romsel_run() == 0)
2128 case MA_MAIN_SWAP_CD:
2129 if (swap_cd_image() == 0)
2132 case MA_MAIN_SWAP_CD_MULTI:
2133 if (swap_cd_multidisk() == 0)
2136 case MA_MAIN_RUN_BIOS:
2137 if (run_bios() == 0)
2140 case MA_MAIN_RUN_EXE:
2144 case MA_MAIN_CHEATS:
2147 case MA_MAIN_LOAD_CHEATS:
2150 case MA_MAIN_CREDITS:
2151 draw_menu_message(credits_text, draw_frame_credits);
2152 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2155 emu_core_ask_exit();
2158 lprintf("%s: something unknown selected\n", __FUNCTION__);
2165 static menu_entry e_menu_main2[] =
2167 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2168 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2169 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2170 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2171 mee_handler ("Memcard manager", menu_loop_memcards),
2172 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2176 static int main_menu2_handler(int id, int keys)
2180 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2181 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2182 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2183 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2185 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2188 static const char h_extra[] = "Change CD, manage memcards..\n";
2190 static menu_entry e_menu_main[] =
2194 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2195 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2196 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2197 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2198 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2199 mee_handler ("Options", menu_loop_options),
2200 mee_handler ("Controls", menu_loop_keyconfig),
2201 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2202 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2203 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2204 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2208 // ----------------------------
2210 static void menu_leave_emu(void);
2212 void menu_loop(void)
2214 static int warned_about_bios = 0;
2219 if (config_save_counter == 0) {
2221 if (bioses[1] != NULL) {
2222 // autoselect BIOS to make user's life easier
2223 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2226 else if (!warned_about_bios) {
2228 warned_about_bios = 1;
2232 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2233 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2234 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2235 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2236 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2238 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2241 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2242 } while (!ready_to_go && !g_emu_want_quit);
2244 /* wait until menu, ok, back is released */
2245 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2248 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2253 static int qsort_strcmp(const void *p1, const void *p2)
2255 char * const *s1 = (char * const *)p1;
2256 char * const *s2 = (char * const *)p2;
2257 return strcasecmp(*s1, *s2);
2260 static void scan_bios_plugins(void)
2262 char fname[MAXPATHLEN];
2264 int bios_i, gpu_i, spu_i, mc_i;
2269 gpu_plugins[0] = "builtin_gpu";
2270 spu_plugins[0] = "builtin_spu";
2271 memcards[0] = "(none)";
2272 bios_i = gpu_i = spu_i = mc_i = 1;
2274 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2275 dir = opendir(fname);
2277 perror("scan_bios_plugins bios opendir");
2292 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2295 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2296 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2297 printf("bad BIOS file: %s\n", ent->d_name);
2301 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2302 bioses[bios_i++] = strdup(ent->d_name);
2306 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2312 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2313 dir = opendir(fname);
2315 perror("scan_bios_plugins plugins opendir");
2329 p = strstr(ent->d_name, ".so");
2333 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2334 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2336 fprintf(stderr, "%s\n", dlerror());
2340 // now what do we have here?
2341 tmp = dlsym(h, "GPUinit");
2344 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2345 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2349 tmp = dlsym(h, "SPUinit");
2352 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2353 spu_plugins[spu_i++] = strdup(ent->d_name);
2357 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2364 dir = opendir("." MEMCARD_DIR);
2366 perror("scan_bios_plugins memcards opendir");
2381 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2384 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2385 if (stat(fname, &st) != 0) {
2386 printf("bad memcard file: %s\n", ent->d_name);
2390 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2391 memcards[mc_i++] = strdup(ent->d_name);
2395 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2399 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2404 void menu_init(void)
2406 char buff[MAXPATHLEN];
2409 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2411 scan_bios_plugins();
2414 menu_set_defconfig();
2415 menu_load_config(0);
2416 menu_do_last_cd_img(1);
2421 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2422 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2423 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2424 fprintf(stderr, "OOM\n");
2428 emu_make_path(buff, "skin/background.png", sizeof(buff));
2429 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2431 i = plat_target.cpu_clock_set != NULL
2432 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2433 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2435 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2436 e_menu_gfx_options[i].data = plat_target.vout_methods;
2437 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2438 plat_target.vout_methods != NULL);
2440 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2441 e_menu_gfx_options[i].data = plat_target.hwfilters;
2442 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2443 plat_target.hwfilters != NULL);
2445 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2446 plat_target.gamma_set != NULL);
2448 #ifndef __ARM_ARCH_7A__
2449 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2451 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2452 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2453 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2454 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2455 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2456 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2457 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2460 void menu_notify_mode_change(int w, int h, int bpp)
2464 last_vout_bpp = bpp;
2467 static void menu_leave_emu(void)
2469 if (GPU_close != NULL) {
2470 int ret = GPU_close();
2472 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2475 plat_video_menu_enter(ready_to_go);
2477 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2478 if (pl_vout_buf != NULL && ready_to_go) {
2479 int x = max(0, g_menuscreen_w - last_vout_w);
2480 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2481 int w = min(g_menuscreen_w, last_vout_w);
2482 int h = min(g_menuscreen_h, last_vout_h);
2483 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2484 char *s = pl_vout_buf;
2486 if (last_vout_bpp == 16) {
2487 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2488 menu_darken_bg(d, s, w, 0);
2491 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2492 rgb888_to_rgb565(d, s, w * 3);
2493 menu_darken_bg(d, d, w, 0);
2499 cpu_clock = plat_target_cpu_clock_get();
2502 void menu_prepare_emu(void)
2504 R3000Acpu *prev_cpu = psxCpu;
2506 plat_video_menu_leave();
2508 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2509 if (psxCpu != prev_cpu) {
2510 prev_cpu->Shutdown();
2512 // note that this does not really reset, just clears drc caches
2516 // core doesn't care about Config.Cdda changes,
2517 // so handle them manually here
2523 plat_target_cpu_clock_set(cpu_clock);
2525 // push config to GPU plugin
2526 plugin_call_rearmed_cbs();
2528 if (GPU_open != NULL) {
2529 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2531 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2537 void menu_update_msg(const char *msg)
2539 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2540 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2542 menu_error_time = plat_get_ticks_ms();
2543 lprintf("msg: %s\n", menu_error_msg);
2546 void menu_finish(void)
2548 if (cpu_clock_st > 0)
2549 plat_target_cpu_clock_set(cpu_clock_st);