2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2013
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
17 #include <sys/types.h>
26 #include "plugin_lib.h"
29 #include "libpicofe/plat.h"
30 #include "libpicofe/input.h"
31 #include "libpicofe/linux/in_evdev.h"
32 #include "libpicofe/plat.h"
33 #include "../libpcsxcore/misc.h"
34 #include "../libpcsxcore/cdrom.h"
35 #include "../libpcsxcore/cdriso.h"
36 #include "../libpcsxcore/cheat.h"
37 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
38 #include "../plugins/dfinput/externals.h"
39 #include "../plugins/gpulib/cspace.h"
40 #include "psemu_plugin_defs.h"
43 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
45 #define array_size(x) (sizeof(x) / sizeof(x[0]))
56 MA_MAIN_SWAP_CD_MULTI,
87 static int last_vout_w, last_vout_h, last_vout_bpp;
88 static int cpu_clock, cpu_clock_st, volume_boost, frameskip;
89 static char last_selected_fname[MAXPATHLEN];
90 static int config_save_counter, region, in_type_sel1, in_type_sel2;
92 static int memcard1_sel, memcard2_sel;
93 int g_opts, g_scaler, g_gamma = 100;
94 int soft_scaling, analog_deadzone; // for Caanoo
97 #ifdef __ARM_ARCH_7A__
98 #define DEFAULT_PSX_CLOCK 57
99 #define DEFAULT_PSX_CLOCK_S "57"
101 #define DEFAULT_PSX_CLOCK 50
102 #define DEFAULT_PSX_CLOCK_S "50"
106 extern int iUseReverb;
107 extern int iUseInterpolation;
111 static const char *bioses[24];
112 static const char *gpu_plugins[16];
113 static const char *spu_plugins[16];
114 static const char *memcards[32];
115 static int bios_sel, gpu_plugsel, spu_plugsel;
117 #ifndef UI_FEATURES_H
118 #define MENU_BIOS_PATH "bios/"
119 #define MENU_SHOW_VARSCALER 0
120 #define MENU_SHOW_VOUTMODE 1
121 #define MENU_SHOW_SCALER2 0
122 #define MENU_SHOW_NUBS_BTNS 0
123 #define MENU_SHOW_VIBRATION 0
124 #define MENU_SHOW_DEADZONE 0
125 #define MENU_SHOW_MINIMIZE 0
126 #define MENU_SHOW_FULLSCREEN 1
127 #define MENU_SHOW_VOLUME 0
130 static int min(int x, int y) { return x < y ? x : y; }
131 static int max(int x, int y) { return x > y ? x : y; }
133 void emu_make_path(char *buff, const char *end, int size)
137 end_len = strlen(end);
138 pos = plat_get_root_dir(buff, size);
139 strncpy(buff + pos, end, size - pos);
141 if (pos + end_len > size - 1)
142 printf("Warning: path truncated: %s\n", buff);
145 static int emu_check_save_file(int slot, int *time)
147 char fname[MAXPATHLEN];
151 ret = emu_check_state(slot);
152 if (ret != 0 || time == NULL)
153 return ret == 0 ? 1 : 0;
155 ret = get_state_filename(fname, sizeof(fname), slot);
159 ret = stat(fname, &status);
163 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
164 return 1; // probably bad rtc like on some Caanoos
166 *time = status.st_mtime;
171 static int emu_save_load_game(int load, int unused)
176 ret = emu_load_state(state_slot);
178 // reflect hle/bios mode from savestate
181 else if (bios_sel == 0 && bioses[1] != NULL)
182 // XXX: maybe find the right bios instead
186 ret = emu_save_state(state_slot);
191 static void rm_namelist_entry(struct dirent **namelist,
192 int count, const char *name)
196 for (i = 1; i < count; i++) {
197 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
200 if (strcmp(name, namelist[i]->d_name) == 0) {
208 static int optional_cdimg_filter(struct dirent **namelist, int count,
212 char buf[256], buf2[256];
213 int i, d, ret, good_cue;
217 for (i = 1; i < count; i++) {
218 if (namelist[i] == NULL || namelist[i]->d_type == DT_DIR)
221 ext = strrchr(namelist[i]->d_name, '.');
223 // should not happen but whatever
230 // first find .cue files and remove files they reference
231 if (strcasecmp(ext, "cue") == 0)
233 snprintf(buf, sizeof(buf), "%s/%s", basedir,
234 namelist[i]->d_name);
244 while (fgets(buf, sizeof(buf), f)) {
245 ret = sscanf(buf, " FILE \"%256[^\"]\"", buf2);
247 ret = sscanf(buf, " FILE %256s", buf2);
251 p = strrchr(buf2, '/');
253 p = strrchr(buf2, '\\');
257 snprintf(buf, sizeof(buf), "%s/%s", basedir, p);
258 ret = stat(buf, &statf);
260 rm_namelist_entry(namelist, count, p);
273 p = strcasestr(namelist[i]->d_name, "track");
275 ret = strtoul(p + 5, NULL, 10);
285 for (i = d = 1; i < count; i++)
286 if (namelist[i] != NULL)
287 namelist[d++] = namelist[i];
292 // propagate menu settings to the emu vars
293 static void menu_sync_config(void)
295 static int allow_abs_only_old;
300 Config.PsxType = region - 1;
302 cycle_multiplier = 10000 / psx_clock;
304 switch (in_type_sel1) {
305 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
306 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
307 default: in_type1 = PSE_PAD_TYPE_STANDARD;
309 switch (in_type_sel2) {
310 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
311 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
312 default: in_type2 = PSE_PAD_TYPE_STANDARD;
314 if (in_evdev_allow_abs_only != allow_abs_only_old) {
316 allow_abs_only_old = in_evdev_allow_abs_only;
319 iVolume = 768 + 128 * volume_boost;
320 pl_rearmed_cbs.frameskip = frameskip - 1;
321 pl_timing_prepare(Config.PsxType);
324 static void menu_set_defconfig(void)
326 emu_set_default_config();
329 g_scaler = SCALE_4_3;
332 analog_deadzone = 50;
335 plat_target.vout_fullscreen = 0;
336 psx_clock = DEFAULT_PSX_CLOCK;
339 in_type_sel1 = in_type_sel2 = 0;
340 in_evdev_allow_abs_only = 0;
345 #define CE_CONFIG_STR(val) \
346 { #val, 0, Config.val }
348 #define CE_CONFIG_VAL(val) \
349 { #val, sizeof(Config.val), &Config.val }
351 #define CE_STR(val) \
354 #define CE_INTVAL(val) \
355 { #val, sizeof(val), &val }
357 #define CE_INTVAL_N(name, val) \
358 { name, sizeof(val), &val }
360 #define CE_INTVAL_P(val) \
361 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
363 // 'versioned' var, used when defaults change
364 #define CE_CONFIG_STR_V(val, ver) \
365 { #val #ver, 0, Config.val }
367 #define CE_INTVAL_V(val, ver) \
368 { #val #ver, sizeof(val), &val }
370 #define CE_INTVAL_PV(val, ver) \
371 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
373 static const struct {
379 CE_CONFIG_STR_V(Gpu, 3),
381 // CE_CONFIG_STR(Cdr),
383 // CE_CONFIG_VAL(Sio),
386 CE_CONFIG_VAL(Debug),
387 CE_CONFIG_VAL(PsxOut),
388 CE_CONFIG_VAL(SpuIrq),
389 CE_CONFIG_VAL(RCntFix),
390 CE_CONFIG_VAL(VSyncWA),
393 CE_INTVAL_V(g_scaler, 2),
394 CE_INTVAL(g_layer_x),
395 CE_INTVAL(g_layer_y),
396 CE_INTVAL(g_layer_w),
397 CE_INTVAL(g_layer_h),
398 CE_INTVAL(soft_filter),
399 CE_INTVAL(plat_target.vout_method),
400 CE_INTVAL(plat_target.hwfilter),
401 CE_INTVAL(plat_target.vout_fullscreen),
402 CE_INTVAL(state_slot),
403 CE_INTVAL(cpu_clock),
405 CE_INTVAL(in_type_sel1),
406 CE_INTVAL(in_type_sel2),
407 CE_INTVAL(analog_deadzone),
408 CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
409 CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
410 CE_INTVAL_V(frameskip, 3),
411 CE_INTVAL_P(gpu_peops.iUseDither),
412 CE_INTVAL_P(gpu_peops.dwActFixes),
413 CE_INTVAL_P(gpu_unai.lineskip),
414 CE_INTVAL_P(gpu_unai.abe_hack),
415 CE_INTVAL_P(gpu_unai.no_light),
416 CE_INTVAL_P(gpu_unai.no_blend),
417 CE_INTVAL_P(gpu_neon.allow_interlace),
418 CE_INTVAL_P(gpu_neon.enhancement_enable),
419 CE_INTVAL_P(gpu_neon.enhancement_no_main),
420 CE_INTVAL_P(gpu_peopsgl.bDrawDither),
421 CE_INTVAL_P(gpu_peopsgl.iFilterType),
422 CE_INTVAL_P(gpu_peopsgl.iFrameTexType),
423 CE_INTVAL_P(gpu_peopsgl.iUseMask),
424 CE_INTVAL_P(gpu_peopsgl.bOpaquePass),
425 CE_INTVAL_P(gpu_peopsgl.bAdvancedBlend),
426 CE_INTVAL_P(gpu_peopsgl.bUseFastMdec),
427 CE_INTVAL_P(gpu_peopsgl.iVRamSize),
428 CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
429 CE_INTVAL_P(gpu_peopsgl.dwActFixes),
430 CE_INTVAL_V(iUseReverb, 3),
431 CE_INTVAL_V(iXAPitch, 3),
432 CE_INTVAL_V(iUseInterpolation, 3),
433 CE_INTVAL(config_save_counter),
434 CE_INTVAL(in_evdev_allow_abs_only),
435 CE_INTVAL(volume_boost),
436 CE_INTVAL(psx_clock),
437 CE_INTVAL(new_dynarec_hacks),
438 CE_INTVAL(in_enable_vibration),
441 static char *get_cd_label(void)
443 static char trimlabel[33];
446 strncpy(trimlabel, CdromLabel, 32);
448 for (j = 31; j >= 0; j--)
449 if (trimlabel[j] == ' ')
455 static void make_cfg_fname(char *buf, size_t size, int is_game)
458 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
460 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
463 static void keys_write_all(FILE *f);
464 static char *mystrip(char *str);
466 static int menu_write_config(int is_game)
468 char cfgfile[MAXPATHLEN];
472 config_save_counter++;
474 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
475 f = fopen(cfgfile, "w");
477 printf("menu_write_config: failed to open: %s\n", cfgfile);
481 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
482 fprintf(f, "%s = ", config_data[i].name);
483 switch (config_data[i].len) {
485 fprintf(f, "%s\n", (char *)config_data[i].val);
488 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
491 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
494 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
497 printf("menu_write_config: unhandled len %d for %s\n",
498 (int)config_data[i].len, config_data[i].name);
509 static int menu_do_last_cd_img(int is_get)
511 static const char *defaults[] = { "/media", "/mnt/sd", "/mnt" };
517 snprintf(path, sizeof(path), "." PCSX_DOT_DIR "lastcdimg.txt");
518 f = fopen(path, is_get ? "r" : "w");
525 ret = fread(last_selected_fname, 1, sizeof(last_selected_fname) - 1, f);
526 last_selected_fname[ret] = 0;
527 mystrip(last_selected_fname);
530 fprintf(f, "%s\n", last_selected_fname);
535 for (i = 0; last_selected_fname[0] == 0
536 || stat(last_selected_fname, &st) != 0; i++)
538 if (i >= ARRAY_SIZE(defaults))
540 strcpy(last_selected_fname, defaults[i]);
547 static void parse_str_val(char *cval, const char *src)
550 strncpy(cval, src, MAXPATHLEN);
551 cval[MAXPATHLEN - 1] = 0;
552 tmp = strchr(cval, '\n');
554 tmp = strchr(cval, '\r');
559 static void keys_load_all(const char *cfg);
561 static int menu_load_config(int is_game)
563 char cfgfile[MAXPATHLEN];
569 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
570 f = fopen(cfgfile, "r");
572 printf("menu_load_config: failed to open: %s\n", cfgfile);
576 fseek(f, 0, SEEK_END);
579 printf("bad size %ld: %s\n", size, cfgfile);
583 cfg = malloc(size + 1);
587 fseek(f, 0, SEEK_SET);
588 if (fread(cfg, 1, size, f) != size) {
589 printf("failed to read: %s\n", cfgfile);
594 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
598 tmp = strstr(cfg, config_data[i].name);
601 tmp += strlen(config_data[i].name);
602 if (strncmp(tmp, " = ", 3) != 0)
606 if (config_data[i].len == 0) {
607 parse_str_val(config_data[i].val, tmp);
612 val = strtoul(tmp, &tmp2, 16);
613 if (tmp2 == NULL || tmp == tmp2)
614 continue; // parse failed
616 switch (config_data[i].len) {
618 *(u8 *)config_data[i].val = val;
621 *(u16 *)config_data[i].val = val;
624 *(u32 *)config_data[i].val = val;
627 printf("menu_load_config: unhandled len %d for %s\n",
628 (int)config_data[i].len, config_data[i].name);
634 char *tmp = strstr(cfg, "lastcdimg = ");
637 parse_str_val(last_selected_fname, tmp);
652 for (i = bios_sel = 0; bioses[i] != NULL; i++)
653 if (strcmp(Config.Bios, bioses[i]) == 0)
654 { bios_sel = i; break; }
656 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
657 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
658 { gpu_plugsel = i; break; }
660 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
661 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
662 { spu_plugsel = i; break; }
667 static const char *filter_exts[] = {
668 "bin", "img", "mdf", "iso", "cue", "z",
669 "bz", "znx", "pbp", "cbn"
672 // rrrr rggg gggb bbbb
673 static unsigned short fname2color(const char *fname)
675 static const char *other_exts[] = {
676 "ccd", "toc", "mds", "sub", "table", "index", "sbi"
678 const char *ext = strrchr(fname, '.');
684 for (i = 0; i < array_size(filter_exts); i++)
685 if (strcasecmp(ext, filter_exts[i]) == 0)
687 for (i = 0; i < array_size(other_exts); i++)
688 if (strcasecmp(ext, other_exts[i]) == 0)
693 static void draw_savestate_bg(int slot);
695 #define MENU_ALIGN_LEFT
696 #ifdef __ARM_ARCH_7A__ // assume hires device
702 #include "libpicofe/menu.c"
704 // a bit of black magic here
705 static void draw_savestate_bg(int slot)
707 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
709 char fname[MAXPATHLEN];
716 ret = get_state_filename(fname, sizeof(fname), slot);
720 f = gzopen(fname, "rb");
724 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
725 fprintf(stderr, "gzseek failed\n");
730 gpu = malloc(sizeof(*gpu));
736 ret = gzread(f, gpu, sizeof(*gpu));
738 if (ret != sizeof(*gpu)) {
739 fprintf(stderr, "gzread failed\n");
743 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
745 if (gpu->ulStatus & 0x800000)
746 goto out; // disabled
748 x = gpu->ulControl[5] & 0x3ff;
749 y = (gpu->ulControl[5] >> 10) & 0x1ff;
750 w = psx_widths[(gpu->ulStatus >> 16) & 7];
751 tmp = gpu->ulControl[7];
752 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
753 if (gpu->ulStatus & 0x80000) // doubleheight
755 if (h <= 0 || h > 512)
761 s = (u16 *)gpu->psxVRam + y * 1024 + x;
763 x = max(0, g_menuscreen_w - w) & ~3;
764 y = max(0, g_menuscreen_h / 2 - h / 2);
765 w = min(g_menuscreen_w, w);
766 h = min(g_menuscreen_h, h);
767 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
769 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
770 if (gpu->ulStatus & 0x200000)
771 bgr888_to_rgb565(d, s, w * 3);
773 bgr555_to_rgb565(d, s, w * 2);
775 // darken this so that menu text is visible
776 if (g_menuscreen_w - w < 320)
777 menu_darken_bg(d, d, w * 2, 0);
784 // -------------- key config --------------
786 me_bind_action me_ctrl_actions[] =
788 { "UP ", 1 << DKEY_UP},
789 { "DOWN ", 1 << DKEY_DOWN },
790 { "LEFT ", 1 << DKEY_LEFT },
791 { "RIGHT ", 1 << DKEY_RIGHT },
792 { "TRIANGLE", 1 << DKEY_TRIANGLE },
793 { "CIRCLE ", 1 << DKEY_CIRCLE },
794 { "CROSS ", 1 << DKEY_CROSS },
795 { "SQUARE ", 1 << DKEY_SQUARE },
796 { "L1 ", 1 << DKEY_L1 },
797 { "R1 ", 1 << DKEY_R1 },
798 { "L2 ", 1 << DKEY_L2 },
799 { "R2 ", 1 << DKEY_R2 },
800 { "L3 ", 1 << DKEY_L3 },
801 { "R3 ", 1 << DKEY_R3 },
802 { "START ", 1 << DKEY_START },
803 { "SELECT ", 1 << DKEY_SELECT },
807 me_bind_action emuctrl_actions[] =
809 { "Save State ", 1 << SACTION_SAVE_STATE },
810 { "Load State ", 1 << SACTION_LOAD_STATE },
811 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
812 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
813 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
814 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
815 { "Show/Hide FPS ", 1 << SACTION_TOGGLE_FPS },
816 #ifdef __ARM_ARCH_7A__
817 { "Switch Renderer ", 1 << SACTION_SWITCH_DISPMODE },
819 { "Fast Forward ", 1 << SACTION_FAST_FORWARD },
820 #if MENU_SHOW_MINIMIZE
821 { "Minimize ", 1 << SACTION_MINIMIZE },
823 #if MENU_SHOW_FULLSCREEN
824 { "Toggle fullscreen", 1 << SACTION_TOGGLE_FULLSCREEN },
826 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
827 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
828 { "Gun A button ", 1 << SACTION_GUN_A },
829 { "Gun B button ", 1 << SACTION_GUN_B },
830 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
832 { "Volume Up ", 1 << SACTION_VOLUME_UP },
833 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
838 static char *mystrip(char *str)
843 for (i = 0; i < len; i++)
844 if (str[i] != ' ') break;
845 if (i > 0) memmove(str, str + i, len - i + 1);
848 for (i = len - 1; i >= 0; i--)
849 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
855 static void get_line(char *d, size_t size, const char *s)
860 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
871 static void keys_write_all(FILE *f)
875 for (d = 0; d < IN_MAX_DEVS; d++)
877 const int *binds = in_get_dev_binds(d);
878 const char *name = in_get_dev_name(d, 0, 0);
881 if (binds == NULL || name == NULL)
884 fprintf(f, "binddev = %s\n", name);
885 in_get_config(d, IN_CFG_BIND_COUNT, &count);
887 for (k = 0; k < count; k++)
892 act[0] = act[31] = 0;
893 name = in_get_key_name(d, k);
895 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
896 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
897 mask = me_ctrl_actions[i].mask;
899 strncpy(act, me_ctrl_actions[i].name, 31);
900 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
903 mask = me_ctrl_actions[i].mask << 16;
905 strncpy(act, me_ctrl_actions[i].name, 31);
906 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
911 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
912 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
913 mask = emuctrl_actions[i].mask;
915 strncpy(act, emuctrl_actions[i].name, 31);
916 fprintf(f, "bind %s = %s\n", name, mystrip(act));
922 for (k = 0; k < array_size(in_adev); k++)
925 fprintf(f, "bind_analog = %d\n", k);
930 static int parse_bind_val(const char *val, int *type)
934 *type = IN_BINDTYPE_NONE;
938 if (strncasecmp(val, "player", 6) == 0)
940 int player, shift = 0;
941 player = atoi(val + 6) - 1;
943 if ((unsigned int)player > 1)
948 *type = IN_BINDTYPE_PLAYER12;
949 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
950 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
951 return me_ctrl_actions[i].mask << shift;
954 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
955 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
956 *type = IN_BINDTYPE_EMU;
957 return emuctrl_actions[i].mask;
964 static void keys_load_all(const char *cfg)
966 char dev[256], key[128], *act;
972 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
975 get_line(dev, sizeof(dev), p);
976 dev_id = in_config_parse_dev(dev);
978 printf("input: can't handle dev: %s\n", dev);
982 in_unbind_all(dev_id, -1, -1);
983 while ((p = strstr(p, "bind"))) {
984 if (strncmp(p, "binddev = ", 10) == 0)
987 if (strncmp(p, "bind_analog", 11) == 0) {
988 ret = sscanf(p, "bind_analog = %d", &bind);
991 printf("input: parse error: %16s..\n", p);
994 if ((unsigned int)bind >= array_size(in_adev)) {
995 printf("input: analog id %d out of range\n", bind);
998 in_adev[bind] = dev_id;
1004 printf("input: parse error: %16s..\n", p);
1008 get_line(key, sizeof(key), p);
1009 act = strchr(key, '=');
1011 printf("parse failed: %16s..\n", p);
1019 bind = parse_bind_val(act, &bindtype);
1020 if (bind != -1 && bind != 0) {
1021 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
1022 in_config_bind_key(dev_id, key, bind, bindtype);
1025 lprintf("config: unhandled action \"%s\"\n", act);
1031 static int key_config_loop_wrap(int id, int keys)
1034 case MA_CTRL_PLAYER1:
1035 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
1037 case MA_CTRL_PLAYER2:
1038 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
1041 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
1049 static const char h_nubmode[] = "Maps nub-like analog controls to PSX ones better\n"
1050 "Might cause problems with real analog sticks";
1051 static const char *adevnames[IN_MAX_DEVS + 2];
1052 static int stick_sel[2];
1054 static menu_entry e_menu_keyconfig_analog[] =
1056 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
1057 mee_range (" X axis", 0, in_adev_axis[0][0], 0, 7),
1058 mee_range (" Y axis", 0, in_adev_axis[0][1], 0, 7),
1059 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[0], 1, h_nubmode),
1060 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
1061 mee_range (" X axis", 0, in_adev_axis[1][0], 0, 7),
1062 mee_range (" Y axis", 0, in_adev_axis[1][1], 0, 7),
1063 mee_onoff_h(" nub mode", 0, in_adev_is_nublike[1], 1, h_nubmode),
1067 static int key_config_analog(int id, int keys)
1069 int i, d, count, sel = 0;
1070 int sel2dev_map[IN_MAX_DEVS];
1072 memset(adevnames, 0, sizeof(adevnames));
1073 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
1074 memset(stick_sel, 0, sizeof(stick_sel));
1076 adevnames[0] = "None";
1078 for (d = 0; d < IN_MAX_DEVS; d++)
1080 const char *name = in_get_dev_name(d, 0, 1);
1085 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1089 if (in_adev[0] == d) stick_sel[0] = i;
1090 if (in_adev[1] == d) stick_sel[1] = i;
1092 adevnames[i++] = name;
1094 adevnames[i] = NULL;
1096 me_loop(e_menu_keyconfig_analog, &sel);
1098 in_adev[0] = sel2dev_map[stick_sel[0]];
1099 in_adev[1] = sel2dev_map[stick_sel[1]];
1104 static const char *mgn_dev_name(int id, int *offs)
1106 const char *name = NULL;
1109 if (id == MA_CTRL_DEV_FIRST)
1112 for (; it < IN_MAX_DEVS; it++) {
1113 name = in_get_dev_name(it, 1, 1);
1122 static const char *mgn_saveloadcfg(int id, int *offs)
1127 static int mh_savecfg(int id, int keys)
1129 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1130 menu_update_msg("config saved");
1132 menu_update_msg("failed to write config");
1137 static int mh_input_rescan(int id, int keys)
1139 //menu_sync_config();
1141 menu_update_msg("rescan complete.");
1146 static const char *men_in_type_sel[] = {
1147 "Standard (SCPH-1080)",
1148 "Analog (SCPH-1150)",
1152 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1153 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1154 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1156 static menu_entry e_menu_keyconfig[] =
1158 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1159 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1160 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1161 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1163 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1164 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1165 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1166 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1167 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1168 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1169 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1170 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1171 mee_handler ("Rescan devices:", mh_input_rescan),
1173 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1174 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1175 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1176 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1177 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1178 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1179 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1183 static int menu_loop_keyconfig(int id, int keys)
1187 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1188 me_loop(e_menu_keyconfig, &sel);
1192 // ------------ gfx options menu ------------
1194 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1195 static const char *men_soft_filter[] = { "None",
1197 "scale2x", "eagle2x",
1200 static const char *men_dummy[] = { NULL };
1201 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1202 "using d-pad or move it using R+d-pad";
1203 static const char h_overlay[] = "Overlay provides hardware accelerated scaling";
1204 static const char h_soft_filter[] = "Works only if game uses low resolution modes";
1205 static const char h_gamma[] = "Gamma/brightness adjustment (default 100)";
1207 static int menu_loop_cscaler(int id, int keys)
1211 g_scaler = SCALE_CUSTOM;
1213 plat_gvideo_open(Config.PsxType);
1217 menu_draw_begin(0, 1);
1218 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1219 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1220 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1223 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1224 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
1225 if (inp & PBTN_UP) g_layer_y--;
1226 if (inp & PBTN_DOWN) g_layer_y++;
1227 if (inp & PBTN_LEFT) g_layer_x--;
1228 if (inp & PBTN_RIGHT) g_layer_x++;
1229 if (!(inp & PBTN_R)) {
1230 if (inp & PBTN_UP) g_layer_h += 2;
1231 if (inp & PBTN_DOWN) g_layer_h -= 2;
1232 if (inp & PBTN_LEFT) g_layer_w += 2;
1233 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1235 if (inp & (PBTN_MOK|PBTN_MBACK))
1238 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1239 if (g_layer_x < 0) g_layer_x = 0;
1240 if (g_layer_x > 640) g_layer_x = 640;
1241 if (g_layer_y < 0) g_layer_y = 0;
1242 if (g_layer_y > 420) g_layer_y = 420;
1243 if (g_layer_w < 160) g_layer_w = 160;
1244 if (g_layer_h < 60) g_layer_h = 60;
1245 if (g_layer_x + g_layer_w > 800)
1246 g_layer_w = 800 - g_layer_x;
1247 if (g_layer_y + g_layer_h > 480)
1248 g_layer_h = 480 - g_layer_y;
1250 plat_gvideo_open(Config.PsxType);
1254 plat_gvideo_close();
1259 static menu_entry e_menu_gfx_options[] =
1261 mee_enum ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler),
1262 mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy),
1263 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
1264 mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy),
1265 mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter),
1266 mee_range_h ("Gamma adjustment", MA_OPT_GAMMA, g_gamma, 1, 200, h_gamma),
1267 // mee_onoff ("Vsync", 0, vsync, 1),
1268 mee_cust_h ("Setup custom scaler", MA_OPT_VARSCALER_C, menu_loop_cscaler, NULL, h_cscaler),
1272 static int menu_loop_gfx_options(int id, int keys)
1276 me_loop(e_menu_gfx_options, &sel);
1281 // ------------ bios/plugins ------------
1285 static const char h_gpu_neon[] =
1286 "Configure built-in NEON GPU plugin";
1287 static const char h_gpu_neon_enhanced[] =
1288 "Renders in double resolution at the cost of lower performance\n"
1289 "(not available for high resolution games)";
1290 static const char h_gpu_neon_enhanced_hack[] =
1291 "Speed hack for above option (glitches some games)";
1292 static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1294 static menu_entry e_menu_plugin_gpu_neon[] =
1296 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
1297 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1298 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
1302 static int menu_loop_plugin_gpu_neon(int id, int keys)
1305 me_loop(e_menu_plugin_gpu_neon, &sel);
1311 static menu_entry e_menu_plugin_gpu_unai[] =
1313 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1314 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1315 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1316 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1320 static int menu_loop_plugin_gpu_unai(int id, int keys)
1323 me_loop(e_menu_plugin_gpu_unai, &sel);
1327 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1328 //static const char h_gpu_0[] = "Needed for Chrono Cross";
1329 static const char h_gpu_1[] = "Capcom fighting games";
1330 static const char h_gpu_2[] = "Black screens in Lunar";
1331 static const char h_gpu_3[] = "Compatibility mode";
1332 static const char h_gpu_6[] = "Pandemonium 2";
1333 //static const char h_gpu_7[] = "Skip every second frame";
1334 static const char h_gpu_8[] = "Needed by Dark Forces";
1335 static const char h_gpu_9[] = "better g-colors, worse textures";
1336 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1338 static menu_entry e_menu_plugin_gpu_peops[] =
1340 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1341 // mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1342 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1343 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1344 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1345 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1346 // mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1347 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1348 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1349 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1353 static int menu_loop_plugin_gpu_peops(int id, int keys)
1356 me_loop(e_menu_plugin_gpu_peops, &sel);
1360 static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1361 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1362 static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1364 static menu_entry e_menu_plugin_gpu_peopsgl[] =
1366 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1367 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1368 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1369 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1370 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1371 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1372 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1373 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1374 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1375 mee_label ("Fixes/hacks:"),
1376 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1377 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1378 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1379 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1380 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1381 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1382 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1383 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1384 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1385 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1386 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1390 static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1393 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1397 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1398 static const char h_spu_volboost[] = "Large values cause distortion";
1400 static menu_entry e_menu_plugin_spu[] =
1402 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1403 mee_onoff ("Reverb", 0, iUseReverb, 2),
1404 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1405 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1409 static int menu_loop_plugin_spu(int id, int keys)
1412 me_loop(e_menu_plugin_spu, &sel);
1416 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1417 "savestates and can't be changed there. Must save\n"
1418 "config and reload the game for change to take effect";
1419 static const char h_plugin_gpu[] =
1421 "builtin_gpu is the NEON GPU, very fast and accurate\n"
1423 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1424 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1425 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
1426 "must save config and reload the game if changed";
1427 static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1428 "must save config and reload the game if changed";
1429 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1430 static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
1431 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1432 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1434 static menu_entry e_menu_plugin_options[] =
1436 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1437 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1438 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
1440 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1442 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1443 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1444 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
1445 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1449 static menu_entry e_menu_main2[];
1451 static int menu_loop_plugin_options(int id, int keys)
1454 me_loop(e_menu_plugin_options, &sel);
1456 // sync BIOS/plugins
1457 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1458 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1459 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1460 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1465 // ------------ adv options menu ------------
1467 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1468 "(lower value - less work for the emu, may be faster)";
1469 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1470 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1471 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1473 static menu_entry e_menu_speed_hacks[] =
1475 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1476 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1477 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1478 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1482 static int menu_loop_speed_hacks(int id, int keys)
1485 me_loop(e_menu_speed_hacks, &sel);
1489 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1490 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1491 "(green: normal, red: fmod, blue: noise)";
1492 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1493 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1494 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1495 "(proper .cue/.bin dump is needed otherwise)";
1496 static const char h_cfg_sio[] = "You should not need this, breaks games";
1497 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1498 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1499 "(timing hack, breaks other games)";
1500 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1501 "(timing hack, breaks other games)";
1502 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1503 "Might be useful to overcome some dynarec bugs";
1504 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1505 "must reload game for any change to take effect";
1507 static menu_entry e_menu_adv_options[] =
1509 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1510 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1511 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1512 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1513 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1514 //mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1515 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1516 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1517 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1518 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1519 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1523 static int menu_loop_adv_options(int id, int keys)
1526 me_loop(e_menu_adv_options, &sel);
1530 // ------------ options menu ------------
1532 static int mh_restore_defaults(int id, int keys)
1534 menu_set_defconfig();
1535 menu_update_msg("defaults restored");
1539 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1540 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1542 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1543 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1544 "loading state or both";
1546 static const char h_restore_def[] = "Switches back to default / recommended\n"
1548 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1550 static menu_entry e_menu_options[] =
1552 // mee_range ("Save slot", 0, state_slot, 0, 9),
1553 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1554 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1555 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1556 mee_enum ("Region", 0, region, men_region),
1557 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1558 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1559 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1560 mee_handler ("[Advanced]", menu_loop_adv_options),
1561 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1562 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1563 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1567 static int menu_loop_options(int id, int keys)
1572 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1573 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
1574 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1576 me_loop(e_menu_options, &sel);
1581 // ------------ debug menu ------------
1583 static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
1585 int w = min(g_menuscreen_w, 1024);
1586 int h = min(g_menuscreen_h, 512);
1587 u16 *d = g_menuscreen_ptr;
1588 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
1592 gpuf->ulFreezeVersion = 1;
1593 if (GPU_freeze != NULL)
1594 GPU_freeze(1, gpuf);
1596 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1597 bgr555_to_rgb565(d, s, w * 2);
1599 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1600 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1601 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1602 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1603 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1606 static void debug_menu_loop(void)
1608 int inp, df_x = 0, df_y = 0;
1611 gpuf = malloc(sizeof(*gpuf));
1617 menu_draw_begin(0, 1);
1618 draw_frame_debug(gpuf, df_x, df_y);
1621 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1622 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
1623 if (inp & PBTN_MBACK) break;
1624 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1625 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
1626 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1627 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
1633 // --------- memcard manager ---------
1635 static void draw_mc_icon(int dx, int dy, const u16 *s)
1640 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1642 for (y = 0; y < 16; y++, s += 16) {
1643 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1644 for (x = 0; x < 16; x++) {
1646 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1647 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1653 static void draw_mc_bg(void)
1655 McdBlock *blocks1, *blocks2;
1659 blocks1 = malloc(15 * sizeof(blocks1[0]));
1660 blocks2 = malloc(15 * sizeof(blocks1[0]));
1661 if (blocks1 == NULL || blocks2 == NULL)
1664 for (i = 0; i < 15; i++) {
1665 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1666 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1669 menu_draw_begin(1, 1);
1671 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1673 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1677 maxicons = g_menuscreen_h / 32;
1680 row2 = g_menuscreen_w / 2;
1681 for (i = 0; i < maxicons; i++) {
1682 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1683 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1685 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1686 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1689 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1697 static void handle_memcard_sel(void)
1700 if (memcard1_sel != 0)
1701 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1703 if (memcard2_sel != 0)
1704 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1705 LoadMcds(Config.Mcd1, Config.Mcd2);
1709 static menu_entry e_memcard_options[] =
1711 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1712 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1716 static int menu_loop_memcards(int id, int keys)
1722 memcard1_sel = memcard2_sel = 0;
1723 p = strrchr(Config.Mcd1, '/');
1725 for (i = 0; memcards[i] != NULL; i++)
1726 if (strcmp(p + 1, memcards[i]) == 0)
1727 { memcard1_sel = i; break; }
1728 p = strrchr(Config.Mcd2, '/');
1730 for (i = 0; memcards[i] != NULL; i++)
1731 if (strcmp(p + 1, memcards[i]) == 0)
1732 { memcard2_sel = i; break; }
1734 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1736 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1741 // ------------ cheats menu ------------
1743 static void draw_cheatlist(int sel)
1745 int max_cnt, start, i, pos, active;
1747 max_cnt = g_menuscreen_h / me_sfont_h;
1748 start = max_cnt / 2 - sel;
1750 menu_draw_begin(1, 1);
1752 for (i = 0; i < NumCheats; i++) {
1754 if (pos < 0) continue;
1755 if (pos >= max_cnt) break;
1756 active = Cheats[i].Enabled;
1757 smalltext_out16(14, pos * me_sfont_h,
1758 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1759 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1760 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1764 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1766 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1770 static void menu_loop_cheats(void)
1772 static int menu_sel = 0;
1777 draw_cheatlist(menu_sel);
1778 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1779 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1780 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1781 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1782 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1783 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1784 if (inp & PBTN_MOK) { // action
1785 if (menu_sel < NumCheats)
1786 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1789 if (inp & PBTN_MBACK)
1794 // --------- main menu help ----------
1796 static void menu_bios_warn(void)
1799 static const char msg[] =
1800 "You don't seem to have copied any BIOS\n"
1802 MENU_BIOS_PATH "\n\n"
1804 "While many games work fine with fake\n"
1805 "(HLE) BIOS, others (like MGS and FF8)\n"
1806 "require BIOS to work.\n"
1807 "After copying the file, you'll also need\n"
1808 "to select it in the emu's menu:\n"
1809 "options->[BIOS/Plugins]\n\n"
1810 "The file is usually named SCPH1001.BIN,\n"
1811 "but other not compressed files can be\n"
1813 "Press %s or %s to continue";
1814 char tmp_msg[sizeof(msg) + 64];
1816 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1817 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
1820 draw_menu_message(tmp_msg, NULL);
1822 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
1823 if (inp & (PBTN_MBACK|PBTN_MOK))
1828 // ------------ main menu ------------
1830 static menu_entry e_menu_main[];
1833 static void draw_frame_main(void)
1842 if (CdromId[0] != 0) {
1843 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1844 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1845 Config.HLE ? "HLE" : "BIOS");
1846 smalltext_out16(4, 1, buff, 0x105f);
1850 capacity = plat_target_bat_capacity_get();
1852 tmp = localtime(<ime);
1853 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1854 if (capacity >= 0) {
1855 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1860 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
1864 static void draw_frame_credits(void)
1866 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1869 static const char credits_text[] =
1871 "(C) 1999-2003 PCSX Team\n"
1872 "(C) 2005-2009 PCSX-df Team\n"
1873 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1874 "ARM recompiler (C) 2009-2011 Ari64\n"
1876 "ARM NEON GPU (c) 2011-2012 Exophase\n"
1878 "PEOpS GPU and SPU by Pete Bernert\n"
1879 " and the P.E.Op.S. team\n"
1880 "PCSX4ALL plugin by PCSX4ALL team\n"
1881 " Chui, Franxis, Unai\n\n"
1882 "integration, optimization and\n"
1883 " frontend (C) 2010-2012 notaz\n";
1885 static int reset_game(void)
1888 if (bios_sel == 0 && !Config.HLE)
1894 if (CheckCdrom() != -1) {
1900 static int reload_plugins(const char *cdimg)
1906 set_cd_image(cdimg);
1908 pcnt_hook_plugins();
1910 if (OpenPlugins() == -1) {
1911 menu_update_msg("failed to open plugins");
1914 plugin_call_rearmed_cbs();
1916 cdrIsoMultidiskCount = 1;
1918 CdromLabel[0] = '\0';
1923 static int run_bios(void)
1929 if (reload_plugins(NULL) != 0)
1937 static int run_exe(void)
1941 fname = menu_loop_romsel(last_selected_fname,
1942 sizeof(last_selected_fname), NULL);
1947 if (reload_plugins(NULL) != 0)
1951 if (Load(fname) != 0) {
1952 menu_update_msg("exe load failed, bad file?");
1961 static int run_cd_image(const char *fname)
1964 reload_plugins(fname);
1966 // always autodetect, menu_sync_config will override as needed
1969 if (CheckCdrom() == -1) {
1970 // Only check the CD if we are starting the console with a CD
1972 menu_update_msg("unsupported/invalid CD image");
1978 // Read main executable directly from CDRom and start it
1979 if (LoadCdrom() == -1) {
1981 menu_update_msg("failed to load CD image");
1991 static int romsel_run(void)
1993 int prev_gpu, prev_spu;
1996 fname = menu_loop_romsel(last_selected_fname,
1997 sizeof(last_selected_fname), optional_cdimg_filter);
2001 printf("selected file: %s\n", fname);
2003 new_dynarec_clear_full();
2005 if (run_cd_image(fname) != 0)
2008 prev_gpu = gpu_plugsel;
2009 prev_spu = spu_plugsel;
2010 if (menu_load_config(1) != 0)
2011 menu_load_config(0);
2013 // check for plugin changes, have to repeat
2014 // loading if game config changed plugins to reload them
2015 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
2016 printf("plugin change detected, reloading plugins..\n");
2017 if (run_cd_image(fname) != 0)
2021 strcpy(last_selected_fname, fname);
2022 menu_do_last_cd_img(0);
2026 static int swap_cd_image(void)
2030 fname = menu_loop_romsel(last_selected_fname,
2031 sizeof(last_selected_fname), optional_cdimg_filter);
2035 printf("selected file: %s\n", fname);
2038 CdromLabel[0] = '\0';
2040 set_cd_image(fname);
2041 if (ReloadCdromPlugin() < 0) {
2042 menu_update_msg("failed to load cdr plugin");
2045 if (CDR_open() < 0) {
2046 menu_update_msg("failed to open cdr plugin");
2050 SetCdOpenCaseTime(time(NULL) + 2);
2053 strcpy(last_selected_fname, fname);
2057 static int swap_cd_multidisk(void)
2059 cdrIsoMultidiskSelect++;
2061 CdromLabel[0] = '\0';
2064 if (CDR_open() < 0) {
2065 menu_update_msg("failed to open cdr plugin");
2069 SetCdOpenCaseTime(time(NULL) + 2);
2075 static void load_pcsx_cht(void)
2081 fname = menu_loop_romsel(path, sizeof(path), NULL);
2085 printf("selected cheat file: %s\n", fname);
2088 if (NumCheats == 0 && NumCodes == 0)
2089 menu_update_msg("failed to load cheats");
2091 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
2092 menu_update_msg(path);
2094 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2097 static int main_menu_handler(int id, int keys)
2101 case MA_MAIN_RESUME_GAME:
2105 case MA_MAIN_SAVE_STATE:
2107 return menu_loop_savestate(0);
2109 case MA_MAIN_LOAD_STATE:
2111 return menu_loop_savestate(1);
2113 case MA_MAIN_RESET_GAME:
2114 if (ready_to_go && reset_game() == 0)
2117 case MA_MAIN_LOAD_ROM:
2118 if (romsel_run() == 0)
2121 case MA_MAIN_SWAP_CD:
2122 if (swap_cd_image() == 0)
2125 case MA_MAIN_SWAP_CD_MULTI:
2126 if (swap_cd_multidisk() == 0)
2129 case MA_MAIN_RUN_BIOS:
2130 if (run_bios() == 0)
2133 case MA_MAIN_RUN_EXE:
2137 case MA_MAIN_CHEATS:
2140 case MA_MAIN_LOAD_CHEATS:
2143 case MA_MAIN_CREDITS:
2144 draw_menu_message(credits_text, draw_frame_credits);
2145 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
2151 lprintf("%s: something unknown selected\n", __FUNCTION__);
2158 static menu_entry e_menu_main2[] =
2160 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2161 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2162 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2163 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
2164 mee_handler ("Memcard manager", menu_loop_memcards),
2165 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
2169 static int main_menu2_handler(int id, int keys)
2173 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
2174 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
2175 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2176 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
2178 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2181 static const char h_extra[] = "Change CD, manage memcards..\n";
2183 static menu_entry e_menu_main[] =
2187 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2188 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2189 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2190 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2191 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2192 mee_handler ("Options", menu_loop_options),
2193 mee_handler ("Controls", menu_loop_keyconfig),
2194 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
2195 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
2196 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2197 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2201 // ----------------------------
2203 static void menu_leave_emu(void);
2205 void menu_loop(void)
2207 static int warned_about_bios = 0;
2212 if (config_save_counter == 0) {
2214 if (bioses[1] != NULL) {
2215 // autoselect BIOS to make user's life easier
2216 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[1]);
2219 else if (!warned_about_bios) {
2221 warned_about_bios = 1;
2225 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
2226 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2227 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
2228 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2229 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
2231 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2234 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
2235 } while (!ready_to_go);
2237 /* wait until menu, ok, back is released */
2238 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2241 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2246 static int qsort_strcmp(const void *p1, const void *p2)
2248 char * const *s1 = (char * const *)p1;
2249 char * const *s2 = (char * const *)p2;
2250 return strcasecmp(*s1, *s2);
2253 static void scan_bios_plugins(void)
2255 char fname[MAXPATHLEN];
2257 int bios_i, gpu_i, spu_i, mc_i;
2262 gpu_plugins[0] = "builtin_gpu";
2263 spu_plugins[0] = "builtin_spu";
2264 memcards[0] = "(none)";
2265 bios_i = gpu_i = spu_i = mc_i = 1;
2267 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2268 dir = opendir(fname);
2270 perror("scan_bios_plugins bios opendir");
2285 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2288 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2289 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2290 printf("bad BIOS file: %s\n", ent->d_name);
2294 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2295 bioses[bios_i++] = strdup(ent->d_name);
2299 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2305 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2306 dir = opendir(fname);
2308 perror("scan_bios_plugins plugins opendir");
2322 p = strstr(ent->d_name, ".so");
2326 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2327 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2329 fprintf(stderr, "%s\n", dlerror());
2333 // now what do we have here?
2334 tmp = dlsym(h, "GPUinit");
2337 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2338 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2342 tmp = dlsym(h, "SPUinit");
2345 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2346 spu_plugins[spu_i++] = strdup(ent->d_name);
2350 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2357 dir = opendir("." MEMCARD_DIR);
2359 perror("scan_bios_plugins memcards opendir");
2374 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2377 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2378 if (stat(fname, &st) != 0) {
2379 printf("bad memcard file: %s\n", ent->d_name);
2383 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2384 memcards[mc_i++] = strdup(ent->d_name);
2388 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2392 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2397 void menu_init(void)
2399 char buff[MAXPATHLEN];
2402 cpu_clock_st = cpu_clock = plat_target_cpu_clock_get();
2404 scan_bios_plugins();
2407 menu_set_defconfig();
2408 menu_load_config(0);
2409 menu_do_last_cd_img(1);
2414 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2415 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2416 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2417 fprintf(stderr, "OOM\n");
2421 emu_make_path(buff, "skin/background.png", sizeof(buff));
2422 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2424 i = plat_target.cpu_clock_set != NULL
2425 && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0;
2426 me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i);
2428 i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE);
2429 e_menu_gfx_options[i].data = plat_target.vout_methods;
2430 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE,
2431 plat_target.vout_methods != NULL);
2433 i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER);
2434 e_menu_gfx_options[i].data = plat_target.hwfilters;
2435 me_enable(e_menu_gfx_options, MA_OPT_HWFILTER,
2436 plat_target.hwfilters != NULL);
2438 me_enable(e_menu_gfx_options, MA_OPT_GAMMA,
2439 plat_target.gamma_set != NULL);
2441 #ifndef __ARM_ARCH_7A__
2442 me_enable(e_menu_gfx_options, MA_OPT_SWFILTER, 0);
2444 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER);
2445 me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE);
2446 me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER);
2447 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2);
2448 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS);
2449 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION);
2450 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, MENU_SHOW_DEADZONE);
2453 void menu_notify_mode_change(int w, int h, int bpp)
2457 last_vout_bpp = bpp;
2460 static void menu_leave_emu(void)
2462 if (GPU_close != NULL) {
2463 int ret = GPU_close();
2465 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2468 plat_video_menu_enter(ready_to_go);
2470 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2471 if (pl_vout_buf != NULL && ready_to_go) {
2472 int x = max(0, g_menuscreen_w - last_vout_w);
2473 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2474 int w = min(g_menuscreen_w, last_vout_w);
2475 int h = min(g_menuscreen_h, last_vout_h);
2476 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2477 char *s = pl_vout_buf;
2479 if (last_vout_bpp == 16) {
2480 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
2481 menu_darken_bg(d, s, w, 0);
2484 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
2485 rgb888_to_rgb565(d, s, w * 3);
2486 menu_darken_bg(d, d, w, 0);
2492 cpu_clock = plat_target_cpu_clock_get();
2495 void menu_prepare_emu(void)
2497 R3000Acpu *prev_cpu = psxCpu;
2499 plat_video_menu_leave();
2501 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2502 if (psxCpu != prev_cpu)
2503 // note that this does not really reset, just clears drc caches
2506 // core doesn't care about Config.Cdda changes,
2507 // so handle them manually here
2513 plat_target_cpu_clock_set(cpu_clock);
2515 // push config to GPU plugin
2516 plugin_call_rearmed_cbs();
2518 if (GPU_open != NULL) {
2519 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2521 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2527 void menu_update_msg(const char *msg)
2529 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2530 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2532 menu_error_time = plat_get_ticks_ms();
2533 lprintf("msg: %s\n", menu_error_msg);
2536 void menu_finish(void)
2538 if (cpu_clock_st > 0)
2539 plat_target_cpu_clock_set(cpu_clock_st);