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 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
671 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
675 static char *mystrip(char *str)
680 for (i = 0; i < len; i++)
681 if (str[i] != ' ') break;
682 if (i > 0) memmove(str, str + i, len - i + 1);
685 for (i = len - 1; i >= 0; i--)
686 if (str[i] != ' ') break;
692 static void get_line(char *d, size_t size, const char *s)
697 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
708 static void keys_write_all(FILE *f)
712 for (d = 0; d < IN_MAX_DEVS; d++)
714 const int *binds = in_get_dev_binds(d);
715 const char *name = in_get_dev_name(d, 0, 0);
718 if (binds == NULL || name == NULL)
721 fprintf(f, "binddev = %s\n", name);
722 in_get_config(d, IN_CFG_BIND_COUNT, &count);
724 for (k = 0; k < count; k++)
729 act[0] = act[31] = 0;
730 name = in_get_key_name(d, k);
732 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
733 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
734 mask = me_ctrl_actions[i].mask;
736 strncpy(act, me_ctrl_actions[i].name, 31);
737 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
740 mask = me_ctrl_actions[i].mask << 16;
742 strncpy(act, me_ctrl_actions[i].name, 31);
743 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
748 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
749 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
750 mask = emuctrl_actions[i].mask;
752 strncpy(act, emuctrl_actions[i].name, 31);
753 fprintf(f, "bind %s = %s\n", name, mystrip(act));
761 static int parse_bind_val(const char *val, int *type)
765 *type = IN_BINDTYPE_NONE;
769 if (strncasecmp(val, "player", 6) == 0)
771 int player, shift = 0;
772 player = atoi(val + 6) - 1;
774 if ((unsigned int)player > 1)
779 *type = IN_BINDTYPE_PLAYER12;
780 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
781 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
782 return me_ctrl_actions[i].mask << shift;
785 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
786 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
787 *type = IN_BINDTYPE_EMU;
788 return emuctrl_actions[i].mask;
795 static void keys_load_all(const char *cfg)
797 char dev[256], key[128], *act;
803 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
806 get_line(dev, sizeof(dev), p);
807 dev_id = in_config_parse_dev(dev);
809 printf("input: can't handle dev: %s\n", dev);
813 in_unbind_all(dev_id, -1, -1);
814 while ((p = strstr(p, "bind"))) {
815 if (strncmp(p, "binddev = ", 10) == 0)
820 printf("input: parse error: %16s..\n", p);
824 get_line(key, sizeof(key), p);
825 act = strchr(key, '=');
827 printf("parse failed: %16s..\n", p);
835 bind = parse_bind_val(act, &bindtype);
836 if (bind != -1 && bind != 0) {
837 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
838 in_config_bind_key(dev_id, key, bind, bindtype);
841 lprintf("config: unhandled action \"%s\"\n", act);
846 static int key_config_loop_wrap(int id, int keys)
849 case MA_CTRL_PLAYER1:
850 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
852 case MA_CTRL_PLAYER2:
853 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
856 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
864 static const char *mgn_dev_name(int id, int *offs)
866 const char *name = NULL;
869 if (id == MA_CTRL_DEV_FIRST)
872 for (; it < IN_MAX_DEVS; it++) {
873 name = in_get_dev_name(it, 1, 1);
882 static const char *mgn_saveloadcfg(int id, int *offs)
887 static int mh_savecfg(int id, int keys)
889 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
890 me_update_msg("config saved");
892 me_update_msg("failed to write config");
897 static const char *men_in_type_sel[] = { "Standard (SCPH-1080)", "Analog (SCPH-1150)", NULL };
899 static menu_entry e_menu_keyconfig[] =
901 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
902 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
903 mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
905 mee_enum ("Controller", 0, in_type_sel, men_in_type_sel),
906 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
907 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
909 mee_label ("Input devices:"),
910 mee_label_mk (MA_CTRL_DEV_FIRST, 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),
916 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
920 static int menu_loop_keyconfig(int id, int keys)
924 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
925 me_loop(e_menu_keyconfig, &sel, NULL);
929 // ------------ gfx options menu ------------
931 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
932 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
933 "using d-pad or move it using R+d-pad";
934 static const char *men_dummy[] = { NULL };
936 static int menu_loop_cscaler(int id, int keys)
940 scaling = SCALE_CUSTOM;
942 omap_enable_layer(1);
947 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
948 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
949 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
952 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
953 if (inp & PBTN_UP) g_layer_y--;
954 if (inp & PBTN_DOWN) g_layer_y++;
955 if (inp & PBTN_LEFT) g_layer_x--;
956 if (inp & PBTN_RIGHT) g_layer_x++;
957 if (!(inp & PBTN_R)) {
958 if (inp & PBTN_UP) g_layer_h += 2;
959 if (inp & PBTN_DOWN) g_layer_h -= 2;
960 if (inp & PBTN_LEFT) g_layer_w += 2;
961 if (inp & PBTN_RIGHT) g_layer_w -= 2;
963 if (inp & (PBTN_MOK|PBTN_MBACK))
966 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
967 if (g_layer_x < 0) g_layer_x = 0;
968 if (g_layer_x > 640) g_layer_x = 640;
969 if (g_layer_y < 0) g_layer_y = 0;
970 if (g_layer_y > 420) g_layer_y = 420;
971 if (g_layer_w < 160) g_layer_w = 160;
972 if (g_layer_h < 60) g_layer_h = 60;
973 if (g_layer_x + g_layer_w > 800)
974 g_layer_w = 800 - g_layer_x;
975 if (g_layer_y + g_layer_h > 480)
976 g_layer_h = 480 - g_layer_y;
977 omap_enable_layer(1);
981 omap_enable_layer(0);
986 static menu_entry e_menu_gfx_options[] =
988 mee_enum ("Scaler", 0, scaling, men_scaler),
989 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
990 // mee_onoff ("Vsync", 0, vsync, 1),
991 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
995 static int menu_loop_gfx_options(int id, int keys)
999 me_loop(e_menu_gfx_options, &sel, NULL);
1004 // ------------ bios/plugins ------------
1006 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1007 static const char h_gpu_0[] = "Needed for Chrono Cross";
1008 static const char h_gpu_1[] = "Capcom fighting games";
1009 static const char h_gpu_2[] = "Black screens in Lunar";
1010 static const char h_gpu_3[] = "Compatibility mode";
1011 static const char h_gpu_6[] = "Pandemonium 2";
1012 static const char h_gpu_7[] = "Skip every second frame";
1013 static const char h_gpu_8[] = "Needed by Dark Forces";
1014 static const char h_gpu_9[] = "better g-colors, worse textures";
1015 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1017 static menu_entry e_menu_plugin_gpu[] =
1019 mee_enum ("Dithering", 0, iUseDither, men_gpu_dithering),
1020 mee_onoff_h ("Odd/even bit hack", 0, dwActFixes, 1<<0, h_gpu_0),
1021 mee_onoff_h ("Expand screen width", 0, dwActFixes, 1<<1, h_gpu_1),
1022 mee_onoff_h ("Ignore brightness color", 0, dwActFixes, 1<<2, h_gpu_2),
1023 mee_onoff_h ("Disable coordinate check", 0, dwActFixes, 1<<3, h_gpu_3),
1024 mee_onoff_h ("Lazy screen update", 0, dwActFixes, 1<<6, h_gpu_6),
1025 mee_onoff_h ("Old frame skipping", 0, dwActFixes, 1<<7, h_gpu_7),
1026 mee_onoff_h ("Repeated flat tex triangles ",0,dwActFixes, 1<<8, h_gpu_8),
1027 mee_onoff_h ("Draw quads with triangles", 0, dwActFixes, 1<<9, h_gpu_9),
1028 mee_onoff_h ("Fake 'gpu busy' states", 0, dwActFixes, 1<<10, h_gpu_10),
1032 static int menu_loop_plugin_gpu(int id, int keys)
1035 me_loop(e_menu_plugin_gpu, &sel, NULL);
1039 static const char *men_spu_reverb[] = { "Off", "Fake", "On", NULL };
1040 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1041 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1042 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1044 static menu_entry e_menu_plugin_spu[] =
1046 mee_enum ("Reverb", 0, iUseReverb, men_spu_reverb),
1047 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1048 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1049 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1050 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1054 static int menu_loop_plugin_spu(int id, int keys)
1057 me_loop(e_menu_plugin_spu, &sel, NULL);
1061 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1062 "and can't be changed there. Must save config and reload\n"
1063 "the game for change to take effect";
1064 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1065 "for plugin change to take effect";
1066 static const char h_gpu[] = "Configure built-in P.E.Op.S. SoftGL Driver V1.17";
1067 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1069 static menu_entry e_menu_plugin_options[] =
1071 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1072 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1073 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1074 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu, h_gpu),
1075 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1079 static menu_entry e_menu_main[];
1081 static int menu_loop_plugin_options(int id, int keys)
1084 me_loop(e_menu_plugin_options, &sel, NULL);
1086 // sync BIOS/plugins
1087 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1088 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1089 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1090 me_enable(e_menu_main, MA_MAIN_RUN_BIOS, bios_sel != 0);
1095 // ------------ adv options menu ------------
1097 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1098 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1099 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1100 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1101 "(proper .cue/.bin dump is needed otherwise)";
1102 static const char h_cfg_sio[] = "This should be enabled for certain memcards/gamepads";
1103 static const char h_cfg_spuirq[] = "Compatibility tweak; should probably be left off";
1104 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix";
1105 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix";
1106 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1107 "Might be useful to overcome some dynarec bugs";
1109 static menu_entry e_menu_adv_options[] =
1111 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1112 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1113 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1114 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1115 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1116 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1117 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1118 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1119 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1123 static int menu_loop_adv_options(int id, int keys)
1126 me_loop(e_menu_adv_options, &sel, NULL);
1130 // ------------ options menu ------------
1132 static int mh_restore_defaults(int id, int keys)
1134 menu_set_defconfig();
1135 me_update_msg("defaults restored");
1139 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1141 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1142 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1143 "loading state or both";
1145 static const char h_restore_def[] = "Switches back to default / recommended\n"
1147 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1149 static menu_entry e_menu_options[] =
1151 // mee_range ("Save slot", 0, state_slot, 0, 9),
1152 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1153 mee_onoff_h ("Frameskip", 0, UseFrameSkip, 1, h_frameskip),
1154 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1155 mee_enum ("Region", 0, region, men_region),
1156 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1157 mee_handler ("[Display]", menu_loop_gfx_options),
1158 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1159 mee_handler ("[Advanced]", menu_loop_adv_options),
1160 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1161 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1162 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1166 static int menu_loop_options(int id, int keys)
1171 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1172 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1173 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1175 me_loop(e_menu_options, &sel, NULL);
1180 // ------------ debug menu ------------
1182 static void draw_frame_debug(GPUFreeze_t *gpuf)
1184 int w = min(g_menuscreen_w, 1024);
1185 int h = min(g_menuscreen_h, 512);
1186 u16 *d = g_menuscreen_ptr;
1187 u16 *s = (u16 *)gpuf->psxVRam;
1191 gpuf->ulFreezeVersion = 1;
1192 if (GPU_freeze != NULL)
1193 GPU_freeze(1, gpuf);
1195 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1196 bgr555_to_rgb565(d, s, w * 2);
1198 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1199 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1200 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1201 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1202 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1205 static void debug_menu_loop(void)
1210 gpuf = malloc(sizeof(*gpuf));
1217 draw_frame_debug(gpuf);
1220 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1221 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1222 if (inp & PBTN_MBACK)
1229 // ------------ main menu ------------
1231 static void menu_bios_warn(void)
1234 static const char msg[] =
1235 "You don't seem to have copied any BIOS files to\n"
1236 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1237 "While many games work fine with fake (HLE) BIOS,\n"
1238 "others (like MGS and FF8) require BIOS to work.\n"
1239 "After copying the file, you'll also need to\n"
1240 "select it in the emu's options->[BIOS/Plugins]\n\n"
1241 "The file is usually named SCPH1001.BIN, but\n"
1242 "other not compressed files can be used too.\n\n"
1243 "Press (B) or (X) to continue";
1247 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);