2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2015
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"
42 #include "arm_features.h"
45 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
47 #define array_size(x) (sizeof(x) / sizeof(x[0]))
58 MA_MAIN_SWAP_CD_MULTI,
89 MA_OPT_SCANLINE_LEVEL,
92 static int last_vout_w, last_vout_h, last_vout_bpp;
93 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
94 static char last_selected_fname[MAXPATHLEN];
95 static int config_save_counter, region, in_type_sel1, in_type_sel2;
97 static int memcard1_sel = -1, memcard2_sel = -1;
98 extern int g_autostateld_opt;
99 static int menu_iopts[8];
100 int g_opts, g_scaler, g_gamma = 100;
101 int scanlines, scanline_level = 20;
102 int soft_scaling, analog_deadzone; // for Caanoo
105 #ifndef HAVE_PRE_ARMV7
106 #define DEFAULT_PSX_CLOCK (10000 / CYCLE_MULT_DEFAULT)
107 #define DEFAULT_PSX_CLOCK_S "57"
109 #define DEFAULT_PSX_CLOCK 50
110 #define DEFAULT_PSX_CLOCK_S "50"
113 static const char *bioses[24];
114 static const char *gpu_plugins[16];
115 static const char *spu_plugins[16];
116 static const char *memcards[32];
117 static int bios_sel, gpu_plugsel, spu_plugsel;
119 #ifndef UI_FEATURES_H
120 #define MENU_BIOS_PATH "bios/"
121 #define MENU_SHOW_VARSCALER 0
122 #define MENU_SHOW_VOUTMODE 1
123 #define MENU_SHOW_SCALER2 0
124 #define MENU_SHOW_NUBS_BTNS 0
125 #define MENU_SHOW_VIBRATION 0
126 #define MENU_SHOW_DEADZONE 0
127 #define MENU_SHOW_MINIMIZE 0
128 #define MENU_SHOW_FULLSCREEN 1
129 #define MENU_SHOW_VOLUME 0
132 static int min(int x, int y) { return x < y ? x : y; }
133 static int max(int x, int y) { return x > y ? x : y; }
135 void emu_make_path(char *buff, const char *end, int size)
139 end_len = strlen(end);
140 pos = plat_get_root_dir(buff, size);
141 strncpy(buff + pos, end, size - pos);
143 if (pos + end_len > size - 1)
144 printf("Warning: path truncated: %s\n", buff);
147 static int emu_check_save_file(int slot, int *time)
149 char fname[MAXPATHLEN];
153 ret = emu_check_state(slot);
154 if (ret != 0 || time == NULL)
155 return ret == 0 ? 1 : 0;
157 ret = get_state_filename(fname, sizeof(fname), slot);
161 ret = stat(fname, &status);
165 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
166 return 1; // probably bad rtc like on some Caanoos
168 *time = status.st_mtime;
173 static int emu_save_load_game(int load, int unused)
178 ret = emu_load_state(state_slot);
180 // reflect hle/bios mode from savestate
183 else if (bios_sel == 0 && bioses[1] != NULL)
184 // XXX: maybe find the right bios instead
188 ret = emu_save_state(state_slot);
193 static void rm_namelist_entry(struct dirent **namelist,
194 int count, const char *name)
198 for (i = 1; i < count; i++) {
199 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
202 if (strcmp(name, namelist[i]->d_name) == 0) {
210 static int optional_cdimg_filter(struct dirent **namelist, int count,
214 char buf[256], buf2[256];
215 int i, d, ret, good_cue;
222 for (i = 1; i < count; i++) {
223 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
226 ext = strrchr(namelist[i]->d_name, '.');
228 // should not happen but whatever
235 // first find .cue files and remove files they reference
236 if (strcasecmp(ext, "cue") == 0)
238 snprintf(buf, sizeof(buf), "%s/%s", basedir,
239 namelist[i]->d_name);
249 while (fgets(buf, sizeof(buf), f)) {
250 ret = sscanf(buf, " FILE \"%256[^\"]\"", buf2);
252 ret = sscanf(buf, " FILE %256s", buf2);
256 p = strrchr(buf2, '/');
258 p = strrchr(buf2, '\\');
264 snprintf(buf, sizeof(buf), "%s/%s", basedir, p);
265 ret = stat64(buf, &statf);
267 rm_namelist_entry(namelist, count, p);
280 p = strcasestr(namelist[i]->d_name, "track");
282 ret = strtoul(p + 5, NULL, 10);
292 for (i = d = 1; i < count; i++)
293 if (namelist[i] != NULL)
294 namelist[d++] = namelist[i];
299 // propagate menu settings to the emu vars
300 static void menu_sync_config(void)
302 static int allow_abs_only_old;
307 Config.PsxType = region - 1;
309 Config.cycle_multiplier = 10000 / psx_clock;
311 switch (in_type_sel1) {
312 case 1: in_type[0] = PSE_PAD_TYPE_ANALOGPAD; break;
313 case 2: in_type[0] = PSE_PAD_TYPE_NEGCON; break;
314 default: in_type[0] = PSE_PAD_TYPE_STANDARD;
316 switch (in_type_sel2) {
317 case 1: in_type[1] = PSE_PAD_TYPE_ANALOGPAD; break;
318 case 2: in_type[1] = PSE_PAD_TYPE_NEGCON; break;
319 default: in_type[1] = PSE_PAD_TYPE_STANDARD;
321 if (in_evdev_allow_abs_only != allow_abs_only_old) {
323 allow_abs_only_old = in_evdev_allow_abs_only;
326 spu_config.iVolume = 768 + 128 * volume_boost;
327 pl_rearmed_cbs.frameskip = frameskip - 1;
328 pl_timing_prepare(Config.PsxType);
331 static void menu_set_defconfig(void)
333 emu_set_default_config();
336 g_scaler = SCALE_4_3;
340 analog_deadzone = 50;
345 plat_target.vout_fullscreen = 0;
346 psx_clock = DEFAULT_PSX_CLOCK;
349 in_type_sel1 = in_type_sel2 = 0;
350 in_evdev_allow_abs_only = 0;
355 #define CE_CONFIG_STR(val) \
356 { #val, 0, Config.val }
358 #define CE_CONFIG_VAL(val) \
359 { #val, sizeof(Config.val), &Config.val }
361 #define CE_STR(val) \
364 #define CE_INTVAL(val) \
365 { #val, sizeof(val), &val }
367 #define CE_INTVAL_N(name, val) \
368 { name, sizeof(val), &val }
370 #define CE_INTVAL_P(val) \
371 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
373 // 'versioned' var, used when defaults change
374 #define CE_CONFIG_STR_V(val, ver) \
375 { #val #ver, 0, Config.val }
377 #define CE_INTVAL_V(val, ver) \
378 { #val #ver, sizeof(val), &val }
380 #define CE_INTVAL_PV(val, ver) \
381 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
383 static const struct {
389 CE_CONFIG_STR_V(Gpu, 3),
391 // CE_CONFIG_STR(Cdr),
395 CE_CONFIG_VAL(Debug),
396 CE_CONFIG_VAL(PsxOut),
397 CE_CONFIG_VAL(icache_emulation),
398 CE_CONFIG_VAL(DisableStalls),
401 CE_INTVAL_V(g_scaler, 3),
403 CE_INTVAL(g_layer_x),
404 CE_INTVAL(g_layer_y),
405 CE_INTVAL(g_layer_w),
406 CE_INTVAL(g_layer_h),
407 CE_INTVAL(soft_filter),
408 CE_INTVAL(scanlines),
409 CE_INTVAL(scanline_level),
410 CE_INTVAL(plat_target.vout_method),
411 CE_INTVAL(plat_target.hwfilter),
412 CE_INTVAL(plat_target.vout_fullscreen),
413 CE_INTVAL(state_slot),
414 CE_INTVAL(cpu_clock),
416 CE_INTVAL(in_type_sel1),
417 CE_INTVAL(in_type_sel2),
418 CE_INTVAL(analog_deadzone),
419 CE_INTVAL(memcard1_sel),
420 CE_INTVAL(memcard2_sel),
421 CE_INTVAL(g_autostateld_opt),
422 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
423 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
424 CE_INTVAL_V(frameskip, 3),
425 CE_INTVAL_P(gpu_peops.iUseDither),
426 CE_INTVAL_P(gpu_peops.dwActFixes),
427 CE_INTVAL_P(gpu_unai.lineskip),
428 CE_INTVAL_P(gpu_unai.abe_hack),
429 CE_INTVAL_P(gpu_unai.no_light),
430 CE_INTVAL_P(gpu_unai.no_blend),
431 CE_INTVAL_P(gpu_senquack.ilace_force),
432 CE_INTVAL_P(gpu_senquack.pixel_skip),
433 CE_INTVAL_P(gpu_senquack.lighting),
434 CE_INTVAL_P(gpu_senquack.fast_lighting),
435 CE_INTVAL_P(gpu_senquack.blending),
436 CE_INTVAL_P(gpu_senquack.dithering),
437 CE_INTVAL_P(gpu_senquack.scale_hires),
438 CE_INTVAL_P(gpu_neon.allow_interlace),
439 CE_INTVAL_P(gpu_neon.enhancement_enable),
440 CE_INTVAL_P(gpu_neon.enhancement_no_main),
441 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
442 CE_INTVAL_P(gpu_peopsgl.iFilterType),
443 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
444 CE_INTVAL_P(gpu_peopsgl.iUseMask),
445 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
446 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
447 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
448 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
449 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
450 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
451 CE_INTVAL(spu_config.iUseReverb),
452 CE_INTVAL(spu_config.iXAPitch),
453 CE_INTVAL(spu_config.iUseInterpolation),
454 CE_INTVAL(spu_config.iTempo),
455 CE_INTVAL(spu_config.iUseThread),
456 CE_INTVAL(config_save_counter),
457 CE_INTVAL(in_evdev_allow_abs_only),
458 CE_INTVAL(volume_boost),
459 CE_INTVAL(psx_clock),
460 CE_INTVAL(new_dynarec_hacks),
461 CE_INTVAL(in_enable_vibration),
464 static char *get_cd_label(void)
466 static char trimlabel[33];
469 strncpy(trimlabel, CdromLabel, 32);
471 for (j = 31; j >= 0; j--)
472 if (trimlabel[j] == ' ')
478 static void make_cfg_fname(char *buf, size_t size, int is_game)
481 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
483 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
486 static void keys_write_all(FILE *f);
487 static char *mystrip(char *str);
489 static int menu_write_config(int is_game)
491 char cfgfile[MAXPATHLEN];
495 config_save_counter++;
497 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
498 f = fopen(cfgfile, "w");
500 printf("menu_write_config: failed to open: %s\n", cfgfile);
504 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
505 fprintf(f, "%s = ", config_data[i].name);
506 switch (config_data[i].len) {
508 fprintf(f, "%s\n", (char *)config_data[i].val);
511 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
514 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
517 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
520 printf("menu_write_config: unhandled len %d for %s\n",
521 (int)config_data[i].len, config_data[i].name);
532 static int menu_do_last_cd_img(int is_get)
534 static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
540 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
541 f = fopen(path, is_get ? "r" : "w");
548 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
549 last_selected_fname[ret] = 0;
550 mystrip(last_selected_fname);
553 fprintf(f, "%s\n", last_selected_fname);
558 for (i = 0; last_selected_fname[0] == 0
559 || stat64(last_selected_fname, &st) != 0; i++)
561 if (i >= ARRAY_SIZE(defaults))
563 strcpy(last_selected_fname, defaults[i]);
570 static void parse_str_val(char *cval, const char *src)
573 strncpy(cval, src, MAXPATHLEN);
574 cval[MAXPATHLEN - 1] = 0;
575 tmp = strchr(cval, '\n');
577 tmp = strchr(cval, '\r');
582 static void keys_load_all(const char *cfg);
584 static int menu_load_config(int is_game)
586 char cfgfile[MAXPATHLEN];
592 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
593 f = fopen(cfgfile, "r");
595 printf("menu_load_config: failed to open: %s\n", cfgfile);
599 fseek(f, 0, SEEK_END);
602 printf("bad size %ld: %s\n", size, cfgfile);
606 cfg = malloc(size + 1);
610 fseek(f, 0, SEEK_SET);
611 if (fread(cfg, 1, size, f) != size) {
612 printf("failed to read: %s\n", cfgfile);
617 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
621 tmp = strstr(cfg, config_data[i].name);
624 tmp += strlen(config_data[i].name);
625 if (strncmp(tmp, " = ", 3) != 0)
629 if (config_data[i].len == 0) {
630 parse_str_val(config_data[i].val, tmp);
635 val = strtoul(tmp, &tmp2, 16);
636 if (tmp2 == NULL || tmp == tmp2)
637 continue; // parse failed
639 switch (config_data[i].len) {
641 *(u8 *)config_data[i].val = val;
644 *(u16 *)config_data[i].val = val;
647 *(u32 *)config_data[i].val = val;
650 printf("menu_load_config: unhandled len %d for %s\n",
651 (int)config_data[i].len, config_data[i].name);
657 char *tmp = strstr(cfg, "lastcdimg = ");
660 parse_str_val(last_selected_fname, tmp);
675 for (i = bios_sel = 0; bioses[i] != NULL; i++)
676 if (strcmp(Config.Bios, bioses[i]) == 0)
677 { bios_sel = i; break; }
679 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
680 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
681 { gpu_plugsel = i; break; }
683 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
684 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
685 { spu_plugsel = i; break; }
687 // memcard selections
688 char mcd1_old[sizeof(Config.Mcd1)];
689 char mcd2_old[sizeof(Config.Mcd2)];
690 strcpy(mcd1_old, Config.Mcd1);
691 strcpy(mcd2_old, Config.Mcd2);
693 if ((unsigned int)memcard1_sel < ARRAY_SIZE(memcards)) {
694 if (memcard1_sel == 0)
695 strcpy(Config.Mcd1, "none");
696 else if (memcards[memcard1_sel] != NULL)
697 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s",
698 MEMCARD_DIR, memcards[memcard1_sel]);
700 if ((unsigned int)memcard2_sel < ARRAY_SIZE(memcards)) {
701 if (memcard2_sel == 0)
702 strcpy(Config.Mcd2, "none");
703 else if (memcards[memcard2_sel] != NULL)
704 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s",
705 MEMCARD_DIR, memcards[memcard2_sel]);
707 if (strcmp(mcd1_old, Config.Mcd1) || strcmp(mcd2_old, Config.Mcd2))
708 LoadMcds(Config.Mcd1, Config.Mcd2);
713 static const char *filter_exts[] = {
714 "bin", "img", "mdf", "iso", "cue", "z",
718 "bz", "znx", "pbp", "cbn", NULL
721 // rrrr rggg gggb bbbb
722 static unsigned short fname2color(const char *fname)
724 static const char *other_exts[] = {
725 "ccd", "toc", "mds", "sub", "table", "index", "sbi"
727 const char *ext = strrchr(fname, '.');
733 for (i = 0; filter_exts[i] != NULL; i++)
734 if (strcasecmp(ext, filter_exts[i]) == 0)
736 for (i = 0; i < array_size(other_exts); i++)
737 if (strcasecmp(ext, other_exts[i]) == 0)
742 static void draw_savestate_bg(int slot);
744 #define MENU_ALIGN_LEFT
745 #ifndef HAVE_PRE_ARMV7 // assume hires device
751 #include "libpicofe/menu.c"
753 // a bit of black magic here
754 static void draw_savestate_bg(int slot)
756 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
758 char fname[MAXPATHLEN];
765 ret = get_state_filename(fname, sizeof(fname), slot);
769 f = gzopen(fname, "rb");
773 if ((ret = (int)gzseek(f, 0x29933d, SEEK_SET)) != 0x29933d) {
774 fprintf(stderr, "gzseek failed: %d\n", ret);
779 gpu = malloc(sizeof(*gpu));
785 ret = gzread(f, gpu, sizeof(*gpu));
787 if (ret != sizeof(*gpu)) {
788 fprintf(stderr, "gzread failed\n");
792 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
794 if (gpu->ulStatus & 0x800000)
795 goto out; // disabled
797 x = gpu->ulControl[5] & 0x3ff;
798 y = (gpu->ulControl[5] >> 10) & 0x1ff;
799 w = psx_widths[(gpu->ulStatus >> 16) & 7];
800 tmp = gpu->ulControl[7];
801 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
802 if (gpu->ulStatus & 0x80000) // doubleheight
804 if (h <= 0 || h > 512)
810 s = (u16 *)gpu->psxVRam + y * 1024 + x;
812 x = max(0, g_menuscreen_w - w) & ~3;
813 y = max(0, g_menuscreen_h / 2 - h / 2);
814 w = min(g_menuscreen_w, w);
815 h = min(g_menuscreen_h, h);
816 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
818 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
819 if (gpu->ulStatus & 0x200000)
820 bgr888_to_rgb565(d, s, w * 3);
822 bgr555_to_rgb565(d, s, w * 2);
824 // darken this so that menu text is visible
825 if (g_menuscreen_w - w < 320)
826 menu_darken_bg(d, d, w, 0);
833 // -------------- key config --------------
835 me_bind_action me_ctrl_actions[] =
837 { "UP ", 1 << DKEY_UP},
838 { "DOWN ", 1 << DKEY_DOWN },
839 { "LEFT ", 1 << DKEY_LEFT },
840 { "RIGHT ", 1 << DKEY_RIGHT },
841 { "TRIANGLE", 1 << DKEY_TRIANGLE },
842 { "CIRCLE ", 1 << DKEY_CIRCLE },
843 { "CROSS ", 1 << DKEY_CROSS },
844 { "SQUARE ", 1 << DKEY_SQUARE },
845 { "L1 ", 1 << DKEY_L1 },
846 { "R1 ", 1 << DKEY_R1 },
847 { "L2 ", 1 << DKEY_L2 },
848 { "R2 ", 1 << DKEY_R2 },
849 { "L3 ", 1 << DKEY_L3 },
850 { "R3 ", 1 << DKEY_R3 },
851 { "START ", 1 << DKEY_START },
852 { "SELECT ", 1 << DKEY_SELECT },
856 me_bind_action emuctrl_actions[] =
858 { "Save State ", 1 << SACTION_SAVE_STATE },
859 { "Load State ", 1 << SACTION_LOAD_STATE },
860 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
861 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
862 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
863 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
864 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
865 #ifndef HAVE_PRE_ARMV7
866 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
868 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
869 #if MENU_SHOW_MINIMIZE
870 { "Minimize ", 1 << SACTION_MINIMIZE },
872 #if MENU_SHOW_FULLSCREEN
873 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
875 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
876 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
877 { "Gun A button ", 1 << SACTION_GUN_A },
878 { "Gun B button ", 1 << SACTION_GUN_B },
879 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
881 { "Volume Up ", 1 << SACTION_VOLUME_UP },
882 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
887 static char *mystrip(char *str)
892 for (i = 0; i < len; i++)
893 if (str[i] != ' ') break;
894 if (i > 0) memmove(str, str + i, len - i + 1);
897 for (i = len - 1; i >= 0; i--)
898 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
904 static void get_line(char *d, size_t size, const char *s)
909 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
918 static void keys_write_all(FILE *f)
922 for (d = 0; d < IN_MAX_DEVS; d++)
924 const int *binds = in_get_dev_binds(d);
925 const char *name = in_get_dev_name(d, 0, 0);
928 if (binds == NULL || name == NULL)
931 fprintf(f, "binddev = %s\n", name);
932 in_get_config(d, IN_CFG_BIND_COUNT, &count);
934 for (k = 0; k < count; k++)
939 act[0] = act[31] = 0;
940 name = in_get_key_name(d, k);
942 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
943 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
944 mask = me_ctrl_actions[i].mask;
946 strncpy(act, me_ctrl_actions[i].name, 31);
947 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
950 mask = me_ctrl_actions[i].mask << 16;
952 strncpy(act, me_ctrl_actions[i].name, 31);
953 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
958 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
959 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
960 mask = emuctrl_actions[i].mask;
962 strncpy(act, emuctrl_actions[i].name, 31);
963 fprintf(f, "bind %s = %s\n", name, mystrip(act));
969 for (k = 0; k < array_size(in_adev); k++)
972 fprintf(f, "bind_analog = %d\n", k);
977 static int parse_bind_val(const char *val, int *type)
981 *type = IN_BINDTYPE_NONE;
985 if (strncasecmp(val, "player", 6) == 0)
987 int player, shift = 0;
988 player = atoi(val + 6) - 1;
990 if ((unsigned int)player > 1)
995 *type = IN_BINDTYPE_PLAYER12;
996 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
997 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
998 return me_ctrl_actions[i].mask << shift;
1001 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
1002 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
1003 *type = IN_BINDTYPE_EMU;
1004 return emuctrl_actions[i].mask;
1011 static void keys_load_all(const char *cfg)
1013 char dev[256], key[128], *act;
1019 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
1022 // don't strip 'dev' because there are weird devices
1023 // with names with space at the end
1024 get_line(dev, sizeof(dev), p);
1026 dev_id = in_config_parse_dev(dev);
1028 printf("input: can't handle dev: %s\n", dev);
1032 in_unbind_all(dev_id, -1, -1);
1033 while ((p = strstr(p, "bind"))) {
1034 if (strncmp(p, "binddev = ", 10) == 0)
1037 if (strncmp(p, "bind_analog", 11) == 0) {
1038 ret = sscanf(p, "bind_analog = %d", &bind);
1041 printf("input: parse error: %16s..\n", p);
1044 if ((unsigned int)bind >= array_size(in_adev)) {
1045 printf("input: analog id %d out of range\n", bind);
1048 in_adev[bind] = dev_id;
1054 printf("input: parse error: %16s..\n", p);
1058 get_line(key, sizeof(key), p);
1059 act = strchr(key, '=');
1061 printf("parse failed: %16s..\n", p);
1069 bind = parse_bind_val(act, &bindtype);
1070 if (bind != -1 && bind != 0) {
1071 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
1072 in_config_bind_key(dev_id, key, bind, bindtype);
1075 lprintf("config: unhandled action \"%s\"\n", act);
1081 static int key_config_loop_wrap(int id, int keys)
1084 case MA_CTRL_PLAYER1:
1085 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
1087 case MA_CTRL_PLAYER2:
1088 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
1091 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
1099 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
1100 "Might cause problems with real analog sticks";
1101 static const char *adevnames[IN_MAX_DEVS + 2];
1102 static int stick_sel[2];
1104 static menu_entry e_menu_keyconfig_analog[] =
1106 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
1107 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
1108 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
1109 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
1110 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
1111 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
1112 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
1113 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
1117 static int key_config_analog(int id, int keys)
1119 int i, d, count, sel = 0;
1120 int sel2dev_map[IN_MAX_DEVS];
1122 memset(adevnames, 0, sizeof(adevnames));
1123 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1124 memset(stick_sel, 0, sizeof(stick_sel));
1126 adevnames[0] = "None";
1128 for (d = 0; d < IN_MAX_DEVS; d++)
1130 const char *name = in_get_dev_name(d, 0, 1);
1135 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1139 if (in_adev[0] == d) stick_sel[0] = i;
1140 if (in_adev[1] == d) stick_sel[1] = i;
1142 adevnames[i++] = name;
1144 adevnames[i] = NULL;
1146 me_loop(e_menu_keyconfig_analog, &sel);
1148 in_adev[0] = sel2dev_map[stick_sel[0]];
1149 in_adev[1] = sel2dev_map[stick_sel[1]];
1154 static const char *mgn_dev_name(int id, int *offs)
1156 const char *name = NULL;
1159 if (id == MA_CTRL_DEV_FIRST)
1162 for (; it < IN_MAX_DEVS; it++) {
1163 name = in_get_dev_name(it, 1, 1);
1172 static const char *mgn_saveloadcfg(int id, int *offs)
1177 static int mh_savecfg(int id, int keys)
1179 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1180 menu_update_msg("config saved");
1182 menu_update_msg("failed to write config");
1187 static int mh_input_rescan(int id, int keys)
1189 //menu_sync_config();
1191 menu_update_msg("rescan complete.");
1196 static const char *men_in_type_sel[] = {
1197 "Standard (SCPH-1080)",
1198 "Analog (SCPH-1150)",
1202 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1203 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1204 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1206 static menu_entry e_menu_keyconfig[] =
1208 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1209 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1210 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1211 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1213 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1214 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1215 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1216 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1217 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1218 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1219 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1220 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1221 mee_handler ("Rescan devices:", mh_input_rescan),
1223 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1224 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1225 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1226 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1227 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1228 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1229 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1233 static int menu_loop_keyconfig(int id, int keys)
1237 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1238 me_loop(e_menu_keyconfig, &sel);
1242 // ------------ gfx options menu ------------
1244 static const char *men_scaler[] = {
1245 "1x1", "integer scaled 2x", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL
1247 static const char *men_soft_filter[] = { "None",
1249 "scale2x", "eagle2x",
1252 static const char *men_dummy[] = { NULL };
1253 static const char h_scaler[] = "int. 2x - scales w. or h. 2x if it fits on screen\n"
1254 "int. 4:3 - uses integer if possible, else fractional";
1255 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1256 "using d-pad or move it using R+d-pad";
1257 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1258 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1260 static const char h_scanline_l[] = "Scanline brightness, 0-100%";
1263 static int menu_loop_cscaler(int id, int keys)
1267 g_scaler = SCALE_CUSTOM;
1269 plat_gvideo_open(Config.PsxType);
1273 menu_draw_begin(0, 1);
1274 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1275 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1276 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1279 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1280 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1281 if (inp & PBTN_UP) g_layer_y--;
1282 if (inp & PBTN_DOWN) g_layer_y++;
1283 if (inp & PBTN_LEFT) g_layer_x--;
1284 if (inp & PBTN_RIGHT) g_layer_x++;
1285 if (!(inp & PBTN_R)) {
1286 if (inp & PBTN_UP) g_layer_h += 2;
1287 if (inp & PBTN_DOWN) g_layer_h -= 2;
1288 if (inp & PBTN_LEFT) g_layer_w += 2;
1289 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1291 if (inp & (PBTN_MOK|PBTN_MBACK))
1294 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1295 if (g_layer_x < 0) g_layer_x = 0;
1296 if (g_layer_x > 640) g_layer_x = 640;
1297 if (g_layer_y < 0) g_layer_y = 0;
1298 if (g_layer_y > 420) g_layer_y = 420;
1299 if (g_layer_w < 160) g_layer_w = 160;
1300 if (g_layer_h < 60) g_layer_h = 60;
1301 if (g_layer_x + g_layer_w > 800)
1302 g_layer_w = 800 - g_layer_x;
1303 if (g_layer_y + g_layer_h > 480)
1304 g_layer_h = 480 - g_layer_y;
1306 plat_gvideo_open(Config.PsxType);
1310 plat_gvideo_close();
1315 static menu_entry e_menu_gfx_options[] =
1317 mee_enum_h ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler, h_scaler),
1318 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1319 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1320 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1321 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1323 mee_onoff ("Scanlines", MA_OPT_SCANLINES, scanlines, 1),
1324 mee_range_h ("Scanline brightness", MA_OPT_SCANLINE_LEVEL, scanline_level, 0, 100, h_scanline_l),
1326 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1327 // mee_onoff ("Vsync", 0, vsync, 1),
1328 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1332 static int menu_loop_gfx_options(int id, int keys)
1336 me_loop(e_menu_gfx_options, &sel);
1341 // ------------ bios/plugins ------------
1343 #ifdef BUILTIN_GPU_NEON
1345 static const char h_gpu_neon[] =
1346 "Configure built-in NEON GPU plugin";
1347 static const char h_gpu_neon_enhanced[] =
1348 "Renders in double resolution at the cost of lower performance\n"
1349 "(not available for high resolution games)";
1350 static const char h_gpu_neon_enhanced_hack[] =
1351 "Speed hack for above option (glitches some games)";
1352 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1354 static menu_entry e_menu_plugin_gpu_neon[] =
1356 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1357 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1358 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1362 static int menu_loop_plugin_gpu_neon(int id, int keys)
1365 me_loop(e_menu_plugin_gpu_neon, &sel);
1371 static menu_entry e_menu_plugin_gpu_unai[] =
1373 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1374 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1375 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1376 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1380 static int menu_loop_plugin_gpu_unai(int id, int keys)
1383 me_loop(e_menu_plugin_gpu_unai, &sel);
1387 static menu_entry e_menu_plugin_gpu_senquack[] =
1389 mee_onoff ("Interlace", 0, pl_rearmed_cbs.gpu_senquack.ilace_force, 1),
1390 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_senquack.dithering, 1),
1391 mee_onoff ("Lighting", 0, pl_rearmed_cbs.gpu_senquack.lighting, 1),
1392 mee_onoff ("Fast lighting", 0, pl_rearmed_cbs.gpu_senquack.fast_lighting, 1),
1393 mee_onoff ("Blending", 0, pl_rearmed_cbs.gpu_senquack.blending, 1),
1394 mee_onoff ("Pixel skip", 0, pl_rearmed_cbs.gpu_senquack.pixel_skip, 1),
1398 static int menu_loop_plugin_gpu_senquack(int id, int keys)
1401 me_loop(e_menu_plugin_gpu_senquack, &sel);
1406 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1407 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1408 static const char h_gpu_1[] = "Capcom fighting games";
1409 static const char h_gpu_2[] = "Black screens in Lunar";
1410 static const char h_gpu_3[] = "Compatibility mode";
1411 static const char h_gpu_6[] = "Pandemonium 2";
1412 //static const char h_gpu_7[] = "Skip every second frame";
1413 static const char h_gpu_8[] = "Needed by Dark Forces";
1414 static const char h_gpu_9[] = "better g-colors, worse textures";
1415 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1417 static menu_entry e_menu_plugin_gpu_peops[] =
1419 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1420 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1421 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1422 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1423 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1424 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1425 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1426 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1427 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1428 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1432 static int menu_loop_plugin_gpu_peops(int id, int keys)
1435 me_loop(e_menu_plugin_gpu_peops, &sel);
1439 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1440 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1441 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1443 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1445 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1446 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1447 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1448 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1449 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1450 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1451 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1452 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1453 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1454 mee_label ("Fixes/hacks:"),
1455 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1456 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1457 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1458 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1459 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1460 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1461 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1462 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1463 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1464 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1465 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1469 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1472 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1476 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1477 static const char h_spu_volboost[] = "Large values cause distortion";
1478 static const char h_spu_tempo[] = "Slows down audio if emu is too slow\n"
1479 "This is inaccurate and breaks games";
1481 static menu_entry e_menu_plugin_spu[] =
1483 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1484 mee_onoff ("Reverb", 0, spu_config.iUseReverb, 1),
1485 mee_enum ("Interpolation", 0, spu_config.iUseInterpolation, men_spu_interp),
1486 //mee_onoff ("Adjust XA pitch", 0, spu_config.iXAPitch, 1),
1487 mee_onoff_h ("Adjust tempo", 0, spu_config.iTempo, 1, h_spu_tempo),
1491 static int menu_loop_plugin_spu(int id, int keys)
1494 me_loop(e_menu_plugin_spu, &sel);
1498 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1499 "savestates and can't be changed there. Must save\n"
1500 "config and reload the game for change to take effect";
1501 static const char h_plugin_gpu[] =
1502 #ifdef BUILTIN_GPU_NEON
1503 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1505 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1506 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1507 "gpu_senquack is more accurate but slower\n"
1508 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1509 "must save config and reload the game if changed";
1510 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1511 "must save config and reload the game if changed";
1512 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1513 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1514 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1515 static const char h_gpu_senquack[] = "Configure Unai/PCSX4ALL Senquack plugin";
1516 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1518 static menu_entry e_menu_plugin_options[] =
1520 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1521 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1522 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1523 #ifdef BUILTIN_GPU_NEON
1524 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1526 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1527 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1528 mee_handler_h ("Configure gpu_senquack GPU plugin", menu_loop_plugin_gpu_senquack, h_gpu_senquack),
1529 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1530 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1534 static menu_entry e_menu_main2[];
1536 static int menu_loop_plugin_options(int id, int keys)
1539 me_loop(e_menu_plugin_options, &sel);
1541 // sync BIOS/plugins
1542 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1543 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1544 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1545 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1550 // ------------ adv options menu ------------
1553 static const char h_cfg_noch[] = "Disables game-specific compatibility hacks";
1554 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1555 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1556 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1558 static const char h_cfg_stalls[] = "Will cause some games to run too fast";
1560 static menu_entry e_menu_speed_hacks[] =
1563 mee_onoff_h ("Disable compat hacks", 0, new_dynarec_hacks, NDHACK_NO_COMPAT_HACKS, h_cfg_noch),
1564 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1565 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1566 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1568 mee_onoff_h ("Disable CPU/GTE stalls", 0, menu_iopts[0], 1, h_cfg_stalls),
1572 static int menu_loop_speed_hacks(int id, int keys)
1575 menu_iopts[0] = Config.DisableStalls;
1576 me_loop(e_menu_speed_hacks, &sel);
1577 Config.DisableStalls = menu_iopts[0];
1581 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1582 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1583 "(green: normal, red: fmod, blue: noise)";
1584 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1585 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1586 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1587 "(proper .cue/.bin dump is needed otherwise)";
1589 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1590 "Might be useful to overcome some dynarec bugs";
1592 static const char h_cfg_shacks[] = "Breaks games but may give better performance";
1593 static const char h_cfg_icache[] = "Support F1 games (only when dynarec is off)";
1594 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1595 "(adjust this if the game is too slow/too fast/hangs)";
1597 enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_CPU };
1599 static menu_entry e_menu_adv_options[] =
1601 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1602 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1603 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1604 mee_onoff_h ("Disable XA Decoding", 0, menu_iopts[AMO_XA], 1, h_cfg_xa),
1605 mee_onoff_h ("Disable CD Audio", 0, menu_iopts[AMO_CDDA], 1, h_cfg_cdda),
1606 mee_onoff_h ("ICache emulation", 0, menu_iopts[AMO_IC], 1, h_cfg_icache),
1607 #if !defined(DRC_DISABLE) || defined(LIGHTREC)
1608 mee_onoff_h ("Disable dynarec (slow!)",0, menu_iopts[AMO_CPU], 1, h_cfg_nodrc),
1610 mee_range_h ("PSX CPU clock, %", 0, psx_clock, 1, 500, h_cfg_psxclk),
1611 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1615 static int menu_loop_adv_options(int id, int keys)
1622 { &Config.Xa, &menu_iopts[AMO_XA] },
1623 { &Config.Cdda, &menu_iopts[AMO_CDDA] },
1624 { &Config.icache_emulation, &menu_iopts[AMO_IC] },
1625 { &Config.Cpu, &menu_iopts[AMO_CPU] },
1628 for (i = 0; i < ARRAY_SIZE(opts); i++)
1629 *opts[i].mopt = *opts[i].opt;
1630 me_loop(e_menu_adv_options, &sel);
1631 for (i = 0; i < ARRAY_SIZE(opts); i++)
1632 *opts[i].opt = *opts[i].mopt;
1636 // ------------ options menu ------------
1638 static int mh_restore_defaults(int id, int keys)
1640 menu_set_defconfig();
1641 menu_update_msg("defaults restored");
1645 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1646 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1648 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1649 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1650 "loading state or both";
1652 static const char h_restore_def[] = "Switches back to default / recommended\n"
1654 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1656 static menu_entry e_menu_options[] =
1658 // mee_range ("Save slot", 0, state_slot, 0, 9),
1659 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1660 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1661 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1662 mee_enum ("Region", 0, region, men_region),
1663 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1665 mee_onoff ("Use C64x DSP for sound", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1),
1667 mee_onoff ("Threaded SPU", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1),
1669 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1670 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1671 mee_handler ("[Advanced]", menu_loop_adv_options),
1672 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1673 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1674 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1678 static int menu_loop_options(int id, int keys)
1682 me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, cpu_clock_st > 0);
1683 me_enable(e_menu_options, MA_OPT_SPU_THREAD, spu_config.iThreadAvail);
1684 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1686 me_loop(e_menu_options, &sel);
1691 // ------------ debug menu ------------
1693 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1695 int w = min(g_menuscreen_w, 1024);
1696 int h = min(g_menuscreen_h, 512);
1697 u16 *d = g_menuscreen_ptr;
1698 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1702 gpuf->ulFreezeVersion = 1;
1703 if (GPU_freeze != NULL)
1704 GPU_freeze(1, gpuf);
1706 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1707 bgr555_to_rgb565(d, s, w * 2);
1709 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1710 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1711 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1712 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1713 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1716 static void debug_menu_loop(void)
1718 int inp, df_x = 0, df_y = 0;
1721 gpuf = malloc(sizeof(*gpuf));
1727 menu_draw_begin(0, 1);
1728 draw_frame_debug(gpuf, df_x, df_y);
1731 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1732 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1733 if (inp & PBTN_MBACK) break;
1734 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1735 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1736 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1737 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1743 // --------- memcard manager ---------
1745 static void draw_mc_icon(int dx, int dy, const u16 *s)
1750 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1752 for (y = 0; y < 16; y++, s += 16) {
1753 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1754 for (x = 0; x < 16; x++) {
1756 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1757 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1763 static void draw_mc_bg(void)
1765 McdBlock *blocks1, *blocks2;
1769 blocks1 = malloc(15 * sizeof(blocks1[0]));
1770 blocks2 = malloc(15 * sizeof(blocks1[0]));
1771 if (blocks1 == NULL || blocks2 == NULL)
1774 for (i = 0; i < 15; i++) {
1775 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1776 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1779 menu_draw_begin(1, 1);
1781 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1783 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1787 maxicons = g_menuscreen_h / 32;
1790 row2 = g_menuscreen_w / 2;
1791 for (i = 0; i < maxicons; i++) {
1792 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1793 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1795 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1796 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1799 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1807 static void handle_memcard_sel(void)
1809 strcpy(Config.Mcd1, "none");
1810 if (memcard1_sel != 0)
1811 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1812 strcpy(Config.Mcd2, "none");
1813 if (memcard2_sel != 0)
1814 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1815 LoadMcds(Config.Mcd1, Config.Mcd2);
1819 static menu_entry e_memcard_options[] =
1821 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1822 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1826 static int menu_loop_memcards(int id, int keys)
1832 memcard1_sel = memcard2_sel = 0;
1833 p = strrchr(Config.Mcd1, '/');
1835 for (i = 0; memcards[i] != NULL; i++)
1836 if (strcmp(p + 1, memcards[i]) == 0)
1837 { memcard1_sel = i; break; }
1838 p = strrchr(Config.Mcd2, '/');
1840 for (i = 0; memcards[i] != NULL; i++)
1841 if (strcmp(p + 1, memcards[i]) == 0)
1842 { memcard2_sel = i; break; }
1844 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1846 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1851 // ------------ cheats menu ------------
1853 static void draw_cheatlist(int sel)
1855 int max_cnt, start, i, pos, active;
1857 max_cnt = g_menuscreen_h / me_sfont_h;
1858 start = max_cnt / 2 - sel;
1860 menu_draw_begin(1, 1);
1862 for (i = 0; i < NumCheats; i++) {
1864 if (pos < 0) continue;
1865 if (pos >= max_cnt) break;
1866 active = Cheats[i].Enabled;
1867 smalltext_out16(14, pos * me_sfont_h,
1868 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1869 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1870 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1874 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1876 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1880 static void menu_loop_cheats(void)
1882 static int menu_sel = 0;
1887 draw_cheatlist(menu_sel);
1888 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1889 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1890 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1891 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1892 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1893 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1894 if (inp & PBTN_MOK) { // action
1895 if (menu_sel < NumCheats)
1896 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1899 if (inp & PBTN_MBACK)
1904 // --------- main menu help ----------
1906 static void menu_bios_warn(void)
1909 static const char msg[] =
1910 "You don't seem to have copied any BIOS\n"
1912 MENU_BIOS_PATH "\n\n"
1914 "While many games work fine with fake\n"
1915 "(HLE) BIOS, others (like MGS and FF8)\n"
1916 "require BIOS to work.\n"
1917 "After copying the file, you'll also need\n"
1918 "to select it in the emu's menu:\n"
1919 "options->[BIOS/Plugins]\n\n"
1920 "The file is usually named SCPH1001.BIN,\n"
1921 "but other not compressed files can be\n"
1923 "Press %s or %s to continue";
1924 char tmp_msg[sizeof(msg) + 64];
1926 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1927 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1930 draw_menu_message(tmp_msg, NULL);
1932 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1933 if (inp & (PBTN_MBACK|PBTN_MOK))
1938 // ------------ main menu ------------
1940 static menu_entry e_menu_main[];
1942 static void draw_frame_main(void)
1951 if (CdromId[0] != 0) {
1952 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1953 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1954 Config.HLE ? "HLE" : "BIOS");
1955 smalltext_out16(4, 1, buff, 0x105f);
1959 capacity = plat_target_bat_capacity_get();
1961 tmp = localtime(<ime);
1962 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1963 if (capacity >= 0) {
1964 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1969 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1973 static void draw_frame_credits(void)
1975 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1978 static const char credits_text[] =
1980 "(C) 1999-2003 PCSX Team\n"
1981 "(C) 2005-2009 PCSX-df Team\n"
1982 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1983 "ARM recompiler (C) 2009-2011 Ari64\n"
1984 #ifdef BUILTIN_GPU_NEON
1985 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1987 "PEOpS GPU and SPU by Pete Bernert\n"
1988 " and the P.E.Op.S. team\n"
1989 "PCSX4ALL plugin by PCSX4ALL team\n"
1990 " Chui, Franxis, Unai\n\n"
1991 "integration, optimization and\n"
1992 " frontend (C) 2010-2015 notaz\n";
1994 static int reset_game(void)
1997 if (bios_sel == 0 && !Config.HLE)
2003 if (CheckCdrom() != -1) {
2009 static int reload_plugins(const char *cdimg)
2015 set_cd_image(cdimg);
2017 pcnt_hook_plugins();
2019 if (OpenPlugins() == -1) {
2020 menu_update_msg("failed to open plugins");
2023 plugin_call_rearmed_cbs();
2025 cdrIsoMultidiskCount = 1;
2027 CdromLabel[0] = '\0';
2032 static int run_bios(void)
2038 if (reload_plugins(NULL) != 0)
2046 static int run_exe(void)
2048 const char *exts[] = { "exe", NULL };
2051 fname = menu_loop_romsel(last_selected_fname,
2052 sizeof(last_selected_fname), exts, NULL);
2057 if (reload_plugins(NULL) != 0)
2061 if (Load(fname) != 0) {
2062 menu_update_msg("exe load failed, bad file?");
2071 static int run_cd_image(const char *fname)
2073 int autoload_state = g_autostateld_opt;
2076 reload_plugins(fname);
2078 // always autodetect, menu_sync_config will override as needed
2081 if (CheckCdrom() == -1) {
2082 // Only check the CD if we are starting the console with a CD
2084 menu_update_msg("unsupported/invalid CD image");
2090 // Read main executable directly from CDRom and start it
2091 if (LoadCdrom() == -1) {
2093 menu_update_msg("failed to load CD image");
2100 if (autoload_state) {
2101 unsigned int newest = 0;
2102 int time, slot, newest_slot = -1;
2104 for (slot = 0; slot < 10; slot++) {
2105 if (emu_check_save_file(slot, &time)) {
2106 if ((unsigned int)time > newest) {
2113 if (newest_slot >= 0) {
2114 lprintf("autoload slot %d\n", newest_slot);
2115 emu_load_state(newest_slot);
2118 lprintf("no save to autoload.\n");
2125 static int romsel_run(void)
2127 int prev_gpu, prev_spu;
2130 fname = menu_loop_romsel(last_selected_fname,
2131 sizeof(last_selected_fname), filter_exts,
2132 optional_cdimg_filter);
2136 printf("selected file: %s\n", fname);
2138 new_dynarec_clear_full();
2140 if (run_cd_image(fname) != 0)
2143 prev_gpu = gpu_plugsel;
2144 prev_spu = spu_plugsel;
2145 if (menu_load_config(1) != 0)
2146 menu_load_config(0);
2148 // check for plugin changes, have to repeat
2149 // loading if game config changed plugins to reload them
2150 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
2151 printf("plugin change detected, reloading plugins..\n");
2152 if (run_cd_image(fname) != 0)
2156 strcpy(last_selected_fname, fname);
2157 menu_do_last_cd_img(0);
2161 static int swap_cd_image(void)
2165 fname = menu_loop_romsel(last_selected_fname,
2166 sizeof(last_selected_fname), filter_exts,
2167 optional_cdimg_filter);
2171 printf("selected file: %s\n", fname);
2174 CdromLabel[0] = '\0';
2176 set_cd_image(fname);
2177 if (ReloadCdromPlugin() < 0) {
2178 menu_update_msg("failed to load cdr plugin");
2181 if (CDR_open() < 0) {
2182 menu_update_msg("failed to open cdr plugin");
2186 SetCdOpenCaseTime(time(NULL) + 2);
2189 strcpy(last_selected_fname, fname);
2193 static int swap_cd_multidisk(void)
2195 cdrIsoMultidiskSelect++;
2197 CdromLabel[0] = '\0';
2200 if (CDR_open() < 0) {
2201 menu_update_msg("failed to open cdr plugin");
2205 SetCdOpenCaseTime(time(NULL) + 2);
2211 static void load_pcsx_cht(void)
2213 static const char *exts[] = { "cht", NULL };
2217 fname = menu_loop_romsel(last_selected_fname,
2218 sizeof(last_selected_fname), exts, NULL);
2222 printf("selected cheat file: %s\n", fname);
2225 if (NumCheats == 0 && NumCodes == 0)
2226 menu_update_msg("failed to load cheats");
2228 snprintf(msg, sizeof(msg), "%d cheat(s) loaded", NumCheats + NumCodes);
2229 menu_update_msg(msg);
2231 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2234 static int main_menu_handler(int id, int keys)
2238 case MA_MAIN_RESUME_GAME:
2242 case MA_MAIN_SAVE_STATE:
2244 return menu_loop_savestate(0);
2246 case MA_MAIN_LOAD_STATE:
2248 return menu_loop_savestate(1);
2250 case MA_MAIN_RESET_GAME:
2251 if (ready_to_go && reset_game() == 0)
2254 case MA_MAIN_LOAD_ROM:
2255 if (romsel_run() == 0)
2258 case MA_MAIN_SWAP_CD:
2259 if (swap_cd_image() == 0)
2262 case MA_MAIN_SWAP_CD_MULTI:
2263 if (swap_cd_multidisk() == 0)
2266 case MA_MAIN_RUN_BIOS:
2267 if (run_bios() == 0)
2270 case MA_MAIN_RUN_EXE:
2274 case MA_MAIN_CHEATS:
2277 case MA_MAIN_LOAD_CHEATS:
2280 case MA_MAIN_CREDITS:
2281 draw_menu_message(credits_text, draw_frame_credits);
2282 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2285 emu_core_ask_exit();
2288 lprintf("%s: something unknown selected\n", __FUNCTION__);
2295 static menu_entry e_menu_main2[] =
2297 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2298 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2299 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2300 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2301 mee_handler ("Memcard manager", menu_loop_memcards),
2302 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2306 static int main_menu2_handler(int id, int keys)
2310 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2311 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2312 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2313 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2315 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2318 static const char h_extra[] = "Change CD, manage memcards..\n";
2320 static menu_entry e_menu_main[] =
2324 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2325 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2326 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2327 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2328 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2329 mee_handler ("Options", menu_loop_options),
2330 mee_handler ("Controls", menu_loop_keyconfig),
2331 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2332 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2333 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2334 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2338 // ----------------------------
2340 static void menu_leave_emu(void);
2342 void menu_loop(void)
2344 static int warned_about_bios = 0;
2349 if (config_save_counter == 0) {
2351 if (bioses[1] != NULL) {
2352 // autoselect BIOS to make user's life easier
2353 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2356 else if (!warned_about_bios) {
2358 warned_about_bios = 1;
2362 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2363 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2364 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2365 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2366 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2368 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2371 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2372 } while (!ready_to_go && !g_emu_want_quit);
2374 /* wait until menu, ok, back is released */
2375 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2378 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2383 static int qsort_strcmp(const void *p1, const void *p2)
2385 char * const *s1 = (char * const *)p1;
2386 char * const *s2 = (char * const *)p2;
2387 return strcasecmp(*s1, *s2);
2390 static void scan_bios_plugins(void)
2392 char fname[MAXPATHLEN];
2394 int bios_i, gpu_i, spu_i, mc_i;
2399 gpu_plugins[0] = "builtin_gpu";
2400 spu_plugins[0] = "builtin_spu";
2401 memcards[0] = "(none)";
2402 bios_i = gpu_i = spu_i = mc_i = 1;
2404 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2405 dir = opendir(fname);
2407 perror("scan_bios_plugins bios opendir");
2422 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2425 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2426 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2427 printf("bad BIOS file: %s\n", ent->d_name);
2431 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2432 bioses[bios_i++] = strdup(ent->d_name);
2436 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2442 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2443 dir = opendir(fname);
2445 perror("scan_bios_plugins plugins opendir");
2459 p = strstr(ent->d_name, ".so");
2463 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2464 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2466 fprintf(stderr, "%s\n", dlerror());
2470 // now what do we have here?
2471 tmp = dlsym(h, "GPUinit");
2474 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2475 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2479 tmp = dlsym(h, "SPUinit");
2482 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2483 spu_plugins[spu_i++] = strdup(ent->d_name);
2487 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2494 dir = opendir("." MEMCARD_DIR);
2496 perror("scan_bios_plugins memcards opendir");
2511 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2514 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2515 if (stat(fname, &st) != 0) {
2516 printf("bad memcard file: %s\n", ent->d_name);
2520 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2521 memcards[mc_i++] = strdup(ent->d_name);
2525 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2529 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2534 void menu_init(void)
2536 char buff[MAXPATHLEN];
2539 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2541 scan_bios_plugins();
2544 menu_set_defconfig();
2545 menu_load_config(0);
2546 menu_do_last_cd_img(1);
2551 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2552 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2553 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2554 fprintf(stderr, "OOM\n");
2558 emu_make_path(buff, "skin/background.png", sizeof(buff));
2559 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2561 i = plat_target.cpu_clock_set != NULL
2562 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2563 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2565 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2566 e_menu_gfx_options[i].data = plat_target.vout_methods;
2567 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2568 plat_target.vout_methods != NULL);
2570 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2571 e_menu_gfx_options[i].data = plat_target.hwfilters;
2572 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2573 plat_target.hwfilters != NULL);
2575 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2576 plat_target.gamma_set != NULL);
2578 #ifdef HAVE_PRE_ARMV7
2579 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2581 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2582 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2583 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2584 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2585 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2586 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2587 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2590 void menu_notify_mode_change(int w, int h, int bpp)
2594 last_vout_bpp = bpp;
2597 static void menu_leave_emu(void)
2599 if (GPU_close != NULL) {
2600 int ret = GPU_close();
2602 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2605 plat_video_menu_enter(ready_to_go);
2607 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2608 if (pl_vout_buf != NULL && ready_to_go) {
2609 int x = max(0, g_menuscreen_w - last_vout_w);
2610 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2611 int w = min(g_menuscreen_w, last_vout_w);
2612 int h = min(g_menuscreen_h, last_vout_h);
2613 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2614 char *s = pl_vout_buf;
2616 if (last_vout_bpp == 16) {
2617 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2618 menu_darken_bg(d, s, w, 0);
2621 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2622 rgb888_to_rgb565(d, s, w * 3);
2623 menu_darken_bg(d, d, w, 0);
2629 cpu_clock = plat_target_cpu_clock_get();
2632 void menu_prepare_emu(void)
2634 R3000Acpu *prev_cpu = psxCpu;
2636 plat_video_menu_leave();
2638 #if !defined(DRC_DISABLE) || defined(LIGHTREC)
2639 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2643 if (psxCpu != prev_cpu) {
2644 prev_cpu->Shutdown();
2646 // note that this does not really reset, just clears drc caches
2651 psxCpu->ApplyConfig();
2653 // core doesn't care about Config.Cdda changes,
2654 // so handle them manually here
2659 plat_target_cpu_clock_set(cpu_clock);
2661 // push config to GPU plugin
2662 plugin_call_rearmed_cbs();
2664 if (GPU_open != NULL) {
2665 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2667 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2673 void menu_update_msg(const char *msg)
2675 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2676 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2678 menu_error_time = plat_get_ticks_ms();
2679 lprintf("msg: %s\n", menu_error_msg);
2682 void menu_finish(void)
2684 if (cpu_clock_st > 0)
2685 plat_target_cpu_clock_set(cpu_clock_st);