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"
30 #include "libpicofe/plat.h"
31 #include "libpicofe/input.h"
32 #include "libpicofe/linux/in_evdev.h"
33 #include "libpicofe/plat.h"
34 #include "../libpcsxcore/misc.h"
35 #include "../libpcsxcore/cdrom.h"
36 #include "../libpcsxcore/cdriso.h"
37 #include "../libpcsxcore/cheat.h"
38 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
39 #include "../plugins/dfinput/externals.h"
40 #include "../plugins/dfsound/spu_config.h"
41 #include "psemu_plugin_defs.h"
44 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
46 #define array_size(x) (sizeof(x) / sizeof(x[0]))
57 MA_MAIN_SWAP_CD_MULTI,
88 static int last_vout_w, last_vout_h, last_vout_bpp;
89 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
90 static char last_selected_fname[MAXPATHLEN];
91 static int config_save_counter, region, in_type_sel1, in_type_sel2;
93 static int memcard1_sel, memcard2_sel;
94 int g_opts, g_scaler, g_gamma = 100;
95 int soft_scaling, analog_deadzone; // for Caanoo
98 #ifdef __ARM_ARCH_7A__
99 #define DEFAULT_PSX_CLOCK 57
100 #define DEFAULT_PSX_CLOCK_S "57"
102 #define DEFAULT_PSX_CLOCK 50
103 #define DEFAULT_PSX_CLOCK_S "50"
106 static const char *bioses[24];
107 static const char *gpu_plugins[16];
108 static const char *spu_plugins[16];
109 static const char *memcards[32];
110 static int bios_sel, gpu_plugsel, spu_plugsel;
112 #ifndef UI_FEATURES_H
113 #define MENU_BIOS_PATH "bios/"
114 #define MENU_SHOW_VARSCALER 0
115 #define MENU_SHOW_VOUTMODE 1
116 #define MENU_SHOW_SCALER2 0
117 #define MENU_SHOW_NUBS_BTNS 0
118 #define MENU_SHOW_VIBRATION 0
119 #define MENU_SHOW_DEADZONE 0
120 #define MENU_SHOW_MINIMIZE 0
121 #define MENU_SHOW_FULLSCREEN 1
122 #define MENU_SHOW_VOLUME 0
125 static int min(int x, int y) { return x < y ? x : y; }
126 static int max(int x, int y) { return x > y ? x : y; }
128 void emu_make_path(char *buff, const char *end, int size)
132 end_len = strlen(end);
133 pos = plat_get_root_dir(buff, size);
134 strncpy(buff + pos, end, size - pos);
136 if (pos + end_len > size - 1)
137 printf("Warning: path truncated: %s\n", buff);
140 static int emu_check_save_file(int slot, int *time)
142 char fname[MAXPATHLEN];
146 ret = emu_check_state(slot);
147 if (ret != 0 || time == NULL)
148 return ret == 0 ? 1 : 0;
150 ret = get_state_filename(fname, sizeof(fname), slot);
154 ret = stat(fname, &status);
158 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
159 return 1; // probably bad rtc like on some Caanoos
161 *time = status.st_mtime;
166 static int emu_save_load_game(int load, int unused)
171 ret = emu_load_state(state_slot);
173 // reflect hle/bios mode from savestate
176 else if (bios_sel == 0 && bioses[1] != NULL)
177 // XXX: maybe find the right bios instead
181 ret = emu_save_state(state_slot);
186 static void rm_namelist_entry(struct dirent **namelist,
187 int count, const char *name)
191 for (i = 1; i < count; i++) {
192 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
195 if (strcmp(name, namelist[i]->d_name) == 0) {
203 static int optional_cdimg_filter(struct dirent **namelist, int count,
207 char buf[256], buf2[256];
208 int i, d, ret, good_cue;
215 for (i = 1; i < count; i++) {
216 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
219 ext = strrchr(namelist[i]->d_name, '.');
221 // should not happen but whatever
228 // first find .cue files and remove files they reference
229 if (strcasecmp(ext, "cue") == 0)
231 snprintf(buf, sizeof(buf), "%s/%s", basedir,
232 namelist[i]->d_name);
242 while (fgets(buf, sizeof(buf), f)) {
243 ret = sscanf(buf, " FILE \"%256[^\"]\"", buf2);
245 ret = sscanf(buf, " FILE %256s", buf2);
249 p = strrchr(buf2, '/');
251 p = strrchr(buf2, '\\');
257 snprintf(buf, sizeof(buf), "%s/%s", basedir, p);
258 ret = stat64(buf, &statf);
260 rm_namelist_entry(namelist, count, p);
273 p = strcasestr(namelist[i]->d_name, "track");
275 ret = strtoul(p + 5, NULL, 10);
285 for (i = d = 1; i < count; i++)
286 if (namelist[i] != NULL)
287 namelist[d++] = namelist[i];
292 // propagate menu settings to the emu vars
293 static void menu_sync_config(void)
295 static int allow_abs_only_old;
300 Config.PsxType = region - 1;
302 cycle_multiplier = 10000 / psx_clock;
304 switch (in_type_sel1) {
305 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
306 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
307 default: in_type1 = PSE_PAD_TYPE_STANDARD;
309 switch (in_type_sel2) {
310 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
311 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
312 default: in_type2 = PSE_PAD_TYPE_STANDARD;
314 if (in_evdev_allow_abs_only != allow_abs_only_old) {
316 allow_abs_only_old = in_evdev_allow_abs_only;
319 spu_config.iVolume = 768 + 128 * volume_boost;
320 pl_rearmed_cbs.frameskip = frameskip - 1;
321 pl_timing_prepare(Config.PsxType);
324 static void menu_set_defconfig(void)
326 emu_set_default_config();
329 g_scaler = SCALE_4_3;
333 analog_deadzone = 50;
336 plat_target.vout_fullscreen = 0;
337 psx_clock = DEFAULT_PSX_CLOCK;
340 in_type_sel1 = in_type_sel2 = 0;
341 in_evdev_allow_abs_only = 0;
346 #define CE_CONFIG_STR(val) \
347 { #val, 0, Config.val }
349 #define CE_CONFIG_VAL(val) \
350 { #val, sizeof(Config.val), &Config.val }
352 #define CE_STR(val) \
355 #define CE_INTVAL(val) \
356 { #val, sizeof(val), &val }
358 #define CE_INTVAL_N(name, val) \
359 { name, sizeof(val), &val }
361 #define CE_INTVAL_P(val) \
362 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
364 // 'versioned' var, used when defaults change
365 #define CE_CONFIG_STR_V(val, ver) \
366 { #val #ver, 0, Config.val }
368 #define CE_INTVAL_V(val, ver) \
369 { #val #ver, sizeof(val), &val }
371 #define CE_INTVAL_PV(val, ver) \
372 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
374 static const struct {
380 CE_CONFIG_STR_V(Gpu, 3),
382 // CE_CONFIG_STR(Cdr),
384 // CE_CONFIG_VAL(Sio),
387 CE_CONFIG_VAL(Debug),
388 CE_CONFIG_VAL(PsxOut),
389 CE_CONFIG_VAL(SpuIrq),
390 CE_CONFIG_VAL(RCntFix),
391 CE_CONFIG_VAL(VSyncWA),
394 CE_INTVAL_V(g_scaler, 3),
396 CE_INTVAL(g_layer_x),
397 CE_INTVAL(g_layer_y),
398 CE_INTVAL(g_layer_w),
399 CE_INTVAL(g_layer_h),
400 CE_INTVAL(soft_filter),
401 CE_INTVAL(plat_target.vout_method),
402 CE_INTVAL(plat_target.hwfilter),
403 CE_INTVAL(plat_target.vout_fullscreen),
404 CE_INTVAL(state_slot),
405 CE_INTVAL(cpu_clock),
407 CE_INTVAL(in_type_sel1),
408 CE_INTVAL(in_type_sel2),
409 CE_INTVAL(analog_deadzone),
410 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
411 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
412 CE_INTVAL_V(frameskip, 3),
413 CE_INTVAL_P(gpu_peops.iUseDither),
414 CE_INTVAL_P(gpu_peops.dwActFixes),
415 CE_INTVAL_P(gpu_unai.lineskip),
416 CE_INTVAL_P(gpu_unai.abe_hack),
417 CE_INTVAL_P(gpu_unai.no_light),
418 CE_INTVAL_P(gpu_unai.no_blend),
419 CE_INTVAL_P(gpu_neon.allow_interlace),
420 CE_INTVAL_P(gpu_neon.enhancement_enable),
421 CE_INTVAL_P(gpu_neon.enhancement_no_main),
422 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
423 CE_INTVAL_P(gpu_peopsgl.iFilterType),
424 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
425 CE_INTVAL_P(gpu_peopsgl.iUseMask),
426 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
427 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
428 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
429 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
430 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
431 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
432 CE_INTVAL(spu_config.iUseReverb),
433 CE_INTVAL(spu_config.iXAPitch),
434 CE_INTVAL(spu_config.iUseInterpolation),
435 CE_INTVAL(spu_config.iTempo),
436 CE_INTVAL(config_save_counter),
437 CE_INTVAL(in_evdev_allow_abs_only),
438 CE_INTVAL(volume_boost),
439 CE_INTVAL(psx_clock),
440 CE_INTVAL(new_dynarec_hacks),
441 CE_INTVAL(in_enable_vibration),
444 static char *get_cd_label(void)
446 static char trimlabel[33];
449 strncpy(trimlabel, CdromLabel, 32);
451 for (j = 31; j >= 0; j--)
452 if (trimlabel[j] == ' ')
458 static void make_cfg_fname(char *buf, size_t size, int is_game)
461 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
463 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
466 static void keys_write_all(FILE *f);
467 static char *mystrip(char *str);
469 static int menu_write_config(int is_game)
471 char cfgfile[MAXPATHLEN];
475 config_save_counter++;
477 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
478 f = fopen(cfgfile, "w");
480 printf("menu_write_config: failed to open: %s\n", cfgfile);
484 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
485 fprintf(f, "%s = ", config_data[i].name);
486 switch (config_data[i].len) {
488 fprintf(f, "%s\n", (char *)config_data[i].val);
491 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
494 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
497 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
500 printf("menu_write_config: unhandled len %d for %s\n",
501 (int)config_data[i].len, config_data[i].name);
512 static int menu_do_last_cd_img(int is_get)
514 static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
520 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
521 f = fopen(path, is_get ? "r" : "w");
528 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
529 last_selected_fname[ret] = 0;
530 mystrip(last_selected_fname);
533 fprintf(f, "%s\n", last_selected_fname);
538 for (i = 0; last_selected_fname[0] == 0
539 || stat64(last_selected_fname, &st) != 0; i++)
541 if (i >= ARRAY_SIZE(defaults))
543 strcpy(last_selected_fname, defaults[i]);
550 static void parse_str_val(char *cval, const char *src)
553 strncpy(cval, src, MAXPATHLEN);
554 cval[MAXPATHLEN - 1] = 0;
555 tmp = strchr(cval, '\n');
557 tmp = strchr(cval, '\r');
562 static void keys_load_all(const char *cfg);
564 static int menu_load_config(int is_game)
566 char cfgfile[MAXPATHLEN];
572 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
573 f = fopen(cfgfile, "r");
575 printf("menu_load_config: failed to open: %s\n", cfgfile);
579 fseek(f, 0, SEEK_END);
582 printf("bad size %ld: %s\n", size, cfgfile);
586 cfg = malloc(size + 1);
590 fseek(f, 0, SEEK_SET);
591 if (fread(cfg, 1, size, f) != size) {
592 printf("failed to read: %s\n", cfgfile);
597 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
601 tmp = strstr(cfg, config_data[i].name);
604 tmp += strlen(config_data[i].name);
605 if (strncmp(tmp, " = ", 3) != 0)
609 if (config_data[i].len == 0) {
610 parse_str_val(config_data[i].val, tmp);
615 val = strtoul(tmp, &tmp2, 16);
616 if (tmp2 == NULL || tmp == tmp2)
617 continue; // parse failed
619 switch (config_data[i].len) {
621 *(u8 *)config_data[i].val = val;
624 *(u16 *)config_data[i].val = val;
627 *(u32 *)config_data[i].val = val;
630 printf("menu_load_config: unhandled len %d for %s\n",
631 (int)config_data[i].len, config_data[i].name);
637 char *tmp = strstr(cfg, "lastcdimg = ");
640 parse_str_val(last_selected_fname, tmp);
655 for (i = bios_sel = 0; bioses[i] != NULL; i++)
656 if (strcmp(Config.Bios, bioses[i]) == 0)
657 { bios_sel = i; break; }
659 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
660 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
661 { gpu_plugsel = i; break; }
663 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
664 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
665 { spu_plugsel = i; break; }
670 static const char *filter_exts[] = {
671 "bin", "img", "mdf", "iso", "cue", "z",
672 "bz", "znx", "pbp", "cbn", NULL
675 // rrrr rggg gggb bbbb
676 static unsigned short fname2color(const char *fname)
678 static const char *other_exts[] = {
679 "ccd", "toc", "mds", "sub", "table", "index", "sbi"
681 const char *ext = strrchr(fname, '.');
687 for (i = 0; filter_exts[i] != NULL; i++)
688 if (strcasecmp(ext, filter_exts[i]) == 0)
690 for (i = 0; i < array_size(other_exts); i++)
691 if (strcasecmp(ext, other_exts[i]) == 0)
696 static void draw_savestate_bg(int slot);
698 #define MENU_ALIGN_LEFT
699 #ifdef __ARM_ARCH_7A__ // assume hires device
705 #include "libpicofe/menu.c"
707 // a bit of black magic here
708 static void draw_savestate_bg(int slot)
710 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
712 char fname[MAXPATHLEN];
719 ret = get_state_filename(fname, sizeof(fname), slot);
723 f = gzopen(fname, "rb");
727 if ((ret = (int)gzseek(f, 0x29933d, SEEK_SET)) != 0x29933d) {
728 fprintf(stderr, "gzseek failed: %d\n", ret);
733 gpu = malloc(sizeof(*gpu));
739 ret = gzread(f, gpu, sizeof(*gpu));
741 if (ret != sizeof(*gpu)) {
742 fprintf(stderr, "gzread failed\n");
746 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
748 if (gpu->ulStatus & 0x800000)
749 goto out; // disabled
751 x = gpu->ulControl[5] & 0x3ff;
752 y = (gpu->ulControl[5] >> 10) & 0x1ff;
753 w = psx_widths[(gpu->ulStatus >> 16) & 7];
754 tmp = gpu->ulControl[7];
755 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
756 if (gpu->ulStatus & 0x80000) // doubleheight
758 if (h <= 0 || h > 512)
764 s = (u16 *)gpu->psxVRam + y * 1024 + x;
766 x = max(0, g_menuscreen_w - w) & ~3;
767 y = max(0, g_menuscreen_h / 2 - h / 2);
768 w = min(g_menuscreen_w, w);
769 h = min(g_menuscreen_h, h);
770 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
772 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
773 if (gpu->ulStatus & 0x200000)
774 bgr888_to_rgb565(d, s, w * 3);
776 bgr555_to_rgb565(d, s, w * 2);
778 // darken this so that menu text is visible
779 if (g_menuscreen_w - w < 320)
780 menu_darken_bg(d, d, w * 2, 0);
787 // -------------- key config --------------
789 me_bind_action me_ctrl_actions[] =
791 { "UP ", 1 << DKEY_UP},
792 { "DOWN ", 1 << DKEY_DOWN },
793 { "LEFT ", 1 << DKEY_LEFT },
794 { "RIGHT ", 1 << DKEY_RIGHT },
795 { "TRIANGLE", 1 << DKEY_TRIANGLE },
796 { "CIRCLE ", 1 << DKEY_CIRCLE },
797 { "CROSS ", 1 << DKEY_CROSS },
798 { "SQUARE ", 1 << DKEY_SQUARE },
799 { "L1 ", 1 << DKEY_L1 },
800 { "R1 ", 1 << DKEY_R1 },
801 { "L2 ", 1 << DKEY_L2 },
802 { "R2 ", 1 << DKEY_R2 },
803 { "L3 ", 1 << DKEY_L3 },
804 { "R3 ", 1 << DKEY_R3 },
805 { "START ", 1 << DKEY_START },
806 { "SELECT ", 1 << DKEY_SELECT },
810 me_bind_action emuctrl_actions[] =
812 { "Save State ", 1 << SACTION_SAVE_STATE },
813 { "Load State ", 1 << SACTION_LOAD_STATE },
814 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
815 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
816 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
817 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
818 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
819 #ifdef __ARM_ARCH_7A__
820 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
822 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
823 #if MENU_SHOW_MINIMIZE
824 { "Minimize ", 1 << SACTION_MINIMIZE },
826 #if MENU_SHOW_FULLSCREEN
827 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
829 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
830 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
831 { "Gun A button ", 1 << SACTION_GUN_A },
832 { "Gun B button ", 1 << SACTION_GUN_B },
833 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
835 { "Volume Up ", 1 << SACTION_VOLUME_UP },
836 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
841 static char *mystrip(char *str)
846 for (i = 0; i < len; i++)
847 if (str[i] != ' ') break;
848 if (i > 0) memmove(str, str + i, len - i + 1);
851 for (i = len - 1; i >= 0; i--)
852 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
858 static void get_line(char *d, size_t size, const char *s)
863 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
874 static void keys_write_all(FILE *f)
878 for (d = 0; d < IN_MAX_DEVS; d++)
880 const int *binds = in_get_dev_binds(d);
881 const char *name = in_get_dev_name(d, 0, 0);
884 if (binds == NULL || name == NULL)
887 fprintf(f, "binddev = %s\n", name);
888 in_get_config(d, IN_CFG_BIND_COUNT, &count);
890 for (k = 0; k < count; k++)
895 act[0] = act[31] = 0;
896 name = in_get_key_name(d, k);
898 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
899 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
900 mask = me_ctrl_actions[i].mask;
902 strncpy(act, me_ctrl_actions[i].name, 31);
903 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
906 mask = me_ctrl_actions[i].mask << 16;
908 strncpy(act, me_ctrl_actions[i].name, 31);
909 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
914 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
915 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
916 mask = emuctrl_actions[i].mask;
918 strncpy(act, emuctrl_actions[i].name, 31);
919 fprintf(f, "bind %s = %s\n", name, mystrip(act));
925 for (k = 0; k < array_size(in_adev); k++)
928 fprintf(f, "bind_analog = %d\n", k);
933 static int parse_bind_val(const char *val, int *type)
937 *type = IN_BINDTYPE_NONE;
941 if (strncasecmp(val, "player", 6) == 0)
943 int player, shift = 0;
944 player = atoi(val + 6) - 1;
946 if ((unsigned int)player > 1)
951 *type = IN_BINDTYPE_PLAYER12;
952 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
953 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
954 return me_ctrl_actions[i].mask << shift;
957 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
958 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
959 *type = IN_BINDTYPE_EMU;
960 return emuctrl_actions[i].mask;
967 static void keys_load_all(const char *cfg)
969 char dev[256], key[128], *act;
975 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
978 get_line(dev, sizeof(dev), p);
979 dev_id = in_config_parse_dev(dev);
981 printf("input: can't handle dev: %s\n", dev);
985 in_unbind_all(dev_id, -1, -1);
986 while ((p = strstr(p, "bind"))) {
987 if (strncmp(p, "binddev = ", 10) == 0)
990 if (strncmp(p, "bind_analog", 11) == 0) {
991 ret = sscanf(p, "bind_analog = %d", &bind);
994 printf("input: parse error: %16s..\n", p);
997 if ((unsigned int)bind >= array_size(in_adev)) {
998 printf("input: analog id %d out of range\n", bind);
1001 in_adev[bind] = dev_id;
1007 printf("input: parse error: %16s..\n", p);
1011 get_line(key, sizeof(key), p);
1012 act = strchr(key, '=');
1014 printf("parse failed: %16s..\n", p);
1022 bind = parse_bind_val(act, &bindtype);
1023 if (bind != -1 && bind != 0) {
1024 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
1025 in_config_bind_key(dev_id, key, bind, bindtype);
1028 lprintf("config: unhandled action \"%s\"\n", act);
1034 static int key_config_loop_wrap(int id, int keys)
1037 case MA_CTRL_PLAYER1:
1038 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
1040 case MA_CTRL_PLAYER2:
1041 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
1044 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
1052 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
1053 "Might cause problems with real analog sticks";
1054 static const char *adevnames[IN_MAX_DEVS + 2];
1055 static int stick_sel[2];
1057 static menu_entry e_menu_keyconfig_analog[] =
1059 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
1060 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
1061 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
1062 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
1063 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
1064 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
1065 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
1066 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
1070 static int key_config_analog(int id, int keys)
1072 int i, d, count, sel = 0;
1073 int sel2dev_map[IN_MAX_DEVS];
1075 memset(adevnames, 0, sizeof(adevnames));
1076 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1077 memset(stick_sel, 0, sizeof(stick_sel));
1079 adevnames[0] = "None";
1081 for (d = 0; d < IN_MAX_DEVS; d++)
1083 const char *name = in_get_dev_name(d, 0, 1);
1088 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1092 if (in_adev[0] == d) stick_sel[0] = i;
1093 if (in_adev[1] == d) stick_sel[1] = i;
1095 adevnames[i++] = name;
1097 adevnames[i] = NULL;
1099 me_loop(e_menu_keyconfig_analog, &sel);
1101 in_adev[0] = sel2dev_map[stick_sel[0]];
1102 in_adev[1] = sel2dev_map[stick_sel[1]];
1107 static const char *mgn_dev_name(int id, int *offs)
1109 const char *name = NULL;
1112 if (id == MA_CTRL_DEV_FIRST)
1115 for (; it < IN_MAX_DEVS; it++) {
1116 name = in_get_dev_name(it, 1, 1);
1125 static const char *mgn_saveloadcfg(int id, int *offs)
1130 static int mh_savecfg(int id, int keys)
1132 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1133 menu_update_msg("config saved");
1135 menu_update_msg("failed to write config");
1140 static int mh_input_rescan(int id, int keys)
1142 //menu_sync_config();
1144 menu_update_msg("rescan complete.");
1149 static const char *men_in_type_sel[] = {
1150 "Standard (SCPH-1080)",
1151 "Analog (SCPH-1150)",
1155 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1156 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1157 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1159 static menu_entry e_menu_keyconfig[] =
1161 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1162 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1163 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1164 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1166 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1167 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1168 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1169 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1170 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1171 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1172 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1173 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1174 mee_handler ("Rescan devices:", mh_input_rescan),
1176 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1177 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1186 static int menu_loop_keyconfig(int id, int keys)
1190 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1191 me_loop(e_menu_keyconfig, &sel);
1195 // ------------ gfx options menu ------------
1197 static const char *men_scaler[] = {
1198 "1x1", "integer scaled 2x", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL
1200 static const char *men_soft_filter[] = { "None",
1202 "scale2x", "eagle2x",
1205 static const char *men_dummy[] = { NULL };
1206 static const char h_scaler[] = "int. 2x - scales w. or h. 2x if it fits on screen\n"
1207 "int. 4:3 - uses integer if possible, else fractional";
1208 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1209 "using d-pad or move it using R+d-pad";
1210 static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
1211 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1212 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1214 static int menu_loop_cscaler(int id, int keys)
1218 g_scaler = SCALE_CUSTOM;
1220 plat_gvideo_open(Config.PsxType);
1224 menu_draw_begin(0, 1);
1225 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1226 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1227 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1230 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1231 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1232 if (inp & PBTN_UP) g_layer_y--;
1233 if (inp & PBTN_DOWN) g_layer_y++;
1234 if (inp & PBTN_LEFT) g_layer_x--;
1235 if (inp & PBTN_RIGHT) g_layer_x++;
1236 if (!(inp & PBTN_R)) {
1237 if (inp & PBTN_UP) g_layer_h += 2;
1238 if (inp & PBTN_DOWN) g_layer_h -= 2;
1239 if (inp & PBTN_LEFT) g_layer_w += 2;
1240 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1242 if (inp & (PBTN_MOK|PBTN_MBACK))
1245 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1246 if (g_layer_x < 0) g_layer_x = 0;
1247 if (g_layer_x > 640) g_layer_x = 640;
1248 if (g_layer_y < 0) g_layer_y = 0;
1249 if (g_layer_y > 420) g_layer_y = 420;
1250 if (g_layer_w < 160) g_layer_w = 160;
1251 if (g_layer_h < 60) g_layer_h = 60;
1252 if (g_layer_x + g_layer_w > 800)
1253 g_layer_w = 800 - g_layer_x;
1254 if (g_layer_y + g_layer_h > 480)
1255 g_layer_h = 480 - g_layer_y;
1257 plat_gvideo_open(Config.PsxType);
1261 plat_gvideo_close();
1266 static menu_entry e_menu_gfx_options[] =
1268 mee_enum_h ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler, h_scaler),
1269 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1270 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1271 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1272 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1273 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1274 // mee_onoff ("Vsync", 0, vsync, 1),
1275 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1279 static int menu_loop_gfx_options(int id, int keys)
1283 me_loop(e_menu_gfx_options, &sel);
1288 // ------------ bios/plugins ------------
1292 static const char h_gpu_neon[] =
1293 "Configure built-in NEON GPU plugin";
1294 static const char h_gpu_neon_enhanced[] =
1295 "Renders in double resolution at the cost of lower performance\n"
1296 "(not available for high resolution games)";
1297 static const char h_gpu_neon_enhanced_hack[] =
1298 "Speed hack for above option (glitches some games)";
1299 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1301 static menu_entry e_menu_plugin_gpu_neon[] =
1303 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1304 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1305 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1309 static int menu_loop_plugin_gpu_neon(int id, int keys)
1312 me_loop(e_menu_plugin_gpu_neon, &sel);
1318 static menu_entry e_menu_plugin_gpu_unai[] =
1320 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1321 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1322 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1323 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1327 static int menu_loop_plugin_gpu_unai(int id, int keys)
1330 me_loop(e_menu_plugin_gpu_unai, &sel);
1334 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1335 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1336 static const char h_gpu_1[] = "Capcom fighting games";
1337 static const char h_gpu_2[] = "Black screens in Lunar";
1338 static const char h_gpu_3[] = "Compatibility mode";
1339 static const char h_gpu_6[] = "Pandemonium 2";
1340 //static const char h_gpu_7[] = "Skip every second frame";
1341 static const char h_gpu_8[] = "Needed by Dark Forces";
1342 static const char h_gpu_9[] = "better g-colors, worse textures";
1343 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1345 static menu_entry e_menu_plugin_gpu_peops[] =
1347 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1348 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1349 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1350 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1351 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1352 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1353 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1354 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1355 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1356 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1360 static int menu_loop_plugin_gpu_peops(int id, int keys)
1363 me_loop(e_menu_plugin_gpu_peops, &sel);
1367 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1368 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1369 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1371 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1373 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1374 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1375 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1376 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1377 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1378 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1379 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1380 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1381 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1382 mee_label ("Fixes/hacks:"),
1383 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1384 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1385 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1386 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1387 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1388 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1389 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1390 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1391 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1392 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1393 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1397 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1400 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1404 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1405 static const char h_spu_volboost[] = "Large values cause distortion";
1406 static const char h_spu_tempo[] = "Slows down audio if emu is too slow\n"
1407 "This is inaccurate and breaks games";
1409 static menu_entry e_menu_plugin_spu[] =
1411 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1412 mee_onoff ("Reverb", 0, spu_config.iUseReverb, 1),
1413 mee_enum ("Interpolation", 0, spu_config.iUseInterpolation, men_spu_interp),
1414 mee_onoff ("Adjust XA pitch", 0, spu_config.iXAPitch, 1),
1415 mee_onoff_h ("Adjust tempo", 0, spu_config.iTempo, 1, h_spu_tempo),
1419 static int menu_loop_plugin_spu(int id, int keys)
1422 me_loop(e_menu_plugin_spu, &sel);
1426 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1427 "savestates and can't be changed there. Must save\n"
1428 "config and reload the game for change to take effect";
1429 static const char h_plugin_gpu[] =
1431 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1433 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1434 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1435 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1436 "must save config and reload the game if changed";
1437 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1438 "must save config and reload the game if changed";
1439 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1440 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1441 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1442 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1444 static menu_entry e_menu_plugin_options[] =
1446 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1447 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1448 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1450 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1452 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1453 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1454 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1455 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1459 static menu_entry e_menu_main2[];
1461 static int menu_loop_plugin_options(int id, int keys)
1464 me_loop(e_menu_plugin_options, &sel);
1466 // sync BIOS/plugins
1467 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1468 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1469 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1470 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1475 // ------------ adv options menu ------------
1477 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1478 "(lower value - less work for the emu, may be faster)";
1479 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1480 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1481 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1483 static menu_entry e_menu_speed_hacks[] =
1485 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1486 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1487 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1488 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1492 static int menu_loop_speed_hacks(int id, int keys)
1495 me_loop(e_menu_speed_hacks, &sel);
1499 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1500 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1501 "(green: normal, red: fmod, blue: noise)";
1502 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1503 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1504 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1505 "(proper .cue/.bin dump is needed otherwise)";
1506 static const char h_cfg_sio[] = "You should not need this, breaks games";
1507 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1508 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1509 "(timing hack, breaks other games)";
1510 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1511 "(timing hack, breaks other games)";
1512 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1513 "Might be useful to overcome some dynarec bugs";
1514 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1515 "must reload game for any change to take effect";
1517 static menu_entry e_menu_adv_options[] =
1519 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1520 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1521 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1522 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1523 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1524 //mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1525 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1526 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1527 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1528 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1529 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1533 static int menu_loop_adv_options(int id, int keys)
1536 me_loop(e_menu_adv_options, &sel);
1540 // ------------ options menu ------------
1542 static int mh_restore_defaults(int id, int keys)
1544 menu_set_defconfig();
1545 menu_update_msg("defaults restored");
1549 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1550 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1552 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1553 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1554 "loading state or both";
1556 static const char h_restore_def[] = "Switches back to default / recommended\n"
1558 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1560 static menu_entry e_menu_options[] =
1562 // mee_range ("Save slot", 0, state_slot, 0, 9),
1563 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1564 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1565 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1566 mee_enum ("Region", 0, region, men_region),
1567 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1568 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1569 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1570 mee_handler ("[Advanced]", menu_loop_adv_options),
1571 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1572 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1573 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1577 static int menu_loop_options(int id, int keys)
1582 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1583 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1584 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1586 me_loop(e_menu_options, &sel);
1591 // ------------ debug menu ------------
1593 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1595 int w = min(g_menuscreen_w, 1024);
1596 int h = min(g_menuscreen_h, 512);
1597 u16 *d = g_menuscreen_ptr;
1598 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1602 gpuf->ulFreezeVersion = 1;
1603 if (GPU_freeze != NULL)
1604 GPU_freeze(1, gpuf);
1606 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1607 bgr555_to_rgb565(d, s, w * 2);
1609 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1610 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1611 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1612 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1613 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1616 static void debug_menu_loop(void)
1618 int inp, df_x = 0, df_y = 0;
1621 gpuf = malloc(sizeof(*gpuf));
1627 menu_draw_begin(0, 1);
1628 draw_frame_debug(gpuf, df_x, df_y);
1631 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1632 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1633 if (inp & PBTN_MBACK) break;
1634 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1635 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1636 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1637 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1643 // --------- memcard manager ---------
1645 static void draw_mc_icon(int dx, int dy, const u16 *s)
1650 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1652 for (y = 0; y < 16; y++, s += 16) {
1653 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1654 for (x = 0; x < 16; x++) {
1656 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1657 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1663 static void draw_mc_bg(void)
1665 McdBlock *blocks1, *blocks2;
1669 blocks1 = malloc(15 * sizeof(blocks1[0]));
1670 blocks2 = malloc(15 * sizeof(blocks1[0]));
1671 if (blocks1 == NULL || blocks2 == NULL)
1674 for (i = 0; i < 15; i++) {
1675 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1676 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1679 menu_draw_begin(1, 1);
1681 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1683 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1687 maxicons = g_menuscreen_h / 32;
1690 row2 = g_menuscreen_w / 2;
1691 for (i = 0; i < maxicons; i++) {
1692 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1693 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1695 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1696 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1699 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1707 static void handle_memcard_sel(void)
1709 strcpy(Config.Mcd1, "none");
1710 if (memcard1_sel != 0)
1711 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1712 strcpy(Config.Mcd2, "none");
1713 if (memcard2_sel != 0)
1714 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1715 LoadMcds(Config.Mcd1, Config.Mcd2);
1719 static menu_entry e_memcard_options[] =
1721 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1722 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1726 static int menu_loop_memcards(int id, int keys)
1732 memcard1_sel = memcard2_sel = 0;
1733 p = strrchr(Config.Mcd1, '/');
1735 for (i = 0; memcards[i] != NULL; i++)
1736 if (strcmp(p + 1, memcards[i]) == 0)
1737 { memcard1_sel = i; break; }
1738 p = strrchr(Config.Mcd2, '/');
1740 for (i = 0; memcards[i] != NULL; i++)
1741 if (strcmp(p + 1, memcards[i]) == 0)
1742 { memcard2_sel = i; break; }
1744 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1746 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1751 // ------------ cheats menu ------------
1753 static void draw_cheatlist(int sel)
1755 int max_cnt, start, i, pos, active;
1757 max_cnt = g_menuscreen_h / me_sfont_h;
1758 start = max_cnt / 2 - sel;
1760 menu_draw_begin(1, 1);
1762 for (i = 0; i < NumCheats; i++) {
1764 if (pos < 0) continue;
1765 if (pos >= max_cnt) break;
1766 active = Cheats[i].Enabled;
1767 smalltext_out16(14, pos * me_sfont_h,
1768 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1769 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1770 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1774 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1776 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1780 static void menu_loop_cheats(void)
1782 static int menu_sel = 0;
1787 draw_cheatlist(menu_sel);
1788 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1789 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1790 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1791 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1792 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1793 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1794 if (inp & PBTN_MOK) { // action
1795 if (menu_sel < NumCheats)
1796 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1799 if (inp & PBTN_MBACK)
1804 // --------- main menu help ----------
1806 static void menu_bios_warn(void)
1809 static const char msg[] =
1810 "You don't seem to have copied any BIOS\n"
1812 MENU_BIOS_PATH "\n\n"
1814 "While many games work fine with fake\n"
1815 "(HLE) BIOS, others (like MGS and FF8)\n"
1816 "require BIOS to work.\n"
1817 "After copying the file, you'll also need\n"
1818 "to select it in the emu's menu:\n"
1819 "options->[BIOS/Plugins]\n\n"
1820 "The file is usually named SCPH1001.BIN,\n"
1821 "but other not compressed files can be\n"
1823 "Press %s or %s to continue";
1824 char tmp_msg[sizeof(msg) + 64];
1826 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1827 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1830 draw_menu_message(tmp_msg, NULL);
1832 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1833 if (inp & (PBTN_MBACK|PBTN_MOK))
1838 // ------------ main menu ------------
1840 static menu_entry e_menu_main[];
1842 static void draw_frame_main(void)
1851 if (CdromId[0] != 0) {
1852 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1853 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1854 Config.HLE ? "HLE" : "BIOS");
1855 smalltext_out16(4, 1, buff, 0x105f);
1859 capacity = plat_target_bat_capacity_get();
1861 tmp = localtime(<ime);
1862 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1863 if (capacity >= 0) {
1864 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1869 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1873 static void draw_frame_credits(void)
1875 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1878 static const char credits_text[] =
1880 "(C) 1999-2003 PCSX Team\n"
1881 "(C) 2005-2009 PCSX-df Team\n"
1882 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1883 "ARM recompiler (C) 2009-2011 Ari64\n"
1885 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1887 "PEOpS GPU and SPU by Pete Bernert\n"
1888 " and the P.E.Op.S. team\n"
1889 "PCSX4ALL plugin by PCSX4ALL team\n"
1890 " Chui, Franxis, Unai\n\n"
1891 "integration, optimization and\n"
1892 " frontend (C) 2010-2012 notaz\n";
1894 static int reset_game(void)
1897 if (bios_sel == 0 && !Config.HLE)
1903 if (CheckCdrom() != -1) {
1909 static int reload_plugins(const char *cdimg)
1915 set_cd_image(cdimg);
1917 pcnt_hook_plugins();
1919 if (OpenPlugins() == -1) {
1920 menu_update_msg("failed to open plugins");
1923 plugin_call_rearmed_cbs();
1925 cdrIsoMultidiskCount = 1;
1927 CdromLabel[0] = '\0';
1932 static int run_bios(void)
1938 if (reload_plugins(NULL) != 0)
1946 static int run_exe(void)
1948 const char *exts[] = { "exe", NULL };
1951 fname = menu_loop_romsel(last_selected_fname,
1952 sizeof(last_selected_fname), exts, NULL);
1957 if (reload_plugins(NULL) != 0)
1961 if (Load(fname) != 0) {
1962 menu_update_msg("exe load failed, bad file?");
1971 static int run_cd_image(const char *fname)
1974 reload_plugins(fname);
1976 // always autodetect, menu_sync_config will override as needed
1979 if (CheckCdrom() == -1) {
1980 // Only check the CD if we are starting the console with a CD
1982 menu_update_msg("unsupported/invalid CD image");
1988 // Read main executable directly from CDRom and start it
1989 if (LoadCdrom() == -1) {
1991 menu_update_msg("failed to load CD image");
2001 static int romsel_run(void)
2003 int prev_gpu, prev_spu;
2006 fname = menu_loop_romsel(last_selected_fname,
2007 sizeof(last_selected_fname), filter_exts,
2008 optional_cdimg_filter);
2012 printf("selected file: %s\n", fname);
2014 new_dynarec_clear_full();
2016 if (run_cd_image(fname) != 0)
2019 prev_gpu = gpu_plugsel;
2020 prev_spu = spu_plugsel;
2021 if (menu_load_config(1) != 0)
2022 menu_load_config(0);
2024 // check for plugin changes, have to repeat
2025 // loading if game config changed plugins to reload them
2026 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
2027 printf("plugin change detected, reloading plugins..\n");
2028 if (run_cd_image(fname) != 0)
2032 strcpy(last_selected_fname, fname);
2033 menu_do_last_cd_img(0);
2037 static int swap_cd_image(void)
2041 fname = menu_loop_romsel(last_selected_fname,
2042 sizeof(last_selected_fname), filter_exts,
2043 optional_cdimg_filter);
2047 printf("selected file: %s\n", fname);
2050 CdromLabel[0] = '\0';
2052 set_cd_image(fname);
2053 if (ReloadCdromPlugin() < 0) {
2054 menu_update_msg("failed to load cdr plugin");
2057 if (CDR_open() < 0) {
2058 menu_update_msg("failed to open cdr plugin");
2062 SetCdOpenCaseTime(time(NULL) + 2);
2065 strcpy(last_selected_fname, fname);
2069 static int swap_cd_multidisk(void)
2071 cdrIsoMultidiskSelect++;
2073 CdromLabel[0] = '\0';
2076 if (CDR_open() < 0) {
2077 menu_update_msg("failed to open cdr plugin");
2081 SetCdOpenCaseTime(time(NULL) + 2);
2087 static void load_pcsx_cht(void)
2089 static const char *exts[] = { "cht", NULL };
2093 fname = menu_loop_romsel(last_selected_fname,
2094 sizeof(last_selected_fname), exts, NULL);
2098 printf("selected cheat file: %s\n", fname);
2101 if (NumCheats == 0 && NumCodes == 0)
2102 menu_update_msg("failed to load cheats");
2104 snprintf(msg, sizeof(msg), "%d cheat(s) loaded", NumCheats + NumCodes);
2105 menu_update_msg(msg);
2107 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2110 static int main_menu_handler(int id, int keys)
2114 case MA_MAIN_RESUME_GAME:
2118 case MA_MAIN_SAVE_STATE:
2120 return menu_loop_savestate(0);
2122 case MA_MAIN_LOAD_STATE:
2124 return menu_loop_savestate(1);
2126 case MA_MAIN_RESET_GAME:
2127 if (ready_to_go && reset_game() == 0)
2130 case MA_MAIN_LOAD_ROM:
2131 if (romsel_run() == 0)
2134 case MA_MAIN_SWAP_CD:
2135 if (swap_cd_image() == 0)
2138 case MA_MAIN_SWAP_CD_MULTI:
2139 if (swap_cd_multidisk() == 0)
2142 case MA_MAIN_RUN_BIOS:
2143 if (run_bios() == 0)
2146 case MA_MAIN_RUN_EXE:
2150 case MA_MAIN_CHEATS:
2153 case MA_MAIN_LOAD_CHEATS:
2156 case MA_MAIN_CREDITS:
2157 draw_menu_message(credits_text, draw_frame_credits);
2158 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2161 emu_core_ask_exit();
2164 lprintf("%s: something unknown selected\n", __FUNCTION__);
2171 static menu_entry e_menu_main2[] =
2173 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2174 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2175 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2176 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2177 mee_handler ("Memcard manager", menu_loop_memcards),
2178 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2182 static int main_menu2_handler(int id, int keys)
2186 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2187 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2188 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2189 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2191 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2194 static const char h_extra[] = "Change CD, manage memcards..\n";
2196 static menu_entry e_menu_main[] =
2200 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2201 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2202 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2203 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2204 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2205 mee_handler ("Options", menu_loop_options),
2206 mee_handler ("Controls", menu_loop_keyconfig),
2207 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2208 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2209 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2210 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2214 // ----------------------------
2216 static void menu_leave_emu(void);
2218 void menu_loop(void)
2220 static int warned_about_bios = 0;
2225 if (config_save_counter == 0) {
2227 if (bioses[1] != NULL) {
2228 // autoselect BIOS to make user's life easier
2229 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2232 else if (!warned_about_bios) {
2234 warned_about_bios = 1;
2238 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2239 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2240 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2241 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2242 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2244 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2247 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2248 } while (!ready_to_go && !g_emu_want_quit);
2250 /* wait until menu, ok, back is released */
2251 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2254 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2259 static int qsort_strcmp(const void *p1, const void *p2)
2261 char * const *s1 = (char * const *)p1;
2262 char * const *s2 = (char * const *)p2;
2263 return strcasecmp(*s1, *s2);
2266 static void scan_bios_plugins(void)
2268 char fname[MAXPATHLEN];
2270 int bios_i, gpu_i, spu_i, mc_i;
2275 gpu_plugins[0] = "builtin_gpu";
2276 spu_plugins[0] = "builtin_spu";
2277 memcards[0] = "(none)";
2278 bios_i = gpu_i = spu_i = mc_i = 1;
2280 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2281 dir = opendir(fname);
2283 perror("scan_bios_plugins bios opendir");
2298 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2301 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2302 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2303 printf("bad BIOS file: %s\n", ent->d_name);
2307 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2308 bioses[bios_i++] = strdup(ent->d_name);
2312 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2318 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2319 dir = opendir(fname);
2321 perror("scan_bios_plugins plugins opendir");
2335 p = strstr(ent->d_name, ".so");
2339 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2340 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2342 fprintf(stderr, "%s\n", dlerror());
2346 // now what do we have here?
2347 tmp = dlsym(h, "GPUinit");
2350 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2351 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2355 tmp = dlsym(h, "SPUinit");
2358 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2359 spu_plugins[spu_i++] = strdup(ent->d_name);
2363 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2370 dir = opendir("." MEMCARD_DIR);
2372 perror("scan_bios_plugins memcards opendir");
2387 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2390 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2391 if (stat(fname, &st) != 0) {
2392 printf("bad memcard file: %s\n", ent->d_name);
2396 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2397 memcards[mc_i++] = strdup(ent->d_name);
2401 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2405 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2410 void menu_init(void)
2412 char buff[MAXPATHLEN];
2415 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2417 scan_bios_plugins();
2420 menu_set_defconfig();
2421 menu_load_config(0);
2422 menu_do_last_cd_img(1);
2427 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2428 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2429 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2430 fprintf(stderr, "OOM\n");
2434 emu_make_path(buff, "skin/background.png", sizeof(buff));
2435 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2437 i = plat_target.cpu_clock_set != NULL
2438 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2439 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2441 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2442 e_menu_gfx_options[i].data = plat_target.vout_methods;
2443 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2444 plat_target.vout_methods != NULL);
2446 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2447 e_menu_gfx_options[i].data = plat_target.hwfilters;
2448 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2449 plat_target.hwfilters != NULL);
2451 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2452 plat_target.gamma_set != NULL);
2454 #ifndef __ARM_ARCH_7A__
2455 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2457 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2458 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2459 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2460 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2461 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2462 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2463 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2466 void menu_notify_mode_change(int w, int h, int bpp)
2470 last_vout_bpp = bpp;
2473 static void menu_leave_emu(void)
2475 if (GPU_close != NULL) {
2476 int ret = GPU_close();
2478 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2481 plat_video_menu_enter(ready_to_go);
2483 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2484 if (pl_vout_buf != NULL && ready_to_go) {
2485 int x = max(0, g_menuscreen_w - last_vout_w);
2486 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2487 int w = min(g_menuscreen_w, last_vout_w);
2488 int h = min(g_menuscreen_h, last_vout_h);
2489 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2490 char *s = pl_vout_buf;
2492 if (last_vout_bpp == 16) {
2493 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2494 menu_darken_bg(d, s, w, 0);
2497 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2498 rgb888_to_rgb565(d, s, w * 3);
2499 menu_darken_bg(d, d, w, 0);
2505 cpu_clock = plat_target_cpu_clock_get();
2508 void menu_prepare_emu(void)
2510 R3000Acpu *prev_cpu = psxCpu;
2512 plat_video_menu_leave();
2514 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2515 if (psxCpu != prev_cpu) {
2516 prev_cpu->Shutdown();
2518 // note that this does not really reset, just clears drc caches
2522 // core doesn't care about Config.Cdda changes,
2523 // so handle them manually here
2529 plat_target_cpu_clock_set(cpu_clock);
2531 // push config to GPU plugin
2532 plugin_call_rearmed_cbs();
2534 if (GPU_open != NULL) {
2535 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2537 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2543 void menu_update_msg(const char *msg)
2545 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2546 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2548 menu_error_time = plat_get_ticks_ms();
2549 lprintf("msg: %s\n", menu_error_msg);
2552 void menu_finish(void)
2554 if (cpu_clock_st > 0)
2555 plat_target_cpu_clock_set(cpu_clock_st);