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 "../plugins/dfinput/pad.h"
32 #define array_size(x) (sizeof(x) / sizeof(x[0]))
66 static int last_psx_w, last_psx_h, last_psx_bpp;
67 static int scaling, filter, cpu_clock, cpu_clock_st;
68 static char rom_fname_reload[MAXPATHLEN];
69 static char last_selected_fname[MAXPATHLEN];
70 static int warned_about_bios, region, in_type_sel;
73 // from softgpu plugin
74 extern int iUseDither;
75 extern int UseFrameSkip;
76 extern uint32_t dwActFixes;
77 extern float fFrameRateHz;
78 extern int dwFrameRateTicks;
81 extern int iUseReverb;
82 extern int iUseInterpolation;
84 extern int iSPUIRQWait;
87 static const char *bioses[24];
88 static const char *gpu_plugins[16];
89 static const char *spu_plugins[16];
90 static int bios_sel, gpu_plugsel, spu_plugsel;
93 static int min(int x, int y) { return x < y ? x : y; }
94 static int max(int x, int y) { return x > y ? x : y; }
96 void emu_make_path(char *buff, const char *end, int size)
100 end_len = strlen(end);
101 pos = plat_get_root_dir(buff, size);
102 strncpy(buff + pos, end, size - pos);
104 if (pos + end_len > size - 1)
105 printf("Warning: path truncated: %s\n", buff);
108 static int emu_check_save_file(int slot)
110 int ret = emu_check_state(slot);
111 return ret == 0 ? 1 : 0;
114 static int emu_save_load_game(int load, int unused)
119 ret = emu_load_state(state_slot);
121 // reflect hle/bios mode from savestate
124 else if (bios_sel == 0 && bioses[1] != NULL)
125 // XXX: maybe find the right bios instead
129 ret = emu_save_state(state_slot);
134 // propagate menu settings to the emu vars
135 static void menu_sync_config(void)
140 Config.PsxType = region - 1;
142 in_type = in_type_sel ? PSE_PAD_TYPE_ANALOGPAD : PSE_PAD_TYPE_STANDARD;
144 pl_frame_interval = Config.PsxType ? 20000 : 16667;
145 // used by P.E.Op.S. frameskip code
146 fFrameRateHz = Config.PsxType ? 50.0f : 59.94f;
147 dwFrameRateTicks = (100000*100 / (unsigned long)(fFrameRateHz*100));
150 static void menu_set_defconfig(void)
157 Config.Xa = Config.Cdda = Config.Sio =
158 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
165 iUseInterpolation = 1;
173 #define CE_CONFIG_STR(val) \
174 { #val, 0, Config.val }
176 #define CE_CONFIG_VAL(val) \
177 { #val, sizeof(Config.val), &Config.val }
179 #define CE_STR(val) \
182 #define CE_INTVAL(val) \
183 { #val, sizeof(val), &val }
185 // 'versioned' var, used when defaults change
186 #define CE_INTVAL_V(val, ver) \
187 { #val #ver, sizeof(val), &val }
189 static const struct {
197 // CE_CONFIG_STR(Cdr),
202 CE_CONFIG_VAL(Debug),
203 CE_CONFIG_VAL(PsxOut),
204 CE_CONFIG_VAL(SpuIrq),
205 CE_CONFIG_VAL(RCntFix),
206 CE_CONFIG_VAL(VSyncWA),
210 CE_INTVAL(g_layer_x),
211 CE_INTVAL(g_layer_y),
212 CE_INTVAL(g_layer_w),
213 CE_INTVAL(g_layer_h),
215 CE_INTVAL(state_slot),
216 CE_INTVAL(cpu_clock),
218 CE_INTVAL(in_type_sel),
219 CE_INTVAL(iUseDither),
220 CE_INTVAL(UseFrameSkip),
221 CE_INTVAL(dwActFixes),
222 CE_INTVAL(iUseReverb),
224 CE_INTVAL_V(iUseInterpolation, 2),
225 CE_INTVAL_V(iSPUIRQWait, 2),
226 CE_INTVAL(iUseTimer),
227 CE_INTVAL(warned_about_bios),
230 static char *get_cd_label(void)
232 static char trimlabel[33];
235 strncpy(trimlabel, CdromLabel, 32);
237 for (j = 31; j >= 0; j--)
238 if (trimlabel[j] == ' ')
244 static void make_cfg_fname(char *buf, size_t size, int is_game)
247 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
249 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
252 static void keys_write_all(FILE *f);
254 static int menu_write_config(int is_game)
256 char cfgfile[MAXPATHLEN];
260 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
261 f = fopen(cfgfile, "w");
263 printf("menu_write_config: failed to open: %s\n", cfgfile);
267 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
268 fprintf(f, "%s = ", config_data[i].name);
269 switch (config_data[i].len) {
271 fprintf(f, "%s\n", (char *)config_data[i].val);
274 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
277 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
280 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
283 printf("menu_write_config: unhandled len %d for %s\n",
284 config_data[i].len, config_data[i].name);
290 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
298 static void parse_str_val(char *cval, const char *src)
301 strncpy(cval, src, MAXPATHLEN);
302 cval[MAXPATHLEN - 1] = 0;
303 tmp = strchr(cval, '\n');
305 tmp = strchr(cval, '\r');
310 static void keys_load_all(const char *cfg);
312 static int menu_load_config(int is_game)
314 char cfgfile[MAXPATHLEN];
320 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
321 f = fopen(cfgfile, "r");
323 printf("menu_load_config: failed to open: %s\n", cfgfile);
327 fseek(f, 0, SEEK_END);
330 printf("bad size %ld: %s\n", size, cfgfile);
334 cfg = malloc(size + 1);
338 fseek(f, 0, SEEK_SET);
339 if (fread(cfg, 1, size, f) != size) {
340 printf("failed to read: %s\n", cfgfile);
345 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
349 tmp = strstr(cfg, config_data[i].name);
352 tmp += strlen(config_data[i].name);
353 if (strncmp(tmp, " = ", 3) != 0)
357 if (config_data[i].len == 0) {
358 parse_str_val(config_data[i].val, tmp);
363 val = strtoul(tmp, &tmp2, 16);
364 if (tmp2 == NULL || tmp == tmp2)
365 continue; // parse failed
367 switch (config_data[i].len) {
369 *(u8 *)config_data[i].val = val;
372 *(u16 *)config_data[i].val = val;
375 *(u32 *)config_data[i].val = val;
378 printf("menu_load_config: unhandled len %d for %s\n",
379 config_data[i].len, config_data[i].name);
385 char *tmp = strstr(cfg, "lastcdimg = ");
388 parse_str_val(last_selected_fname, tmp);
395 for (i = bios_sel = 0; bioses[i] != NULL; i++)
396 if (strcmp(Config.Bios, bioses[i]) == 0)
397 { bios_sel = i; break; }
399 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
400 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
401 { gpu_plugsel = i; break; }
403 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
404 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
405 { spu_plugsel = i; break; }
416 // rrrr rggg gggb bbbb
417 static unsigned short fname2color(const char *fname)
419 static const char *cdimg_exts[] = { ".bin", ".img", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
420 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
421 const char *ext = strrchr(fname, '.');
426 for (i = 0; i < array_size(cdimg_exts); i++)
427 if (strcasecmp(ext, cdimg_exts[i]) == 0)
429 for (i = 0; i < array_size(other_exts); i++)
430 if (strcasecmp(ext, other_exts[i]) == 0)
435 static void draw_savestate_bg(int slot);
437 #define MENU_ALIGN_LEFT
438 #define menu_init menu_init_common
439 #include "common/menu.c"
442 // a bit of black magic here
443 static void draw_savestate_bg(int slot)
445 extern void bgr555_to_rgb565(void *dst, void *src, int bytes);
446 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
448 char fname[MAXPATHLEN];
455 ret = get_state_filename(fname, sizeof(fname), slot);
459 f = gzopen(fname, "rb");
463 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
464 fprintf(stderr, "gzseek failed\n");
469 gpu = malloc(sizeof(*gpu));
475 ret = gzread(f, gpu, sizeof(*gpu));
477 if (ret != sizeof(*gpu)) {
478 fprintf(stderr, "gzread failed\n");
482 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
484 if ((gpu->ulStatus & 0x800000) || (gpu->ulStatus & 0x200000))
485 goto out; // disabled || 24bpp (NYET)
487 x = gpu->ulControl[5] & 0x3ff;
488 y = (gpu->ulControl[5] >> 10) & 0x1ff;
489 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~3);
490 w = psx_widths[(gpu->ulStatus >> 16) & 7];
491 tmp = gpu->ulControl[7];
492 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
493 if (gpu->ulStatus & 0x80000) // doubleheight
496 x = max(0, g_menuscreen_w - w) & ~3;
497 y = max(0, g_menuscreen_h / 2 - h / 2);
498 w = min(g_menuscreen_w, w);
499 h = min(g_menuscreen_h, h);
500 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
502 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
503 bgr555_to_rgb565(d, s, w * 2);
509 // ---------- pandora specific -----------
511 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
512 static char **pnd_filter_list;
514 static int get_cpu_clock(void)
518 f = fopen("/proc/pandora/cpu_mhz_max", "r");
520 fscanf(f, "%d", &ret);
526 static void apply_cpu_clock(void)
530 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
531 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
532 pnd_script_base, cpu_clock);
537 static void apply_filter(int which)
543 if (pnd_filter_list == NULL || which == old)
546 for (i = 0; i < which; i++)
547 if (pnd_filter_list[i] == NULL)
550 if (pnd_filter_list[i] == NULL)
553 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
558 static menu_entry e_menu_gfx_options[];
560 static void pnd_menu_init(void)
568 cpu_clock_st = cpu_clock = get_cpu_clock();
570 dir = opendir("/etc/pandora/conf/dss_fir");
572 perror("filter opendir");
585 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
594 mfilters = calloc(count + 1, sizeof(mfilters[0]));
595 if (mfilters == NULL)
599 for (i = 0; (ent = readdir(dir)); ) {
602 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
605 len = strlen(ent->d_name);
607 // skip pre-HF5 extra files
608 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
610 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
613 // have to cut "_up_h" for pre-HF5
614 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
617 if (len > sizeof(buff) - 1)
620 strncpy(buff, ent->d_name, len);
622 mfilters[i] = strdup(buff);
623 if (mfilters[i] != NULL)
628 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
629 e_menu_gfx_options[i].data = (void *)mfilters;
630 pnd_filter_list = mfilters;
633 void menu_finish(void)
635 cpu_clock = cpu_clock_st;
639 // -------------- key config --------------
641 me_bind_action me_ctrl_actions[] =
643 { "UP ", 1 << DKEY_UP},
644 { "DOWN ", 1 << DKEY_DOWN },
645 { "LEFT ", 1 << DKEY_LEFT },
646 { "RIGHT ", 1 << DKEY_RIGHT },
647 { "TRIANGLE", 1 << DKEY_TRIANGLE },
648 { "CIRCLE ", 1 << DKEY_CIRCLE },
649 { "CROSS ", 1 << DKEY_CROSS },
650 { "SQUARE ", 1 << DKEY_SQUARE },
651 { "L1 ", 1 << DKEY_L1 },
652 { "R1 ", 1 << DKEY_R1 },
653 { "L2 ", 1 << DKEY_L2 },
654 { "R2 ", 1 << DKEY_R2 },
655 { "L3 ", 1 << DKEY_L3 },
656 { "R3 ", 1 << DKEY_R3 },
657 { "START ", 1 << DKEY_START },
658 { "SELECT ", 1 << DKEY_SELECT },
662 me_bind_action emuctrl_actions[] =
664 { "Save State ", 1 << SACTION_SAVE_STATE },
665 { "Load State ", 1 << SACTION_LOAD_STATE },
666 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
667 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
668 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
669 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
673 static char *mystrip(char *str)
678 for (i = 0; i < len; i++)
679 if (str[i] != ' ') break;
680 if (i > 0) memmove(str, str + i, len - i + 1);
683 for (i = len - 1; i >= 0; i--)
684 if (str[i] != ' ') break;
690 static void get_line(char *d, size_t size, const char *s)
695 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
706 static void keys_write_all(FILE *f)
710 for (d = 0; d < IN_MAX_DEVS; d++)
712 const int *binds = in_get_dev_binds(d);
713 const char *name = in_get_dev_name(d, 0, 0);
716 if (binds == NULL || name == NULL)
719 fprintf(f, "binddev = %s\n", name);
720 in_get_config(d, IN_CFG_BIND_COUNT, &count);
722 for (k = 0; k < count; k++)
727 act[0] = act[31] = 0;
728 name = in_get_key_name(d, k);
730 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
731 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
732 mask = me_ctrl_actions[i].mask;
734 strncpy(act, me_ctrl_actions[i].name, 31);
735 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
738 mask = me_ctrl_actions[i].mask << 16;
740 strncpy(act, me_ctrl_actions[i].name, 31);
741 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
746 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
747 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
748 mask = emuctrl_actions[i].mask;
750 strncpy(act, emuctrl_actions[i].name, 31);
751 fprintf(f, "bind %s = %s\n", name, mystrip(act));
759 static int parse_bind_val(const char *val, int *type)
763 *type = IN_BINDTYPE_NONE;
767 if (strncasecmp(val, "player", 6) == 0)
769 int player, shift = 0;
770 player = atoi(val + 6) - 1;
772 if ((unsigned int)player > 1)
777 *type = IN_BINDTYPE_PLAYER12;
778 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
779 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
780 return me_ctrl_actions[i].mask << shift;
783 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
784 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
785 *type = IN_BINDTYPE_EMU;
786 return emuctrl_actions[i].mask;
793 static void keys_load_all(const char *cfg)
795 char dev[256], key[128], *act;
801 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
804 get_line(dev, sizeof(dev), p);
805 dev_id = in_config_parse_dev(dev);
807 printf("input: can't handle dev: %s\n", dev);
811 in_unbind_all(dev_id, -1, -1);
812 while ((p = strstr(p, "bind"))) {
813 if (strncmp(p, "binddev = ", 10) == 0)
818 printf("input: parse error: %16s..\n", p);
822 get_line(key, sizeof(key), p);
823 act = strchr(key, '=');
825 printf("parse failed: %16s..\n", p);
833 bind = parse_bind_val(act, &bindtype);
834 if (bind != -1 && bind != 0) {
835 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
836 in_config_bind_key(dev_id, key, bind, bindtype);
839 lprintf("config: unhandled action \"%s\"\n", act);
844 static int key_config_loop_wrap(int id, int keys)
847 case MA_CTRL_PLAYER1:
848 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
850 case MA_CTRL_PLAYER2:
851 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
854 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
862 static const char *mgn_dev_name(int id, int *offs)
864 const char *name = NULL;
867 if (id == MA_CTRL_DEV_FIRST)
870 for (; it < IN_MAX_DEVS; it++) {
871 name = in_get_dev_name(it, 1, 1);
880 static const char *mgn_saveloadcfg(int id, int *offs)
885 static int mh_savecfg(int id, int keys)
887 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
888 me_update_msg("config saved");
890 me_update_msg("failed to write config");
895 static const char *men_in_type_sel[] = { "Standard (SCPH-1080)", "Analog (SCPH-1150)", NULL };
897 static menu_entry e_menu_keyconfig[] =
899 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
900 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
901 mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
903 mee_enum ("Controller", 0, in_type_sel, men_in_type_sel),
904 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
905 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
907 mee_label ("Input devices:"),
908 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
909 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
918 static int menu_loop_keyconfig(int id, int keys)
922 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
923 me_loop(e_menu_keyconfig, &sel, NULL);
927 // ------------ gfx options menu ------------
929 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
930 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
931 "using d-pad or move it using R+d-pad";
932 static const char *men_dummy[] = { NULL };
934 static int menu_loop_cscaler(int id, int keys)
938 scaling = SCALE_CUSTOM;
940 omap_enable_layer(1);
945 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
946 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
947 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
950 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
951 if (inp & PBTN_UP) g_layer_y--;
952 if (inp & PBTN_DOWN) g_layer_y++;
953 if (inp & PBTN_LEFT) g_layer_x--;
954 if (inp & PBTN_RIGHT) g_layer_x++;
955 if (!(inp & PBTN_R)) {
956 if (inp & PBTN_UP) g_layer_h += 2;
957 if (inp & PBTN_DOWN) g_layer_h -= 2;
958 if (inp & PBTN_LEFT) g_layer_w += 2;
959 if (inp & PBTN_RIGHT) g_layer_w -= 2;
961 if (inp & (PBTN_MOK|PBTN_MBACK))
964 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
965 if (g_layer_x < 0) g_layer_x = 0;
966 if (g_layer_x > 640) g_layer_x = 640;
967 if (g_layer_y < 0) g_layer_y = 0;
968 if (g_layer_y > 420) g_layer_y = 420;
969 if (g_layer_w < 160) g_layer_w = 160;
970 if (g_layer_h < 60) g_layer_h = 60;
971 if (g_layer_x + g_layer_w > 800)
972 g_layer_w = 800 - g_layer_x;
973 if (g_layer_y + g_layer_h > 480)
974 g_layer_h = 480 - g_layer_y;
975 omap_enable_layer(1);
979 omap_enable_layer(0);
984 static menu_entry e_menu_gfx_options[] =
986 mee_enum ("Scaler", 0, scaling, men_scaler),
987 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
988 // mee_onoff ("Vsync", 0, vsync, 1),
989 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
993 static int menu_loop_gfx_options(int id, int keys)
997 me_loop(e_menu_gfx_options, &sel, NULL);
1002 // ------------ bios/plugins ------------
1004 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1005 static const char h_gpu_0[] = "Needed for Chrono Cross";
1006 static const char h_gpu_1[] = "Capcom fighting games";
1007 static const char h_gpu_2[] = "Black screens in Lunar";
1008 static const char h_gpu_3[] = "Compatibility mode";
1009 static const char h_gpu_6[] = "Pandemonium 2";
1010 static const char h_gpu_7[] = "Skip every second frame";
1011 static const char h_gpu_8[] = "Needed by Dark Forces";
1012 static const char h_gpu_9[] = "better g-colors, worse textures";
1013 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1015 static menu_entry e_menu_plugin_gpu[] =
1017 mee_enum ("Dithering", 0, iUseDither, men_gpu_dithering),
1018 mee_onoff_h ("Odd/even bit hack", 0, dwActFixes, 1<<0, h_gpu_0),
1019 mee_onoff_h ("Expand screen width", 0, dwActFixes, 1<<1, h_gpu_1),
1020 mee_onoff_h ("Ignore brightness color", 0, dwActFixes, 1<<2, h_gpu_2),
1021 mee_onoff_h ("Disable coordinate check", 0, dwActFixes, 1<<3, h_gpu_3),
1022 mee_onoff_h ("Lazy screen update", 0, dwActFixes, 1<<6, h_gpu_6),
1023 mee_onoff_h ("Old frame skipping", 0, dwActFixes, 1<<7, h_gpu_7),
1024 mee_onoff_h ("Repeated flat tex triangles ",0,dwActFixes, 1<<8, h_gpu_8),
1025 mee_onoff_h ("Draw quads with triangles", 0, dwActFixes, 1<<9, h_gpu_9),
1026 mee_onoff_h ("Fake 'gpu busy' states", 0, dwActFixes, 1<<10, h_gpu_10),
1030 static int menu_loop_plugin_gpu(int id, int keys)
1033 me_loop(e_menu_plugin_gpu, &sel, NULL);
1037 static const char *men_spu_reverb[] = { "Off", "Fake", "On", NULL };
1038 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1039 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1040 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1042 static menu_entry e_menu_plugin_spu[] =
1044 mee_enum ("Reverb", 0, iUseReverb, men_spu_reverb),
1045 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1046 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1047 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1048 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1052 static int menu_loop_plugin_spu(int id, int keys)
1055 me_loop(e_menu_plugin_spu, &sel, NULL);
1059 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1060 "and can't be changed there. Must save config and reload\n"
1061 "the game for change to take effect";
1062 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1063 "for plugin change to take effect";
1064 static const char h_gpu[] = "Configure built-in P.E.Op.S. SoftGL Driver V1.17";
1065 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1067 static menu_entry e_menu_plugin_options[] =
1069 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1070 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1071 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1072 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu, h_gpu),
1073 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1077 static menu_entry e_menu_main[];
1079 static int menu_loop_plugin_options(int id, int keys)
1082 me_loop(e_menu_plugin_options, &sel, NULL);
1084 // sync BIOS/plugins
1085 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1086 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1087 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1088 me_enable(e_menu_main, MA_MAIN_RUN_BIOS, bios_sel != 0);
1093 // ------------ adv options menu ------------
1095 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1096 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1097 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1098 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1099 "(proper .cue/.bin dump is needed otherwise)";
1100 static const char h_cfg_sio[] = "This should be enabled for certain memcards/gamepads";
1101 static const char h_cfg_spuirq[] = "Compatibility tweak; should probably be left off";
1102 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix";
1103 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix";
1104 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1105 "Might be useful to overcome some dynarec bugs";
1107 static menu_entry e_menu_adv_options[] =
1109 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1110 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1111 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1112 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1113 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1114 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1115 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1116 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1117 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1121 static int menu_loop_adv_options(int id, int keys)
1124 me_loop(e_menu_adv_options, &sel, NULL);
1128 // ------------ options menu ------------
1130 static int mh_restore_defaults(int id, int keys)
1132 menu_set_defconfig();
1133 me_update_msg("defaults restored");
1137 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1139 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1140 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1141 "loading state or both";
1143 static const char h_restore_def[] = "Switches back to default / recommended\n"
1146 static menu_entry e_menu_options[] =
1148 // mee_range ("Save slot", 0, state_slot, 0, 9),
1149 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1150 mee_onoff ("Frameskip", 0, UseFrameSkip, 1),
1151 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1152 mee_enum ("Region", 0, region, men_region),
1153 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1154 mee_handler ("[Display]", menu_loop_gfx_options),
1155 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1156 mee_handler ("[Advanced]", menu_loop_adv_options),
1157 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1158 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1159 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1163 static int menu_loop_options(int id, int keys)
1168 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1169 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1170 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1172 me_loop(e_menu_options, &sel, NULL);
1177 // ------------ debug menu ------------
1179 static void draw_frame_debug(void)
1181 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1184 static void debug_menu_loop(void)
1194 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1195 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1196 if (inp & PBTN_MBACK)
1201 // ------------ main menu ------------
1203 static void menu_bios_warn(void)
1206 static const char msg[] =
1207 "You don't seem to have copied any BIOS files to\n"
1208 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1209 "While many games work fine with fake (HLE) BIOS,\n"
1210 "others (like MGS and FF8) require BIOS to work.\n"
1211 "After copying the file, you'll also need to\n"
1212 "select it in the emu's options->[BIOS/Plugins]\n\n"
1213 "The file is usually named SCPH1001.BIN, but\n"
1214 "other not compressed files can be used too.\n\n"
1215 "Press (B) or (X) to continue";
1220 draw_menu_message(msg, NULL);
1223 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1224 if (inp & (PBTN_MBACK|PBTN_MOK))
1229 // ------------ main menu ------------
1233 static void draw_frame_main(void)
1235 if (CdromId[0] != 0) {
1237 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1238 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1239 Config.HLE ? "HLE" : "BIOS");
1240 smalltext_out16(4, 1, buff, 0x105f);
1244 static void draw_frame_credits(void)
1246 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1249 static const char credits_text[] =
1251 "(C) 1999-2003 PCSX Team\n"
1252 "(C) 2005-2009 PCSX-df Team\n"
1253 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1254 "GPU and SPU code by Pete Bernert\n"
1255 " and the P.E.Op.S. team\n"
1256 "ARM recompiler (C) 2009-2011 Ari64\n"
1257 "PCSX4ALL plugins by PCSX4ALL team\n"
1258 " Chui, Franxis, Unai\n\n"
1259 "integration, optimization and\n"
1260 " frontend (C) 2010-2011 notaz\n";
1262 static int reset_game(void)
1265 if (bios_sel == 0 && !Config.HLE)
1271 if (CheckCdrom() != -1) {
1277 static int run_bios(void)
1283 pl_fbdev_buf = NULL;
1288 pcnt_hook_plugins();
1290 if (OpenPlugins() == -1) {
1291 me_update_msg("failed to open plugins");
1294 plugin_call_rearmed_cbs();
1297 CdromLabel[0] = '\0';
1305 static int run_cd_image(const char *fname)
1308 pl_fbdev_buf = NULL;
1311 set_cd_image(fname);
1313 pcnt_hook_plugins();
1315 if (OpenPlugins() == -1) {
1316 me_update_msg("failed to open plugins");
1319 plugin_call_rearmed_cbs();
1321 if (CheckCdrom() == -1) {
1322 // Only check the CD if we are starting the console with a CD
1324 me_update_msg("unsupported/invalid CD image");
1330 // Read main executable directly from CDRom and start it
1331 if (LoadCdrom() == -1) {
1333 me_update_msg("failed to load CD image");
1341 static int romsel_run(void)
1343 int prev_gpu, prev_spu;
1346 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1350 printf("selected file: %s\n", fname);
1352 if (run_cd_image(fname) != 0)
1355 prev_gpu = gpu_plugsel;
1356 prev_spu = spu_plugsel;
1357 if (menu_load_config(1) != 0)
1358 menu_load_config(0);
1360 // check for plugin changes, have to repeat
1361 // loading if game config changed plugins to reload them
1362 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1363 printf("plugin change detected, reloading plugins..\n");
1364 if (run_cd_image(fname) != 0)
1368 strcpy(last_selected_fname, rom_fname_reload);
1372 static int swap_cd_image(void)
1376 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1380 printf("selected file: %s\n", fname);
1383 CdromLabel[0] = '\0';
1385 set_cd_image(fname);
1386 if (ReloadCdromPlugin() < 0) {
1387 me_update_msg("failed to load cdr plugin");
1390 if (CDR_open() < 0) {
1391 me_update_msg("failed to open cdr plugin");
1395 SetCdOpenCaseTime(time(NULL) + 2);
1398 strcpy(last_selected_fname, rom_fname_reload);
1402 static int main_menu_handler(int id, int keys)
1406 case MA_MAIN_RESUME_GAME:
1410 case MA_MAIN_SAVE_STATE:
1412 return menu_loop_savestate(0);
1414 case MA_MAIN_LOAD_STATE:
1416 return menu_loop_savestate(1);
1418 case MA_MAIN_RESET_GAME:
1419 if (ready_to_go && reset_game() == 0)
1422 case MA_MAIN_LOAD_ROM:
1423 if (romsel_run() == 0)
1426 case MA_MAIN_SWAP_CD:
1427 if (swap_cd_image() == 0)
1430 case MA_MAIN_RUN_BIOS:
1431 if (run_bios() == 0)
1434 case MA_MAIN_CREDITS:
1435 draw_menu_message(credits_text, draw_frame_credits);
1436 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1442 lprintf("%s: something unknown selected\n", __FUNCTION__);
1449 static menu_entry e_menu_main[] =
1453 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1454 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1455 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1456 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1457 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1458 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1459 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1460 mee_handler ("Options", menu_loop_options),
1461 mee_handler ("Controls", menu_loop_keyconfig),
1462 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1463 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1467 // ----------------------------
1469 static void menu_leave_emu(void);
1471 void menu_loop(void)
1477 if (bioses[1] == NULL && !warned_about_bios) {
1479 warned_about_bios = 1;
1482 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1483 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1484 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1485 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1486 me_enable(e_menu_main, MA_MAIN_SWAP_CD, ready_to_go);
1487 me_enable(e_menu_main, MA_MAIN_RUN_BIOS, bios_sel != 0);
1489 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1492 me_loop(e_menu_main, &sel, draw_frame_main);
1493 } while (!ready_to_go);
1495 /* wait until menu, ok, back is released */
1496 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1499 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1504 static void scan_bios_plugins(void)
1506 char fname[MAXPATHLEN];
1508 int bios_i, gpu_i, spu_i;
1513 gpu_plugins[0] = "builtin_gpu";
1514 spu_plugins[0] = "builtin_spu";
1515 bios_i = gpu_i = spu_i = 1;
1517 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1518 dir = opendir(fname);
1520 perror("scan_bios_plugins bios opendir");
1535 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1538 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1539 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1540 printf("bad BIOS file: %s\n", ent->d_name);
1544 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1545 bioses[bios_i++] = strdup(ent->d_name);
1549 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1555 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1556 dir = opendir(fname);
1558 perror("scan_bios_plugins opendir");
1572 p = strstr(ent->d_name, ".so");
1576 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1577 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1579 fprintf(stderr, "%s\n", dlerror());
1583 // now what do we have here?
1584 tmp = dlsym(h, "GPUinit");
1587 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1588 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1592 tmp = dlsym(h, "SPUinit");
1595 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1596 spu_plugins[spu_i++] = strdup(ent->d_name);
1600 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1607 void menu_init(void)
1609 char buff[MAXPATHLEN];
1611 strcpy(last_selected_fname, "/media");
1613 scan_bios_plugins();
1617 menu_set_defconfig();
1618 menu_load_config(0);
1623 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1624 if (g_menubg_src_ptr == NULL)
1626 emu_make_path(buff, "skin/background.png", sizeof(buff));
1627 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1630 void menu_notify_mode_change(int w, int h, int bpp)
1636 if (scaling == SCALE_1_1) {
1637 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1638 g_layer_w = w; g_layer_h = h;
1642 static void menu_leave_emu(void)
1644 if (GPU_close != NULL) {
1645 int ret = GPU_close();
1647 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1650 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1651 if (pl_fbdev_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1652 int x = max(0, g_menuscreen_w - last_psx_w);
1653 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1654 int w = min(g_menuscreen_w, last_psx_w);
1655 int h = min(g_menuscreen_h, last_psx_h);
1656 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1657 u16 *s = pl_fbdev_buf;
1659 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1660 menu_darken_bg(d, s, w, 0);
1664 cpu_clock = get_cpu_clock();
1666 plat_video_menu_enter(ready_to_go);
1669 void menu_prepare_emu(void)
1671 R3000Acpu *prev_cpu = psxCpu;
1673 plat_video_menu_leave();
1677 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
1680 g_layer_x = 80; g_layer_y = 0;
1681 g_layer_w = 640; g_layer_h = 480;
1683 case SCALE_FULLSCREEN:
1684 g_layer_x = 0; g_layer_y = 0;
1685 g_layer_w = 800; g_layer_h = 480;
1690 apply_filter(filter);
1693 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
1694 if (psxCpu != prev_cpu)
1695 // note that this does not really reset, just clears drc caches
1698 // core doesn't care about Config.Cdda changes,
1699 // so handle them manually here
1705 if (GPU_open != NULL) {
1706 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
1708 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
1711 dfinput_activate(in_type == PSE_PAD_TYPE_ANALOGPAD);
1714 void me_update_msg(const char *msg)
1716 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
1717 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
1719 menu_error_time = plat_get_ticks_ms();
1720 lprintf("msg: %s\n", menu_error_msg);