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 "common/plat.h"
25 #include "../libpcsxcore/misc.h"
26 #include "../libpcsxcore/cdrom.h"
27 #include "../libpcsxcore/psemu_plugin_defs.h"
28 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
29 #include "../plugins/dfinput/pad.h"
33 #define array_size(x) (sizeof(x) / sizeof(x[0]))
67 static int last_psx_w, last_psx_h, last_psx_bpp;
68 static int scaling, filter, cpu_clock, cpu_clock_st;
69 static char rom_fname_reload[MAXPATHLEN];
70 static char last_selected_fname[MAXPATHLEN];
71 static int warned_about_bios, region, in_type_sel;
74 // from softgpu plugin
75 extern int iUseDither;
76 extern int UseFrameSkip;
77 extern uint32_t dwActFixes;
78 extern float fFrameRateHz;
79 extern int dwFrameRateTicks;
82 extern int iUseReverb;
83 extern int iUseInterpolation;
85 extern int iSPUIRQWait;
88 static const char *bioses[24];
89 static const char *gpu_plugins[16];
90 static const char *spu_plugins[16];
91 static int bios_sel, gpu_plugsel, spu_plugsel;
94 static int min(int x, int y) { return x < y ? x : y; }
95 static int max(int x, int y) { return x > y ? x : y; }
97 void emu_make_path(char *buff, const char *end, int size)
101 end_len = strlen(end);
102 pos = plat_get_root_dir(buff, size);
103 strncpy(buff + pos, end, size - pos);
105 if (pos + end_len > size - 1)
106 printf("Warning: path truncated: %s\n", buff);
109 static int emu_check_save_file(int slot)
111 int ret = emu_check_state(slot);
112 return ret == 0 ? 1 : 0;
115 static int emu_save_load_game(int load, int unused)
120 ret = emu_load_state(state_slot);
122 // reflect hle/bios mode from savestate
125 else if (bios_sel == 0 && bioses[1] != NULL)
126 // XXX: maybe find the right bios instead
130 ret = emu_save_state(state_slot);
135 // propagate menu settings to the emu vars
136 static void menu_sync_config(void)
141 Config.PsxType = region - 1;
143 in_type = in_type_sel ? PSE_PAD_TYPE_ANALOGPAD : PSE_PAD_TYPE_STANDARD;
145 pl_frame_interval = Config.PsxType ? 20000 : 16667;
146 // used by P.E.Op.S. frameskip code
147 fFrameRateHz = Config.PsxType ? 50.0f : 59.94f;
148 dwFrameRateTicks = (100000*100 / (unsigned long)(fFrameRateHz*100));
151 static void menu_set_defconfig(void)
158 Config.Xa = Config.Cdda = Config.Sio =
159 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
166 iUseInterpolation = 1;
174 #define CE_CONFIG_STR(val) \
175 { #val, 0, Config.val }
177 #define CE_CONFIG_VAL(val) \
178 { #val, sizeof(Config.val), &Config.val }
180 #define CE_STR(val) \
183 #define CE_INTVAL(val) \
184 { #val, sizeof(val), &val }
186 // 'versioned' var, used when defaults change
187 #define CE_INTVAL_V(val, ver) \
188 { #val #ver, sizeof(val), &val }
190 static const struct {
198 // CE_CONFIG_STR(Cdr),
203 CE_CONFIG_VAL(Debug),
204 CE_CONFIG_VAL(PsxOut),
205 CE_CONFIG_VAL(SpuIrq),
206 CE_CONFIG_VAL(RCntFix),
207 CE_CONFIG_VAL(VSyncWA),
211 CE_INTVAL(g_layer_x),
212 CE_INTVAL(g_layer_y),
213 CE_INTVAL(g_layer_w),
214 CE_INTVAL(g_layer_h),
216 CE_INTVAL(state_slot),
217 CE_INTVAL(cpu_clock),
219 CE_INTVAL(in_type_sel),
220 CE_INTVAL(iUseDither),
221 CE_INTVAL(UseFrameSkip),
222 CE_INTVAL(dwActFixes),
223 CE_INTVAL(iUseReverb),
225 CE_INTVAL_V(iUseInterpolation, 2),
226 CE_INTVAL_V(iSPUIRQWait, 2),
227 CE_INTVAL(iUseTimer),
228 CE_INTVAL(warned_about_bios),
231 static char *get_cd_label(void)
233 static char trimlabel[33];
236 strncpy(trimlabel, CdromLabel, 32);
238 for (j = 31; j >= 0; j--)
239 if (trimlabel[j] == ' ')
245 static void make_cfg_fname(char *buf, size_t size, int is_game)
248 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
250 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
253 static void keys_write_all(FILE *f);
255 static int menu_write_config(int is_game)
257 char cfgfile[MAXPATHLEN];
261 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
262 f = fopen(cfgfile, "w");
264 printf("menu_write_config: failed to open: %s\n", cfgfile);
268 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
269 fprintf(f, "%s = ", config_data[i].name);
270 switch (config_data[i].len) {
272 fprintf(f, "%s\n", (char *)config_data[i].val);
275 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
278 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
281 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
284 printf("menu_write_config: unhandled len %d for %s\n",
285 config_data[i].len, config_data[i].name);
291 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
299 static void parse_str_val(char *cval, const char *src)
302 strncpy(cval, src, MAXPATHLEN);
303 cval[MAXPATHLEN - 1] = 0;
304 tmp = strchr(cval, '\n');
306 tmp = strchr(cval, '\r');
311 static void keys_load_all(const char *cfg);
313 static int menu_load_config(int is_game)
315 char cfgfile[MAXPATHLEN];
321 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
322 f = fopen(cfgfile, "r");
324 printf("menu_load_config: failed to open: %s\n", cfgfile);
328 fseek(f, 0, SEEK_END);
331 printf("bad size %ld: %s\n", size, cfgfile);
335 cfg = malloc(size + 1);
339 fseek(f, 0, SEEK_SET);
340 if (fread(cfg, 1, size, f) != size) {
341 printf("failed to read: %s\n", cfgfile);
346 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
350 tmp = strstr(cfg, config_data[i].name);
353 tmp += strlen(config_data[i].name);
354 if (strncmp(tmp, " = ", 3) != 0)
358 if (config_data[i].len == 0) {
359 parse_str_val(config_data[i].val, tmp);
364 val = strtoul(tmp, &tmp2, 16);
365 if (tmp2 == NULL || tmp == tmp2)
366 continue; // parse failed
368 switch (config_data[i].len) {
370 *(u8 *)config_data[i].val = val;
373 *(u16 *)config_data[i].val = val;
376 *(u32 *)config_data[i].val = val;
379 printf("menu_load_config: unhandled len %d for %s\n",
380 config_data[i].len, config_data[i].name);
386 char *tmp = strstr(cfg, "lastcdimg = ");
389 parse_str_val(last_selected_fname, tmp);
396 for (i = bios_sel = 0; bioses[i] != NULL; i++)
397 if (strcmp(Config.Bios, bioses[i]) == 0)
398 { bios_sel = i; break; }
400 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
401 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
402 { gpu_plugsel = i; break; }
404 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
405 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
406 { spu_plugsel = i; break; }
417 // rrrr rggg gggb bbbb
418 static unsigned short fname2color(const char *fname)
420 static const char *cdimg_exts[] = { ".bin", ".img", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
421 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
422 const char *ext = strrchr(fname, '.');
427 for (i = 0; i < array_size(cdimg_exts); i++)
428 if (strcasecmp(ext, cdimg_exts[i]) == 0)
430 for (i = 0; i < array_size(other_exts); i++)
431 if (strcasecmp(ext, other_exts[i]) == 0)
436 static void draw_savestate_bg(int slot);
438 #define MENU_ALIGN_LEFT
439 #define menu_init menu_init_common
440 #include "common/menu.c"
443 // a bit of black magic here
444 static void draw_savestate_bg(int slot)
446 extern void bgr555_to_rgb565(void *dst, void *src, int bytes);
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(void)
1182 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1185 static void debug_menu_loop(void)
1195 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1196 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1197 if (inp & PBTN_MBACK)
1202 // ------------ main menu ------------
1204 static void menu_bios_warn(void)
1207 static const char msg[] =
1208 "You don't seem to have copied any BIOS files to\n"
1209 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1210 "While many games work fine with fake (HLE) BIOS,\n"
1211 "others (like MGS and FF8) require BIOS to work.\n"
1212 "After copying the file, you'll also need to\n"
1213 "select it in the emu's options->[BIOS/Plugins]\n\n"
1214 "The file is usually named SCPH1001.BIN, but\n"
1215 "other not compressed files can be used too.\n\n"
1216 "Press (B) or (X) to continue";
1221 draw_menu_message(msg, NULL);
1224 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1225 if (inp & (PBTN_MBACK|PBTN_MOK))
1230 // ------------ main menu ------------
1234 static void draw_frame_main(void)
1236 if (CdromId[0] != 0) {
1238 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1239 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1240 Config.HLE ? "HLE" : "BIOS");
1241 smalltext_out16(4, 1, buff, 0x105f);
1245 static void draw_frame_credits(void)
1247 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1250 static const char credits_text[] =
1252 "(C) 1999-2003 PCSX Team\n"
1253 "(C) 2005-2009 PCSX-df Team\n"
1254 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1255 "GPU and SPU code by Pete Bernert\n"
1256 " and the P.E.Op.S. team\n"
1257 "ARM recompiler (C) 2009-2011 Ari64\n"
1258 "PCSX4ALL plugins by PCSX4ALL team\n"
1259 " Chui, Franxis, Unai\n\n"
1260 "integration, optimization and\n"
1261 " frontend (C) 2010-2011 notaz\n";
1263 static int reset_game(void)
1266 if (bios_sel == 0 && !Config.HLE)
1272 if (CheckCdrom() != -1) {
1278 static int run_bios(void)
1284 pl_fbdev_buf = NULL;
1289 pcnt_hook_plugins();
1291 if (OpenPlugins() == -1) {
1292 me_update_msg("failed to open plugins");
1295 plugin_call_rearmed_cbs();
1298 CdromLabel[0] = '\0';
1306 static int run_cd_image(const char *fname)
1309 pl_fbdev_buf = NULL;
1312 set_cd_image(fname);
1314 pcnt_hook_plugins();
1316 if (OpenPlugins() == -1) {
1317 me_update_msg("failed to open plugins");
1320 plugin_call_rearmed_cbs();
1322 if (CheckCdrom() == -1) {
1323 // Only check the CD if we are starting the console with a CD
1325 me_update_msg("unsupported/invalid CD image");
1331 // Read main executable directly from CDRom and start it
1332 if (LoadCdrom() == -1) {
1334 me_update_msg("failed to load CD image");
1342 static int romsel_run(void)
1344 int prev_gpu, prev_spu;
1347 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1351 printf("selected file: %s\n", fname);
1353 new_dynarec_clear_full();
1355 if (run_cd_image(fname) != 0)
1358 prev_gpu = gpu_plugsel;
1359 prev_spu = spu_plugsel;
1360 if (menu_load_config(1) != 0)
1361 menu_load_config(0);
1363 // check for plugin changes, have to repeat
1364 // loading if game config changed plugins to reload them
1365 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1366 printf("plugin change detected, reloading plugins..\n");
1367 if (run_cd_image(fname) != 0)
1371 strcpy(last_selected_fname, rom_fname_reload);
1375 static int swap_cd_image(void)
1379 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1383 printf("selected file: %s\n", fname);
1386 CdromLabel[0] = '\0';
1388 set_cd_image(fname);
1389 if (ReloadCdromPlugin() < 0) {
1390 me_update_msg("failed to load cdr plugin");
1393 if (CDR_open() < 0) {
1394 me_update_msg("failed to open cdr plugin");
1398 SetCdOpenCaseTime(time(NULL) + 2);
1401 strcpy(last_selected_fname, rom_fname_reload);
1405 static int main_menu_handler(int id, int keys)
1409 case MA_MAIN_RESUME_GAME:
1413 case MA_MAIN_SAVE_STATE:
1415 return menu_loop_savestate(0);
1417 case MA_MAIN_LOAD_STATE:
1419 return menu_loop_savestate(1);
1421 case MA_MAIN_RESET_GAME:
1422 if (ready_to_go && reset_game() == 0)
1425 case MA_MAIN_LOAD_ROM:
1426 if (romsel_run() == 0)
1429 case MA_MAIN_SWAP_CD:
1430 if (swap_cd_image() == 0)
1433 case MA_MAIN_RUN_BIOS:
1434 if (run_bios() == 0)
1437 case MA_MAIN_CREDITS:
1438 draw_menu_message(credits_text, draw_frame_credits);
1439 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1445 lprintf("%s: something unknown selected\n", __FUNCTION__);
1452 static menu_entry e_menu_main[] =
1456 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1457 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1458 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1459 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1460 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1461 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1462 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1463 mee_handler ("Options", menu_loop_options),
1464 mee_handler ("Controls", menu_loop_keyconfig),
1465 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1466 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1470 // ----------------------------
1472 static void menu_leave_emu(void);
1474 void menu_loop(void)
1480 if (bioses[1] == NULL && !warned_about_bios) {
1482 warned_about_bios = 1;
1485 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1486 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1487 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1488 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1489 me_enable(e_menu_main, MA_MAIN_SWAP_CD, ready_to_go);
1490 me_enable(e_menu_main, MA_MAIN_RUN_BIOS, bios_sel != 0);
1492 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1495 me_loop(e_menu_main, &sel, draw_frame_main);
1496 } while (!ready_to_go);
1498 /* wait until menu, ok, back is released */
1499 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1502 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1507 static void scan_bios_plugins(void)
1509 char fname[MAXPATHLEN];
1511 int bios_i, gpu_i, spu_i;
1516 gpu_plugins[0] = "builtin_gpu";
1517 spu_plugins[0] = "builtin_spu";
1518 bios_i = gpu_i = spu_i = 1;
1520 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1521 dir = opendir(fname);
1523 perror("scan_bios_plugins bios opendir");
1538 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1541 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1542 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1543 printf("bad BIOS file: %s\n", ent->d_name);
1547 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1548 bioses[bios_i++] = strdup(ent->d_name);
1552 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1558 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1559 dir = opendir(fname);
1561 perror("scan_bios_plugins opendir");
1575 p = strstr(ent->d_name, ".so");
1579 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1580 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1582 fprintf(stderr, "%s\n", dlerror());
1586 // now what do we have here?
1587 tmp = dlsym(h, "GPUinit");
1590 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1591 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1595 tmp = dlsym(h, "SPUinit");
1598 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1599 spu_plugins[spu_i++] = strdup(ent->d_name);
1603 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1610 void menu_init(void)
1612 char buff[MAXPATHLEN];
1614 strcpy(last_selected_fname, "/media");
1616 scan_bios_plugins();
1620 menu_set_defconfig();
1621 menu_load_config(0);
1626 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1627 if (g_menubg_src_ptr == NULL)
1629 emu_make_path(buff, "skin/background.png", sizeof(buff));
1630 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1633 void menu_notify_mode_change(int w, int h, int bpp)
1639 if (scaling == SCALE_1_1) {
1640 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1641 g_layer_w = w; g_layer_h = h;
1645 static void menu_leave_emu(void)
1647 if (GPU_close != NULL) {
1648 int ret = GPU_close();
1650 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1653 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1654 if (pl_fbdev_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1655 int x = max(0, g_menuscreen_w - last_psx_w);
1656 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1657 int w = min(g_menuscreen_w, last_psx_w);
1658 int h = min(g_menuscreen_h, last_psx_h);
1659 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1660 u16 *s = pl_fbdev_buf;
1662 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1663 menu_darken_bg(d, s, w, 0);
1667 cpu_clock = get_cpu_clock();
1669 plat_video_menu_enter(ready_to_go);
1672 void menu_prepare_emu(void)
1674 R3000Acpu *prev_cpu = psxCpu;
1676 plat_video_menu_leave();
1680 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
1683 g_layer_x = 80; g_layer_y = 0;
1684 g_layer_w = 640; g_layer_h = 480;
1686 case SCALE_FULLSCREEN:
1687 g_layer_x = 0; g_layer_y = 0;
1688 g_layer_w = 800; g_layer_h = 480;
1693 apply_filter(filter);
1696 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
1697 if (psxCpu != prev_cpu)
1698 // note that this does not really reset, just clears drc caches
1701 // core doesn't care about Config.Cdda changes,
1702 // so handle them manually here
1708 if (GPU_open != NULL) {
1709 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
1711 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
1714 dfinput_activate(in_type == PSE_PAD_TYPE_ANALOGPAD);
1717 void me_update_msg(const char *msg)
1719 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
1720 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
1722 menu_error_time = plat_get_ticks_ms();
1723 lprintf("msg: %s\n", menu_error_msg);