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]))
73 static int last_psx_w, last_psx_h, last_psx_bpp;
74 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost;
75 static char rom_fname_reload[MAXPATHLEN];
76 static char last_selected_fname[MAXPATHLEN];
77 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
78 static int memcard1_sel, memcard2_sel;
82 extern int iUseReverb;
83 extern int iUseInterpolation;
85 extern int iSPUIRQWait;
89 static const char *bioses[24];
90 static const char *gpu_plugins[16];
91 static const char *spu_plugins[16];
92 static const char *memcards[32];
93 static int bios_sel, gpu_plugsel, spu_plugsel;
96 static int min(int x, int y) { return x < y ? x : y; }
97 static int max(int x, int y) { return x > y ? x : y; }
99 void emu_make_path(char *buff, const char *end, int size)
103 end_len = strlen(end);
104 pos = plat_get_root_dir(buff, size);
105 strncpy(buff + pos, end, size - pos);
107 if (pos + end_len > size - 1)
108 printf("Warning: path truncated: %s\n", buff);
111 static int emu_check_save_file(int slot)
113 int ret = emu_check_state(slot);
114 return ret == 0 ? 1 : 0;
117 static int emu_save_load_game(int load, int unused)
122 ret = emu_load_state(state_slot);
124 // reflect hle/bios mode from savestate
127 else if (bios_sel == 0 && bioses[1] != NULL)
128 // XXX: maybe find the right bios instead
132 ret = emu_save_state(state_slot);
137 // propagate menu settings to the emu vars
138 static void menu_sync_config(void)
140 static int allow_abs_only_old;
145 Config.PsxType = region - 1;
147 switch (in_type_sel1) {
148 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
149 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
150 default: in_type1 = PSE_PAD_TYPE_STANDARD;
152 switch (in_type_sel2) {
153 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
154 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
155 default: in_type2 = PSE_PAD_TYPE_STANDARD;
157 if (in_evdev_allow_abs_only != allow_abs_only_old) {
158 pandora_rescan_inputs();
159 allow_abs_only_old = in_evdev_allow_abs_only;
162 iVolume = 768 + 128 * volume_boost;
163 pl_timing_prepare(Config.PsxType);
166 static void menu_set_defconfig(void)
173 in_type_sel1 = in_type_sel2 = 0;
174 in_evdev_allow_abs_only = 0;
175 Config.Xa = Config.Cdda = Config.Sio =
176 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
177 Config.CdrReschedule = 0;
179 pl_rearmed_cbs.frameskip = 0;
180 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
181 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
182 pl_rearmed_cbs.gpu_unai.abe_hack =
183 pl_rearmed_cbs.gpu_unai.no_light =
184 pl_rearmed_cbs.gpu_unai.no_blend = 0;
187 iUseInterpolation = 1;
195 #define CE_CONFIG_STR(val) \
196 { #val, 0, Config.val }
198 #define CE_CONFIG_VAL(val) \
199 { #val, sizeof(Config.val), &Config.val }
201 #define CE_STR(val) \
204 #define CE_INTVAL(val) \
205 { #val, sizeof(val), &val }
207 #define CE_INTVAL_P(val) \
208 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
210 // 'versioned' var, used when defaults change
211 #define CE_INTVAL_V(val, ver) \
212 { #val #ver, sizeof(val), &val }
214 static const struct {
222 // CE_CONFIG_STR(Cdr),
227 CE_CONFIG_VAL(Debug),
228 CE_CONFIG_VAL(PsxOut),
229 CE_CONFIG_VAL(SpuIrq),
230 CE_CONFIG_VAL(RCntFix),
231 CE_CONFIG_VAL(VSyncWA),
233 CE_CONFIG_VAL(CdrReschedule),
235 CE_INTVAL_V(scaling, 2),
236 CE_INTVAL(g_layer_x),
237 CE_INTVAL(g_layer_y),
238 CE_INTVAL(g_layer_w),
239 CE_INTVAL(g_layer_h),
241 CE_INTVAL(state_slot),
242 CE_INTVAL(cpu_clock),
244 CE_INTVAL(in_type_sel1),
245 CE_INTVAL(in_type_sel2),
246 CE_INTVAL_P(frameskip),
247 CE_INTVAL_P(gpu_peops.iUseDither),
248 CE_INTVAL_P(gpu_peops.dwActFixes),
249 CE_INTVAL_P(gpu_unai.abe_hack),
250 CE_INTVAL_P(gpu_unai.no_light),
251 CE_INTVAL_P(gpu_unai.no_blend),
252 CE_INTVAL(iUseReverb),
254 CE_INTVAL_V(iUseInterpolation, 2),
255 CE_INTVAL_V(iSPUIRQWait, 2),
256 CE_INTVAL(iUseTimer),
257 CE_INTVAL(warned_about_bios),
258 CE_INTVAL(in_evdev_allow_abs_only),
259 CE_INTVAL(volume_boost),
262 static char *get_cd_label(void)
264 static char trimlabel[33];
267 strncpy(trimlabel, CdromLabel, 32);
269 for (j = 31; j >= 0; j--)
270 if (trimlabel[j] == ' ')
276 static void make_cfg_fname(char *buf, size_t size, int is_game)
279 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
281 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
284 static void keys_write_all(FILE *f);
286 static int menu_write_config(int is_game)
288 char cfgfile[MAXPATHLEN];
292 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
293 f = fopen(cfgfile, "w");
295 printf("menu_write_config: failed to open: %s\n", cfgfile);
299 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
300 fprintf(f, "%s = ", config_data[i].name);
301 switch (config_data[i].len) {
303 fprintf(f, "%s\n", (char *)config_data[i].val);
306 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
309 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
312 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
315 printf("menu_write_config: unhandled len %d for %s\n",
316 config_data[i].len, config_data[i].name);
322 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
330 static void parse_str_val(char *cval, const char *src)
333 strncpy(cval, src, MAXPATHLEN);
334 cval[MAXPATHLEN - 1] = 0;
335 tmp = strchr(cval, '\n');
337 tmp = strchr(cval, '\r');
342 static void keys_load_all(const char *cfg);
344 static int menu_load_config(int is_game)
346 char cfgfile[MAXPATHLEN];
352 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
353 f = fopen(cfgfile, "r");
355 printf("menu_load_config: failed to open: %s\n", cfgfile);
359 fseek(f, 0, SEEK_END);
362 printf("bad size %ld: %s\n", size, cfgfile);
366 cfg = malloc(size + 1);
370 fseek(f, 0, SEEK_SET);
371 if (fread(cfg, 1, size, f) != size) {
372 printf("failed to read: %s\n", cfgfile);
377 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
381 tmp = strstr(cfg, config_data[i].name);
384 tmp += strlen(config_data[i].name);
385 if (strncmp(tmp, " = ", 3) != 0)
389 if (config_data[i].len == 0) {
390 parse_str_val(config_data[i].val, tmp);
395 val = strtoul(tmp, &tmp2, 16);
396 if (tmp2 == NULL || tmp == tmp2)
397 continue; // parse failed
399 switch (config_data[i].len) {
401 *(u8 *)config_data[i].val = val;
404 *(u16 *)config_data[i].val = val;
407 *(u32 *)config_data[i].val = val;
410 printf("menu_load_config: unhandled len %d for %s\n",
411 config_data[i].len, config_data[i].name);
417 char *tmp = strstr(cfg, "lastcdimg = ");
420 parse_str_val(last_selected_fname, tmp);
427 for (i = bios_sel = 0; bioses[i] != NULL; i++)
428 if (strcmp(Config.Bios, bioses[i]) == 0)
429 { bios_sel = i; break; }
431 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
432 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
433 { gpu_plugsel = i; break; }
435 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
436 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
437 { spu_plugsel = i; break; }
448 // rrrr rggg gggb bbbb
449 static unsigned short fname2color(const char *fname)
451 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
452 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
453 const char *ext = strrchr(fname, '.');
458 for (i = 0; i < array_size(cdimg_exts); i++)
459 if (strcasecmp(ext, cdimg_exts[i]) == 0)
461 for (i = 0; i < array_size(other_exts); i++)
462 if (strcasecmp(ext, other_exts[i]) == 0)
467 static void draw_savestate_bg(int slot);
469 static const char *filter_exts[] = {
470 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
473 #define MENU_ALIGN_LEFT
474 #define menu_init menu_init_common
475 #include "common/menu.c"
478 // a bit of black magic here
479 static void draw_savestate_bg(int slot)
481 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
483 char fname[MAXPATHLEN];
490 ret = get_state_filename(fname, sizeof(fname), slot);
494 f = gzopen(fname, "rb");
498 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
499 fprintf(stderr, "gzseek failed\n");
504 gpu = malloc(sizeof(*gpu));
510 ret = gzread(f, gpu, sizeof(*gpu));
512 if (ret != sizeof(*gpu)) {
513 fprintf(stderr, "gzread failed\n");
517 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
519 if (gpu->ulStatus & 0x800000)
520 goto out; // disabled
522 x = gpu->ulControl[5] & 0x3ff;
523 y = (gpu->ulControl[5] >> 10) & 0x1ff;
524 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
525 w = psx_widths[(gpu->ulStatus >> 16) & 7];
526 tmp = gpu->ulControl[7];
527 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
528 if (gpu->ulStatus & 0x80000) // doubleheight
531 x = max(0, g_menuscreen_w - w) & ~3;
532 y = max(0, g_menuscreen_h / 2 - h / 2);
533 w = min(g_menuscreen_w, w);
534 h = min(g_menuscreen_h, h);
535 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
537 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
538 if (gpu->ulStatus & 0x200000)
539 bgr888_to_rgb565(d, s, w * 3);
541 bgr555_to_rgb565(d, s, w * 2);
547 // ---------- pandora specific -----------
549 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
550 static char **pnd_filter_list;
552 static int get_cpu_clock(void)
556 f = fopen("/proc/pandora/cpu_mhz_max", "r");
558 fscanf(f, "%d", &ret);
564 static void apply_cpu_clock(void)
568 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
569 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
570 pnd_script_base, cpu_clock);
575 static void apply_filter(int which)
581 if (pnd_filter_list == NULL || which == old)
584 for (i = 0; i < which; i++)
585 if (pnd_filter_list[i] == NULL)
588 if (pnd_filter_list[i] == NULL)
591 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
596 static void apply_lcdrate(int pal)
604 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
605 pnd_script_base, pal ? 50 : 60);
610 static menu_entry e_menu_gfx_options[];
612 static void pnd_menu_init(void)
620 cpu_clock_st = cpu_clock = get_cpu_clock();
622 dir = opendir("/etc/pandora/conf/dss_fir");
624 perror("filter opendir");
637 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
646 mfilters = calloc(count + 1, sizeof(mfilters[0]));
647 if (mfilters == NULL)
651 for (i = 0; (ent = readdir(dir)); ) {
654 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
657 len = strlen(ent->d_name);
659 // skip pre-HF5 extra files
660 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
662 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
665 // have to cut "_up_h" for pre-HF5
666 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
669 if (len > sizeof(buff) - 1)
672 strncpy(buff, ent->d_name, len);
674 mfilters[i] = strdup(buff);
675 if (mfilters[i] != NULL)
680 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
681 e_menu_gfx_options[i].data = (void *)mfilters;
682 pnd_filter_list = mfilters;
685 void menu_finish(void)
687 cpu_clock = cpu_clock_st;
691 // -------------- key config --------------
693 me_bind_action me_ctrl_actions[] =
695 { "UP ", 1 << DKEY_UP},
696 { "DOWN ", 1 << DKEY_DOWN },
697 { "LEFT ", 1 << DKEY_LEFT },
698 { "RIGHT ", 1 << DKEY_RIGHT },
699 { "TRIANGLE", 1 << DKEY_TRIANGLE },
700 { "CIRCLE ", 1 << DKEY_CIRCLE },
701 { "CROSS ", 1 << DKEY_CROSS },
702 { "SQUARE ", 1 << DKEY_SQUARE },
703 { "L1 ", 1 << DKEY_L1 },
704 { "R1 ", 1 << DKEY_R1 },
705 { "L2 ", 1 << DKEY_L2 },
706 { "R2 ", 1 << DKEY_R2 },
707 { "L3 ", 1 << DKEY_L3 },
708 { "R3 ", 1 << DKEY_R3 },
709 { "START ", 1 << DKEY_START },
710 { "SELECT ", 1 << DKEY_SELECT },
714 me_bind_action emuctrl_actions[] =
716 { "Save State ", 1 << SACTION_SAVE_STATE },
717 { "Load State ", 1 << SACTION_LOAD_STATE },
718 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
719 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
720 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
721 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
722 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
723 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
724 { "Gun A button ", 1 << SACTION_GUN_A },
725 { "Gun B button ", 1 << SACTION_GUN_B },
726 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
730 static char *mystrip(char *str)
735 for (i = 0; i < len; i++)
736 if (str[i] != ' ') break;
737 if (i > 0) memmove(str, str + i, len - i + 1);
740 for (i = len - 1; i >= 0; i--)
741 if (str[i] != ' ') break;
747 static void get_line(char *d, size_t size, const char *s)
752 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
763 static void keys_write_all(FILE *f)
767 for (d = 0; d < IN_MAX_DEVS; d++)
769 const int *binds = in_get_dev_binds(d);
770 const char *name = in_get_dev_name(d, 0, 0);
773 if (binds == NULL || name == NULL)
776 fprintf(f, "binddev = %s\n", name);
777 in_get_config(d, IN_CFG_BIND_COUNT, &count);
779 for (k = 0; k < count; k++)
784 act[0] = act[31] = 0;
785 name = in_get_key_name(d, k);
787 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
788 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
789 mask = me_ctrl_actions[i].mask;
791 strncpy(act, me_ctrl_actions[i].name, 31);
792 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
795 mask = me_ctrl_actions[i].mask << 16;
797 strncpy(act, me_ctrl_actions[i].name, 31);
798 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
803 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
804 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
805 mask = emuctrl_actions[i].mask;
807 strncpy(act, emuctrl_actions[i].name, 31);
808 fprintf(f, "bind %s = %s\n", name, mystrip(act));
816 static int parse_bind_val(const char *val, int *type)
820 *type = IN_BINDTYPE_NONE;
824 if (strncasecmp(val, "player", 6) == 0)
826 int player, shift = 0;
827 player = atoi(val + 6) - 1;
829 if ((unsigned int)player > 1)
834 *type = IN_BINDTYPE_PLAYER12;
835 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
836 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
837 return me_ctrl_actions[i].mask << shift;
840 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
841 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
842 *type = IN_BINDTYPE_EMU;
843 return emuctrl_actions[i].mask;
850 static void keys_load_all(const char *cfg)
852 char dev[256], key[128], *act;
858 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
861 get_line(dev, sizeof(dev), p);
862 dev_id = in_config_parse_dev(dev);
864 printf("input: can't handle dev: %s\n", dev);
868 in_unbind_all(dev_id, -1, -1);
869 while ((p = strstr(p, "bind"))) {
870 if (strncmp(p, "binddev = ", 10) == 0)
875 printf("input: parse error: %16s..\n", p);
879 get_line(key, sizeof(key), p);
880 act = strchr(key, '=');
882 printf("parse failed: %16s..\n", p);
890 bind = parse_bind_val(act, &bindtype);
891 if (bind != -1 && bind != 0) {
892 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
893 in_config_bind_key(dev_id, key, bind, bindtype);
896 lprintf("config: unhandled action \"%s\"\n", act);
902 static int key_config_loop_wrap(int id, int keys)
905 case MA_CTRL_PLAYER1:
906 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
908 case MA_CTRL_PLAYER2:
909 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
912 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
920 static const char *mgn_dev_name(int id, int *offs)
922 const char *name = NULL;
925 if (id == MA_CTRL_DEV_FIRST)
928 for (; it < IN_MAX_DEVS; it++) {
929 name = in_get_dev_name(it, 1, 1);
938 static const char *mgn_saveloadcfg(int id, int *offs)
943 static int mh_savecfg(int id, int keys)
945 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
946 me_update_msg("config saved");
948 me_update_msg("failed to write config");
953 static int mh_input_rescan(int id, int keys)
955 //menu_sync_config();
956 pandora_rescan_inputs();
957 me_update_msg("rescan complete.");
962 static const char *men_in_type_sel[] = {
963 "Standard (SCPH-1080)",
964 "Analog (SCPH-1150)",
968 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
969 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
971 static menu_entry e_menu_keyconfig[] =
973 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
974 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
975 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
977 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
978 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
979 mee_onoff_h ("Nubs as buttons", 0, in_evdev_allow_abs_only, 1, h_nub_btns),
980 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
981 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
982 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
983 mee_handler ("Rescan devices", mh_input_rescan),
985 mee_label ("Input devices:"),
986 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
987 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
988 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
989 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
990 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
991 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
992 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
996 static int menu_loop_keyconfig(int id, int keys)
1000 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1001 me_loop(e_menu_keyconfig, &sel);
1005 // ------------ gfx options menu ------------
1007 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1008 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1009 "using d-pad or move it using R+d-pad";
1010 static const char *men_dummy[] = { NULL };
1012 static int menu_loop_cscaler(int id, int keys)
1016 scaling = SCALE_CUSTOM;
1018 omap_enable_layer(1);
1023 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1024 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1025 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1028 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1029 if (inp & PBTN_UP) g_layer_y--;
1030 if (inp & PBTN_DOWN) g_layer_y++;
1031 if (inp & PBTN_LEFT) g_layer_x--;
1032 if (inp & PBTN_RIGHT) g_layer_x++;
1033 if (!(inp & PBTN_R)) {
1034 if (inp & PBTN_UP) g_layer_h += 2;
1035 if (inp & PBTN_DOWN) g_layer_h -= 2;
1036 if (inp & PBTN_LEFT) g_layer_w += 2;
1037 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1039 if (inp & (PBTN_MOK|PBTN_MBACK))
1042 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1043 if (g_layer_x < 0) g_layer_x = 0;
1044 if (g_layer_x > 640) g_layer_x = 640;
1045 if (g_layer_y < 0) g_layer_y = 0;
1046 if (g_layer_y > 420) g_layer_y = 420;
1047 if (g_layer_w < 160) g_layer_w = 160;
1048 if (g_layer_h < 60) g_layer_h = 60;
1049 if (g_layer_x + g_layer_w > 800)
1050 g_layer_w = 800 - g_layer_x;
1051 if (g_layer_y + g_layer_h > 480)
1052 g_layer_h = 480 - g_layer_y;
1053 omap_enable_layer(1);
1057 omap_enable_layer(0);
1062 static menu_entry e_menu_gfx_options[] =
1064 mee_enum ("Scaler", 0, scaling, men_scaler),
1065 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1066 // mee_onoff ("Vsync", 0, vsync, 1),
1067 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1071 static int menu_loop_gfx_options(int id, int keys)
1075 me_loop(e_menu_gfx_options, &sel);
1080 // ------------ bios/plugins ------------
1082 static menu_entry e_menu_plugin_gpu_unai[] =
1084 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1085 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1086 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1090 static int menu_loop_plugin_gpu_unai(int id, int keys)
1093 me_loop(e_menu_plugin_gpu_unai, &sel);
1097 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1098 static const char h_gpu_0[] = "Needed for Chrono Cross";
1099 static const char h_gpu_1[] = "Capcom fighting games";
1100 static const char h_gpu_2[] = "Black screens in Lunar";
1101 static const char h_gpu_3[] = "Compatibility mode";
1102 static const char h_gpu_6[] = "Pandemonium 2";
1103 static const char h_gpu_7[] = "Skip every second frame";
1104 static const char h_gpu_8[] = "Needed by Dark Forces";
1105 static const char h_gpu_9[] = "better g-colors, worse textures";
1106 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1108 static menu_entry e_menu_plugin_gpu_peops[] =
1110 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1111 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1112 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1113 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1114 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1115 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1116 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1117 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1118 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1119 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1123 static int menu_loop_plugin_gpu_peops(int id, int keys)
1126 me_loop(e_menu_plugin_gpu_peops, &sel);
1130 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1131 static const char h_spu_volboost[] = "Large values cause distortion";
1132 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1133 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1135 static menu_entry e_menu_plugin_spu[] =
1137 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1138 mee_onoff ("Reverb", 0, iUseReverb, 2),
1139 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1140 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1141 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1142 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1146 static int menu_loop_plugin_spu(int id, int keys)
1149 me_loop(e_menu_plugin_spu, &sel);
1153 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1154 "and can't be changed there. Must save config and reload\n"
1155 "the game for change to take effect";
1156 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1157 "for plugin change to take effect";
1158 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1159 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1160 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1162 static menu_entry e_menu_plugin_options[] =
1164 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1165 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1166 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1167 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1168 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1169 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1173 static menu_entry e_menu_main2[];
1175 static int menu_loop_plugin_options(int id, int keys)
1178 me_loop(e_menu_plugin_options, &sel);
1180 // sync BIOS/plugins
1181 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1182 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1183 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1184 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1189 // ------------ adv options menu ------------
1191 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1192 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1193 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1194 "(green: normal, red: fmod, blue: noise)";
1195 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1196 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1197 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1198 "(proper .cue/.bin dump is needed otherwise)";
1199 static const char h_cfg_sio[] = "You should not need this, breaks games";
1200 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1201 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1202 "(timing hack, breaks other games)";
1203 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1204 "(timing hack, breaks other games)";
1205 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1206 "(CD timing hack, breaks FMVs)";
1207 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1208 "Might be useful to overcome some dynarec bugs";
1210 static menu_entry e_menu_adv_options[] =
1212 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1213 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1214 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1215 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1216 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1217 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1218 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1219 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1220 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1221 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1222 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1226 static int menu_loop_adv_options(int id, int keys)
1229 me_loop(e_menu_adv_options, &sel);
1233 // ------------ options menu ------------
1235 static int mh_restore_defaults(int id, int keys)
1237 menu_set_defconfig();
1238 me_update_msg("defaults restored");
1242 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1244 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1245 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1246 "loading state or both";
1248 static const char h_restore_def[] = "Switches back to default / recommended\n"
1250 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1252 static menu_entry e_menu_options[] =
1254 // mee_range ("Save slot", 0, state_slot, 0, 9),
1255 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1256 mee_onoff_h ("Frameskip", 0, pl_rearmed_cbs.frameskip, 1, h_frameskip),
1257 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1258 mee_enum ("Region", 0, region, men_region),
1259 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1260 mee_handler ("[Display]", menu_loop_gfx_options),
1261 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1262 mee_handler ("[Advanced]", menu_loop_adv_options),
1263 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1264 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1265 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1269 static int menu_loop_options(int id, int keys)
1274 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1275 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1276 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1278 me_loop(e_menu_options, &sel);
1283 // ------------ debug menu ------------
1285 static void draw_frame_debug(GPUFreeze_t *gpuf)
1287 int w = min(g_menuscreen_w, 1024);
1288 int h = min(g_menuscreen_h, 512);
1289 u16 *d = g_menuscreen_ptr;
1290 u16 *s = (u16 *)gpuf->psxVRam;
1294 gpuf->ulFreezeVersion = 1;
1295 if (GPU_freeze != NULL)
1296 GPU_freeze(1, gpuf);
1298 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1299 bgr555_to_rgb565(d, s, w * 2);
1301 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1302 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1303 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1304 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1305 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1308 static void debug_menu_loop(void)
1313 gpuf = malloc(sizeof(*gpuf));
1320 draw_frame_debug(gpuf);
1323 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1324 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1325 if (inp & PBTN_MBACK)
1332 // --------- memcard manager ---------
1334 static void draw_mc_icon(int dx, int dy, const u16 *s)
1339 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1341 for (y = 0; y < 16; y++, s += 16) {
1342 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1343 for (x = 0; x < 16; x++) {
1345 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1346 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1352 static void draw_mc_bg(void)
1354 McdBlock *blocks1, *blocks2;
1358 blocks1 = malloc(15 * sizeof(blocks1[0]));
1359 blocks2 = malloc(15 * sizeof(blocks1[0]));
1360 if (blocks1 == NULL || blocks2 == NULL)
1363 for (i = 0; i < 15; i++) {
1364 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1365 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1370 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1372 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1376 maxicons = g_menuscreen_h / 32;
1379 row2 = g_menuscreen_w / 2;
1380 for (i = 0; i < maxicons; i++) {
1381 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1382 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1384 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1385 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1388 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1396 static void handle_memcard_sel(void)
1399 if (memcard1_sel != 0)
1400 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1402 if (memcard2_sel != 0)
1403 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1404 LoadMcds(Config.Mcd1, Config.Mcd2);
1408 static menu_entry e_memcard_options[] =
1410 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1411 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1415 static int menu_loop_memcards(int id, int keys)
1421 memcard1_sel = memcard2_sel = 0;
1422 p = strrchr(Config.Mcd1, '/');
1424 for (i = 0; memcards[i] != NULL; i++)
1425 if (strcmp(p + 1, memcards[i]) == 0)
1426 { memcard1_sel = i; break; }
1427 p = strrchr(Config.Mcd2, '/');
1429 for (i = 0; memcards[i] != NULL; i++)
1430 if (strcmp(p + 1, memcards[i]) == 0)
1431 { memcard2_sel = i; break; }
1433 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1435 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1440 // --------- main menu help ----------
1442 static void menu_bios_warn(void)
1445 static const char msg[] =
1446 "You don't seem to have copied any BIOS files to\n"
1447 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1448 "While many games work fine with fake (HLE) BIOS,\n"
1449 "others (like MGS and FF8) require BIOS to work.\n"
1450 "After copying the file, you'll also need to\n"
1451 "select it in the emu's options->[BIOS/Plugins]\n\n"
1452 "The file is usually named SCPH1001.BIN, but\n"
1453 "other not compressed files can be used too.\n\n"
1454 "Press (B) or (X) to continue";
1458 draw_menu_message(msg, NULL);
1460 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1461 if (inp & (PBTN_MBACK|PBTN_MOK))
1466 // ------------ main menu ------------
1470 static void draw_frame_main(void)
1472 if (CdromId[0] != 0) {
1474 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1475 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1476 Config.HLE ? "HLE" : "BIOS");
1477 smalltext_out16(4, 1, buff, 0x105f);
1481 static void draw_frame_credits(void)
1483 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1486 static const char credits_text[] =
1488 "(C) 1999-2003 PCSX Team\n"
1489 "(C) 2005-2009 PCSX-df Team\n"
1490 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1491 "GPU and SPU code by Pete Bernert\n"
1492 " and the P.E.Op.S. team\n"
1493 "ARM recompiler (C) 2009-2011 Ari64\n"
1494 "PCSX4ALL plugins by PCSX4ALL team\n"
1495 " Chui, Franxis, Unai\n\n"
1496 "integration, optimization and\n"
1497 " frontend (C) 2010-2011 notaz\n";
1499 static int reset_game(void)
1502 if (bios_sel == 0 && !Config.HLE)
1508 if (CheckCdrom() != -1) {
1514 static int reload_plugins(const char *cdimg)
1520 set_cd_image(cdimg);
1522 pcnt_hook_plugins();
1524 if (OpenPlugins() == -1) {
1525 me_update_msg("failed to open plugins");
1528 plugin_call_rearmed_cbs();
1531 CdromLabel[0] = '\0';
1536 static int run_bios(void)
1542 if (reload_plugins(NULL) != 0)
1550 static int run_exe(void)
1554 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1559 if (reload_plugins(NULL) != 0)
1563 if (Load(fname) != 0) {
1564 me_update_msg("exe load failed, bad file?");
1573 static int run_cd_image(const char *fname)
1576 reload_plugins(fname);
1578 if (CheckCdrom() == -1) {
1579 // Only check the CD if we are starting the console with a CD
1581 me_update_msg("unsupported/invalid CD image");
1587 // Read main executable directly from CDRom and start it
1588 if (LoadCdrom() == -1) {
1590 me_update_msg("failed to load CD image");
1598 static int romsel_run(void)
1600 int prev_gpu, prev_spu;
1603 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1607 printf("selected file: %s\n", fname);
1609 new_dynarec_clear_full();
1611 if (run_cd_image(fname) != 0)
1614 prev_gpu = gpu_plugsel;
1615 prev_spu = spu_plugsel;
1616 if (menu_load_config(1) != 0)
1617 menu_load_config(0);
1619 // check for plugin changes, have to repeat
1620 // loading if game config changed plugins to reload them
1621 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1622 printf("plugin change detected, reloading plugins..\n");
1623 if (run_cd_image(fname) != 0)
1627 strcpy(last_selected_fname, rom_fname_reload);
1631 static int swap_cd_image(void)
1635 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1639 printf("selected file: %s\n", fname);
1642 CdromLabel[0] = '\0';
1644 set_cd_image(fname);
1645 if (ReloadCdromPlugin() < 0) {
1646 me_update_msg("failed to load cdr plugin");
1649 if (CDR_open() < 0) {
1650 me_update_msg("failed to open cdr plugin");
1654 SetCdOpenCaseTime(time(NULL) + 2);
1657 strcpy(last_selected_fname, rom_fname_reload);
1661 static int main_menu_handler(int id, int keys)
1665 case MA_MAIN_RESUME_GAME:
1669 case MA_MAIN_SAVE_STATE:
1671 return menu_loop_savestate(0);
1673 case MA_MAIN_LOAD_STATE:
1675 return menu_loop_savestate(1);
1677 case MA_MAIN_RESET_GAME:
1678 if (ready_to_go && reset_game() == 0)
1681 case MA_MAIN_LOAD_ROM:
1682 if (romsel_run() == 0)
1685 case MA_MAIN_SWAP_CD:
1686 if (swap_cd_image() == 0)
1689 case MA_MAIN_RUN_BIOS:
1690 if (run_bios() == 0)
1693 case MA_MAIN_RUN_EXE:
1697 case MA_MAIN_CREDITS:
1698 draw_menu_message(credits_text, draw_frame_credits);
1699 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1705 lprintf("%s: something unknown selected\n", __FUNCTION__);
1712 static menu_entry e_menu_main2[] =
1714 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1715 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1716 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1717 mee_handler ("Memcard manager", menu_loop_memcards),
1721 static int main_menu2_handler(int id, int keys)
1725 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1726 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1728 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1731 static const char h_extra[] = "Change CD, manage memcards..\n";
1733 static menu_entry e_menu_main[] =
1737 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1738 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1739 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1740 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1741 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1742 mee_handler ("Options", menu_loop_options),
1743 mee_handler ("Controls", menu_loop_keyconfig),
1744 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1745 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1746 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1750 // ----------------------------
1752 static void menu_leave_emu(void);
1754 void menu_loop(void)
1760 if (bioses[1] == NULL && !warned_about_bios) {
1762 warned_about_bios = 1;
1765 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1766 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1767 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1768 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1770 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1773 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1774 } while (!ready_to_go);
1776 /* wait until menu, ok, back is released */
1777 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1780 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1785 static int qsort_strcmp(const void *p1, const void *p2)
1787 char * const *s1 = (char * const *)p1;
1788 char * const *s2 = (char * const *)p2;
1789 return strcasecmp(*s1, *s2);
1792 static void scan_bios_plugins(void)
1794 char fname[MAXPATHLEN];
1796 int bios_i, gpu_i, spu_i, mc_i;
1801 gpu_plugins[0] = "builtin_gpu";
1802 spu_plugins[0] = "builtin_spu";
1803 memcards[0] = "(none)";
1804 bios_i = gpu_i = spu_i = mc_i = 1;
1806 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1807 dir = opendir(fname);
1809 perror("scan_bios_plugins bios opendir");
1824 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1827 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1828 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1829 printf("bad BIOS file: %s\n", ent->d_name);
1833 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1834 bioses[bios_i++] = strdup(ent->d_name);
1838 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1844 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1845 dir = opendir(fname);
1847 perror("scan_bios_plugins plugins opendir");
1861 p = strstr(ent->d_name, ".so");
1865 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1866 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1868 fprintf(stderr, "%s\n", dlerror());
1872 // now what do we have here?
1873 tmp = dlsym(h, "GPUinit");
1876 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1877 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1881 tmp = dlsym(h, "SPUinit");
1884 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1885 spu_plugins[spu_i++] = strdup(ent->d_name);
1889 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1896 dir = opendir("." MEMCARD_DIR);
1898 perror("scan_bios_plugins memcards opendir");
1913 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1916 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1917 if (stat(fname, &st) != 0) {
1918 printf("bad memcard file: %s\n", ent->d_name);
1922 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1923 memcards[mc_i++] = strdup(ent->d_name);
1927 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1931 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1936 void menu_init(void)
1938 char buff[MAXPATHLEN];
1940 strcpy(last_selected_fname, "/media");
1942 scan_bios_plugins();
1946 menu_set_defconfig();
1947 menu_load_config(0);
1952 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1953 if (g_menubg_src_ptr == NULL)
1955 emu_make_path(buff, "skin/background.png", sizeof(buff));
1956 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1959 void menu_notify_mode_change(int w, int h, int bpp)
1970 g_layer_w = w; g_layer_h = h;
1974 mult = 240.0f / (float)h * 4.0f / 3.0f;
1977 g_layer_w = mult * (float)g_menuscreen_h;
1978 g_layer_h = g_menuscreen_h;
1979 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
1983 // 4:3 that prefers integer scaling
1984 imult = g_menuscreen_h / h;
1985 g_layer_w = w * imult;
1986 g_layer_h = h * imult;
1987 mult = (float)g_layer_w / (float)g_layer_h;
1988 if (mult < 1.25f || mult > 1.666f)
1989 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
1990 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
1993 case SCALE_FULLSCREEN:
1994 g_layer_w = g_menuscreen_w;
1995 g_layer_h = g_menuscreen_h;
2002 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2003 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2004 if (g_layer_x < 0) g_layer_x = 0;
2005 if (g_layer_y < 0) g_layer_y = 0;
2006 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2007 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2010 static void menu_leave_emu(void)
2012 if (GPU_close != NULL) {
2013 int ret = GPU_close();
2015 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2018 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2019 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2020 int x = max(0, g_menuscreen_w - last_psx_w);
2021 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2022 int w = min(g_menuscreen_w, last_psx_w);
2023 int h = min(g_menuscreen_h, last_psx_h);
2024 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2025 u16 *s = pl_vout_buf;
2027 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2028 menu_darken_bg(d, s, w, 0);
2032 cpu_clock = get_cpu_clock();
2034 plat_video_menu_enter(ready_to_go);
2037 void menu_prepare_emu(void)
2039 R3000Acpu *prev_cpu = psxCpu;
2041 plat_video_menu_leave();
2043 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2045 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2046 if (psxCpu != prev_cpu)
2047 // note that this does not really reset, just clears drc caches
2050 // core doesn't care about Config.Cdda changes,
2051 // so handle them manually here
2056 apply_lcdrate(Config.PsxType);
2057 apply_filter(filter);
2060 // push config to GPU plugin
2061 plugin_call_rearmed_cbs();
2063 if (GPU_open != NULL) {
2064 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2066 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2072 void me_update_msg(const char *msg)
2074 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2075 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2077 menu_error_time = plat_get_ticks_ms();
2078 lprintf("msg: %s\n", menu_error_msg);