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, '\\');
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 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, 2),
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_V(iUseReverb, 3),
433 CE_INTVAL_V(iXAPitch, 3),
434 CE_INTVAL_V(iUseInterpolation, 3),
435 CE_INTVAL(config_save_counter),
436 CE_INTVAL(in_evdev_allow_abs_only),
437 CE_INTVAL(volume_boost),
438 CE_INTVAL(psx_clock),
439 CE_INTVAL(new_dynarec_hacks),
440 CE_INTVAL(in_enable_vibration),
443 static char *get_cd_label(void)
445 static char trimlabel[33];
448 strncpy(trimlabel, CdromLabel, 32);
450 for (j = 31; j >= 0; j--)
451 if (trimlabel[j] == ' ')
457 static void make_cfg_fname(char *buf, size_t size, int is_game)
460 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
462 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
465 static void keys_write_all(FILE *f);
466 static char *mystrip(char *str);
468 static int menu_write_config(int is_game)
470 char cfgfile[MAXPATHLEN];
474 config_save_counter++;
476 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
477 f = fopen(cfgfile, "w");
479 printf("menu_write_config: failed to open: %s\n", cfgfile);
483 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
484 fprintf(f, "%s = ", config_data[i].name);
485 switch (config_data[i].len) {
487 fprintf(f, "%s\n", (char *)config_data[i].val);
490 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
493 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
496 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
499 printf("menu_write_config: unhandled len %d for %s\n",
500 (int)config_data[i].len, config_data[i].name);
511 static int menu_do_last_cd_img(int is_get)
513 static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
519 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
520 f = fopen(path, is_get ? "r" : "w");
527 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
528 last_selected_fname[ret] = 0;
529 mystrip(last_selected_fname);
532 fprintf(f, "%s\n", last_selected_fname);
537 for (i = 0; last_selected_fname[0] == 0
538 || stat64(last_selected_fname, &st) != 0; i++)
540 if (i >= ARRAY_SIZE(defaults))
542 strcpy(last_selected_fname, defaults[i]);
549 static void parse_str_val(char *cval, const char *src)
552 strncpy(cval, src, MAXPATHLEN);
553 cval[MAXPATHLEN - 1] = 0;
554 tmp = strchr(cval, '\n');
556 tmp = strchr(cval, '\r');
561 static void keys_load_all(const char *cfg);
563 static int menu_load_config(int is_game)
565 char cfgfile[MAXPATHLEN];
571 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
572 f = fopen(cfgfile, "r");
574 printf("menu_load_config: failed to open: %s\n", cfgfile);
578 fseek(f, 0, SEEK_END);
581 printf("bad size %ld: %s\n", size, cfgfile);
585 cfg = malloc(size + 1);
589 fseek(f, 0, SEEK_SET);
590 if (fread(cfg, 1, size, f) != size) {
591 printf("failed to read: %s\n", cfgfile);
596 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
600 tmp = strstr(cfg, config_data[i].name);
603 tmp += strlen(config_data[i].name);
604 if (strncmp(tmp, " = ", 3) != 0)
608 if (config_data[i].len == 0) {
609 parse_str_val(config_data[i].val, tmp);
614 val = strtoul(tmp, &tmp2, 16);
615 if (tmp2 == NULL || tmp == tmp2)
616 continue; // parse failed
618 switch (config_data[i].len) {
620 *(u8 *)config_data[i].val = val;
623 *(u16 *)config_data[i].val = val;
626 *(u32 *)config_data[i].val = val;
629 printf("menu_load_config: unhandled len %d for %s\n",
630 (int)config_data[i].len, config_data[i].name);
636 char *tmp = strstr(cfg, "lastcdimg = ");
639 parse_str_val(last_selected_fname, tmp);
654 for (i = bios_sel = 0; bioses[i] != NULL; i++)
655 if (strcmp(Config.Bios, bioses[i]) == 0)
656 { bios_sel = i; break; }
658 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
659 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
660 { gpu_plugsel = i; break; }
662 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
663 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
664 { spu_plugsel = i; break; }
669 static const char *filter_exts[] = {
670 "bin", "img", "mdf", "iso", "cue", "z",
671 "bz", "znx", "pbp", "cbn", NULL
674 // rrrr rggg gggb bbbb
675 static unsigned short fname2color(const char *fname)
677 static const char *other_exts[] = {
678 "ccd", "toc", "mds", "sub", "table", "index", "sbi"
680 const char *ext = strrchr(fname, '.');
686 for (i = 0; filter_exts[i] != NULL; i++)
687 if (strcasecmp(ext, filter_exts[i]) == 0)
689 for (i = 0; i < array_size(other_exts); i++)
690 if (strcasecmp(ext, other_exts[i]) == 0)
695 static void draw_savestate_bg(int slot);
697 #define MENU_ALIGN_LEFT
698 #ifdef __ARM_ARCH_7A__ // assume hires device
704 #include "libpicofe/menu.c"
706 // a bit of black magic here
707 static void draw_savestate_bg(int slot)
709 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
711 char fname[MAXPATHLEN];
718 ret = get_state_filename(fname, sizeof(fname), slot);
722 f = gzopen(fname, "rb");
726 if ((ret = (int)gzseek(f, 0x29933d, SEEK_SET)) != 0x29933d) {
727 fprintf(stderr, "gzseek failed: %d\n", ret);
732 gpu = malloc(sizeof(*gpu));
738 ret = gzread(f, gpu, sizeof(*gpu));
740 if (ret != sizeof(*gpu)) {
741 fprintf(stderr, "gzread failed\n");
745 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
747 if (gpu->ulStatus & 0x800000)
748 goto out; // disabled
750 x = gpu->ulControl[5] & 0x3ff;
751 y = (gpu->ulControl[5] >> 10) & 0x1ff;
752 w = psx_widths[(gpu->ulStatus >> 16) & 7];
753 tmp = gpu->ulControl[7];
754 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
755 if (gpu->ulStatus & 0x80000) // doubleheight
757 if (h <= 0 || h > 512)
763 s = (u16 *)gpu->psxVRam + y * 1024 + x;
765 x = max(0, g_menuscreen_w - w) & ~3;
766 y = max(0, g_menuscreen_h / 2 - h / 2);
767 w = min(g_menuscreen_w, w);
768 h = min(g_menuscreen_h, h);
769 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
771 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
772 if (gpu->ulStatus & 0x200000)
773 bgr888_to_rgb565(d, s, w * 3);
775 bgr555_to_rgb565(d, s, w * 2);
777 // darken this so that menu text is visible
778 if (g_menuscreen_w - w < 320)
779 menu_darken_bg(d, d, w * 2, 0);
786 // -------------- key config --------------
788 me_bind_action me_ctrl_actions[] =
790 { "UP ", 1 << DKEY_UP},
791 { "DOWN ", 1 << DKEY_DOWN },
792 { "LEFT ", 1 << DKEY_LEFT },
793 { "RIGHT ", 1 << DKEY_RIGHT },
794 { "TRIANGLE", 1 << DKEY_TRIANGLE },
795 { "CIRCLE ", 1 << DKEY_CIRCLE },
796 { "CROSS ", 1 << DKEY_CROSS },
797 { "SQUARE ", 1 << DKEY_SQUARE },
798 { "L1 ", 1 << DKEY_L1 },
799 { "R1 ", 1 << DKEY_R1 },
800 { "L2 ", 1 << DKEY_L2 },
801 { "R2 ", 1 << DKEY_R2 },
802 { "L3 ", 1 << DKEY_L3 },
803 { "R3 ", 1 << DKEY_R3 },
804 { "START ", 1 << DKEY_START },
805 { "SELECT ", 1 << DKEY_SELECT },
809 me_bind_action emuctrl_actions[] =
811 { "Save State ", 1 << SACTION_SAVE_STATE },
812 { "Load State ", 1 << SACTION_LOAD_STATE },
813 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
814 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
815 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
816 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
817 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
818 #ifdef __ARM_ARCH_7A__
819 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
821 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
822 #if MENU_SHOW_MINIMIZE
823 { "Minimize ", 1 << SACTION_MINIMIZE },
825 #if MENU_SHOW_FULLSCREEN
826 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
828 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
829 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
830 { "Gun A button ", 1 << SACTION_GUN_A },
831 { "Gun B button ", 1 << SACTION_GUN_B },
832 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
834 { "Volume Up ", 1 << SACTION_VOLUME_UP },
835 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
840 static char *mystrip(char *str)
845 for (i = 0; i < len; i++)
846 if (str[i] != ' ') break;
847 if (i > 0) memmove(str, str + i, len - i + 1);
850 for (i = len - 1; i >= 0; i--)
851 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
857 static void get_line(char *d, size_t size, const char *s)
862 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
873 static void keys_write_all(FILE *f)
877 for (d = 0; d < IN_MAX_DEVS; d++)
879 const int *binds = in_get_dev_binds(d);
880 const char *name = in_get_dev_name(d, 0, 0);
883 if (binds == NULL || name == NULL)
886 fprintf(f, "binddev = %s\n", name);
887 in_get_config(d, IN_CFG_BIND_COUNT, &count);
889 for (k = 0; k < count; k++)
894 act[0] = act[31] = 0;
895 name = in_get_key_name(d, k);
897 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
898 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
899 mask = me_ctrl_actions[i].mask;
901 strncpy(act, me_ctrl_actions[i].name, 31);
902 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
905 mask = me_ctrl_actions[i].mask << 16;
907 strncpy(act, me_ctrl_actions[i].name, 31);
908 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
913 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
914 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
915 mask = emuctrl_actions[i].mask;
917 strncpy(act, emuctrl_actions[i].name, 31);
918 fprintf(f, "bind %s = %s\n", name, mystrip(act));
924 for (k = 0; k < array_size(in_adev); k++)
927 fprintf(f, "bind_analog = %d\n", k);
932 static int parse_bind_val(const char *val, int *type)
936 *type = IN_BINDTYPE_NONE;
940 if (strncasecmp(val, "player", 6) == 0)
942 int player, shift = 0;
943 player = atoi(val + 6) - 1;
945 if ((unsigned int)player > 1)
950 *type = IN_BINDTYPE_PLAYER12;
951 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
952 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
953 return me_ctrl_actions[i].mask << shift;
956 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
957 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
958 *type = IN_BINDTYPE_EMU;
959 return emuctrl_actions[i].mask;
966 static void keys_load_all(const char *cfg)
968 char dev[256], key[128], *act;
974 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
977 get_line(dev, sizeof(dev), p);
978 dev_id = in_config_parse_dev(dev);
980 printf("input: can't handle dev: %s\n", dev);
984 in_unbind_all(dev_id, -1, -1);
985 while ((p = strstr(p, "bind"))) {
986 if (strncmp(p, "binddev = ", 10) == 0)
989 if (strncmp(p, "bind_analog", 11) == 0) {
990 ret = sscanf(p, "bind_analog = %d", &bind);
993 printf("input: parse error: %16s..\n", p);
996 if ((unsigned int)bind >= array_size(in_adev)) {
997 printf("input: analog id %d out of range\n", bind);
1000 in_adev[bind] = dev_id;
1006 printf("input: parse error: %16s..\n", p);
1010 get_line(key, sizeof(key), p);
1011 act = strchr(key, '=');
1013 printf("parse failed: %16s..\n", p);
1021 bind = parse_bind_val(act, &bindtype);
1022 if (bind != -1 && bind != 0) {
1023 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
1024 in_config_bind_key(dev_id, key, bind, bindtype);
1027 lprintf("config: unhandled action \"%s\"\n", act);
1033 static int key_config_loop_wrap(int id, int keys)
1036 case MA_CTRL_PLAYER1:
1037 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
1039 case MA_CTRL_PLAYER2:
1040 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
1043 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
1051 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
1052 "Might cause problems with real analog sticks";
1053 static const char *adevnames[IN_MAX_DEVS + 2];
1054 static int stick_sel[2];
1056 static menu_entry e_menu_keyconfig_analog[] =
1058 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
1059 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
1060 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
1061 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
1062 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
1063 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
1064 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
1065 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
1069 static int key_config_analog(int id, int keys)
1071 int i, d, count, sel = 0;
1072 int sel2dev_map[IN_MAX_DEVS];
1074 memset(adevnames, 0, sizeof(adevnames));
1075 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1076 memset(stick_sel, 0, sizeof(stick_sel));
1078 adevnames[0] = "None";
1080 for (d = 0; d < IN_MAX_DEVS; d++)
1082 const char *name = in_get_dev_name(d, 0, 1);
1087 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1091 if (in_adev[0] == d) stick_sel[0] = i;
1092 if (in_adev[1] == d) stick_sel[1] = i;
1094 adevnames[i++] = name;
1096 adevnames[i] = NULL;
1098 me_loop(e_menu_keyconfig_analog, &sel);
1100 in_adev[0] = sel2dev_map[stick_sel[0]];
1101 in_adev[1] = sel2dev_map[stick_sel[1]];
1106 static const char *mgn_dev_name(int id, int *offs)
1108 const char *name = NULL;
1111 if (id == MA_CTRL_DEV_FIRST)
1114 for (; it < IN_MAX_DEVS; it++) {
1115 name = in_get_dev_name(it, 1, 1);
1124 static const char *mgn_saveloadcfg(int id, int *offs)
1129 static int mh_savecfg(int id, int keys)
1131 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1132 menu_update_msg("config saved");
1134 menu_update_msg("failed to write config");
1139 static int mh_input_rescan(int id, int keys)
1141 //menu_sync_config();
1143 menu_update_msg("rescan complete.");
1148 static const char *men_in_type_sel[] = {
1149 "Standard (SCPH-1080)",
1150 "Analog (SCPH-1150)",
1154 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1155 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1156 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1158 static menu_entry e_menu_keyconfig[] =
1160 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1161 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1162 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1163 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1165 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1166 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1167 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1168 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1169 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1170 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1171 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1172 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1173 mee_handler ("Rescan devices:", mh_input_rescan),
1175 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1176 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1185 static int menu_loop_keyconfig(int id, int keys)
1189 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1190 me_loop(e_menu_keyconfig, &sel);
1194 // ------------ gfx options menu ------------
1196 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1197 static const char *men_soft_filter[] = { "None",
1199 "scale2x", "eagle2x",
1202 static const char *men_dummy[] = { NULL };
1203 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1204 "using d-pad or move it using R+d-pad";
1205 static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
1206 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1207 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1209 static int menu_loop_cscaler(int id, int keys)
1213 g_scaler = SCALE_CUSTOM;
1215 plat_gvideo_open(Config.PsxType);
1219 menu_draw_begin(0, 1);
1220 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1221 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1222 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1225 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1226 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1227 if (inp & PBTN_UP) g_layer_y--;
1228 if (inp & PBTN_DOWN) g_layer_y++;
1229 if (inp & PBTN_LEFT) g_layer_x--;
1230 if (inp & PBTN_RIGHT) g_layer_x++;
1231 if (!(inp & PBTN_R)) {
1232 if (inp & PBTN_UP) g_layer_h += 2;
1233 if (inp & PBTN_DOWN) g_layer_h -= 2;
1234 if (inp & PBTN_LEFT) g_layer_w += 2;
1235 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1237 if (inp & (PBTN_MOK|PBTN_MBACK))
1240 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1241 if (g_layer_x < 0) g_layer_x = 0;
1242 if (g_layer_x > 640) g_layer_x = 640;
1243 if (g_layer_y < 0) g_layer_y = 0;
1244 if (g_layer_y > 420) g_layer_y = 420;
1245 if (g_layer_w < 160) g_layer_w = 160;
1246 if (g_layer_h < 60) g_layer_h = 60;
1247 if (g_layer_x + g_layer_w > 800)
1248 g_layer_w = 800 - g_layer_x;
1249 if (g_layer_y + g_layer_h > 480)
1250 g_layer_h = 480 - g_layer_y;
1252 plat_gvideo_open(Config.PsxType);
1256 plat_gvideo_close();
1261 static menu_entry e_menu_gfx_options[] =
1263 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1264 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1265 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1266 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1267 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1268 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1269 // mee_onoff ("Vsync", 0, vsync, 1),
1270 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1274 static int menu_loop_gfx_options(int id, int keys)
1278 me_loop(e_menu_gfx_options, &sel);
1283 // ------------ bios/plugins ------------
1287 static const char h_gpu_neon[] =
1288 "Configure built-in NEON GPU plugin";
1289 static const char h_gpu_neon_enhanced[] =
1290 "Renders in double resolution at the cost of lower performance\n"
1291 "(not available for high resolution games)";
1292 static const char h_gpu_neon_enhanced_hack[] =
1293 "Speed hack for above option (glitches some games)";
1294 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1296 static menu_entry e_menu_plugin_gpu_neon[] =
1298 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1299 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1300 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1304 static int menu_loop_plugin_gpu_neon(int id, int keys)
1307 me_loop(e_menu_plugin_gpu_neon, &sel);
1313 static menu_entry e_menu_plugin_gpu_unai[] =
1315 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1316 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1317 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1318 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1322 static int menu_loop_plugin_gpu_unai(int id, int keys)
1325 me_loop(e_menu_plugin_gpu_unai, &sel);
1329 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1330 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1331 static const char h_gpu_1[] = "Capcom fighting games";
1332 static const char h_gpu_2[] = "Black screens in Lunar";
1333 static const char h_gpu_3[] = "Compatibility mode";
1334 static const char h_gpu_6[] = "Pandemonium 2";
1335 //static const char h_gpu_7[] = "Skip every second frame";
1336 static const char h_gpu_8[] = "Needed by Dark Forces";
1337 static const char h_gpu_9[] = "better g-colors, worse textures";
1338 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1340 static menu_entry e_menu_plugin_gpu_peops[] =
1342 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1343 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1344 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1345 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1346 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1347 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1348 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1349 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1350 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1351 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1355 static int menu_loop_plugin_gpu_peops(int id, int keys)
1358 me_loop(e_menu_plugin_gpu_peops, &sel);
1362 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1363 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1364 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1366 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1368 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1369 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1370 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1371 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1372 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1373 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1374 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1375 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1376 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1377 mee_label ("Fixes/hacks:"),
1378 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1379 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1380 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1381 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1382 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1383 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1384 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1385 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1386 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1387 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1388 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1392 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1395 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1399 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1400 static const char h_spu_volboost[] = "Large values cause distortion";
1402 static menu_entry e_menu_plugin_spu[] =
1404 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1405 mee_onoff ("Reverb", 0, iUseReverb, 2),
1406 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1407 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1411 static int menu_loop_plugin_spu(int id, int keys)
1414 me_loop(e_menu_plugin_spu, &sel);
1418 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1419 "savestates and can't be changed there. Must save\n"
1420 "config and reload the game for change to take effect";
1421 static const char h_plugin_gpu[] =
1423 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1425 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1426 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1427 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1428 "must save config and reload the game if changed";
1429 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1430 "must save config and reload the game if changed";
1431 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1432 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1433 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1434 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1436 static menu_entry e_menu_plugin_options[] =
1438 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1439 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1440 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1442 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1444 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1445 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1446 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1447 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1451 static menu_entry e_menu_main2[];
1453 static int menu_loop_plugin_options(int id, int keys)
1456 me_loop(e_menu_plugin_options, &sel);
1458 // sync BIOS/plugins
1459 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1460 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1461 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1462 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1467 // ------------ adv options menu ------------
1469 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1470 "(lower value - less work for the emu, may be faster)";
1471 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1472 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1473 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1475 static menu_entry e_menu_speed_hacks[] =
1477 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1478 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1479 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1480 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1484 static int menu_loop_speed_hacks(int id, int keys)
1487 me_loop(e_menu_speed_hacks, &sel);
1491 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1492 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1493 "(green: normal, red: fmod, blue: noise)";
1494 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1495 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1496 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1497 "(proper .cue/.bin dump is needed otherwise)";
1498 static const char h_cfg_sio[] = "You should not need this, breaks games";
1499 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1500 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1501 "(timing hack, breaks other games)";
1502 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1503 "(timing hack, breaks other games)";
1504 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1505 "Might be useful to overcome some dynarec bugs";
1506 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1507 "must reload game for any change to take effect";
1509 static menu_entry e_menu_adv_options[] =
1511 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1512 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1513 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1514 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1515 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1516 //mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1517 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1518 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1519 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1520 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1521 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1525 static int menu_loop_adv_options(int id, int keys)
1528 me_loop(e_menu_adv_options, &sel);
1532 // ------------ options menu ------------
1534 static int mh_restore_defaults(int id, int keys)
1536 menu_set_defconfig();
1537 menu_update_msg("defaults restored");
1541 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1542 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1544 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1545 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1546 "loading state or both";
1548 static const char h_restore_def[] = "Switches back to default / recommended\n"
1550 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1552 static menu_entry e_menu_options[] =
1554 // mee_range ("Save slot", 0, state_slot, 0, 9),
1555 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1556 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1557 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1558 mee_enum ("Region", 0, region, men_region),
1559 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1560 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1561 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1562 mee_handler ("[Advanced]", menu_loop_adv_options),
1563 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1564 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1565 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1569 static int menu_loop_options(int id, int keys)
1574 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1575 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1576 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1578 me_loop(e_menu_options, &sel);
1583 // ------------ debug menu ------------
1585 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1587 int w = min(g_menuscreen_w, 1024);
1588 int h = min(g_menuscreen_h, 512);
1589 u16 *d = g_menuscreen_ptr;
1590 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1594 gpuf->ulFreezeVersion = 1;
1595 if (GPU_freeze != NULL)
1596 GPU_freeze(1, gpuf);
1598 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1599 bgr555_to_rgb565(d, s, w * 2);
1601 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1602 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1603 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1604 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1605 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1608 static void debug_menu_loop(void)
1610 int inp, df_x = 0, df_y = 0;
1613 gpuf = malloc(sizeof(*gpuf));
1619 menu_draw_begin(0, 1);
1620 draw_frame_debug(gpuf, df_x, df_y);
1623 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1624 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1625 if (inp & PBTN_MBACK) break;
1626 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1627 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1628 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1629 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1635 // --------- memcard manager ---------
1637 static void draw_mc_icon(int dx, int dy, const u16 *s)
1642 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1644 for (y = 0; y < 16; y++, s += 16) {
1645 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1646 for (x = 0; x < 16; x++) {
1648 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1649 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1655 static void draw_mc_bg(void)
1657 McdBlock *blocks1, *blocks2;
1661 blocks1 = malloc(15 * sizeof(blocks1[0]));
1662 blocks2 = malloc(15 * sizeof(blocks1[0]));
1663 if (blocks1 == NULL || blocks2 == NULL)
1666 for (i = 0; i < 15; i++) {
1667 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1668 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1671 menu_draw_begin(1, 1);
1673 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1675 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1679 maxicons = g_menuscreen_h / 32;
1682 row2 = g_menuscreen_w / 2;
1683 for (i = 0; i < maxicons; i++) {
1684 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1685 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1687 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1688 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1691 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1699 static void handle_memcard_sel(void)
1702 if (memcard1_sel != 0)
1703 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1705 if (memcard2_sel != 0)
1706 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1707 LoadMcds(Config.Mcd1, Config.Mcd2);
1711 static menu_entry e_memcard_options[] =
1713 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1714 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1718 static int menu_loop_memcards(int id, int keys)
1724 memcard1_sel = memcard2_sel = 0;
1725 p = strrchr(Config.Mcd1, '/');
1727 for (i = 0; memcards[i] != NULL; i++)
1728 if (strcmp(p + 1, memcards[i]) == 0)
1729 { memcard1_sel = i; break; }
1730 p = strrchr(Config.Mcd2, '/');
1732 for (i = 0; memcards[i] != NULL; i++)
1733 if (strcmp(p + 1, memcards[i]) == 0)
1734 { memcard2_sel = i; break; }
1736 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1738 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1743 // ------------ cheats menu ------------
1745 static void draw_cheatlist(int sel)
1747 int max_cnt, start, i, pos, active;
1749 max_cnt = g_menuscreen_h / me_sfont_h;
1750 start = max_cnt / 2 - sel;
1752 menu_draw_begin(1, 1);
1754 for (i = 0; i < NumCheats; i++) {
1756 if (pos < 0) continue;
1757 if (pos >= max_cnt) break;
1758 active = Cheats[i].Enabled;
1759 smalltext_out16(14, pos * me_sfont_h,
1760 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1761 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1762 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1766 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1768 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1772 static void menu_loop_cheats(void)
1774 static int menu_sel = 0;
1779 draw_cheatlist(menu_sel);
1780 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1781 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1782 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1783 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1784 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1785 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1786 if (inp & PBTN_MOK) { // action
1787 if (menu_sel < NumCheats)
1788 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1791 if (inp & PBTN_MBACK)
1796 // --------- main menu help ----------
1798 static void menu_bios_warn(void)
1801 static const char msg[] =
1802 "You don't seem to have copied any BIOS\n"
1804 MENU_BIOS_PATH "\n\n"
1806 "While many games work fine with fake\n"
1807 "(HLE) BIOS, others (like MGS and FF8)\n"
1808 "require BIOS to work.\n"
1809 "After copying the file, you'll also need\n"
1810 "to select it in the emu's menu:\n"
1811 "options->[BIOS/Plugins]\n\n"
1812 "The file is usually named SCPH1001.BIN,\n"
1813 "but other not compressed files can be\n"
1815 "Press %s or %s to continue";
1816 char tmp_msg[sizeof(msg) + 64];
1818 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1819 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1822 draw_menu_message(tmp_msg, NULL);
1824 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1825 if (inp & (PBTN_MBACK|PBTN_MOK))
1830 // ------------ main menu ------------
1832 static menu_entry e_menu_main[];
1835 static void draw_frame_main(void)
1844 if (CdromId[0] != 0) {
1845 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1846 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1847 Config.HLE ? "HLE" : "BIOS");
1848 smalltext_out16(4, 1, buff, 0x105f);
1852 capacity = plat_target_bat_capacity_get();
1854 tmp = localtime(<ime);
1855 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1856 if (capacity >= 0) {
1857 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1862 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1866 static void draw_frame_credits(void)
1868 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1871 static const char credits_text[] =
1873 "(C) 1999-2003 PCSX Team\n"
1874 "(C) 2005-2009 PCSX-df Team\n"
1875 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1876 "ARM recompiler (C) 2009-2011 Ari64\n"
1878 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1880 "PEOpS GPU and SPU by Pete Bernert\n"
1881 " and the P.E.Op.S. team\n"
1882 "PCSX4ALL plugin by PCSX4ALL team\n"
1883 " Chui, Franxis, Unai\n\n"
1884 "integration, optimization and\n"
1885 " frontend (C) 2010-2012 notaz\n";
1887 static int reset_game(void)
1890 if (bios_sel == 0 && !Config.HLE)
1896 if (CheckCdrom() != -1) {
1902 static int reload_plugins(const char *cdimg)
1908 set_cd_image(cdimg);
1910 pcnt_hook_plugins();
1912 if (OpenPlugins() == -1) {
1913 menu_update_msg("failed to open plugins");
1916 plugin_call_rearmed_cbs();
1918 cdrIsoMultidiskCount = 1;
1920 CdromLabel[0] = '\0';
1925 static int run_bios(void)
1931 if (reload_plugins(NULL) != 0)
1939 static int run_exe(void)
1941 const char *exts[] = { "exe", NULL };
1944 fname = menu_loop_romsel(last_selected_fname,
1945 sizeof(last_selected_fname), exts, NULL);
1950 if (reload_plugins(NULL) != 0)
1954 if (Load(fname) != 0) {
1955 menu_update_msg("exe load failed, bad file?");
1964 static int run_cd_image(const char *fname)
1967 reload_plugins(fname);
1969 // always autodetect, menu_sync_config will override as needed
1972 if (CheckCdrom() == -1) {
1973 // Only check the CD if we are starting the console with a CD
1975 menu_update_msg("unsupported/invalid CD image");
1981 // Read main executable directly from CDRom and start it
1982 if (LoadCdrom() == -1) {
1984 menu_update_msg("failed to load CD image");
1994 static int romsel_run(void)
1996 int prev_gpu, prev_spu;
1999 fname = menu_loop_romsel(last_selected_fname,
2000 sizeof(last_selected_fname), filter_exts,
2001 optional_cdimg_filter);
2005 printf("selected file: %s\n", fname);
2007 new_dynarec_clear_full();
2009 if (run_cd_image(fname) != 0)
2012 prev_gpu = gpu_plugsel;
2013 prev_spu = spu_plugsel;
2014 if (menu_load_config(1) != 0)
2015 menu_load_config(0);
2017 // check for plugin changes, have to repeat
2018 // loading if game config changed plugins to reload them
2019 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
2020 printf("plugin change detected, reloading plugins..\n");
2021 if (run_cd_image(fname) != 0)
2025 strcpy(last_selected_fname, fname);
2026 menu_do_last_cd_img(0);
2030 static int swap_cd_image(void)
2034 fname = menu_loop_romsel(last_selected_fname,
2035 sizeof(last_selected_fname), filter_exts,
2036 optional_cdimg_filter);
2040 printf("selected file: %s\n", fname);
2043 CdromLabel[0] = '\0';
2045 set_cd_image(fname);
2046 if (ReloadCdromPlugin() < 0) {
2047 menu_update_msg("failed to load cdr plugin");
2050 if (CDR_open() < 0) {
2051 menu_update_msg("failed to open cdr plugin");
2055 SetCdOpenCaseTime(time(NULL) + 2);
2058 strcpy(last_selected_fname, fname);
2062 static int swap_cd_multidisk(void)
2064 cdrIsoMultidiskSelect++;
2066 CdromLabel[0] = '\0';
2069 if (CDR_open() < 0) {
2070 menu_update_msg("failed to open cdr plugin");
2074 SetCdOpenCaseTime(time(NULL) + 2);
2080 static void load_pcsx_cht(void)
2082 const char *exts[] = { "cht", NULL };
2087 fname = menu_loop_romsel(path, sizeof(path), exts, NULL);
2091 printf("selected cheat file: %s\n", fname);
2094 if (NumCheats == 0 && NumCodes == 0)
2095 menu_update_msg("failed to load cheats");
2097 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
2098 menu_update_msg(path);
2100 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2103 static int main_menu_handler(int id, int keys)
2107 case MA_MAIN_RESUME_GAME:
2111 case MA_MAIN_SAVE_STATE:
2113 return menu_loop_savestate(0);
2115 case MA_MAIN_LOAD_STATE:
2117 return menu_loop_savestate(1);
2119 case MA_MAIN_RESET_GAME:
2120 if (ready_to_go && reset_game() == 0)
2123 case MA_MAIN_LOAD_ROM:
2124 if (romsel_run() == 0)
2127 case MA_MAIN_SWAP_CD:
2128 if (swap_cd_image() == 0)
2131 case MA_MAIN_SWAP_CD_MULTI:
2132 if (swap_cd_multidisk() == 0)
2135 case MA_MAIN_RUN_BIOS:
2136 if (run_bios() == 0)
2139 case MA_MAIN_RUN_EXE:
2143 case MA_MAIN_CHEATS:
2146 case MA_MAIN_LOAD_CHEATS:
2149 case MA_MAIN_CREDITS:
2150 draw_menu_message(credits_text, draw_frame_credits);
2151 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2157 lprintf("%s: something unknown selected\n", __FUNCTION__);
2164 static menu_entry e_menu_main2[] =
2166 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2167 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2168 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2169 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2170 mee_handler ("Memcard manager", menu_loop_memcards),
2171 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2175 static int main_menu2_handler(int id, int keys)
2179 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2180 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2181 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2182 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2184 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2187 static const char h_extra[] = "Change CD, manage memcards..\n";
2189 static menu_entry e_menu_main[] =
2193 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2194 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2195 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2196 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2197 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2198 mee_handler ("Options", menu_loop_options),
2199 mee_handler ("Controls", menu_loop_keyconfig),
2200 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2201 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2202 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2203 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2207 // ----------------------------
2209 static void menu_leave_emu(void);
2211 void menu_loop(void)
2213 static int warned_about_bios = 0;
2218 if (config_save_counter == 0) {
2220 if (bioses[1] != NULL) {
2221 // autoselect BIOS to make user's life easier
2222 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2225 else if (!warned_about_bios) {
2227 warned_about_bios = 1;
2231 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2232 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2233 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2234 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2235 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2237 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2240 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2241 } while (!ready_to_go);
2243 /* wait until menu, ok, back is released */
2244 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2247 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2252 static int qsort_strcmp(const void *p1, const void *p2)
2254 char * const *s1 = (char * const *)p1;
2255 char * const *s2 = (char * const *)p2;
2256 return strcasecmp(*s1, *s2);
2259 static void scan_bios_plugins(void)
2261 char fname[MAXPATHLEN];
2263 int bios_i, gpu_i, spu_i, mc_i;
2268 gpu_plugins[0] = "builtin_gpu";
2269 spu_plugins[0] = "builtin_spu";
2270 memcards[0] = "(none)";
2271 bios_i = gpu_i = spu_i = mc_i = 1;
2273 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2274 dir = opendir(fname);
2276 perror("scan_bios_plugins bios opendir");
2291 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2294 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2295 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2296 printf("bad BIOS file: %s\n", ent->d_name);
2300 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2301 bioses[bios_i++] = strdup(ent->d_name);
2305 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2311 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2312 dir = opendir(fname);
2314 perror("scan_bios_plugins plugins opendir");
2328 p = strstr(ent->d_name, ".so");
2332 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2333 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2335 fprintf(stderr, "%s\n", dlerror());
2339 // now what do we have here?
2340 tmp = dlsym(h, "GPUinit");
2343 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2344 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2348 tmp = dlsym(h, "SPUinit");
2351 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2352 spu_plugins[spu_i++] = strdup(ent->d_name);
2356 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2363 dir = opendir("." MEMCARD_DIR);
2365 perror("scan_bios_plugins memcards opendir");
2380 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2383 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2384 if (stat(fname, &st) != 0) {
2385 printf("bad memcard file: %s\n", ent->d_name);
2389 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2390 memcards[mc_i++] = strdup(ent->d_name);
2394 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2398 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2403 void menu_init(void)
2405 char buff[MAXPATHLEN];
2408 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2410 scan_bios_plugins();
2413 menu_set_defconfig();
2414 menu_load_config(0);
2415 menu_do_last_cd_img(1);
2420 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2421 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2422 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2423 fprintf(stderr, "OOM\n");
2427 emu_make_path(buff, "skin/background.png", sizeof(buff));
2428 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2430 i = plat_target.cpu_clock_set != NULL
2431 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2432 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2434 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2435 e_menu_gfx_options[i].data = plat_target.vout_methods;
2436 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2437 plat_target.vout_methods != NULL);
2439 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2440 e_menu_gfx_options[i].data = plat_target.hwfilters;
2441 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2442 plat_target.hwfilters != NULL);
2444 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2445 plat_target.gamma_set != NULL);
2447 #ifndef __ARM_ARCH_7A__
2448 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2450 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2451 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2452 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2453 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2454 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2455 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2456 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2459 void menu_notify_mode_change(int w, int h, int bpp)
2463 last_vout_bpp = bpp;
2466 static void menu_leave_emu(void)
2468 if (GPU_close != NULL) {
2469 int ret = GPU_close();
2471 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2474 plat_video_menu_enter(ready_to_go);
2476 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2477 if (pl_vout_buf != NULL && ready_to_go) {
2478 int x = max(0, g_menuscreen_w - last_vout_w);
2479 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2480 int w = min(g_menuscreen_w, last_vout_w);
2481 int h = min(g_menuscreen_h, last_vout_h);
2482 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2483 char *s = pl_vout_buf;
2485 if (last_vout_bpp == 16) {
2486 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2487 menu_darken_bg(d, s, w, 0);
2490 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2491 rgb888_to_rgb565(d, s, w * 3);
2492 menu_darken_bg(d, d, w, 0);
2498 cpu_clock = plat_target_cpu_clock_get();
2501 void menu_prepare_emu(void)
2503 R3000Acpu *prev_cpu = psxCpu;
2505 plat_video_menu_leave();
2507 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2508 if (psxCpu != prev_cpu) {
2509 prev_cpu->Shutdown();
2511 // note that this does not really reset, just clears drc caches
2515 // core doesn't care about Config.Cdda changes,
2516 // so handle them manually here
2522 plat_target_cpu_clock_set(cpu_clock);
2524 // push config to GPU plugin
2525 plugin_call_rearmed_cbs();
2527 if (GPU_open != NULL) {
2528 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2530 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2536 void menu_update_msg(const char *msg)
2538 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2539 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2541 menu_error_time = plat_get_ticks_ms();
2542 lprintf("msg: %s\n", menu_error_msg);
2545 void menu_finish(void)
2547 if (cpu_clock_st > 0)
2548 plat_target_cpu_clock_set(cpu_clock_st);