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/dfsound/spu_config.h"
40 #include "psemu_plugin_defs.h"
41 #include "arm_features.h"
44 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
46 #define array_size(x) (sizeof(x) / sizeof(x[0]))
57 MA_MAIN_SWAP_CD_MULTI,
88 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;
94 static int frameskip = 1; // 0 - auto, 1 - off
95 static char last_selected_fname[MAXPATHLEN];
96 static int config_save_counter, region, in_type_sel1, in_type_sel2;
98 static int memcard1_sel = -1, memcard2_sel = -1;
99 extern int g_autostateld_opt;
100 static int menu_iopts[8];
101 int g_opts, g_scaler, g_gamma = 100;
102 int scanlines, scanline_level = 20;
103 int soft_scaling, analog_deadzone; // for Caanoo
106 #ifndef HAVE_PRE_ARMV7
107 #define DEFAULT_PSX_CLOCK (10000 / CYCLE_MULT_DEFAULT)
108 #define DEFAULT_PSX_CLOCK_S "57"
110 #define DEFAULT_PSX_CLOCK 50
111 #define DEFAULT_PSX_CLOCK_S "50"
114 static const char *bioses[32];
115 static const char *gpu_plugins[16];
116 static const char *spu_plugins[16];
117 static const char *memcards[32];
118 static int bios_sel, gpu_plugsel, spu_plugsel;
120 #ifndef UI_FEATURES_H
121 #define MENU_BIOS_PATH "bios/"
122 #define MENU_SHOW_VARSCALER 0
123 #define MENU_SHOW_VOUTMODE 1
124 #define MENU_SHOW_SCALER2 0
125 #define MENU_SHOW_NUBS_BTNS 0
126 #define MENU_SHOW_VIBRATION 0
127 #define MENU_SHOW_DEADZONE 0
128 #define MENU_SHOW_MINIMIZE 0
129 #define MENU_SHOW_FULLSCREEN 1
130 #define MENU_SHOW_VOLUME 0
133 static int min(int x, int y) { return x < y ? x : y; }
134 static int max(int x, int y) { return x > y ? x : y; }
136 void emu_make_path(char *buff, const char *end, int size)
140 end_len = strlen(end);
141 pos = plat_get_root_dir(buff, size);
142 strncpy(buff + pos, end, size - pos);
144 if (pos + end_len > size - 1)
145 printf("Warning: path truncated: %s\n", buff);
148 static int emu_check_save_file(int slot, int *time)
150 char fname[MAXPATHLEN];
154 ret = emu_check_state(slot);
155 if (ret != 0 || time == NULL)
156 return ret == 0 ? 1 : 0;
158 ret = get_state_filename(fname, sizeof(fname), slot);
162 ret = stat(fname, &status);
166 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
167 return 1; // probably bad rtc like on some Caanoos
169 *time = status.st_mtime;
174 static int emu_save_load_game(int load, int unused)
179 ret = emu_load_state(state_slot);
181 // reflect hle/bios mode from savestate
184 else if (bios_sel == 0 && bioses[1] != NULL)
185 // XXX: maybe find the right bios instead
189 ret = emu_save_state(state_slot);
194 static void rm_namelist_entry(struct dirent **namelist,
195 int count, const char *name)
199 for (i = 1; i < count; i++) {
200 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
203 if (strcmp(name, namelist[i]->d_name) == 0) {
211 static int optional_cdimg_filter(struct dirent **namelist, int count,
215 char buf[256], buf2[256];
216 int i, d, ret, good_cue;
223 for (i = 1; i < count; i++) {
224 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
227 ext = strrchr(namelist[i]->d_name, '.');
229 // should not happen but whatever
236 // first find .cue files and remove files they reference
237 if (strcasecmp(ext, "cue") == 0)
239 snprintf(buf, sizeof(buf), "%s/%s", basedir,
240 namelist[i]->d_name);
250 while (fgets(buf, sizeof(buf), f)) {
251 ret = sscanf(buf, " FILE \"%256[^\"]\"", buf2);
253 ret = sscanf(buf, " FILE %256s", buf2);
257 p = strrchr(buf2, '/');
259 p = strrchr(buf2, '\\');
265 snprintf(buf, sizeof(buf), "%s/%s", basedir, p);
266 ret = stat64(buf, &statf);
268 rm_namelist_entry(namelist, count, p);
281 p = strcasestr(namelist[i]->d_name, "track");
283 ret = strtoul(p + 5, NULL, 10);
293 for (i = d = 1; i < count; i++)
294 if (namelist[i] != NULL)
295 namelist[d++] = namelist[i];
300 // propagate menu settings to the emu vars
301 static void menu_sync_config(void)
303 static int allow_abs_only_old;
308 Config.PsxType = region - 1;
310 Config.cycle_multiplier = 10000 / psx_clock;
312 switch (in_type_sel1) {
313 case 1: in_type[0] = PSE_PAD_TYPE_ANALOGPAD; break;
314 case 2: in_type[0] = PSE_PAD_TYPE_NEGCON; break;
315 default: in_type[0] = PSE_PAD_TYPE_STANDARD;
317 switch (in_type_sel2) {
318 case 1: in_type[1] = PSE_PAD_TYPE_ANALOGPAD; break;
319 case 2: in_type[1] = PSE_PAD_TYPE_NEGCON; break;
320 default: in_type[1] = PSE_PAD_TYPE_STANDARD;
322 if (in_evdev_allow_abs_only != allow_abs_only_old) {
324 allow_abs_only_old = in_evdev_allow_abs_only;
327 spu_config.iVolume = 768 + 128 * volume_boost;
328 pl_rearmed_cbs.frameskip = frameskip - 1;
329 pl_timing_prepare(Config.PsxType);
332 static void menu_set_defconfig(void)
334 emu_set_default_config();
337 g_scaler = SCALE_4_3;
340 frameskip = 1; // 1 - off
341 analog_deadzone = 50;
346 plat_target.vout_fullscreen = 0;
347 psx_clock = DEFAULT_PSX_CLOCK;
350 in_type_sel1 = in_type_sel2 = 0;
351 in_evdev_allow_abs_only = 0;
356 #define CE_CONFIG_STR(val) \
357 { #val, 0, Config.val }
359 #define CE_CONFIG_VAL(val) \
360 { #val, sizeof(Config.val), &Config.val }
362 #define CE_STR(val) \
365 #define CE_INTVAL(val) \
366 { #val, sizeof(val), &val }
368 #define CE_INTVAL_N(name, val) \
369 { name, sizeof(val), &val }
371 #define CE_INTVAL_P(val) \
372 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
374 // 'versioned' var, used when defaults change
375 #define CE_CONFIG_STR_V(val, ver) \
376 { #val #ver, 0, Config.val }
378 #define CE_INTVAL_V(val, ver) \
379 { #val #ver, sizeof(val), &val }
381 #define CE_INTVAL_PV(val, ver) \
382 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
384 static const struct {
390 CE_CONFIG_STR_V(Gpu, 3),
392 // CE_CONFIG_STR(Cdr),
396 CE_CONFIG_VAL(Debug),
397 CE_CONFIG_VAL(PsxOut),
398 CE_CONFIG_VAL(icache_emulation),
399 CE_CONFIG_VAL(DisableStalls),
401 CE_CONFIG_VAL(GpuListWalking),
402 CE_CONFIG_VAL(PreciseExceptions),
404 CE_INTVAL_V(g_scaler, 3),
406 CE_INTVAL(g_layer_x),
407 CE_INTVAL(g_layer_y),
408 CE_INTVAL(g_layer_w),
409 CE_INTVAL(g_layer_h),
410 CE_INTVAL(soft_filter),
411 CE_INTVAL(scanlines),
412 CE_INTVAL(scanline_level),
413 CE_INTVAL(plat_target.vout_method),
414 CE_INTVAL(plat_target.hwfilter),
415 CE_INTVAL(plat_target.vout_fullscreen),
416 CE_INTVAL(state_slot),
417 CE_INTVAL(cpu_clock),
419 CE_INTVAL(in_type_sel1),
420 CE_INTVAL(in_type_sel2),
421 CE_INTVAL(analog_deadzone),
422 CE_INTVAL(memcard1_sel),
423 CE_INTVAL(memcard2_sel),
424 CE_INTVAL(g_autostateld_opt),
425 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
426 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
427 CE_INTVAL_V(frameskip, 4),
428 CE_INTVAL_P(gpu_peops.iUseDither),
429 CE_INTVAL_P(gpu_peops.dwActFixes),
430 CE_INTVAL_P(gpu_unai.lineskip),
431 CE_INTVAL_P(gpu_unai.abe_hack),
432 CE_INTVAL_P(gpu_unai.no_light),
433 CE_INTVAL_P(gpu_unai.no_blend),
434 CE_INTVAL_P(gpu_senquack.ilace_force),
435 CE_INTVAL_P(gpu_senquack.pixel_skip),
436 CE_INTVAL_P(gpu_senquack.lighting),
437 CE_INTVAL_P(gpu_senquack.fast_lighting),
438 CE_INTVAL_P(gpu_senquack.blending),
439 CE_INTVAL_P(gpu_senquack.dithering),
440 CE_INTVAL_P(gpu_senquack.scale_hires),
441 CE_INTVAL_P(gpu_neon.allow_interlace),
442 CE_INTVAL_P(gpu_neon.enhancement_enable),
443 CE_INTVAL_P(gpu_neon.enhancement_no_main),
444 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
445 CE_INTVAL_P(gpu_peopsgl.iFilterType),
446 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
447 CE_INTVAL_P(gpu_peopsgl.iUseMask),
448 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
449 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
450 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
451 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
452 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
453 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
454 CE_INTVAL_P(screen_centering_type),
455 CE_INTVAL_P(screen_centering_x),
456 CE_INTVAL_P(screen_centering_y),
457 CE_INTVAL(spu_config.iUseReverb),
458 CE_INTVAL(spu_config.iXAPitch),
459 CE_INTVAL(spu_config.iUseInterpolation),
460 CE_INTVAL(spu_config.iTempo),
461 CE_INTVAL(spu_config.iUseThread),
462 CE_INTVAL(config_save_counter),
463 CE_INTVAL(in_evdev_allow_abs_only),
464 CE_INTVAL(volume_boost),
465 CE_INTVAL(psx_clock),
466 CE_INTVAL(new_dynarec_hacks),
467 CE_INTVAL(in_enable_vibration),
470 static char *get_cd_label(void)
472 static char trimlabel[33];
475 strncpy(trimlabel, CdromLabel, 32);
477 for (j = 31; j >= 0; j--)
478 if (trimlabel[j] == ' ')
484 static void make_cfg_fname(char *buf, size_t size, int is_game)
487 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
489 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
492 static void keys_write_all(FILE *f);
493 static char *mystrip(char *str);
495 static int menu_write_config(int is_game)
497 char cfgfile[MAXPATHLEN];
501 config_save_counter++;
503 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
504 f = fopen(cfgfile, "w");
506 printf("menu_write_config: failed to open: %s\n", cfgfile);
510 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
511 fprintf(f, "%s = ", config_data[i].name);
512 switch (config_data[i].len) {
514 fprintf(f, "%s\n", (char *)config_data[i].val);
517 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
520 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
523 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
526 printf("menu_write_config: unhandled len %d for %s\n",
527 (int)config_data[i].len, config_data[i].name);
538 static int menu_do_last_cd_img(int is_get)
540 static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
546 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
547 f = fopen(path, is_get ? "r" : "w");
554 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
555 last_selected_fname[ret] = 0;
556 mystrip(last_selected_fname);
559 fprintf(f, "%s\n", last_selected_fname);
564 for (i = 0; last_selected_fname[0] == 0
565 || stat64(last_selected_fname, &st) != 0; i++)
567 if (i >= ARRAY_SIZE(defaults))
569 strcpy(last_selected_fname, defaults[i]);
576 static void parse_str_val(char *cval, const char *src)
579 strncpy(cval, src, MAXPATHLEN);
580 cval[MAXPATHLEN - 1] = 0;
581 tmp = strchr(cval, '\n');
583 tmp = strchr(cval, '\r');
588 static void keys_load_all(const char *cfg);
590 static int menu_load_config(int is_game)
592 char cfgfile[MAXPATHLEN];
598 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
599 f = fopen(cfgfile, "r");
601 printf("menu_load_config: failed to open: %s\n", cfgfile);
605 fseek(f, 0, SEEK_END);
608 printf("bad size %ld: %s\n", size, cfgfile);
612 cfg = malloc(size + 1);
616 fseek(f, 0, SEEK_SET);
617 if (fread(cfg, 1, size, f) != size) {
618 printf("failed to read: %s\n", cfgfile);
623 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
627 tmp = strstr(cfg, config_data[i].name);
630 tmp += strlen(config_data[i].name);
631 if (strncmp(tmp, " = ", 3) != 0)
635 if (config_data[i].len == 0) {
636 parse_str_val(config_data[i].val, tmp);
641 val = strtoul(tmp, &tmp2, 16);
642 if (tmp2 == NULL || tmp == tmp2)
643 continue; // parse failed
645 switch (config_data[i].len) {
647 *(u8 *)config_data[i].val = val;
650 *(u16 *)config_data[i].val = val;
653 *(u32 *)config_data[i].val = val;
656 printf("menu_load_config: unhandled len %d for %s\n",
657 (int)config_data[i].len, config_data[i].name);
663 char *tmp = strstr(cfg, "lastcdimg = ");
666 parse_str_val(last_selected_fname, tmp);
681 for (i = bios_sel = 0; bioses[i] != NULL; i++)
682 if (strcmp(Config.Bios, bioses[i]) == 0)
683 { bios_sel = i; break; }
685 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
686 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
687 { gpu_plugsel = i; break; }
689 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
690 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
691 { spu_plugsel = i; break; }
693 // memcard selections
694 char mcd1_old[sizeof(Config.Mcd1)];
695 char mcd2_old[sizeof(Config.Mcd2)];
696 strcpy(mcd1_old, Config.Mcd1);
697 strcpy(mcd2_old, Config.Mcd2);
699 if ((unsigned int)memcard1_sel < ARRAY_SIZE(memcards)) {
700 if (memcard1_sel == 0)
701 strcpy(Config.Mcd1, "none");
702 else if (memcards[memcard1_sel] != NULL)
703 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s",
704 MEMCARD_DIR, memcards[memcard1_sel]);
706 if ((unsigned int)memcard2_sel < ARRAY_SIZE(memcards)) {
707 if (memcard2_sel == 0)
708 strcpy(Config.Mcd2, "none");
709 else if (memcards[memcard2_sel] != NULL)
710 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s",
711 MEMCARD_DIR, memcards[memcard2_sel]);
713 if (strcmp(mcd1_old, Config.Mcd1) || strcmp(mcd2_old, Config.Mcd2))
714 LoadMcds(Config.Mcd1, Config.Mcd2);
719 static const char *filter_exts[] = {
720 "bin", "img", "mdf", "iso", "cue", "z",
724 "bz", "znx", "pbp", "cbn", NULL
727 // rrrr rggg gggb bbbb
728 static unsigned short fname2color(const char *fname)
730 static const char *other_exts[] = {
731 "ccd", "toc", "mds", "sub", "table", "index", "sbi"
733 const char *ext = strrchr(fname, '.');
739 for (i = 0; filter_exts[i] != NULL; i++)
740 if (strcasecmp(ext, filter_exts[i]) == 0)
742 for (i = 0; i < array_size(other_exts); i++)
743 if (strcasecmp(ext, other_exts[i]) == 0)
748 static void draw_savestate_bg(int slot);
750 #define MENU_ALIGN_LEFT
751 #ifndef HAVE_PRE_ARMV7 // assume hires device
757 #include "libpicofe/menu.c"
759 // a bit of black magic here
760 static void draw_savestate_bg(int slot)
762 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
764 char fname[MAXPATHLEN];
771 ret = get_state_filename(fname, sizeof(fname), slot);
775 f = gzopen(fname, "rb");
779 if ((ret = (int)gzseek(f, 0x29933d, SEEK_SET)) != 0x29933d) {
780 fprintf(stderr, "gzseek failed: %d\n", ret);
785 gpu = malloc(sizeof(*gpu));
791 ret = gzread(f, gpu, sizeof(*gpu));
793 if (ret != sizeof(*gpu)) {
794 fprintf(stderr, "gzread failed\n");
798 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
800 if (gpu->ulStatus & 0x800000)
801 goto out; // disabled
803 x = gpu->ulControl[5] & 0x3ff;
804 y = (gpu->ulControl[5] >> 10) & 0x1ff;
805 w = psx_widths[(gpu->ulStatus >> 16) & 7];
806 tmp = gpu->ulControl[7];
807 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
808 if (gpu->ulStatus & 0x80000) // doubleheight
810 if (h <= 0 || h > 512)
816 s = (u16 *)gpu->psxVRam + y * 1024 + x;
818 x = max(0, g_menuscreen_w - w) & ~3;
819 y = max(0, g_menuscreen_h / 2 - h / 2);
820 w = min(g_menuscreen_w, w);
821 h = min(g_menuscreen_h, h);
822 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
824 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
825 if (gpu->ulStatus & 0x200000)
826 bgr888_to_rgb565(d, s, w * 3);
828 bgr555_to_rgb565(d, s, w * 2);
830 // darken this so that menu text is visible
831 if (g_menuscreen_w - w < 320)
832 menu_darken_bg(d, d, w, 0);
839 // -------------- key config --------------
841 me_bind_action me_ctrl_actions[] =
843 { "UP ", 1 << DKEY_UP},
844 { "DOWN ", 1 << DKEY_DOWN },
845 { "LEFT ", 1 << DKEY_LEFT },
846 { "RIGHT ", 1 << DKEY_RIGHT },
847 { "TRIANGLE", 1 << DKEY_TRIANGLE },
848 { "CIRCLE ", 1 << DKEY_CIRCLE },
849 { "CROSS ", 1 << DKEY_CROSS },
850 { "SQUARE ", 1 << DKEY_SQUARE },
851 { "L1 ", 1 << DKEY_L1 },
852 { "R1 ", 1 << DKEY_R1 },
853 { "L2 ", 1 << DKEY_L2 },
854 { "R2 ", 1 << DKEY_R2 },
855 { "L3 ", 1 << DKEY_L3 },
856 { "R3 ", 1 << DKEY_R3 },
857 { "START ", 1 << DKEY_START },
858 { "SELECT ", 1 << DKEY_SELECT },
862 me_bind_action emuctrl_actions[] =
864 { "Save State ", 1 << SACTION_SAVE_STATE },
865 { "Load State ", 1 << SACTION_LOAD_STATE },
866 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
867 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
868 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
869 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
870 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
871 #ifndef HAVE_PRE_ARMV7
872 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
874 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
875 #if MENU_SHOW_MINIMIZE
876 { "Minimize ", 1 << SACTION_MINIMIZE },
878 #if MENU_SHOW_FULLSCREEN
879 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
881 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
882 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
883 { "Gun A button ", 1 << SACTION_GUN_A },
884 { "Gun B button ", 1 << SACTION_GUN_B },
885 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
887 { "Volume Up ", 1 << SACTION_VOLUME_UP },
888 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
893 static char *mystrip(char *str)
898 for (i = 0; i < len; i++)
899 if (str[i] != ' ') break;
900 if (i > 0) memmove(str, str + i, len - i + 1);
903 for (i = len - 1; i >= 0; i--)
904 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
910 static void get_line(char *d, size_t size, const char *s)
915 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
924 static void keys_write_all(FILE *f)
928 for (d = 0; d < IN_MAX_DEVS; d++)
930 const int *binds = in_get_dev_binds(d);
931 const char *name = in_get_dev_name(d, 0, 0);
934 if (binds == NULL || name == NULL)
937 fprintf(f, "binddev = %s\n", name);
938 in_get_config(d, IN_CFG_BIND_COUNT, &count);
940 for (k = 0; k < count; k++)
945 act[0] = act[31] = 0;
946 name = in_get_key_name(d, k);
948 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
949 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
950 mask = me_ctrl_actions[i].mask;
952 strncpy(act, me_ctrl_actions[i].name, 31);
953 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
956 mask = me_ctrl_actions[i].mask << 16;
958 strncpy(act, me_ctrl_actions[i].name, 31);
959 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
964 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
965 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
966 mask = emuctrl_actions[i].mask;
968 strncpy(act, emuctrl_actions[i].name, 31);
969 fprintf(f, "bind %s = %s\n", name, mystrip(act));
975 for (k = 0; k < array_size(in_adev); k++)
978 fprintf(f, "bind_analog = %d\n", k);
983 static int parse_bind_val(const char *val, int *type)
987 *type = IN_BINDTYPE_NONE;
991 if (strncasecmp(val, "player", 6) == 0)
993 int player, shift = 0;
994 player = atoi(val + 6) - 1;
996 if ((unsigned int)player > 1)
1001 *type = IN_BINDTYPE_PLAYER12;
1002 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
1003 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
1004 return me_ctrl_actions[i].mask << shift;
1007 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
1008 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
1009 *type = IN_BINDTYPE_EMU;
1010 return emuctrl_actions[i].mask;
1017 static void keys_load_all(const char *cfg)
1019 char dev[256], key[128], *act;
1025 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
1028 // don't strip 'dev' because there are weird devices
1029 // with names with space at the end
1030 get_line(dev, sizeof(dev), p);
1032 dev_id = in_config_parse_dev(dev);
1034 printf("input: can't handle dev: %s\n", dev);
1038 in_unbind_all(dev_id, -1, -1);
1039 while ((p = strstr(p, "bind"))) {
1040 if (strncmp(p, "binddev = ", 10) == 0)
1043 if (strncmp(p, "bind_analog", 11) == 0) {
1044 ret = sscanf(p, "bind_analog = %d", &bind);
1047 printf("input: parse error: %16s..\n", p);
1050 if ((unsigned int)bind >= array_size(in_adev)) {
1051 printf("input: analog id %d out of range\n", bind);
1054 in_adev[bind] = dev_id;
1060 printf("input: parse error: %16s..\n", p);
1064 get_line(key, sizeof(key), p);
1065 act = strchr(key, '=');
1067 printf("parse failed: %16s..\n", p);
1075 bind = parse_bind_val(act, &bindtype);
1076 if (bind != -1 && bind != 0) {
1077 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
1078 in_config_bind_key(dev_id, key, bind, bindtype);
1081 lprintf("config: unhandled action \"%s\"\n", act);
1087 static int key_config_loop_wrap(int id, int keys)
1090 case MA_CTRL_PLAYER1:
1091 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
1093 case MA_CTRL_PLAYER2:
1094 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
1097 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
1105 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
1106 "Might cause problems with real analog sticks";
1107 static const char *adevnames[IN_MAX_DEVS + 2];
1108 static int stick_sel[2];
1110 static menu_entry e_menu_keyconfig_analog[] =
1112 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
1113 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
1114 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
1115 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
1116 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
1117 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
1118 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
1119 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
1123 static int key_config_analog(int id, int keys)
1125 int i, d, count, sel = 0;
1126 int sel2dev_map[IN_MAX_DEVS];
1128 memset(adevnames, 0, sizeof(adevnames));
1129 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1130 memset(stick_sel, 0, sizeof(stick_sel));
1132 adevnames[0] = "None";
1134 for (d = 0; d < IN_MAX_DEVS; d++)
1136 const char *name = in_get_dev_name(d, 0, 1);
1141 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1145 if (in_adev[0] == d) stick_sel[0] = i;
1146 if (in_adev[1] == d) stick_sel[1] = i;
1148 adevnames[i++] = name;
1150 adevnames[i] = NULL;
1152 me_loop(e_menu_keyconfig_analog, &sel);
1154 in_adev[0] = sel2dev_map[stick_sel[0]];
1155 in_adev[1] = sel2dev_map[stick_sel[1]];
1160 static const char *mgn_dev_name(int id, int *offs)
1162 const char *name = NULL;
1165 if (id == MA_CTRL_DEV_FIRST)
1168 for (; it < IN_MAX_DEVS; it++) {
1169 name = in_get_dev_name(it, 1, 1);
1178 static const char *mgn_saveloadcfg(int id, int *offs)
1183 static int mh_savecfg(int id, int keys)
1185 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1186 menu_update_msg("config saved");
1188 menu_update_msg("failed to write config");
1193 static int mh_input_rescan(int id, int keys)
1195 //menu_sync_config();
1197 menu_update_msg("rescan complete.");
1202 static const char *men_in_type_sel[] = {
1203 "Standard (SCPH-1080)",
1204 "Analog (SCPH-1150)",
1208 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1209 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1210 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1212 static menu_entry e_menu_keyconfig[] =
1214 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1215 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1216 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1217 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1219 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1220 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1221 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1222 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1223 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1224 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1225 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1226 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1227 mee_handler ("Rescan devices:", mh_input_rescan),
1229 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1230 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1231 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1232 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1233 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1234 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1235 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1239 static int menu_loop_keyconfig(int id, int keys)
1243 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1244 me_loop(e_menu_keyconfig, &sel);
1248 // ------------ gfx options menu ------------
1250 static const char *men_scaler[] = {
1251 "1x1", "integer scaled 2x", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL
1253 static const char *men_soft_filter[] = { "None",
1255 "scale2x", "eagle2x",
1258 static const char *men_dummy[] = { NULL };
1259 static const char *men_centering[] = { "Auto", "Ingame", "Force", NULL };
1260 static const char h_scaler[] = "int. 2x - scales w. or h. 2x if it fits on screen\n"
1261 "int. 4:3 - uses integer if possible, else fractional";
1262 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1263 "using d-pad or move it using R+d-pad";
1264 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1265 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1267 static const char h_scanline_l[] = "Scanline brightness, 0-100%";
1270 static int menu_loop_cscaler(int id, int keys)
1274 g_scaler = SCALE_CUSTOM;
1276 plat_gvideo_open(Config.PsxType);
1280 menu_draw_begin(0, 1);
1281 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1282 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1283 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1286 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1287 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1288 if (inp & PBTN_UP) g_layer_y--;
1289 if (inp & PBTN_DOWN) g_layer_y++;
1290 if (inp & PBTN_LEFT) g_layer_x--;
1291 if (inp & PBTN_RIGHT) g_layer_x++;
1292 if (!(inp & PBTN_R)) {
1293 if (inp & PBTN_UP) g_layer_h += 2;
1294 if (inp & PBTN_DOWN) g_layer_h -= 2;
1295 if (inp & PBTN_LEFT) g_layer_w += 2;
1296 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1298 if (inp & (PBTN_MOK|PBTN_MBACK))
1301 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1302 if (g_layer_x < 0) g_layer_x = 0;
1303 if (g_layer_x > 640) g_layer_x = 640;
1304 if (g_layer_y < 0) g_layer_y = 0;
1305 if (g_layer_y > 420) g_layer_y = 420;
1306 if (g_layer_w < 160) g_layer_w = 160;
1307 if (g_layer_h < 60) g_layer_h = 60;
1308 if (g_layer_x + g_layer_w > 800)
1309 g_layer_w = 800 - g_layer_x;
1310 if (g_layer_y + g_layer_h > 480)
1311 g_layer_h = 480 - g_layer_y;
1313 plat_gvideo_open(Config.PsxType);
1317 plat_gvideo_close();
1322 static menu_entry e_menu_gfx_options[] =
1324 mee_enum ("Screen centering", MA_OPT_CENTERING, pl_rearmed_cbs.screen_centering_type, men_centering),
1325 mee_enum_h ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler, h_scaler),
1326 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1327 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1328 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1329 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1331 mee_onoff ("Scanlines", MA_OPT_SCANLINES, scanlines, 1),
1332 mee_range_h ("Scanline brightness", MA_OPT_SCANLINE_LEVEL, scanline_level, 0, 100, h_scanline_l),
1334 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1335 // mee_onoff ("Vsync", 0, vsync, 1),
1336 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1340 static int menu_loop_gfx_options(int id, int keys)
1344 me_loop(e_menu_gfx_options, &sel);
1349 // ------------ bios/plugins ------------
1351 #ifdef BUILTIN_GPU_NEON
1353 static const char h_gpu_neon[] =
1354 "Configure built-in NEON GPU plugin";
1355 static const char h_gpu_neon_enhanced[] =
1356 "Renders in double resolution at the cost of lower performance\n"
1357 "(not available for high resolution games)";
1358 static const char h_gpu_neon_enhanced_hack[] =
1359 "Speed hack for above option (glitches some games)";
1360 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1362 static menu_entry e_menu_plugin_gpu_neon[] =
1364 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1365 mee_onoff_h ("Enhanced resolution", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1366 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1370 static int menu_loop_plugin_gpu_neon(int id, int keys)
1373 me_loop(e_menu_plugin_gpu_neon, &sel);
1379 static menu_entry e_menu_plugin_gpu_unai[] =
1381 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1382 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1383 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1384 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1388 static int menu_loop_plugin_gpu_unai(int id, int keys)
1391 me_loop(e_menu_plugin_gpu_unai, &sel);
1395 static menu_entry e_menu_plugin_gpu_senquack[] =
1397 mee_onoff ("Interlace", 0, pl_rearmed_cbs.gpu_senquack.ilace_force, 1),
1398 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_senquack.dithering, 1),
1399 mee_onoff ("Lighting", 0, pl_rearmed_cbs.gpu_senquack.lighting, 1),
1400 mee_onoff ("Fast lighting", 0, pl_rearmed_cbs.gpu_senquack.fast_lighting, 1),
1401 mee_onoff ("Blending", 0, pl_rearmed_cbs.gpu_senquack.blending, 1),
1402 mee_onoff ("Pixel skip", 0, pl_rearmed_cbs.gpu_senquack.pixel_skip, 1),
1406 static int menu_loop_plugin_gpu_senquack(int id, int keys)
1409 me_loop(e_menu_plugin_gpu_senquack, &sel);
1414 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1415 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1416 static const char h_gpu_1[] = "Capcom fighting games";
1417 static const char h_gpu_2[] = "Black screens in Lunar";
1418 static const char h_gpu_3[] = "Compatibility mode";
1419 static const char h_gpu_6[] = "Pandemonium 2";
1420 //static const char h_gpu_7[] = "Skip every second frame";
1421 static const char h_gpu_8[] = "Needed by Dark Forces";
1422 static const char h_gpu_9[] = "better g-colors, worse textures";
1423 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1425 static menu_entry e_menu_plugin_gpu_peops[] =
1427 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1428 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1429 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1430 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1431 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1432 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1433 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1434 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1435 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1436 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1440 static int menu_loop_plugin_gpu_peops(int id, int keys)
1443 me_loop(e_menu_plugin_gpu_peops, &sel);
1447 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1448 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1449 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1451 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1453 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1454 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1455 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1456 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1457 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1458 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1459 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1460 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1461 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1462 mee_label ("Fixes/hacks:"),
1463 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1464 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1465 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1466 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1467 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1468 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1469 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1470 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1471 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1472 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1473 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1477 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1480 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1484 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1485 static const char h_spu_volboost[] = "Large values cause distortion";
1486 static const char h_spu_tempo[] = "Slows down audio if emu is too slow\n"
1487 "This is inaccurate and breaks games";
1489 static menu_entry e_menu_plugin_spu[] =
1491 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1492 mee_onoff ("Reverb", 0, spu_config.iUseReverb, 1),
1493 mee_enum ("Interpolation", 0, spu_config.iUseInterpolation, men_spu_interp),
1494 //mee_onoff ("Adjust XA pitch", 0, spu_config.iXAPitch, 1),
1495 mee_onoff_h ("Adjust tempo", 0, spu_config.iTempo, 1, h_spu_tempo),
1499 static int menu_loop_plugin_spu(int id, int keys)
1502 me_loop(e_menu_plugin_spu, &sel);
1506 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1507 "savestates and can't be changed there. Must save\n"
1508 "config and reload the game for change to take effect";
1509 static const char h_plugin_gpu[] =
1510 #ifdef BUILTIN_GPU_NEON
1511 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1513 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1514 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1515 "gpu_senquack is more accurate but slower\n"
1516 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1517 "must save config and reload the game if changed";
1518 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1519 "must save config and reload the game if changed";
1520 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1521 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1522 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1523 static const char h_gpu_senquack[] = "Configure Unai/PCSX4ALL Senquack plugin";
1524 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1526 static menu_entry e_menu_plugin_options[] =
1528 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1529 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1530 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1531 #ifdef BUILTIN_GPU_NEON
1532 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1534 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1535 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1536 mee_handler_h ("Configure gpu_senquack GPU plugin", menu_loop_plugin_gpu_senquack, h_gpu_senquack),
1537 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1538 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1542 static menu_entry e_menu_main2[];
1544 static int menu_loop_plugin_options(int id, int keys)
1547 me_loop(e_menu_plugin_options, &sel);
1549 // sync BIOS/plugins
1550 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1551 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1552 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1553 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1558 // ------------ adv options menu ------------
1561 static const char h_cfg_noch[] = "Disables game-specific compatibility hacks";
1562 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1563 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1564 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1566 static const char h_cfg_stalls[] = "Will cause some games to run too fast";
1568 static menu_entry e_menu_speed_hacks[] =
1571 mee_onoff_h ("Disable compat hacks", 0, new_dynarec_hacks, NDHACK_NO_COMPAT_HACKS, h_cfg_noch),
1572 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1573 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1574 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1576 mee_onoff_h ("Disable CPU/GTE stalls", 0, menu_iopts[0], 1, h_cfg_stalls),
1580 static int menu_loop_speed_hacks(int id, int keys)
1583 menu_iopts[0] = Config.DisableStalls;
1584 me_loop(e_menu_speed_hacks, &sel);
1585 Config.DisableStalls = menu_iopts[0];
1589 static const char *men_gpul[] = { "Auto", "Off", "On", NULL };
1591 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1592 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1593 "(green: normal, red: fmod, blue: noise)";
1594 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1595 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1596 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1597 "(proper .cue/.bin dump is needed otherwise)";
1599 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1600 "Might be useful to overcome some dynarec bugs";
1602 static const char h_cfg_shacks[] = "Breaks games but may give better performance";
1603 static const char h_cfg_icache[] = "Support F1 games (only when dynarec is off)";
1604 static const char h_cfg_exc[] = "Emulate some PSX's debug hw like breakpoints\n"
1605 "and exceptions (slow, interpreter only, keep off)";
1606 static const char h_cfg_gpul[] = "Try enabling this if the game misses some graphics\n"
1607 "causes a performance hit";
1608 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1609 "(adjust this if the game is too slow/too fast/hangs)";
1611 enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_BP, AMO_CPU, AMO_GPUL };
1613 static menu_entry e_menu_adv_options[] =
1615 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1616 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1617 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1618 mee_onoff_h ("Disable XA Decoding", 0, menu_iopts[AMO_XA], 1, h_cfg_xa),
1619 mee_onoff_h ("Disable CD Audio", 0, menu_iopts[AMO_CDDA], 1, h_cfg_cdda),
1620 mee_onoff_h ("ICache emulation", 0, menu_iopts[AMO_IC], 1, h_cfg_icache),
1621 mee_onoff_h ("BP exception emulation", 0, menu_iopts[AMO_BP], 1, h_cfg_exc),
1622 mee_enum_h ("GPU l-list slow walking",0, menu_iopts[AMO_GPUL], men_gpul, h_cfg_gpul),
1623 #if !defined(DRC_DISABLE) || defined(LIGHTREC)
1624 mee_onoff_h ("Disable dynarec (slow!)",0, menu_iopts[AMO_CPU], 1, h_cfg_nodrc),
1626 mee_range_h ("PSX CPU clock, %", 0, psx_clock, 1, 500, h_cfg_psxclk),
1627 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1631 static int menu_loop_adv_options(int id, int keys)
1638 { &Config.Xa, &menu_iopts[AMO_XA] },
1639 { &Config.Cdda, &menu_iopts[AMO_CDDA] },
1640 { &Config.icache_emulation, &menu_iopts[AMO_IC] },
1641 { &Config.PreciseExceptions, &menu_iopts[AMO_BP] },
1642 { &Config.Cpu, &menu_iopts[AMO_CPU] },
1645 for (i = 0; i < ARRAY_SIZE(opts); i++)
1646 *opts[i].mopt = *opts[i].opt;
1647 menu_iopts[AMO_GPUL] = Config.GpuListWalking + 1;
1649 me_loop(e_menu_adv_options, &sel);
1651 for (i = 0; i < ARRAY_SIZE(opts); i++)
1652 *opts[i].opt = *opts[i].mopt;
1653 Config.GpuListWalking = menu_iopts[AMO_GPUL] - 1;
1658 // ------------ options menu ------------
1660 static int mh_restore_defaults(int id, int keys)
1662 menu_set_defconfig();
1663 menu_update_msg("defaults restored");
1667 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1668 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1670 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1671 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1672 "loading state or both";
1674 static const char h_restore_def[] = "Switches back to default / recommended\n"
1676 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1678 static menu_entry e_menu_options[] =
1680 // mee_range ("Save slot", 0, state_slot, 0, 9),
1681 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1682 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1683 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1684 mee_enum ("Region", 0, region, men_region),
1685 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1687 mee_onoff ("Use C64x DSP for sound", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1),
1689 mee_onoff ("Threaded SPU", MA_OPT_SPU_THREAD, spu_config.iUseThread, 1),
1691 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1692 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1693 mee_handler ("[Advanced]", menu_loop_adv_options),
1694 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1695 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1696 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1700 static int menu_loop_options(int id, int keys)
1704 me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, cpu_clock_st > 0);
1705 me_enable(e_menu_options, MA_OPT_SPU_THREAD, spu_config.iThreadAvail);
1706 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1708 me_loop(e_menu_options, &sel);
1713 // ------------ debug menu ------------
1715 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1717 int w = min(g_menuscreen_w, 1024);
1718 int h = min(g_menuscreen_h, 512);
1719 u16 *d = g_menuscreen_ptr;
1720 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1724 gpuf->ulFreezeVersion = 1;
1725 if (GPU_freeze != NULL)
1726 GPU_freeze(1, gpuf);
1728 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1729 bgr555_to_rgb565(d, s, w * 2);
1731 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1732 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1733 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1734 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1735 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1738 static void debug_menu_loop(void)
1740 int inp, df_x = 0, df_y = 0;
1743 gpuf = malloc(sizeof(*gpuf));
1749 menu_draw_begin(0, 1);
1750 draw_frame_debug(gpuf, df_x, df_y);
1753 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1754 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1755 if (inp & PBTN_MBACK) break;
1756 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1757 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1758 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1759 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1765 // --------- memcard manager ---------
1767 static void draw_mc_icon(int dx, int dy, const u16 *s)
1772 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1774 for (y = 0; y < 16; y++, s += 16) {
1775 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1776 for (x = 0; x < 16; x++) {
1778 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1779 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1785 static void draw_mc_bg(void)
1787 McdBlock *blocks1, *blocks2;
1791 blocks1 = malloc(15 * sizeof(blocks1[0]));
1792 blocks2 = malloc(15 * sizeof(blocks1[0]));
1793 if (blocks1 == NULL || blocks2 == NULL)
1796 for (i = 0; i < 15; i++) {
1797 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1798 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1801 menu_draw_begin(1, 1);
1803 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1805 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1809 maxicons = g_menuscreen_h / 32;
1812 row2 = g_menuscreen_w / 2;
1813 for (i = 0; i < maxicons; i++) {
1814 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1815 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1817 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1818 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1821 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1829 static void handle_memcard_sel(void)
1831 strcpy(Config.Mcd1, "none");
1832 if (memcard1_sel != 0)
1833 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1834 strcpy(Config.Mcd2, "none");
1835 if (memcard2_sel != 0)
1836 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1837 LoadMcds(Config.Mcd1, Config.Mcd2);
1841 static menu_entry e_memcard_options[] =
1843 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1844 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1848 static int menu_loop_memcards(int id, int keys)
1854 memcard1_sel = memcard2_sel = 0;
1855 p = strrchr(Config.Mcd1, '/');
1857 for (i = 0; memcards[i] != NULL; i++)
1858 if (strcmp(p + 1, memcards[i]) == 0)
1859 { memcard1_sel = i; break; }
1860 p = strrchr(Config.Mcd2, '/');
1862 for (i = 0; memcards[i] != NULL; i++)
1863 if (strcmp(p + 1, memcards[i]) == 0)
1864 { memcard2_sel = i; break; }
1866 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1868 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1873 // ------------ cheats menu ------------
1875 static void draw_cheatlist(int sel)
1877 int max_cnt, start, i, pos, active;
1879 max_cnt = g_menuscreen_h / me_sfont_h;
1880 start = max_cnt / 2 - sel;
1882 menu_draw_begin(1, 1);
1884 for (i = 0; i < NumCheats; i++) {
1886 if (pos < 0) continue;
1887 if (pos >= max_cnt) break;
1888 active = Cheats[i].Enabled;
1889 smalltext_out16(14, pos * me_sfont_h,
1890 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1891 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1892 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1896 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1898 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1902 static void menu_loop_cheats(void)
1904 static int menu_sel = 0;
1909 draw_cheatlist(menu_sel);
1910 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1911 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1912 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1913 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1914 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1915 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1916 if (inp & PBTN_MOK) { // action
1917 if (menu_sel < NumCheats)
1918 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1921 if (inp & PBTN_MBACK)
1926 // --------- main menu help ----------
1928 static void menu_bios_warn(void)
1931 static const char msg[] =
1932 "You don't seem to have copied any BIOS\n"
1934 MENU_BIOS_PATH "\n\n"
1936 "While many games work fine with fake\n"
1937 "(HLE) BIOS, others (like MGS and FF8)\n"
1938 "require BIOS to work.\n"
1939 "After copying the file, you'll also need\n"
1940 "to select it in the emu's menu:\n"
1941 "options->[BIOS/Plugins]\n\n"
1942 "The file is usually named SCPH1001.BIN,\n"
1943 "but other not compressed files can be\n"
1945 "Press %s or %s to continue";
1946 char tmp_msg[sizeof(msg) + 64];
1948 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1949 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1952 draw_menu_message(tmp_msg, NULL);
1954 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1955 if (inp & (PBTN_MBACK|PBTN_MOK))
1960 // ------------ main menu ------------
1962 static menu_entry e_menu_main[];
1964 static void draw_frame_main(void)
1973 if (CdromId[0] != 0) {
1974 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1975 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1976 Config.HLE ? "HLE" : "BIOS");
1977 smalltext_out16(4, 1, buff, 0x105f);
1981 capacity = plat_target_bat_capacity_get();
1983 tmp = localtime(<ime);
1984 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1985 if (capacity >= 0) {
1986 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1991 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1995 static void draw_frame_credits(void)
1997 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
2000 static const char credits_text[] =
2002 "(C) 1999-2003 PCSX Team\n"
2003 "(C) 2005-2009 PCSX-df Team\n"
2004 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
2005 "ARM recompiler (C) 2009-2011 Ari64\n"
2006 #ifdef BUILTIN_GPU_NEON
2007 "ARM NEON GPU (c) 2011-2012 Exophase\n"
2009 "PEOpS GPU and SPU by Pete Bernert\n"
2010 " and the P.E.Op.S. team\n"
2011 "PCSX4ALL plugin by PCSX4ALL team\n"
2012 " Chui, Franxis, Unai\n\n"
2013 "integration, optimization and\n"
2014 " frontend (C) 2010-2015 notaz\n";
2016 static int reset_game(void)
2019 if (bios_sel == 0 && !Config.HLE)
2026 if (LoadCdrom() == -1)
2032 static int reload_plugins(const char *cdimg)
2038 set_cd_image(cdimg);
2040 pcnt_hook_plugins();
2042 if (OpenPlugins() == -1) {
2043 menu_update_msg("failed to open plugins");
2046 plugin_call_rearmed_cbs();
2048 cdrIsoMultidiskCount = 1;
2050 CdromLabel[0] = '\0';
2055 static int run_bios(void)
2057 boolean origSlowBoot = Config.SlowBoot;
2063 if (reload_plugins(NULL) != 0)
2065 Config.SlowBoot = 1;
2067 Config.SlowBoot = origSlowBoot;
2073 static int run_exe(void)
2075 const char *exts[] = { "exe", NULL };
2078 fname = menu_loop_romsel(last_selected_fname,
2079 sizeof(last_selected_fname), exts, NULL);
2084 if (reload_plugins(NULL) != 0)
2088 if (Load(fname) != 0) {
2089 menu_update_msg("exe load failed, bad file?");
2098 static int run_cd_image(const char *fname)
2100 int autoload_state = g_autostateld_opt;
2103 reload_plugins(fname);
2105 // always autodetect, menu_sync_config will override as needed
2108 if (CheckCdrom() == -1) {
2109 // Only check the CD if we are starting the console with a CD
2111 menu_update_msg("unsupported/invalid CD image");
2117 // Read main executable directly from CDRom and start it
2118 if (LoadCdrom() == -1) {
2120 menu_update_msg("failed to load CD image");
2127 if (autoload_state) {
2128 unsigned int newest = 0;
2129 int time, slot, newest_slot = -1;
2131 for (slot = 0; slot < 10; slot++) {
2132 if (emu_check_save_file(slot, &time)) {
2133 if ((unsigned int)time > newest) {
2140 if (newest_slot >= 0) {
2141 lprintf("autoload slot %d\n", newest_slot);
2142 emu_load_state(newest_slot);
2145 lprintf("no save to autoload.\n");
2152 static int romsel_run(void)
2154 int prev_gpu, prev_spu;
2157 fname = menu_loop_romsel(last_selected_fname,
2158 sizeof(last_selected_fname), filter_exts,
2159 optional_cdimg_filter);
2163 printf("selected file: %s\n", fname);
2165 new_dynarec_clear_full();
2167 if (run_cd_image(fname) != 0)
2170 prev_gpu = gpu_plugsel;
2171 prev_spu = spu_plugsel;
2172 if (menu_load_config(1) != 0)
2173 menu_load_config(0);
2175 // check for plugin changes, have to repeat
2176 // loading if game config changed plugins to reload them
2177 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
2178 printf("plugin change detected, reloading plugins..\n");
2179 if (run_cd_image(fname) != 0)
2183 strcpy(last_selected_fname, fname);
2184 menu_do_last_cd_img(0);
2188 static int swap_cd_image(void)
2192 fname = menu_loop_romsel(last_selected_fname,
2193 sizeof(last_selected_fname), filter_exts,
2194 optional_cdimg_filter);
2198 printf("selected file: %s\n", fname);
2201 CdromLabel[0] = '\0';
2203 set_cd_image(fname);
2204 if (ReloadCdromPlugin() < 0) {
2205 menu_update_msg("failed to load cdr plugin");
2208 if (CDR_open() < 0) {
2209 menu_update_msg("failed to open cdr plugin");
2213 SetCdOpenCaseTime(time(NULL) + 2);
2216 strcpy(last_selected_fname, fname);
2220 static int swap_cd_multidisk(void)
2222 cdrIsoMultidiskSelect++;
2224 CdromLabel[0] = '\0';
2227 if (CDR_open() < 0) {
2228 menu_update_msg("failed to open cdr plugin");
2232 SetCdOpenCaseTime(time(NULL) + 2);
2238 static void load_pcsx_cht(void)
2240 static const char *exts[] = { "cht", NULL };
2244 fname = menu_loop_romsel(last_selected_fname,
2245 sizeof(last_selected_fname), exts, NULL);
2249 printf("selected cheat file: %s\n", fname);
2252 if (NumCheats == 0 && NumCodes == 0)
2253 menu_update_msg("failed to load cheats");
2255 snprintf(msg, sizeof(msg), "%d cheat(s) loaded", NumCheats + NumCodes);
2256 menu_update_msg(msg);
2258 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2261 static int main_menu_handler(int id, int keys)
2265 case MA_MAIN_RESUME_GAME:
2269 case MA_MAIN_SAVE_STATE:
2271 return menu_loop_savestate(0);
2273 case MA_MAIN_LOAD_STATE:
2275 return menu_loop_savestate(1);
2277 case MA_MAIN_RESET_GAME:
2278 if (ready_to_go && reset_game() == 0)
2281 case MA_MAIN_LOAD_ROM:
2282 if (romsel_run() == 0)
2285 case MA_MAIN_SWAP_CD:
2286 if (swap_cd_image() == 0)
2289 case MA_MAIN_SWAP_CD_MULTI:
2290 if (swap_cd_multidisk() == 0)
2293 case MA_MAIN_RUN_BIOS:
2294 if (run_bios() == 0)
2297 case MA_MAIN_RUN_EXE:
2301 case MA_MAIN_CHEATS:
2304 case MA_MAIN_LOAD_CHEATS:
2307 case MA_MAIN_CREDITS:
2308 draw_menu_message(credits_text, draw_frame_credits);
2309 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2312 emu_core_ask_exit();
2315 lprintf("%s: something unknown selected\n", __FUNCTION__);
2322 static menu_entry e_menu_main2[] =
2324 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2325 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2326 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2327 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2328 mee_handler ("Memcard manager", menu_loop_memcards),
2329 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2333 static int main_menu2_handler(int id, int keys)
2337 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2338 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2339 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2340 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2342 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2345 static const char h_extra[] = "Change CD, manage memcards..\n";
2347 static menu_entry e_menu_main[] =
2351 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2352 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2353 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2354 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2355 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2356 mee_handler ("Options", menu_loop_options),
2357 mee_handler ("Controls", menu_loop_keyconfig),
2358 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2359 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2360 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2361 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2365 // ----------------------------
2367 static void menu_leave_emu(void);
2369 void menu_loop(void)
2371 static int warned_about_bios = 0;
2376 if (config_save_counter == 0) {
2378 if (bioses[1] != NULL) {
2379 // autoselect BIOS to make user's life easier
2380 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2383 else if (!warned_about_bios) {
2385 warned_about_bios = 1;
2389 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2390 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2391 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2392 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2393 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2395 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2398 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2399 } while (!ready_to_go && !g_emu_want_quit);
2401 /* wait until menu, ok, back is released */
2402 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2405 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2410 static int qsort_strcmp(const void *p1, const void *p2)
2412 char * const *s1 = (char * const *)p1;
2413 char * const *s2 = (char * const *)p2;
2414 return strcasecmp(*s1, *s2);
2417 static void scan_bios_plugins(void)
2419 char fname[MAXPATHLEN];
2421 int bios_i, gpu_i, spu_i, mc_i;
2426 gpu_plugins[0] = "builtin_gpu";
2427 spu_plugins[0] = "builtin_spu";
2428 memcards[0] = "(none)";
2429 bios_i = gpu_i = spu_i = mc_i = 1;
2431 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2432 dir = opendir(fname);
2434 perror("scan_bios_plugins bios opendir");
2449 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2452 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2453 if (stat(fname, &st) != 0
2454 || (st.st_size != 512*1024 && st.st_size != 4*1024*1024)) {
2455 printf("bad BIOS file: %s\n", ent->d_name);
2459 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2460 bioses[bios_i++] = strdup(ent->d_name);
2464 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2470 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2471 dir = opendir(fname);
2473 perror("scan_bios_plugins plugins opendir");
2487 p = strstr(ent->d_name, ".so");
2491 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2492 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2494 fprintf(stderr, "%s\n", dlerror());
2498 // now what do we have here?
2499 tmp = dlsym(h, "GPUinit");
2502 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2503 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2507 tmp = dlsym(h, "SPUinit");
2510 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2511 spu_plugins[spu_i++] = strdup(ent->d_name);
2515 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2522 dir = opendir("." MEMCARD_DIR);
2524 perror("scan_bios_plugins memcards opendir");
2539 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2542 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2543 if (stat(fname, &st) != 0) {
2544 printf("bad memcard file: %s\n", ent->d_name);
2548 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2549 memcards[mc_i++] = strdup(ent->d_name);
2553 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2557 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2562 void menu_init(void)
2564 char buff[MAXPATHLEN];
2567 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2569 scan_bios_plugins();
2572 menu_set_defconfig();
2573 menu_load_config(0);
2574 menu_do_last_cd_img(1);
2579 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2580 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2581 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2582 fprintf(stderr, "OOM\n");
2586 emu_make_path(buff, "skin/background.png", sizeof(buff));
2587 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2589 i = plat_target.cpu_clock_set != NULL
2590 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2591 me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, i);
2593 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2594 e_menu_gfx_options[i].data = plat_target.vout_methods;
2595 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2596 plat_target.vout_methods != NULL);
2598 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2599 e_menu_gfx_options[i].data = plat_target.hwfilters;
2600 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2601 plat_target.hwfilters != NULL);
2603 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2604 plat_target.gamma_set != NULL);
2606 #ifdef HAVE_PRE_ARMV7
2607 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2609 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2610 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2611 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2612 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2613 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2614 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2615 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2618 void menu_notify_mode_change(int w, int h, int bpp)
2622 last_vout_bpp = bpp;
2625 static void menu_leave_emu(void)
2627 if (GPU_close != NULL) {
2628 int ret = GPU_close();
2630 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2633 plat_video_menu_enter(ready_to_go);
2635 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2636 if (pl_vout_buf != NULL && ready_to_go) {
2637 int x = max(0, g_menuscreen_w - last_vout_w);
2638 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2639 int w = min(g_menuscreen_w, last_vout_w);
2640 int h = min(g_menuscreen_h, last_vout_h);
2641 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2642 char *s = pl_vout_buf;
2644 if (last_vout_bpp == 16) {
2645 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2646 menu_darken_bg(d, s, w, 0);
2649 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2650 rgb888_to_rgb565(d, s, w * 3);
2651 menu_darken_bg(d, d, w, 0);
2657 cpu_clock = plat_target_cpu_clock_get();
2660 void menu_prepare_emu(void)
2662 R3000Acpu *prev_cpu = psxCpu;
2664 plat_video_menu_leave();
2666 #if !defined(DRC_DISABLE) || defined(LIGHTREC)
2667 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2671 if (psxCpu != prev_cpu) {
2672 prev_cpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL);
2673 prev_cpu->Shutdown();
2676 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
2680 psxCpu->ApplyConfig();
2682 // core doesn't care about Config.Cdda changes,
2683 // so handle them manually here
2688 plat_target_cpu_clock_set(cpu_clock);
2690 // push config to GPU plugin
2691 plugin_call_rearmed_cbs();
2693 if (GPU_open != NULL) {
2694 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2696 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2700 void menu_update_msg(const char *msg)
2702 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2703 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2705 menu_error_time = plat_get_ticks_ms();
2706 lprintf("msg: %s\n", menu_error_msg);
2709 void menu_finish(void)
2711 if (cpu_clock_st > 0)
2712 plat_target_cpu_clock_set(cpu_clock_st);