2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
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.
21 #include "plugin_lib.h"
24 #include "arm_utils.h"
25 #include "common/plat.h"
26 #include "../libpcsxcore/misc.h"
27 #include "../libpcsxcore/cdrom.h"
28 #include "../libpcsxcore/psemu_plugin_defs.h"
29 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
30 #include "../plugins/dfinput/pad.h"
34 #define array_size(x) (sizeof(x) / sizeof(x[0]))
68 static int last_psx_w, last_psx_h, last_psx_bpp;
69 static int scaling, filter, cpu_clock, cpu_clock_st;
70 static char rom_fname_reload[MAXPATHLEN];
71 static char last_selected_fname[MAXPATHLEN];
72 static int warned_about_bios, region, in_type_sel;
75 // from softgpu plugin
76 extern int iUseDither;
77 extern int UseFrameSkip;
78 extern uint32_t dwActFixes;
79 extern float fFrameRateHz;
80 extern int dwFrameRateTicks;
83 extern int iUseReverb;
84 extern int iUseInterpolation;
86 extern int iSPUIRQWait;
89 static const char *bioses[24];
90 static const char *gpu_plugins[16];
91 static const char *spu_plugins[16];
92 static int bios_sel, gpu_plugsel, spu_plugsel;
95 static int min(int x, int y) { return x < y ? x : y; }
96 static int max(int x, int y) { return x > y ? x : y; }
98 void emu_make_path(char *buff, const char *end, int size)
102 end_len = strlen(end);
103 pos = plat_get_root_dir(buff, size);
104 strncpy(buff + pos, end, size - pos);
106 if (pos + end_len > size - 1)
107 printf("Warning: path truncated: %s\n", buff);
110 static int emu_check_save_file(int slot)
112 int ret = emu_check_state(slot);
113 return ret == 0 ? 1 : 0;
116 static int emu_save_load_game(int load, int unused)
121 ret = emu_load_state(state_slot);
123 // reflect hle/bios mode from savestate
126 else if (bios_sel == 0 && bioses[1] != NULL)
127 // XXX: maybe find the right bios instead
131 ret = emu_save_state(state_slot);
136 // propagate menu settings to the emu vars
137 static void menu_sync_config(void)
142 Config.PsxType = region - 1;
144 in_type = in_type_sel ? PSE_PAD_TYPE_ANALOGPAD : PSE_PAD_TYPE_STANDARD;
146 pl_frame_interval = Config.PsxType ? 20000 : 16667;
147 // used by P.E.Op.S. frameskip code
148 fFrameRateHz = Config.PsxType ? 50.0f : 59.94f;
149 dwFrameRateTicks = (100000*100 / (unsigned long)(fFrameRateHz*100));
152 static void menu_set_defconfig(void)
159 Config.Xa = Config.Cdda = Config.Sio =
160 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
167 iUseInterpolation = 1;
175 #define CE_CONFIG_STR(val) \
176 { #val, 0, Config.val }
178 #define CE_CONFIG_VAL(val) \
179 { #val, sizeof(Config.val), &Config.val }
181 #define CE_STR(val) \
184 #define CE_INTVAL(val) \
185 { #val, sizeof(val), &val }
187 // 'versioned' var, used when defaults change
188 #define CE_INTVAL_V(val, ver) \
189 { #val #ver, sizeof(val), &val }
191 static const struct {
199 // CE_CONFIG_STR(Cdr),
204 CE_CONFIG_VAL(Debug),
205 CE_CONFIG_VAL(PsxOut),
206 CE_CONFIG_VAL(SpuIrq),
207 CE_CONFIG_VAL(RCntFix),
208 CE_CONFIG_VAL(VSyncWA),
212 CE_INTVAL(g_layer_x),
213 CE_INTVAL(g_layer_y),
214 CE_INTVAL(g_layer_w),
215 CE_INTVAL(g_layer_h),
217 CE_INTVAL(state_slot),
218 CE_INTVAL(cpu_clock),
220 CE_INTVAL(in_type_sel),
221 CE_INTVAL(iUseDither),
222 CE_INTVAL(UseFrameSkip),
223 CE_INTVAL(dwActFixes),
224 CE_INTVAL(iUseReverb),
226 CE_INTVAL_V(iUseInterpolation, 2),
227 CE_INTVAL_V(iSPUIRQWait, 2),
228 CE_INTVAL(iUseTimer),
229 CE_INTVAL(warned_about_bios),
232 static char *get_cd_label(void)
234 static char trimlabel[33];
237 strncpy(trimlabel, CdromLabel, 32);
239 for (j = 31; j >= 0; j--)
240 if (trimlabel[j] == ' ')
246 static void make_cfg_fname(char *buf, size_t size, int is_game)
249 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
251 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
254 static void keys_write_all(FILE *f);
256 static int menu_write_config(int is_game)
258 char cfgfile[MAXPATHLEN];
262 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
263 f = fopen(cfgfile, "w");
265 printf("menu_write_config: failed to open: %s\n", cfgfile);
269 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
270 fprintf(f, "%s = ", config_data[i].name);
271 switch (config_data[i].len) {
273 fprintf(f, "%s\n", (char *)config_data[i].val);
276 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
279 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
282 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
285 printf("menu_write_config: unhandled len %d for %s\n",
286 config_data[i].len, config_data[i].name);
292 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
300 static void parse_str_val(char *cval, const char *src)
303 strncpy(cval, src, MAXPATHLEN);
304 cval[MAXPATHLEN - 1] = 0;
305 tmp = strchr(cval, '\n');
307 tmp = strchr(cval, '\r');
312 static void keys_load_all(const char *cfg);
314 static int menu_load_config(int is_game)
316 char cfgfile[MAXPATHLEN];
322 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
323 f = fopen(cfgfile, "r");
325 printf("menu_load_config: failed to open: %s\n", cfgfile);
329 fseek(f, 0, SEEK_END);
332 printf("bad size %ld: %s\n", size, cfgfile);
336 cfg = malloc(size + 1);
340 fseek(f, 0, SEEK_SET);
341 if (fread(cfg, 1, size, f) != size) {
342 printf("failed to read: %s\n", cfgfile);
347 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
351 tmp = strstr(cfg, config_data[i].name);
354 tmp += strlen(config_data[i].name);
355 if (strncmp(tmp, " = ", 3) != 0)
359 if (config_data[i].len == 0) {
360 parse_str_val(config_data[i].val, tmp);
365 val = strtoul(tmp, &tmp2, 16);
366 if (tmp2 == NULL || tmp == tmp2)
367 continue; // parse failed
369 switch (config_data[i].len) {
371 *(u8 *)config_data[i].val = val;
374 *(u16 *)config_data[i].val = val;
377 *(u32 *)config_data[i].val = val;
380 printf("menu_load_config: unhandled len %d for %s\n",
381 config_data[i].len, config_data[i].name);
387 char *tmp = strstr(cfg, "lastcdimg = ");
390 parse_str_val(last_selected_fname, tmp);
397 for (i = bios_sel = 0; bioses[i] != NULL; i++)
398 if (strcmp(Config.Bios, bioses[i]) == 0)
399 { bios_sel = i; break; }
401 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
402 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
403 { gpu_plugsel = i; break; }
405 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
406 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
407 { spu_plugsel = i; break; }
418 // rrrr rggg gggb bbbb
419 static unsigned short fname2color(const char *fname)
421 static const char *cdimg_exts[] = { ".bin", ".img", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
422 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
423 const char *ext = strrchr(fname, '.');
428 for (i = 0; i < array_size(cdimg_exts); i++)
429 if (strcasecmp(ext, cdimg_exts[i]) == 0)
431 for (i = 0; i < array_size(other_exts); i++)
432 if (strcasecmp(ext, other_exts[i]) == 0)
437 static void draw_savestate_bg(int slot);
439 #define MENU_ALIGN_LEFT
440 #define menu_init menu_init_common
441 #include "common/menu.c"
444 // a bit of black magic here
445 static void draw_savestate_bg(int slot)
447 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
449 char fname[MAXPATHLEN];
456 ret = get_state_filename(fname, sizeof(fname), slot);
460 f = gzopen(fname, "rb");
464 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
465 fprintf(stderr, "gzseek failed\n");
470 gpu = malloc(sizeof(*gpu));
476 ret = gzread(f, gpu, sizeof(*gpu));
478 if (ret != sizeof(*gpu)) {
479 fprintf(stderr, "gzread failed\n");
483 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
485 if ((gpu->ulStatus & 0x800000) || (gpu->ulStatus & 0x200000))
486 goto out; // disabled || 24bpp (NYET)
488 x = gpu->ulControl[5] & 0x3ff;
489 y = (gpu->ulControl[5] >> 10) & 0x1ff;
490 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~3);
491 w = psx_widths[(gpu->ulStatus >> 16) & 7];
492 tmp = gpu->ulControl[7];
493 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
494 if (gpu->ulStatus & 0x80000) // doubleheight
497 x = max(0, g_menuscreen_w - w) & ~3;
498 y = max(0, g_menuscreen_h / 2 - h / 2);
499 w = min(g_menuscreen_w, w);
500 h = min(g_menuscreen_h, h);
501 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
503 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
504 bgr555_to_rgb565(d, s, w * 2);
510 // ---------- pandora specific -----------
512 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
513 static char **pnd_filter_list;
515 static int get_cpu_clock(void)
519 f = fopen("/proc/pandora/cpu_mhz_max", "r");
521 fscanf(f, "%d", &ret);
527 static void apply_cpu_clock(void)
531 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
532 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
533 pnd_script_base, cpu_clock);
538 static void apply_filter(int which)
544 if (pnd_filter_list == NULL || which == old)
547 for (i = 0; i < which; i++)
548 if (pnd_filter_list[i] == NULL)
551 if (pnd_filter_list[i] == NULL)
554 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
559 static menu_entry e_menu_gfx_options[];
561 static void pnd_menu_init(void)
569 cpu_clock_st = cpu_clock = get_cpu_clock();
571 dir = opendir("/etc/pandora/conf/dss_fir");
573 perror("filter opendir");
586 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
595 mfilters = calloc(count + 1, sizeof(mfilters[0]));
596 if (mfilters == NULL)
600 for (i = 0; (ent = readdir(dir)); ) {
603 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
606 len = strlen(ent->d_name);
608 // skip pre-HF5 extra files
609 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
611 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
614 // have to cut "_up_h" for pre-HF5
615 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
618 if (len > sizeof(buff) - 1)
621 strncpy(buff, ent->d_name, len);
623 mfilters[i] = strdup(buff);
624 if (mfilters[i] != NULL)
629 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
630 e_menu_gfx_options[i].data = (void *)mfilters;
631 pnd_filter_list = mfilters;
634 void menu_finish(void)
636 cpu_clock = cpu_clock_st;
640 // -------------- key config --------------
642 me_bind_action me_ctrl_actions[] =
644 { "UP ", 1 << DKEY_UP},
645 { "DOWN ", 1 << DKEY_DOWN },
646 { "LEFT ", 1 << DKEY_LEFT },
647 { "RIGHT ", 1 << DKEY_RIGHT },
648 { "TRIANGLE", 1 << DKEY_TRIANGLE },
649 { "CIRCLE ", 1 << DKEY_CIRCLE },
650 { "CROSS ", 1 << DKEY_CROSS },
651 { "SQUARE ", 1 << DKEY_SQUARE },
652 { "L1 ", 1 << DKEY_L1 },
653 { "R1 ", 1 << DKEY_R1 },
654 { "L2 ", 1 << DKEY_L2 },
655 { "R2 ", 1 << DKEY_R2 },
656 { "L3 ", 1 << DKEY_L3 },
657 { "R3 ", 1 << DKEY_R3 },
658 { "START ", 1 << DKEY_START },
659 { "SELECT ", 1 << DKEY_SELECT },
663 me_bind_action emuctrl_actions[] =
665 { "Save State ", 1 << SACTION_SAVE_STATE },
666 { "Load State ", 1 << SACTION_LOAD_STATE },
667 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
668 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
669 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
670 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
674 static char *mystrip(char *str)
679 for (i = 0; i < len; i++)
680 if (str[i] != ' ') break;
681 if (i > 0) memmove(str, str + i, len - i + 1);
684 for (i = len - 1; i >= 0; i--)
685 if (str[i] != ' ') break;
691 static void get_line(char *d, size_t size, const char *s)
696 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
707 static void keys_write_all(FILE *f)
711 for (d = 0; d < IN_MAX_DEVS; d++)
713 const int *binds = in_get_dev_binds(d);
714 const char *name = in_get_dev_name(d, 0, 0);
717 if (binds == NULL || name == NULL)
720 fprintf(f, "binddev = %s\n", name);
721 in_get_config(d, IN_CFG_BIND_COUNT, &count);
723 for (k = 0; k < count; k++)
728 act[0] = act[31] = 0;
729 name = in_get_key_name(d, k);
731 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
732 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
733 mask = me_ctrl_actions[i].mask;
735 strncpy(act, me_ctrl_actions[i].name, 31);
736 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
739 mask = me_ctrl_actions[i].mask << 16;
741 strncpy(act, me_ctrl_actions[i].name, 31);
742 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
747 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
748 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
749 mask = emuctrl_actions[i].mask;
751 strncpy(act, emuctrl_actions[i].name, 31);
752 fprintf(f, "bind %s = %s\n", name, mystrip(act));
760 static int parse_bind_val(const char *val, int *type)
764 *type = IN_BINDTYPE_NONE;
768 if (strncasecmp(val, "player", 6) == 0)
770 int player, shift = 0;
771 player = atoi(val + 6) - 1;
773 if ((unsigned int)player > 1)
778 *type = IN_BINDTYPE_PLAYER12;
779 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
780 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
781 return me_ctrl_actions[i].mask << shift;
784 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
785 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
786 *type = IN_BINDTYPE_EMU;
787 return emuctrl_actions[i].mask;
794 static void keys_load_all(const char *cfg)
796 char dev[256], key[128], *act;
802 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
805 get_line(dev, sizeof(dev), p);
806 dev_id = in_config_parse_dev(dev);
808 printf("input: can't handle dev: %s\n", dev);
812 in_unbind_all(dev_id, -1, -1);
813 while ((p = strstr(p, "bind"))) {
814 if (strncmp(p, "binddev = ", 10) == 0)
819 printf("input: parse error: %16s..\n", p);
823 get_line(key, sizeof(key), p);
824 act = strchr(key, '=');
826 printf("parse failed: %16s..\n", p);
834 bind = parse_bind_val(act, &bindtype);
835 if (bind != -1 && bind != 0) {
836 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
837 in_config_bind_key(dev_id, key, bind, bindtype);
840 lprintf("config: unhandled action \"%s\"\n", act);
845 static int key_config_loop_wrap(int id, int keys)
848 case MA_CTRL_PLAYER1:
849 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
851 case MA_CTRL_PLAYER2:
852 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
855 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
863 static const char *mgn_dev_name(int id, int *offs)
865 const char *name = NULL;
868 if (id == MA_CTRL_DEV_FIRST)
871 for (; it < IN_MAX_DEVS; it++) {
872 name = in_get_dev_name(it, 1, 1);
881 static const char *mgn_saveloadcfg(int id, int *offs)
886 static int mh_savecfg(int id, int keys)
888 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
889 me_update_msg("config saved");
891 me_update_msg("failed to write config");
896 static const char *men_in_type_sel[] = { "Standard (SCPH-1080)", "Analog (SCPH-1150)", NULL };
898 static menu_entry e_menu_keyconfig[] =
900 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
901 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
902 mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
904 mee_enum ("Controller", 0, in_type_sel, men_in_type_sel),
905 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
906 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
908 mee_label ("Input devices:"),
909 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
910 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
911 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
912 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
913 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
914 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
915 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
919 static int menu_loop_keyconfig(int id, int keys)
923 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
924 me_loop(e_menu_keyconfig, &sel, NULL);
928 // ------------ gfx options menu ------------
930 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
931 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
932 "using d-pad or move it using R+d-pad";
933 static const char *men_dummy[] = { NULL };
935 static int menu_loop_cscaler(int id, int keys)
939 scaling = SCALE_CUSTOM;
941 omap_enable_layer(1);
946 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
947 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
948 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
951 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
952 if (inp & PBTN_UP) g_layer_y--;
953 if (inp & PBTN_DOWN) g_layer_y++;
954 if (inp & PBTN_LEFT) g_layer_x--;
955 if (inp & PBTN_RIGHT) g_layer_x++;
956 if (!(inp & PBTN_R)) {
957 if (inp & PBTN_UP) g_layer_h += 2;
958 if (inp & PBTN_DOWN) g_layer_h -= 2;
959 if (inp & PBTN_LEFT) g_layer_w += 2;
960 if (inp & PBTN_RIGHT) g_layer_w -= 2;
962 if (inp & (PBTN_MOK|PBTN_MBACK))
965 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
966 if (g_layer_x < 0) g_layer_x = 0;
967 if (g_layer_x > 640) g_layer_x = 640;
968 if (g_layer_y < 0) g_layer_y = 0;
969 if (g_layer_y > 420) g_layer_y = 420;
970 if (g_layer_w < 160) g_layer_w = 160;
971 if (g_layer_h < 60) g_layer_h = 60;
972 if (g_layer_x + g_layer_w > 800)
973 g_layer_w = 800 - g_layer_x;
974 if (g_layer_y + g_layer_h > 480)
975 g_layer_h = 480 - g_layer_y;
976 omap_enable_layer(1);
980 omap_enable_layer(0);
985 static menu_entry e_menu_gfx_options[] =
987 mee_enum ("Scaler", 0, scaling, men_scaler),
988 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
989 // mee_onoff ("Vsync", 0, vsync, 1),
990 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
994 static int menu_loop_gfx_options(int id, int keys)
998 me_loop(e_menu_gfx_options, &sel, NULL);
1003 // ------------ bios/plugins ------------
1005 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1006 static const char h_gpu_0[] = "Needed for Chrono Cross";
1007 static const char h_gpu_1[] = "Capcom fighting games";
1008 static const char h_gpu_2[] = "Black screens in Lunar";
1009 static const char h_gpu_3[] = "Compatibility mode";
1010 static const char h_gpu_6[] = "Pandemonium 2";
1011 static const char h_gpu_7[] = "Skip every second frame";
1012 static const char h_gpu_8[] = "Needed by Dark Forces";
1013 static const char h_gpu_9[] = "better g-colors, worse textures";
1014 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1016 static menu_entry e_menu_plugin_gpu[] =
1018 mee_enum ("Dithering", 0, iUseDither, men_gpu_dithering),
1019 mee_onoff_h ("Odd/even bit hack", 0, dwActFixes, 1<<0, h_gpu_0),
1020 mee_onoff_h ("Expand screen width", 0, dwActFixes, 1<<1, h_gpu_1),
1021 mee_onoff_h ("Ignore brightness color", 0, dwActFixes, 1<<2, h_gpu_2),
1022 mee_onoff_h ("Disable coordinate check", 0, dwActFixes, 1<<3, h_gpu_3),
1023 mee_onoff_h ("Lazy screen update", 0, dwActFixes, 1<<6, h_gpu_6),
1024 mee_onoff_h ("Old frame skipping", 0, dwActFixes, 1<<7, h_gpu_7),
1025 mee_onoff_h ("Repeated flat tex triangles ",0,dwActFixes, 1<<8, h_gpu_8),
1026 mee_onoff_h ("Draw quads with triangles", 0, dwActFixes, 1<<9, h_gpu_9),
1027 mee_onoff_h ("Fake 'gpu busy' states", 0, dwActFixes, 1<<10, h_gpu_10),
1031 static int menu_loop_plugin_gpu(int id, int keys)
1034 me_loop(e_menu_plugin_gpu, &sel, NULL);
1038 static const char *men_spu_reverb[] = { "Off", "Fake", "On", NULL };
1039 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1040 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1041 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1043 static menu_entry e_menu_plugin_spu[] =
1045 mee_enum ("Reverb", 0, iUseReverb, men_spu_reverb),
1046 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1047 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1048 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1049 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1053 static int menu_loop_plugin_spu(int id, int keys)
1056 me_loop(e_menu_plugin_spu, &sel, NULL);
1060 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1061 "and can't be changed there. Must save config and reload\n"
1062 "the game for change to take effect";
1063 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1064 "for plugin change to take effect";
1065 static const char h_gpu[] = "Configure built-in P.E.Op.S. SoftGL Driver V1.17";
1066 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1068 static menu_entry e_menu_plugin_options[] =
1070 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1071 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1072 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1073 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu, h_gpu),
1074 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1078 static menu_entry e_menu_main[];
1080 static int menu_loop_plugin_options(int id, int keys)
1083 me_loop(e_menu_plugin_options, &sel, NULL);
1085 // sync BIOS/plugins
1086 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1087 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1088 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1089 me_enable(e_menu_main, MA_MAIN_RUN_BIOS, bios_sel != 0);
1094 // ------------ adv options menu ------------
1096 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1097 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1098 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1099 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1100 "(proper .cue/.bin dump is needed otherwise)";
1101 static const char h_cfg_sio[] = "This should be enabled for certain memcards/gamepads";
1102 static const char h_cfg_spuirq[] = "Compatibility tweak; should probably be left off";
1103 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix";
1104 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix";
1105 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1106 "Might be useful to overcome some dynarec bugs";
1108 static menu_entry e_menu_adv_options[] =
1110 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1111 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1112 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1113 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1114 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1115 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1116 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1117 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1118 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1122 static int menu_loop_adv_options(int id, int keys)
1125 me_loop(e_menu_adv_options, &sel, NULL);
1129 // ------------ options menu ------------
1131 static int mh_restore_defaults(int id, int keys)
1133 menu_set_defconfig();
1134 me_update_msg("defaults restored");
1138 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1140 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1141 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1142 "loading state or both";
1144 static const char h_restore_def[] = "Switches back to default / recommended\n"
1147 static menu_entry e_menu_options[] =
1149 // mee_range ("Save slot", 0, state_slot, 0, 9),
1150 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1151 mee_onoff ("Frameskip", 0, UseFrameSkip, 1),
1152 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1153 mee_enum ("Region", 0, region, men_region),
1154 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1155 mee_handler ("[Display]", menu_loop_gfx_options),
1156 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1157 mee_handler ("[Advanced]", menu_loop_adv_options),
1158 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1159 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1160 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1164 static int menu_loop_options(int id, int keys)
1169 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1170 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1171 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1173 me_loop(e_menu_options, &sel, NULL);
1178 // ------------ debug menu ------------
1180 static void draw_frame_debug(GPUFreeze_t *gpuf)
1182 int w = min(g_menuscreen_w, 1024);
1183 int h = min(g_menuscreen_h, 512);
1184 u16 *d = g_menuscreen_ptr;
1185 u16 *s = (u16 *)gpuf->psxVRam;
1189 gpuf->ulFreezeVersion = 1;
1190 if (GPU_freeze != NULL)
1191 GPU_freeze(1, gpuf);
1193 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1194 bgr555_to_rgb565(d, s, w * 2);
1196 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1197 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1198 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1199 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1200 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1203 static void debug_menu_loop(void)
1208 gpuf = malloc(sizeof(*gpuf));
1215 draw_frame_debug(gpuf);
1218 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1219 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1220 if (inp & PBTN_MBACK)
1227 // ------------ main menu ------------
1229 static void menu_bios_warn(void)
1232 static const char msg[] =
1233 "You don't seem to have copied any BIOS files to\n"
1234 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1235 "While many games work fine with fake (HLE) BIOS,\n"
1236 "others (like MGS and FF8) require BIOS to work.\n"
1237 "After copying the file, you'll also need to\n"
1238 "select it in the emu's options->[BIOS/Plugins]\n\n"
1239 "The file is usually named SCPH1001.BIN, but\n"
1240 "other not compressed files can be used too.\n\n"
1241 "Press (B) or (X) to continue";
1246 draw_menu_message(msg, NULL);
1249 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1250 if (inp & (PBTN_MBACK|PBTN_MOK))
1255 // ------------ main menu ------------
1259 static void draw_frame_main(void)
1261 if (CdromId[0] != 0) {
1263 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1264 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1265 Config.HLE ? "HLE" : "BIOS");
1266 smalltext_out16(4, 1, buff, 0x105f);
1270 static void draw_frame_credits(void)
1272 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1275 static const char credits_text[] =
1277 "(C) 1999-2003 PCSX Team\n"
1278 "(C) 2005-2009 PCSX-df Team\n"
1279 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1280 "GPU and SPU code by Pete Bernert\n"
1281 " and the P.E.Op.S. team\n"
1282 "ARM recompiler (C) 2009-2011 Ari64\n"
1283 "PCSX4ALL plugins by PCSX4ALL team\n"
1284 " Chui, Franxis, Unai\n\n"
1285 "integration, optimization and\n"
1286 " frontend (C) 2010-2011 notaz\n";
1288 static int reset_game(void)
1291 if (bios_sel == 0 && !Config.HLE)
1297 if (CheckCdrom() != -1) {
1303 static int run_bios(void)
1309 pl_fbdev_buf = NULL;
1314 pcnt_hook_plugins();
1316 if (OpenPlugins() == -1) {
1317 me_update_msg("failed to open plugins");
1320 plugin_call_rearmed_cbs();
1323 CdromLabel[0] = '\0';
1331 static int run_cd_image(const char *fname)
1334 pl_fbdev_buf = NULL;
1337 set_cd_image(fname);
1339 pcnt_hook_plugins();
1341 if (OpenPlugins() == -1) {
1342 me_update_msg("failed to open plugins");
1345 plugin_call_rearmed_cbs();
1347 if (CheckCdrom() == -1) {
1348 // Only check the CD if we are starting the console with a CD
1350 me_update_msg("unsupported/invalid CD image");
1356 // Read main executable directly from CDRom and start it
1357 if (LoadCdrom() == -1) {
1359 me_update_msg("failed to load CD image");
1367 static int romsel_run(void)
1369 int prev_gpu, prev_spu;
1372 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1376 printf("selected file: %s\n", fname);
1378 new_dynarec_clear_full();
1380 if (run_cd_image(fname) != 0)
1383 prev_gpu = gpu_plugsel;
1384 prev_spu = spu_plugsel;
1385 if (menu_load_config(1) != 0)
1386 menu_load_config(0);
1388 // check for plugin changes, have to repeat
1389 // loading if game config changed plugins to reload them
1390 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1391 printf("plugin change detected, reloading plugins..\n");
1392 if (run_cd_image(fname) != 0)
1396 strcpy(last_selected_fname, rom_fname_reload);
1400 static int swap_cd_image(void)
1404 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1408 printf("selected file: %s\n", fname);
1411 CdromLabel[0] = '\0';
1413 set_cd_image(fname);
1414 if (ReloadCdromPlugin() < 0) {
1415 me_update_msg("failed to load cdr plugin");
1418 if (CDR_open() < 0) {
1419 me_update_msg("failed to open cdr plugin");
1423 SetCdOpenCaseTime(time(NULL) + 2);
1426 strcpy(last_selected_fname, rom_fname_reload);
1430 static int main_menu_handler(int id, int keys)
1434 case MA_MAIN_RESUME_GAME:
1438 case MA_MAIN_SAVE_STATE:
1440 return menu_loop_savestate(0);
1442 case MA_MAIN_LOAD_STATE:
1444 return menu_loop_savestate(1);
1446 case MA_MAIN_RESET_GAME:
1447 if (ready_to_go && reset_game() == 0)
1450 case MA_MAIN_LOAD_ROM:
1451 if (romsel_run() == 0)
1454 case MA_MAIN_SWAP_CD:
1455 if (swap_cd_image() == 0)
1458 case MA_MAIN_RUN_BIOS:
1459 if (run_bios() == 0)
1462 case MA_MAIN_CREDITS:
1463 draw_menu_message(credits_text, draw_frame_credits);
1464 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1470 lprintf("%s: something unknown selected\n", __FUNCTION__);
1477 static menu_entry e_menu_main[] =
1481 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1482 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1483 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1484 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1485 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1486 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1487 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1488 mee_handler ("Options", menu_loop_options),
1489 mee_handler ("Controls", menu_loop_keyconfig),
1490 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1491 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1495 // ----------------------------
1497 static void menu_leave_emu(void);
1499 void menu_loop(void)
1505 if (bioses[1] == NULL && !warned_about_bios) {
1507 warned_about_bios = 1;
1510 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1511 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1512 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1513 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1514 me_enable(e_menu_main, MA_MAIN_SWAP_CD, ready_to_go);
1515 me_enable(e_menu_main, MA_MAIN_RUN_BIOS, bios_sel != 0);
1517 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1520 me_loop(e_menu_main, &sel, draw_frame_main);
1521 } while (!ready_to_go);
1523 /* wait until menu, ok, back is released */
1524 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1527 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1532 static void scan_bios_plugins(void)
1534 char fname[MAXPATHLEN];
1536 int bios_i, gpu_i, spu_i;
1541 gpu_plugins[0] = "builtin_gpu";
1542 spu_plugins[0] = "builtin_spu";
1543 bios_i = gpu_i = spu_i = 1;
1545 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1546 dir = opendir(fname);
1548 perror("scan_bios_plugins bios opendir");
1563 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1566 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1567 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1568 printf("bad BIOS file: %s\n", ent->d_name);
1572 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1573 bioses[bios_i++] = strdup(ent->d_name);
1577 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1583 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1584 dir = opendir(fname);
1586 perror("scan_bios_plugins opendir");
1600 p = strstr(ent->d_name, ".so");
1604 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1605 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1607 fprintf(stderr, "%s\n", dlerror());
1611 // now what do we have here?
1612 tmp = dlsym(h, "GPUinit");
1615 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1616 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1620 tmp = dlsym(h, "SPUinit");
1623 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1624 spu_plugins[spu_i++] = strdup(ent->d_name);
1628 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1635 void menu_init(void)
1637 char buff[MAXPATHLEN];
1639 strcpy(last_selected_fname, "/media");
1641 scan_bios_plugins();
1645 menu_set_defconfig();
1646 menu_load_config(0);
1651 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1652 if (g_menubg_src_ptr == NULL)
1654 emu_make_path(buff, "skin/background.png", sizeof(buff));
1655 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1658 void menu_notify_mode_change(int w, int h, int bpp)
1664 if (scaling == SCALE_1_1) {
1665 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1666 g_layer_w = w; g_layer_h = h;
1670 static void menu_leave_emu(void)
1672 if (GPU_close != NULL) {
1673 int ret = GPU_close();
1675 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1678 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1679 if (pl_fbdev_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1680 int x = max(0, g_menuscreen_w - last_psx_w);
1681 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1682 int w = min(g_menuscreen_w, last_psx_w);
1683 int h = min(g_menuscreen_h, last_psx_h);
1684 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1685 u16 *s = pl_fbdev_buf;
1687 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1688 menu_darken_bg(d, s, w, 0);
1692 cpu_clock = get_cpu_clock();
1694 plat_video_menu_enter(ready_to_go);
1697 void menu_prepare_emu(void)
1699 R3000Acpu *prev_cpu = psxCpu;
1701 plat_video_menu_leave();
1705 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
1708 g_layer_x = 80; g_layer_y = 0;
1709 g_layer_w = 640; g_layer_h = 480;
1711 case SCALE_FULLSCREEN:
1712 g_layer_x = 0; g_layer_y = 0;
1713 g_layer_w = 800; g_layer_h = 480;
1718 apply_filter(filter);
1721 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
1722 if (psxCpu != prev_cpu)
1723 // note that this does not really reset, just clears drc caches
1726 // core doesn't care about Config.Cdda changes,
1727 // so handle them manually here
1733 if (GPU_open != NULL) {
1734 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
1736 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
1739 dfinput_activate(in_type == PSE_PAD_TYPE_ANALOGPAD);
1742 void me_update_msg(const char *msg)
1744 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
1745 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
1747 menu_error_time = plat_get_ticks_ms();
1748 lprintf("msg: %s\n", menu_error_msg);