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"
25 #include "arm_utils.h"
26 #include "common/plat.h"
27 #include "common/input.h"
28 #include "linux/in_evdev.h"
29 #include "../libpcsxcore/misc.h"
30 #include "../libpcsxcore/cdrom.h"
31 #include "../libpcsxcore/psemu_plugin_defs.h"
32 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
33 #include "../plugins/dfinput/main.h"
37 #define array_size(x) (sizeof(x) / sizeof(x[0]))
72 static int last_psx_w, last_psx_h, last_psx_bpp;
73 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost;
74 static char rom_fname_reload[MAXPATHLEN];
75 static char last_selected_fname[MAXPATHLEN];
76 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
77 static int memcard1_sel, memcard2_sel;
81 extern int iUseReverb;
82 extern int iUseInterpolation;
84 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 const char *memcards[32];
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)
139 static int allow_abs_only_old;
144 Config.PsxType = region - 1;
146 switch (in_type_sel1) {
147 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
148 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
149 default: in_type1 = PSE_PAD_TYPE_STANDARD;
151 switch (in_type_sel2) {
152 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
153 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
154 default: in_type2 = PSE_PAD_TYPE_STANDARD;
156 if (in_evdev_allow_abs_only != allow_abs_only_old) {
157 pandora_rescan_inputs();
158 allow_abs_only_old = in_evdev_allow_abs_only;
161 iVolume = 768 + 128 * volume_boost;
162 pl_timing_prepare(Config.PsxType);
165 static void menu_set_defconfig(void)
172 in_type_sel1 = in_type_sel2 = 0;
173 in_evdev_allow_abs_only = 0;
174 Config.Xa = Config.Cdda = Config.Sio =
175 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
176 Config.CdrReschedule = 0;
178 pl_rearmed_cbs.frameskip = 0;
179 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
180 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
183 iUseInterpolation = 1;
191 #define CE_CONFIG_STR(val) \
192 { #val, 0, Config.val }
194 #define CE_CONFIG_VAL(val) \
195 { #val, sizeof(Config.val), &Config.val }
197 #define CE_STR(val) \
200 #define CE_INTVAL(val) \
201 { #val, sizeof(val), &val }
203 #define CE_INTVAL_P(val) \
204 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
206 // 'versioned' var, used when defaults change
207 #define CE_INTVAL_V(val, ver) \
208 { #val #ver, sizeof(val), &val }
210 static const struct {
218 // CE_CONFIG_STR(Cdr),
223 CE_CONFIG_VAL(Debug),
224 CE_CONFIG_VAL(PsxOut),
225 CE_CONFIG_VAL(SpuIrq),
226 CE_CONFIG_VAL(RCntFix),
227 CE_CONFIG_VAL(VSyncWA),
229 CE_CONFIG_VAL(CdrReschedule),
232 CE_INTVAL(g_layer_x),
233 CE_INTVAL(g_layer_y),
234 CE_INTVAL(g_layer_w),
235 CE_INTVAL(g_layer_h),
237 CE_INTVAL(state_slot),
238 CE_INTVAL(cpu_clock),
240 CE_INTVAL(in_type_sel1),
241 CE_INTVAL(in_type_sel2),
242 CE_INTVAL_P(frameskip),
243 CE_INTVAL_P(gpu_peops.iUseDither),
244 CE_INTVAL_P(gpu_peops.dwActFixes),
245 CE_INTVAL(iUseReverb),
247 CE_INTVAL_V(iUseInterpolation, 2),
248 CE_INTVAL_V(iSPUIRQWait, 2),
249 CE_INTVAL(iUseTimer),
250 CE_INTVAL(warned_about_bios),
251 CE_INTVAL(in_evdev_allow_abs_only),
252 CE_INTVAL(volume_boost),
255 static char *get_cd_label(void)
257 static char trimlabel[33];
260 strncpy(trimlabel, CdromLabel, 32);
262 for (j = 31; j >= 0; j--)
263 if (trimlabel[j] == ' ')
269 static void make_cfg_fname(char *buf, size_t size, int is_game)
272 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
274 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
277 static void keys_write_all(FILE *f);
279 static int menu_write_config(int is_game)
281 char cfgfile[MAXPATHLEN];
285 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
286 f = fopen(cfgfile, "w");
288 printf("menu_write_config: failed to open: %s\n", cfgfile);
292 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
293 fprintf(f, "%s = ", config_data[i].name);
294 switch (config_data[i].len) {
296 fprintf(f, "%s\n", (char *)config_data[i].val);
299 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
302 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
305 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
308 printf("menu_write_config: unhandled len %d for %s\n",
309 config_data[i].len, config_data[i].name);
315 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
323 static void parse_str_val(char *cval, const char *src)
326 strncpy(cval, src, MAXPATHLEN);
327 cval[MAXPATHLEN - 1] = 0;
328 tmp = strchr(cval, '\n');
330 tmp = strchr(cval, '\r');
335 static void keys_load_all(const char *cfg);
337 static int menu_load_config(int is_game)
339 char cfgfile[MAXPATHLEN];
345 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
346 f = fopen(cfgfile, "r");
348 printf("menu_load_config: failed to open: %s\n", cfgfile);
352 fseek(f, 0, SEEK_END);
355 printf("bad size %ld: %s\n", size, cfgfile);
359 cfg = malloc(size + 1);
363 fseek(f, 0, SEEK_SET);
364 if (fread(cfg, 1, size, f) != size) {
365 printf("failed to read: %s\n", cfgfile);
370 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
374 tmp = strstr(cfg, config_data[i].name);
377 tmp += strlen(config_data[i].name);
378 if (strncmp(tmp, " = ", 3) != 0)
382 if (config_data[i].len == 0) {
383 parse_str_val(config_data[i].val, tmp);
388 val = strtoul(tmp, &tmp2, 16);
389 if (tmp2 == NULL || tmp == tmp2)
390 continue; // parse failed
392 switch (config_data[i].len) {
394 *(u8 *)config_data[i].val = val;
397 *(u16 *)config_data[i].val = val;
400 *(u32 *)config_data[i].val = val;
403 printf("menu_load_config: unhandled len %d for %s\n",
404 config_data[i].len, config_data[i].name);
410 char *tmp = strstr(cfg, "lastcdimg = ");
413 parse_str_val(last_selected_fname, tmp);
420 for (i = bios_sel = 0; bioses[i] != NULL; i++)
421 if (strcmp(Config.Bios, bioses[i]) == 0)
422 { bios_sel = i; break; }
424 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
425 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
426 { gpu_plugsel = i; break; }
428 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
429 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
430 { spu_plugsel = i; break; }
441 // rrrr rggg gggb bbbb
442 static unsigned short fname2color(const char *fname)
444 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
445 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
446 const char *ext = strrchr(fname, '.');
451 for (i = 0; i < array_size(cdimg_exts); i++)
452 if (strcasecmp(ext, cdimg_exts[i]) == 0)
454 for (i = 0; i < array_size(other_exts); i++)
455 if (strcasecmp(ext, other_exts[i]) == 0)
460 static void draw_savestate_bg(int slot);
462 static const char *filter_exts[] = {
463 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
466 #define MENU_ALIGN_LEFT
467 #define menu_init menu_init_common
468 #include "common/menu.c"
471 // a bit of black magic here
472 static void draw_savestate_bg(int slot)
474 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
476 char fname[MAXPATHLEN];
483 ret = get_state_filename(fname, sizeof(fname), slot);
487 f = gzopen(fname, "rb");
491 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
492 fprintf(stderr, "gzseek failed\n");
497 gpu = malloc(sizeof(*gpu));
503 ret = gzread(f, gpu, sizeof(*gpu));
505 if (ret != sizeof(*gpu)) {
506 fprintf(stderr, "gzread failed\n");
510 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
512 if (gpu->ulStatus & 0x800000)
513 goto out; // disabled
515 x = gpu->ulControl[5] & 0x3ff;
516 y = (gpu->ulControl[5] >> 10) & 0x1ff;
517 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
518 w = psx_widths[(gpu->ulStatus >> 16) & 7];
519 tmp = gpu->ulControl[7];
520 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
521 if (gpu->ulStatus & 0x80000) // doubleheight
524 x = max(0, g_menuscreen_w - w) & ~3;
525 y = max(0, g_menuscreen_h / 2 - h / 2);
526 w = min(g_menuscreen_w, w);
527 h = min(g_menuscreen_h, h);
528 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
530 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
531 if (gpu->ulStatus & 0x200000)
532 bgr888_to_rgb565(d, s, w * 3);
534 bgr555_to_rgb565(d, s, w * 2);
540 // ---------- pandora specific -----------
542 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
543 static char **pnd_filter_list;
545 static int get_cpu_clock(void)
549 f = fopen("/proc/pandora/cpu_mhz_max", "r");
551 fscanf(f, "%d", &ret);
557 static void apply_cpu_clock(void)
561 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
562 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
563 pnd_script_base, cpu_clock);
568 static void apply_filter(int which)
574 if (pnd_filter_list == NULL || which == old)
577 for (i = 0; i < which; i++)
578 if (pnd_filter_list[i] == NULL)
581 if (pnd_filter_list[i] == NULL)
584 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
589 static void apply_lcdrate(int pal)
597 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
598 pnd_script_base, pal ? 50 : 60);
603 static menu_entry e_menu_gfx_options[];
605 static void pnd_menu_init(void)
613 cpu_clock_st = cpu_clock = get_cpu_clock();
615 dir = opendir("/etc/pandora/conf/dss_fir");
617 perror("filter opendir");
630 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
639 mfilters = calloc(count + 1, sizeof(mfilters[0]));
640 if (mfilters == NULL)
644 for (i = 0; (ent = readdir(dir)); ) {
647 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
650 len = strlen(ent->d_name);
652 // skip pre-HF5 extra files
653 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
655 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
658 // have to cut "_up_h" for pre-HF5
659 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
662 if (len > sizeof(buff) - 1)
665 strncpy(buff, ent->d_name, len);
667 mfilters[i] = strdup(buff);
668 if (mfilters[i] != NULL)
673 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
674 e_menu_gfx_options[i].data = (void *)mfilters;
675 pnd_filter_list = mfilters;
678 void menu_finish(void)
680 cpu_clock = cpu_clock_st;
684 // -------------- key config --------------
686 me_bind_action me_ctrl_actions[] =
688 { "UP ", 1 << DKEY_UP},
689 { "DOWN ", 1 << DKEY_DOWN },
690 { "LEFT ", 1 << DKEY_LEFT },
691 { "RIGHT ", 1 << DKEY_RIGHT },
692 { "TRIANGLE", 1 << DKEY_TRIANGLE },
693 { "CIRCLE ", 1 << DKEY_CIRCLE },
694 { "CROSS ", 1 << DKEY_CROSS },
695 { "SQUARE ", 1 << DKEY_SQUARE },
696 { "L1 ", 1 << DKEY_L1 },
697 { "R1 ", 1 << DKEY_R1 },
698 { "L2 ", 1 << DKEY_L2 },
699 { "R2 ", 1 << DKEY_R2 },
700 { "L3 ", 1 << DKEY_L3 },
701 { "R3 ", 1 << DKEY_R3 },
702 { "START ", 1 << DKEY_START },
703 { "SELECT ", 1 << DKEY_SELECT },
707 me_bind_action emuctrl_actions[] =
709 { "Save State ", 1 << SACTION_SAVE_STATE },
710 { "Load State ", 1 << SACTION_LOAD_STATE },
711 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
712 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
713 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
714 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
715 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
716 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
717 { "Gun A button ", 1 << SACTION_GUN_A },
718 { "Gun B button ", 1 << SACTION_GUN_B },
719 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
723 static char *mystrip(char *str)
728 for (i = 0; i < len; i++)
729 if (str[i] != ' ') break;
730 if (i > 0) memmove(str, str + i, len - i + 1);
733 for (i = len - 1; i >= 0; i--)
734 if (str[i] != ' ') break;
740 static void get_line(char *d, size_t size, const char *s)
745 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
756 static void keys_write_all(FILE *f)
760 for (d = 0; d < IN_MAX_DEVS; d++)
762 const int *binds = in_get_dev_binds(d);
763 const char *name = in_get_dev_name(d, 0, 0);
766 if (binds == NULL || name == NULL)
769 fprintf(f, "binddev = %s\n", name);
770 in_get_config(d, IN_CFG_BIND_COUNT, &count);
772 for (k = 0; k < count; k++)
777 act[0] = act[31] = 0;
778 name = in_get_key_name(d, k);
780 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
781 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
782 mask = me_ctrl_actions[i].mask;
784 strncpy(act, me_ctrl_actions[i].name, 31);
785 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
788 mask = me_ctrl_actions[i].mask << 16;
790 strncpy(act, me_ctrl_actions[i].name, 31);
791 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
796 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
797 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
798 mask = emuctrl_actions[i].mask;
800 strncpy(act, emuctrl_actions[i].name, 31);
801 fprintf(f, "bind %s = %s\n", name, mystrip(act));
809 static int parse_bind_val(const char *val, int *type)
813 *type = IN_BINDTYPE_NONE;
817 if (strncasecmp(val, "player", 6) == 0)
819 int player, shift = 0;
820 player = atoi(val + 6) - 1;
822 if ((unsigned int)player > 1)
827 *type = IN_BINDTYPE_PLAYER12;
828 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
829 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
830 return me_ctrl_actions[i].mask << shift;
833 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
834 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
835 *type = IN_BINDTYPE_EMU;
836 return emuctrl_actions[i].mask;
843 static void keys_load_all(const char *cfg)
845 char dev[256], key[128], *act;
851 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
854 get_line(dev, sizeof(dev), p);
855 dev_id = in_config_parse_dev(dev);
857 printf("input: can't handle dev: %s\n", dev);
861 in_unbind_all(dev_id, -1, -1);
862 while ((p = strstr(p, "bind"))) {
863 if (strncmp(p, "binddev = ", 10) == 0)
868 printf("input: parse error: %16s..\n", p);
872 get_line(key, sizeof(key), p);
873 act = strchr(key, '=');
875 printf("parse failed: %16s..\n", p);
883 bind = parse_bind_val(act, &bindtype);
884 if (bind != -1 && bind != 0) {
885 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
886 in_config_bind_key(dev_id, key, bind, bindtype);
889 lprintf("config: unhandled action \"%s\"\n", act);
895 static int key_config_loop_wrap(int id, int keys)
898 case MA_CTRL_PLAYER1:
899 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
901 case MA_CTRL_PLAYER2:
902 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
905 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
913 static const char *mgn_dev_name(int id, int *offs)
915 const char *name = NULL;
918 if (id == MA_CTRL_DEV_FIRST)
921 for (; it < IN_MAX_DEVS; it++) {
922 name = in_get_dev_name(it, 1, 1);
931 static const char *mgn_saveloadcfg(int id, int *offs)
936 static int mh_savecfg(int id, int keys)
938 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
939 me_update_msg("config saved");
941 me_update_msg("failed to write config");
946 static int mh_input_rescan(int id, int keys)
948 //menu_sync_config();
949 pandora_rescan_inputs();
950 me_update_msg("rescan complete.");
955 static const char *men_in_type_sel[] = {
956 "Standard (SCPH-1080)",
957 "Analog (SCPH-1150)",
961 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
962 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
964 static menu_entry e_menu_keyconfig[] =
966 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
967 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
968 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
970 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
971 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
972 mee_onoff_h ("Nubs as buttons", 0, in_evdev_allow_abs_only, 1, h_nub_btns),
973 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
974 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
975 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
976 mee_handler ("Rescan devices", mh_input_rescan),
978 mee_label ("Input devices:"),
979 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
980 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
981 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
982 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
983 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
984 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
985 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
989 static int menu_loop_keyconfig(int id, int keys)
993 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
994 me_loop(e_menu_keyconfig, &sel);
998 // ------------ gfx options menu ------------
1000 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
1001 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1002 "using d-pad or move it using R+d-pad";
1003 static const char *men_dummy[] = { NULL };
1005 static int menu_loop_cscaler(int id, int keys)
1009 scaling = SCALE_CUSTOM;
1011 omap_enable_layer(1);
1016 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1017 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1018 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1021 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1022 if (inp & PBTN_UP) g_layer_y--;
1023 if (inp & PBTN_DOWN) g_layer_y++;
1024 if (inp & PBTN_LEFT) g_layer_x--;
1025 if (inp & PBTN_RIGHT) g_layer_x++;
1026 if (!(inp & PBTN_R)) {
1027 if (inp & PBTN_UP) g_layer_h += 2;
1028 if (inp & PBTN_DOWN) g_layer_h -= 2;
1029 if (inp & PBTN_LEFT) g_layer_w += 2;
1030 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1032 if (inp & (PBTN_MOK|PBTN_MBACK))
1035 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1036 if (g_layer_x < 0) g_layer_x = 0;
1037 if (g_layer_x > 640) g_layer_x = 640;
1038 if (g_layer_y < 0) g_layer_y = 0;
1039 if (g_layer_y > 420) g_layer_y = 420;
1040 if (g_layer_w < 160) g_layer_w = 160;
1041 if (g_layer_h < 60) g_layer_h = 60;
1042 if (g_layer_x + g_layer_w > 800)
1043 g_layer_w = 800 - g_layer_x;
1044 if (g_layer_y + g_layer_h > 480)
1045 g_layer_h = 480 - g_layer_y;
1046 omap_enable_layer(1);
1050 omap_enable_layer(0);
1055 static menu_entry e_menu_gfx_options[] =
1057 mee_enum ("Scaler", 0, scaling, men_scaler),
1058 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1059 // mee_onoff ("Vsync", 0, vsync, 1),
1060 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1064 static int menu_loop_gfx_options(int id, int keys)
1068 me_loop(e_menu_gfx_options, &sel);
1073 // ------------ bios/plugins ------------
1075 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1076 static const char h_gpu_0[] = "Needed for Chrono Cross";
1077 static const char h_gpu_1[] = "Capcom fighting games";
1078 static const char h_gpu_2[] = "Black screens in Lunar";
1079 static const char h_gpu_3[] = "Compatibility mode";
1080 static const char h_gpu_6[] = "Pandemonium 2";
1081 static const char h_gpu_7[] = "Skip every second frame";
1082 static const char h_gpu_8[] = "Needed by Dark Forces";
1083 static const char h_gpu_9[] = "better g-colors, worse textures";
1084 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1086 static menu_entry e_menu_plugin_gpu[] =
1088 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1089 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1090 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1091 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1092 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1093 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1094 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1095 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1096 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1097 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1101 static int menu_loop_plugin_gpu(int id, int keys)
1104 me_loop(e_menu_plugin_gpu, &sel);
1108 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1109 static const char h_spu_volboost[] = "Large values cause distortion";
1110 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1111 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1113 static menu_entry e_menu_plugin_spu[] =
1115 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1116 mee_onoff ("Reverb", 0, iUseReverb, 2),
1117 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1118 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1119 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1120 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1124 static int menu_loop_plugin_spu(int id, int keys)
1127 me_loop(e_menu_plugin_spu, &sel);
1131 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1132 "and can't be changed there. Must save config and reload\n"
1133 "the game for change to take effect";
1134 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1135 "for plugin change to take effect";
1136 static const char h_gpu[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1137 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1139 static menu_entry e_menu_plugin_options[] =
1141 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1142 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1143 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1144 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu, h_gpu),
1145 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1149 static menu_entry e_menu_main2[];
1151 static int menu_loop_plugin_options(int id, int keys)
1154 me_loop(e_menu_plugin_options, &sel);
1156 // sync BIOS/plugins
1157 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1158 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1159 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1160 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1165 // ------------ adv options menu ------------
1167 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1168 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1169 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1170 "(green: normal, red: fmod, blue: noise)";
1171 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1172 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1173 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1174 "(proper .cue/.bin dump is needed otherwise)";
1175 static const char h_cfg_sio[] = "You should not need this, breaks games";
1176 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1177 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1178 "(timing hack, breaks other games)";
1179 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1180 "(timing hack, breaks other games)";
1181 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1182 "(CD timing hack, breaks FMVs)";
1183 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1184 "Might be useful to overcome some dynarec bugs";
1186 static menu_entry e_menu_adv_options[] =
1188 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1189 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1190 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1191 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1192 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1193 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1194 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1195 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1196 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1197 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1198 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1202 static int menu_loop_adv_options(int id, int keys)
1205 me_loop(e_menu_adv_options, &sel);
1209 // ------------ options menu ------------
1211 static int mh_restore_defaults(int id, int keys)
1213 menu_set_defconfig();
1214 me_update_msg("defaults restored");
1218 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1220 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1221 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1222 "loading state or both";
1224 static const char h_restore_def[] = "Switches back to default / recommended\n"
1226 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1228 static menu_entry e_menu_options[] =
1230 // mee_range ("Save slot", 0, state_slot, 0, 9),
1231 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1232 mee_onoff_h ("Frameskip", 0, pl_rearmed_cbs.frameskip, 1, h_frameskip),
1233 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1234 mee_enum ("Region", 0, region, men_region),
1235 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1236 mee_handler ("[Display]", menu_loop_gfx_options),
1237 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1238 mee_handler ("[Advanced]", menu_loop_adv_options),
1239 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1240 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1241 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1245 static int menu_loop_options(int id, int keys)
1250 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1251 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1252 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1254 me_loop(e_menu_options, &sel);
1259 // ------------ debug menu ------------
1261 static void draw_frame_debug(GPUFreeze_t *gpuf)
1263 int w = min(g_menuscreen_w, 1024);
1264 int h = min(g_menuscreen_h, 512);
1265 u16 *d = g_menuscreen_ptr;
1266 u16 *s = (u16 *)gpuf->psxVRam;
1270 gpuf->ulFreezeVersion = 1;
1271 if (GPU_freeze != NULL)
1272 GPU_freeze(1, gpuf);
1274 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1275 bgr555_to_rgb565(d, s, w * 2);
1277 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1278 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1279 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1280 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1281 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1284 static void debug_menu_loop(void)
1289 gpuf = malloc(sizeof(*gpuf));
1296 draw_frame_debug(gpuf);
1299 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1300 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1301 if (inp & PBTN_MBACK)
1308 // --------- memcard manager ---------
1310 static void draw_mc_icon(int dx, int dy, const u16 *s)
1315 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1317 for (y = 0; y < 16; y++, s += 16) {
1318 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1319 for (x = 0; x < 16; x++) {
1321 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1322 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1328 static void draw_mc_bg(void)
1330 McdBlock *blocks1, *blocks2;
1334 blocks1 = malloc(15 * sizeof(blocks1[0]));
1335 blocks2 = malloc(15 * sizeof(blocks1[0]));
1336 if (blocks1 == NULL || blocks2 == NULL)
1339 for (i = 0; i < 15; i++) {
1340 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1341 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1346 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1348 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1352 maxicons = g_menuscreen_h / 32;
1355 row2 = g_menuscreen_w / 2;
1356 for (i = 0; i < maxicons; i++) {
1357 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1358 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1360 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1361 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1364 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1372 static void handle_memcard_sel(void)
1375 if (memcard1_sel != 0)
1376 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1378 if (memcard2_sel != 0)
1379 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1380 LoadMcds(Config.Mcd1, Config.Mcd2);
1384 static menu_entry e_memcard_options[] =
1386 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1387 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1391 static int menu_loop_memcards(int id, int keys)
1397 memcard1_sel = memcard2_sel = 0;
1398 p = strrchr(Config.Mcd1, '/');
1400 for (i = 0; memcards[i] != NULL; i++)
1401 if (strcmp(p + 1, memcards[i]) == 0)
1402 { memcard1_sel = i; break; }
1403 p = strrchr(Config.Mcd2, '/');
1405 for (i = 0; memcards[i] != NULL; i++)
1406 if (strcmp(p + 1, memcards[i]) == 0)
1407 { memcard2_sel = i; break; }
1409 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1411 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1416 // --------- main menu help ----------
1418 static void menu_bios_warn(void)
1421 static const char msg[] =
1422 "You don't seem to have copied any BIOS files to\n"
1423 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1424 "While many games work fine with fake (HLE) BIOS,\n"
1425 "others (like MGS and FF8) require BIOS to work.\n"
1426 "After copying the file, you'll also need to\n"
1427 "select it in the emu's options->[BIOS/Plugins]\n\n"
1428 "The file is usually named SCPH1001.BIN, but\n"
1429 "other not compressed files can be used too.\n\n"
1430 "Press (B) or (X) to continue";
1434 draw_menu_message(msg, NULL);
1436 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1437 if (inp & (PBTN_MBACK|PBTN_MOK))
1442 // ------------ main menu ------------
1446 static void draw_frame_main(void)
1448 if (CdromId[0] != 0) {
1450 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1451 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1452 Config.HLE ? "HLE" : "BIOS");
1453 smalltext_out16(4, 1, buff, 0x105f);
1457 static void draw_frame_credits(void)
1459 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1462 static const char credits_text[] =
1464 "(C) 1999-2003 PCSX Team\n"
1465 "(C) 2005-2009 PCSX-df Team\n"
1466 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1467 "GPU and SPU code by Pete Bernert\n"
1468 " and the P.E.Op.S. team\n"
1469 "ARM recompiler (C) 2009-2011 Ari64\n"
1470 "PCSX4ALL plugins by PCSX4ALL team\n"
1471 " Chui, Franxis, Unai\n\n"
1472 "integration, optimization and\n"
1473 " frontend (C) 2010-2011 notaz\n";
1475 static int reset_game(void)
1478 if (bios_sel == 0 && !Config.HLE)
1484 if (CheckCdrom() != -1) {
1490 static int reload_plugins(const char *cdimg)
1496 set_cd_image(cdimg);
1498 pcnt_hook_plugins();
1500 if (OpenPlugins() == -1) {
1501 me_update_msg("failed to open plugins");
1504 plugin_call_rearmed_cbs();
1507 CdromLabel[0] = '\0';
1512 static int run_bios(void)
1518 if (reload_plugins(NULL) != 0)
1526 static int run_exe(void)
1530 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1535 if (reload_plugins(NULL) != 0)
1539 if (Load(fname) != 0) {
1540 me_update_msg("exe load failed, bad file?");
1549 static int run_cd_image(const char *fname)
1552 reload_plugins(fname);
1554 if (CheckCdrom() == -1) {
1555 // Only check the CD if we are starting the console with a CD
1557 me_update_msg("unsupported/invalid CD image");
1563 // Read main executable directly from CDRom and start it
1564 if (LoadCdrom() == -1) {
1566 me_update_msg("failed to load CD image");
1574 static int romsel_run(void)
1576 int prev_gpu, prev_spu;
1579 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1583 printf("selected file: %s\n", fname);
1585 new_dynarec_clear_full();
1587 if (run_cd_image(fname) != 0)
1590 prev_gpu = gpu_plugsel;
1591 prev_spu = spu_plugsel;
1592 if (menu_load_config(1) != 0)
1593 menu_load_config(0);
1595 // check for plugin changes, have to repeat
1596 // loading if game config changed plugins to reload them
1597 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1598 printf("plugin change detected, reloading plugins..\n");
1599 if (run_cd_image(fname) != 0)
1603 strcpy(last_selected_fname, rom_fname_reload);
1607 static int swap_cd_image(void)
1611 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1615 printf("selected file: %s\n", fname);
1618 CdromLabel[0] = '\0';
1620 set_cd_image(fname);
1621 if (ReloadCdromPlugin() < 0) {
1622 me_update_msg("failed to load cdr plugin");
1625 if (CDR_open() < 0) {
1626 me_update_msg("failed to open cdr plugin");
1630 SetCdOpenCaseTime(time(NULL) + 2);
1633 strcpy(last_selected_fname, rom_fname_reload);
1637 static int main_menu_handler(int id, int keys)
1641 case MA_MAIN_RESUME_GAME:
1645 case MA_MAIN_SAVE_STATE:
1647 return menu_loop_savestate(0);
1649 case MA_MAIN_LOAD_STATE:
1651 return menu_loop_savestate(1);
1653 case MA_MAIN_RESET_GAME:
1654 if (ready_to_go && reset_game() == 0)
1657 case MA_MAIN_LOAD_ROM:
1658 if (romsel_run() == 0)
1661 case MA_MAIN_SWAP_CD:
1662 if (swap_cd_image() == 0)
1665 case MA_MAIN_RUN_BIOS:
1666 if (run_bios() == 0)
1669 case MA_MAIN_RUN_EXE:
1673 case MA_MAIN_CREDITS:
1674 draw_menu_message(credits_text, draw_frame_credits);
1675 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1681 lprintf("%s: something unknown selected\n", __FUNCTION__);
1688 static menu_entry e_menu_main2[] =
1690 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1691 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1692 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1693 mee_handler ("Memcard manager", menu_loop_memcards),
1697 static int main_menu2_handler(int id, int keys)
1701 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1702 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1704 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1707 static const char h_extra[] = "Change CD, manage memcards..\n";
1709 static menu_entry e_menu_main[] =
1713 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1714 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1715 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1716 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1717 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1718 mee_handler ("Options", menu_loop_options),
1719 mee_handler ("Controls", menu_loop_keyconfig),
1720 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1721 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1722 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1726 // ----------------------------
1728 static void menu_leave_emu(void);
1730 void menu_loop(void)
1736 if (bioses[1] == NULL && !warned_about_bios) {
1738 warned_about_bios = 1;
1741 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1742 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1743 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1744 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1746 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1749 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1750 } while (!ready_to_go);
1752 /* wait until menu, ok, back is released */
1753 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1756 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1761 static int qsort_strcmp(const void *p1, const void *p2)
1763 char * const *s1 = (char * const *)p1;
1764 char * const *s2 = (char * const *)p2;
1765 return strcasecmp(*s1, *s2);
1768 static void scan_bios_plugins(void)
1770 char fname[MAXPATHLEN];
1772 int bios_i, gpu_i, spu_i, mc_i;
1777 gpu_plugins[0] = "builtin_gpu";
1778 spu_plugins[0] = "builtin_spu";
1779 memcards[0] = "(none)";
1780 bios_i = gpu_i = spu_i = mc_i = 1;
1782 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1783 dir = opendir(fname);
1785 perror("scan_bios_plugins bios opendir");
1800 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1803 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1804 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1805 printf("bad BIOS file: %s\n", ent->d_name);
1809 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1810 bioses[bios_i++] = strdup(ent->d_name);
1814 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1820 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1821 dir = opendir(fname);
1823 perror("scan_bios_plugins plugins opendir");
1837 p = strstr(ent->d_name, ".so");
1841 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1842 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1844 fprintf(stderr, "%s\n", dlerror());
1848 // now what do we have here?
1849 tmp = dlsym(h, "GPUinit");
1852 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1853 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1857 tmp = dlsym(h, "SPUinit");
1860 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1861 spu_plugins[spu_i++] = strdup(ent->d_name);
1865 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1872 dir = opendir("." MEMCARD_DIR);
1874 perror("scan_bios_plugins memcards opendir");
1889 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1892 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1893 if (stat(fname, &st) != 0) {
1894 printf("bad memcard file: %s\n", ent->d_name);
1898 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1899 memcards[mc_i++] = strdup(ent->d_name);
1903 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1907 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1912 void menu_init(void)
1914 char buff[MAXPATHLEN];
1916 strcpy(last_selected_fname, "/media");
1918 scan_bios_plugins();
1922 menu_set_defconfig();
1923 menu_load_config(0);
1928 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1929 if (g_menubg_src_ptr == NULL)
1931 emu_make_path(buff, "skin/background.png", sizeof(buff));
1932 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1935 void menu_notify_mode_change(int w, int h, int bpp)
1941 if (scaling == SCALE_1_1) {
1942 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1943 g_layer_w = w; g_layer_h = h;
1947 static void menu_leave_emu(void)
1949 if (GPU_close != NULL) {
1950 int ret = GPU_close();
1952 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1955 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1956 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1957 int x = max(0, g_menuscreen_w - last_psx_w);
1958 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1959 int w = min(g_menuscreen_w, last_psx_w);
1960 int h = min(g_menuscreen_h, last_psx_h);
1961 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1962 u16 *s = pl_vout_buf;
1964 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1965 menu_darken_bg(d, s, w, 0);
1969 cpu_clock = get_cpu_clock();
1971 plat_video_menu_enter(ready_to_go);
1974 void menu_prepare_emu(void)
1976 R3000Acpu *prev_cpu = psxCpu;
1978 plat_video_menu_leave();
1982 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
1985 g_layer_x = 80; g_layer_y = 0;
1986 g_layer_w = 640; g_layer_h = 480;
1988 case SCALE_FULLSCREEN:
1989 g_layer_x = 0; g_layer_y = 0;
1990 g_layer_w = 800; g_layer_h = 480;
1996 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
1997 if (psxCpu != prev_cpu)
1998 // note that this does not really reset, just clears drc caches
2001 // core doesn't care about Config.Cdda changes,
2002 // so handle them manually here
2007 apply_lcdrate(Config.PsxType);
2008 apply_filter(filter);
2011 // push config to GPU plugin
2012 plugin_call_rearmed_cbs();
2014 if (GPU_open != NULL) {
2015 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2017 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2023 void me_update_msg(const char *msg)
2025 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2026 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2028 menu_error_time = plat_get_ticks_ms();
2029 lprintf("msg: %s\n", menu_error_msg);