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"
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"
36 #define array_size(x) (sizeof(x) / sizeof(x[0]))
75 static int last_psx_w, last_psx_h, last_psx_bpp;
76 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
77 static char rom_fname_reload[MAXPATHLEN];
78 static char last_selected_fname[MAXPATHLEN];
79 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
81 static int memcard1_sel, memcard2_sel;
82 int g_opts, analog_deadzone;
84 #ifdef __ARM_ARCH_7A__
85 #define DEFAULT_PSX_CLOCK 57
86 #define DEFAULT_PSX_CLOCK_S "57"
88 #define DEFAULT_PSX_CLOCK 50
89 #define DEFAULT_PSX_CLOCK_S "50"
93 extern int iUseReverb;
94 extern int iUseInterpolation;
96 extern int iSPUIRQWait;
100 static const char *bioses[24];
101 static const char *gpu_plugins[16];
102 static const char *spu_plugins[16];
103 static const char *memcards[32];
104 static int bios_sel, gpu_plugsel, spu_plugsel;
107 static int min(int x, int y) { return x < y ? x : y; }
108 static int max(int x, int y) { return x > y ? x : y; }
110 void emu_make_path(char *buff, const char *end, int size)
114 end_len = strlen(end);
115 pos = plat_get_root_dir(buff, size);
116 strncpy(buff + pos, end, size - pos);
118 if (pos + end_len > size - 1)
119 printf("Warning: path truncated: %s\n", buff);
122 static int emu_check_save_file(int slot)
124 int ret = emu_check_state(slot);
125 return ret == 0 ? 1 : 0;
128 static int emu_save_load_game(int load, int unused)
133 ret = emu_load_state(state_slot);
135 // reflect hle/bios mode from savestate
138 else if (bios_sel == 0 && bioses[1] != NULL)
139 // XXX: maybe find the right bios instead
143 ret = emu_save_state(state_slot);
148 // propagate menu settings to the emu vars
149 static void menu_sync_config(void)
151 static int allow_abs_only_old;
156 Config.PsxType = region - 1;
158 cycle_multiplier = 10000 / psx_clock;
160 switch (in_type_sel1) {
161 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
162 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
163 default: in_type1 = PSE_PAD_TYPE_STANDARD;
165 switch (in_type_sel2) {
166 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
167 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
168 default: in_type2 = PSE_PAD_TYPE_STANDARD;
170 if (in_evdev_allow_abs_only != allow_abs_only_old) {
171 plat_rescan_inputs();
172 allow_abs_only_old = in_evdev_allow_abs_only;
175 iVolume = 768 + 128 * volume_boost;
176 pl_rearmed_cbs.frameskip = frameskip - 1;
177 pl_timing_prepare(Config.PsxType);
180 static void menu_set_defconfig(void)
182 emu_set_default_config();
188 analog_deadzone = 50;
189 psx_clock = DEFAULT_PSX_CLOCK;
192 in_type_sel1 = in_type_sel2 = 0;
193 in_evdev_allow_abs_only = 0;
198 #define CE_CONFIG_STR(val) \
199 { #val, 0, Config.val }
201 #define CE_CONFIG_VAL(val) \
202 { #val, sizeof(Config.val), &Config.val }
204 #define CE_STR(val) \
207 #define CE_INTVAL(val) \
208 { #val, sizeof(val), &val }
210 #define CE_INTVAL_P(val) \
211 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
213 // 'versioned' var, used when defaults change
214 #define CE_INTVAL_V(val, ver) \
215 { #val #ver, sizeof(val), &val }
217 #define CE_INTVAL_PV(val, ver) \
218 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
220 static const struct {
228 // CE_CONFIG_STR(Cdr),
233 CE_CONFIG_VAL(Debug),
234 CE_CONFIG_VAL(PsxOut),
235 CE_CONFIG_VAL(SpuIrq),
236 CE_CONFIG_VAL(RCntFix),
237 CE_CONFIG_VAL(VSyncWA),
239 CE_CONFIG_VAL(CdrReschedule),
241 CE_INTVAL_V(scaling, 2),
242 CE_INTVAL(g_layer_x),
243 CE_INTVAL(g_layer_y),
244 CE_INTVAL(g_layer_w),
245 CE_INTVAL(g_layer_h),
247 CE_INTVAL(state_slot),
248 CE_INTVAL(cpu_clock),
250 CE_INTVAL(in_type_sel1),
251 CE_INTVAL(in_type_sel2),
252 CE_INTVAL(analog_deadzone),
253 CE_INTVAL_V(frameskip, 2),
254 CE_INTVAL_P(gpu_peops.iUseDither),
255 CE_INTVAL_P(gpu_peops.dwActFixes),
256 CE_INTVAL_P(gpu_unai.abe_hack),
257 CE_INTVAL_P(gpu_unai.no_light),
258 CE_INTVAL_P(gpu_unai.no_blend),
259 CE_INTVAL_V(iUseReverb, 3),
260 CE_INTVAL_V(iXAPitch, 3),
261 CE_INTVAL_V(iUseInterpolation, 3),
262 CE_INTVAL_V(iSPUIRQWait, 3),
263 CE_INTVAL_V(iUseTimer, 3),
264 CE_INTVAL(warned_about_bios),
265 CE_INTVAL(in_evdev_allow_abs_only),
266 CE_INTVAL(volume_boost),
267 CE_INTVAL(psx_clock),
268 CE_INTVAL(new_dynarec_hacks),
271 static char *get_cd_label(void)
273 static char trimlabel[33];
276 strncpy(trimlabel, CdromLabel, 32);
278 for (j = 31; j >= 0; j--)
279 if (trimlabel[j] == ' ')
285 static void make_cfg_fname(char *buf, size_t size, int is_game)
288 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
290 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
293 static void keys_write_all(FILE *f);
295 static int menu_write_config(int is_game)
297 char cfgfile[MAXPATHLEN];
301 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
302 f = fopen(cfgfile, "w");
304 printf("menu_write_config: failed to open: %s\n", cfgfile);
308 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
309 fprintf(f, "%s = ", config_data[i].name);
310 switch (config_data[i].len) {
312 fprintf(f, "%s\n", (char *)config_data[i].val);
315 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
318 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
321 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
324 printf("menu_write_config: unhandled len %d for %s\n",
325 config_data[i].len, config_data[i].name);
331 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
339 static void parse_str_val(char *cval, const char *src)
342 strncpy(cval, src, MAXPATHLEN);
343 cval[MAXPATHLEN - 1] = 0;
344 tmp = strchr(cval, '\n');
346 tmp = strchr(cval, '\r');
351 static void keys_load_all(const char *cfg);
353 static int menu_load_config(int is_game)
355 char cfgfile[MAXPATHLEN];
361 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
362 f = fopen(cfgfile, "r");
364 printf("menu_load_config: failed to open: %s\n", cfgfile);
368 fseek(f, 0, SEEK_END);
371 printf("bad size %ld: %s\n", size, cfgfile);
375 cfg = malloc(size + 1);
379 fseek(f, 0, SEEK_SET);
380 if (fread(cfg, 1, size, f) != size) {
381 printf("failed to read: %s\n", cfgfile);
386 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
390 tmp = strstr(cfg, config_data[i].name);
393 tmp += strlen(config_data[i].name);
394 if (strncmp(tmp, " = ", 3) != 0)
398 if (config_data[i].len == 0) {
399 parse_str_val(config_data[i].val, tmp);
404 val = strtoul(tmp, &tmp2, 16);
405 if (tmp2 == NULL || tmp == tmp2)
406 continue; // parse failed
408 switch (config_data[i].len) {
410 *(u8 *)config_data[i].val = val;
413 *(u16 *)config_data[i].val = val;
416 *(u32 *)config_data[i].val = val;
419 printf("menu_load_config: unhandled len %d for %s\n",
420 config_data[i].len, config_data[i].name);
426 char *tmp = strstr(cfg, "lastcdimg = ");
429 parse_str_val(last_selected_fname, tmp);
444 for (i = bios_sel = 0; bioses[i] != NULL; i++)
445 if (strcmp(Config.Bios, bioses[i]) == 0)
446 { bios_sel = i; break; }
448 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
449 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
450 { gpu_plugsel = i; break; }
452 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
453 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
454 { spu_plugsel = i; break; }
459 // rrrr rggg gggb bbbb
460 static unsigned short fname2color(const char *fname)
462 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
463 ".bz", ".znx", ".pbp", ".cbn" };
464 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
465 ".table", ".index", ".sbi" };
466 const char *ext = strrchr(fname, '.');
471 for (i = 0; i < array_size(cdimg_exts); i++)
472 if (strcasecmp(ext, cdimg_exts[i]) == 0)
474 for (i = 0; i < array_size(other_exts); i++)
475 if (strcasecmp(ext, other_exts[i]) == 0)
480 static void draw_savestate_bg(int slot);
482 static const char *filter_exts[] = {
483 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
486 #define MENU_ALIGN_LEFT
487 #ifdef __ARM_ARCH_7A__ // assume hires device
493 #define menu_init menu_init_common
494 #include "common/menu.c"
497 // a bit of black magic here
498 static void draw_savestate_bg(int slot)
500 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
502 char fname[MAXPATHLEN];
509 ret = get_state_filename(fname, sizeof(fname), slot);
513 f = gzopen(fname, "rb");
517 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
518 fprintf(stderr, "gzseek failed\n");
523 gpu = malloc(sizeof(*gpu));
529 ret = gzread(f, gpu, sizeof(*gpu));
531 if (ret != sizeof(*gpu)) {
532 fprintf(stderr, "gzread failed\n");
536 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
538 if (gpu->ulStatus & 0x800000)
539 goto out; // disabled
541 x = gpu->ulControl[5] & 0x3ff;
542 y = (gpu->ulControl[5] >> 10) & 0x1ff;
543 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
544 w = psx_widths[(gpu->ulStatus >> 16) & 7];
545 tmp = gpu->ulControl[7];
546 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
547 if (gpu->ulStatus & 0x80000) // doubleheight
550 x = max(0, g_menuscreen_w - w) & ~3;
551 y = max(0, g_menuscreen_h / 2 - h / 2);
552 w = min(g_menuscreen_w, w);
553 h = min(g_menuscreen_h, h);
554 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
556 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
557 if (gpu->ulStatus & 0x200000)
558 bgr888_to_rgb565(d, s, w * 3);
560 bgr555_to_rgb565(d, s, w * 2);
561 #ifndef __ARM_ARCH_7A__
562 // better darken this on small screens
563 menu_darken_bg(d, d, w * 2, 0);
571 // ---------- XXX: pandora specific -----------
573 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
574 static char **pnd_filter_list;
576 static void apply_filter(int which)
582 if (pnd_filter_list == NULL || which == old)
585 for (i = 0; i < which; i++)
586 if (pnd_filter_list[i] == NULL)
589 if (pnd_filter_list[i] == NULL)
592 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
597 static void apply_lcdrate(int pal)
605 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
606 pnd_script_base, pal ? 50 : 60);
611 static menu_entry e_menu_gfx_options[];
613 static void pnd_menu_init(void)
621 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
623 dir = opendir("/etc/pandora/conf/dss_fir");
625 perror("filter opendir");
638 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
647 mfilters = calloc(count + 1, sizeof(mfilters[0]));
648 if (mfilters == NULL)
652 for (i = 0; (ent = readdir(dir)); ) {
655 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
658 len = strlen(ent->d_name);
660 // skip pre-HF5 extra files
661 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
663 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
666 // have to cut "_up_h" for pre-HF5
667 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
670 if (len > sizeof(buff) - 1)
673 strncpy(buff, ent->d_name, len);
675 mfilters[i] = strdup(buff);
676 if (mfilters[i] != NULL)
681 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
682 e_menu_gfx_options[i].data = (void *)mfilters;
683 pnd_filter_list = mfilters;
686 void menu_finish(void)
688 plat_cpu_clock_apply(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 plat_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", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
980 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
981 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
982 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
983 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
984 mee_handler ("Rescan devices", mh_input_rescan),
986 mee_label ("Input devices:"),
987 mee_label_mk (MA_CTRL_DEV_FIRST, 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),
993 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
997 static int menu_loop_keyconfig(int id, int keys)
1001 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1002 me_loop(e_menu_keyconfig, &sel);
1006 // ------------ gfx options menu ------------
1008 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1009 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1010 "using d-pad or move it using R+d-pad";
1011 static const char *men_dummy[] = { NULL };
1013 static int menu_loop_cscaler(int id, int keys)
1017 scaling = SCALE_CUSTOM;
1019 omap_enable_layer(1);
1024 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1025 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1026 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1029 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1030 if (inp & PBTN_UP) g_layer_y--;
1031 if (inp & PBTN_DOWN) g_layer_y++;
1032 if (inp & PBTN_LEFT) g_layer_x--;
1033 if (inp & PBTN_RIGHT) g_layer_x++;
1034 if (!(inp & PBTN_R)) {
1035 if (inp & PBTN_UP) g_layer_h += 2;
1036 if (inp & PBTN_DOWN) g_layer_h -= 2;
1037 if (inp & PBTN_LEFT) g_layer_w += 2;
1038 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1040 if (inp & (PBTN_MOK|PBTN_MBACK))
1043 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1044 if (g_layer_x < 0) g_layer_x = 0;
1045 if (g_layer_x > 640) g_layer_x = 640;
1046 if (g_layer_y < 0) g_layer_y = 0;
1047 if (g_layer_y > 420) g_layer_y = 420;
1048 if (g_layer_w < 160) g_layer_w = 160;
1049 if (g_layer_h < 60) g_layer_h = 60;
1050 if (g_layer_x + g_layer_w > 800)
1051 g_layer_w = 800 - g_layer_x;
1052 if (g_layer_y + g_layer_h > 480)
1053 g_layer_h = 480 - g_layer_y;
1054 omap_enable_layer(1);
1058 omap_enable_layer(0);
1063 static menu_entry e_menu_gfx_options[] =
1065 mee_enum ("Scaler", 0, scaling, men_scaler),
1066 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1067 // mee_onoff ("Vsync", 0, vsync, 1),
1068 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1072 static int menu_loop_gfx_options(int id, int keys)
1076 me_loop(e_menu_gfx_options, &sel);
1081 // ------------ bios/plugins ------------
1083 static menu_entry e_menu_plugin_gpu_unai[] =
1085 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1086 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1087 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1091 static int menu_loop_plugin_gpu_unai(int id, int keys)
1094 me_loop(e_menu_plugin_gpu_unai, &sel);
1098 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1099 static const char h_gpu_0[] = "Needed for Chrono Cross";
1100 static const char h_gpu_1[] = "Capcom fighting games";
1101 static const char h_gpu_2[] = "Black screens in Lunar";
1102 static const char h_gpu_3[] = "Compatibility mode";
1103 static const char h_gpu_6[] = "Pandemonium 2";
1104 static const char h_gpu_7[] = "Skip every second frame";
1105 static const char h_gpu_8[] = "Needed by Dark Forces";
1106 static const char h_gpu_9[] = "better g-colors, worse textures";
1107 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1109 static menu_entry e_menu_plugin_gpu_peops[] =
1111 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1112 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1113 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1114 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1115 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1116 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1117 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1118 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1119 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1120 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1124 static int menu_loop_plugin_gpu_peops(int id, int keys)
1127 me_loop(e_menu_plugin_gpu_peops, &sel);
1131 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1132 static const char h_spu_volboost[] = "Large values cause distortion";
1133 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1134 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1136 static menu_entry e_menu_plugin_spu[] =
1138 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1139 mee_onoff ("Reverb", 0, iUseReverb, 2),
1140 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1141 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1142 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1143 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1147 static int menu_loop_plugin_spu(int id, int keys)
1150 me_loop(e_menu_plugin_spu, &sel);
1154 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1155 "savestates and can't be changed there. Must save\n"
1156 "config and reload the game for change to take effect";
1157 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1158 "for plugin change to take effect";
1159 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1160 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1161 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1163 static menu_entry e_menu_plugin_options[] =
1165 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1166 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1167 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1168 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1169 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1170 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1174 static menu_entry e_menu_main2[];
1176 static int menu_loop_plugin_options(int id, int keys)
1179 me_loop(e_menu_plugin_options, &sel);
1181 // sync BIOS/plugins
1182 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1183 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1184 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1185 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1190 // ------------ adv options menu ------------
1192 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1193 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1194 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1195 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1197 static menu_entry e_menu_speed_hacks[] =
1199 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1200 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1201 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1202 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1206 static int menu_loop_speed_hacks(int id, int keys)
1209 me_loop(e_menu_speed_hacks, &sel);
1213 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1214 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1215 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1216 "(green: normal, red: fmod, blue: noise)";
1217 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1218 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1219 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1220 "(proper .cue/.bin dump is needed otherwise)";
1221 static const char h_cfg_sio[] = "You should not need this, breaks games";
1222 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1223 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1224 "(timing hack, breaks other games)";
1225 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1226 "(timing hack, breaks other games)";
1227 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1228 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1229 "Might be useful to overcome some dynarec bugs";
1230 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1231 "must reload game for any change to take effect";
1233 static menu_entry e_menu_adv_options[] =
1235 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1236 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1237 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1238 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1239 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1240 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1241 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1242 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1243 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1244 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1245 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1246 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1250 static int menu_loop_adv_options(int id, int keys)
1253 me_loop(e_menu_adv_options, &sel);
1257 // ------------ options menu ------------
1259 static int mh_restore_defaults(int id, int keys)
1261 menu_set_defconfig();
1262 me_update_msg("defaults restored");
1266 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1267 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1269 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1270 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1271 "loading state or both";
1273 static const char h_restore_def[] = "Switches back to default / recommended\n"
1275 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1277 static menu_entry e_menu_options[] =
1279 // mee_range ("Save slot", 0, state_slot, 0, 9),
1280 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1281 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1282 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1283 mee_enum ("Region", 0, region, men_region),
1284 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1285 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1286 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1287 mee_handler ("[Advanced]", menu_loop_adv_options),
1288 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1289 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1290 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1294 static int menu_loop_options(int id, int keys)
1299 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1300 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1301 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1303 me_loop(e_menu_options, &sel);
1308 // ------------ debug menu ------------
1310 static void draw_frame_debug(GPUFreeze_t *gpuf)
1312 int w = min(g_menuscreen_w, 1024);
1313 int h = min(g_menuscreen_h, 512);
1314 u16 *d = g_menuscreen_ptr;
1315 u16 *s = (u16 *)gpuf->psxVRam;
1319 gpuf->ulFreezeVersion = 1;
1320 if (GPU_freeze != NULL)
1321 GPU_freeze(1, gpuf);
1323 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1324 bgr555_to_rgb565(d, s, w * 2);
1326 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1327 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1328 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1329 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1330 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1333 static void debug_menu_loop(void)
1338 gpuf = malloc(sizeof(*gpuf));
1345 draw_frame_debug(gpuf);
1348 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1349 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1350 if (inp & PBTN_MBACK)
1357 // --------- memcard manager ---------
1359 static void draw_mc_icon(int dx, int dy, const u16 *s)
1364 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1366 for (y = 0; y < 16; y++, s += 16) {
1367 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1368 for (x = 0; x < 16; x++) {
1370 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1371 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1377 static void draw_mc_bg(void)
1379 McdBlock *blocks1, *blocks2;
1383 blocks1 = malloc(15 * sizeof(blocks1[0]));
1384 blocks2 = malloc(15 * sizeof(blocks1[0]));
1385 if (blocks1 == NULL || blocks2 == NULL)
1388 for (i = 0; i < 15; i++) {
1389 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1390 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1395 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1397 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1401 maxicons = g_menuscreen_h / 32;
1404 row2 = g_menuscreen_w / 2;
1405 for (i = 0; i < maxicons; i++) {
1406 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1407 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1409 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1410 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1413 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1421 static void handle_memcard_sel(void)
1424 if (memcard1_sel != 0)
1425 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1427 if (memcard2_sel != 0)
1428 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1429 LoadMcds(Config.Mcd1, Config.Mcd2);
1433 static menu_entry e_memcard_options[] =
1435 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1436 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1440 static int menu_loop_memcards(int id, int keys)
1446 memcard1_sel = memcard2_sel = 0;
1447 p = strrchr(Config.Mcd1, '/');
1449 for (i = 0; memcards[i] != NULL; i++)
1450 if (strcmp(p + 1, memcards[i]) == 0)
1451 { memcard1_sel = i; break; }
1452 p = strrchr(Config.Mcd2, '/');
1454 for (i = 0; memcards[i] != NULL; i++)
1455 if (strcmp(p + 1, memcards[i]) == 0)
1456 { memcard2_sel = i; break; }
1458 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1460 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1465 // --------- main menu help ----------
1467 static void menu_bios_warn(void)
1470 static const char msg[] =
1471 "You don't seem to have copied any BIOS\n"
1473 #ifdef __ARM_ARCH_7A__ // XXX
1474 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1476 "pcsx_rearmed/bios/\n\n"
1478 "While many games work fine with fake\n"
1479 "(HLE) BIOS, others (like MGS and FF8)\n"
1480 "require BIOS to work.\n"
1481 "After copying the file, you'll also need\n"
1482 "to select it in the emu's menu:\n"
1483 "options->[BIOS/Plugins]\n\n"
1484 "The file is usually named SCPH1001.BIN,\n"
1485 "but other not compressed files can be\n"
1487 "Press (B) or (X) to continue";
1491 draw_menu_message(msg, NULL);
1493 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1494 if (inp & (PBTN_MBACK|PBTN_MOK))
1499 // ------------ main menu ------------
1503 static void draw_frame_main(void)
1510 if (CdromId[0] != 0) {
1511 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1512 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1513 Config.HLE ? "HLE" : "BIOS");
1514 smalltext_out16(4, 1, buff, 0x105f);
1519 tmp = localtime(<ime);
1520 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1521 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1522 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1526 static void draw_frame_credits(void)
1528 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1531 static const char credits_text[] =
1533 "(C) 1999-2003 PCSX Team\n"
1534 "(C) 2005-2009 PCSX-df Team\n"
1535 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1536 "GPU and SPU code by Pete Bernert\n"
1537 " and the P.E.Op.S. team\n"
1538 "ARM recompiler (C) 2009-2011 Ari64\n"
1539 "PCSX4ALL plugins by PCSX4ALL team\n"
1540 " Chui, Franxis, Unai\n\n"
1541 "integration, optimization and\n"
1542 " frontend (C) 2010-2011 notaz\n";
1544 static int reset_game(void)
1547 if (bios_sel == 0 && !Config.HLE)
1553 if (CheckCdrom() != -1) {
1559 static int reload_plugins(const char *cdimg)
1565 set_cd_image(cdimg);
1567 pcnt_hook_plugins();
1569 if (OpenPlugins() == -1) {
1570 me_update_msg("failed to open plugins");
1573 plugin_call_rearmed_cbs();
1576 CdromLabel[0] = '\0';
1581 static int run_bios(void)
1587 if (reload_plugins(NULL) != 0)
1595 static int run_exe(void)
1599 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1604 if (reload_plugins(NULL) != 0)
1608 if (Load(fname) != 0) {
1609 me_update_msg("exe load failed, bad file?");
1618 static int run_cd_image(const char *fname)
1621 reload_plugins(fname);
1623 // always autodetect, menu_sync_config will override as needed
1626 if (CheckCdrom() == -1) {
1627 // Only check the CD if we are starting the console with a CD
1629 me_update_msg("unsupported/invalid CD image");
1635 // Read main executable directly from CDRom and start it
1636 if (LoadCdrom() == -1) {
1638 me_update_msg("failed to load CD image");
1646 static int romsel_run(void)
1648 int prev_gpu, prev_spu;
1651 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1655 printf("selected file: %s\n", fname);
1657 new_dynarec_clear_full();
1659 if (run_cd_image(fname) != 0)
1662 prev_gpu = gpu_plugsel;
1663 prev_spu = spu_plugsel;
1664 if (menu_load_config(1) != 0)
1665 menu_load_config(0);
1667 // check for plugin changes, have to repeat
1668 // loading if game config changed plugins to reload them
1669 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1670 printf("plugin change detected, reloading plugins..\n");
1671 if (run_cd_image(fname) != 0)
1676 printf("note: running without BIOS, expect compatibility problems\n");
1678 strcpy(last_selected_fname, rom_fname_reload);
1682 static int swap_cd_image(void)
1686 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1690 printf("selected file: %s\n", fname);
1693 CdromLabel[0] = '\0';
1695 set_cd_image(fname);
1696 if (ReloadCdromPlugin() < 0) {
1697 me_update_msg("failed to load cdr plugin");
1700 if (CDR_open() < 0) {
1701 me_update_msg("failed to open cdr plugin");
1705 SetCdOpenCaseTime(time(NULL) + 2);
1708 strcpy(last_selected_fname, rom_fname_reload);
1712 static int main_menu_handler(int id, int keys)
1716 case MA_MAIN_RESUME_GAME:
1720 case MA_MAIN_SAVE_STATE:
1722 return menu_loop_savestate(0);
1724 case MA_MAIN_LOAD_STATE:
1726 return menu_loop_savestate(1);
1728 case MA_MAIN_RESET_GAME:
1729 if (ready_to_go && reset_game() == 0)
1732 case MA_MAIN_LOAD_ROM:
1733 if (romsel_run() == 0)
1736 case MA_MAIN_SWAP_CD:
1737 if (swap_cd_image() == 0)
1740 case MA_MAIN_RUN_BIOS:
1741 if (run_bios() == 0)
1744 case MA_MAIN_RUN_EXE:
1748 case MA_MAIN_CREDITS:
1749 draw_menu_message(credits_text, draw_frame_credits);
1750 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1756 lprintf("%s: something unknown selected\n", __FUNCTION__);
1763 static menu_entry e_menu_main2[] =
1765 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1766 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1767 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1768 mee_handler ("Memcard manager", menu_loop_memcards),
1772 static int main_menu2_handler(int id, int keys)
1776 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1777 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1779 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1782 static const char h_extra[] = "Change CD, manage memcards..\n";
1784 static menu_entry e_menu_main[] =
1788 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1789 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1790 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1791 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1792 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1793 mee_handler ("Options", menu_loop_options),
1794 mee_handler ("Controls", menu_loop_keyconfig),
1795 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1796 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1797 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1801 // ----------------------------
1803 static void menu_leave_emu(void);
1805 void menu_loop(void)
1811 if (bioses[1] == NULL && !warned_about_bios) {
1813 warned_about_bios = 1;
1816 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1817 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1818 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1819 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1821 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1824 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1825 } while (!ready_to_go);
1827 /* wait until menu, ok, back is released */
1828 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1831 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1836 static int qsort_strcmp(const void *p1, const void *p2)
1838 char * const *s1 = (char * const *)p1;
1839 char * const *s2 = (char * const *)p2;
1840 return strcasecmp(*s1, *s2);
1843 static void scan_bios_plugins(void)
1845 char fname[MAXPATHLEN];
1847 int bios_i, gpu_i, spu_i, mc_i;
1852 gpu_plugins[0] = "builtin_gpu";
1853 spu_plugins[0] = "builtin_spu";
1854 memcards[0] = "(none)";
1855 bios_i = gpu_i = spu_i = mc_i = 1;
1857 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1858 dir = opendir(fname);
1860 perror("scan_bios_plugins bios opendir");
1875 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1878 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1879 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1880 printf("bad BIOS file: %s\n", ent->d_name);
1884 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1885 bioses[bios_i++] = strdup(ent->d_name);
1889 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1895 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1896 dir = opendir(fname);
1898 perror("scan_bios_plugins plugins opendir");
1912 p = strstr(ent->d_name, ".so");
1916 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1917 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1919 fprintf(stderr, "%s\n", dlerror());
1923 // now what do we have here?
1924 tmp = dlsym(h, "GPUinit");
1927 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1928 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1932 tmp = dlsym(h, "SPUinit");
1935 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1936 spu_plugins[spu_i++] = strdup(ent->d_name);
1940 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1947 dir = opendir("." MEMCARD_DIR);
1949 perror("scan_bios_plugins memcards opendir");
1964 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1967 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1968 if (stat(fname, &st) != 0) {
1969 printf("bad memcard file: %s\n", ent->d_name);
1973 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1974 memcards[mc_i++] = strdup(ent->d_name);
1978 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1982 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1987 void menu_init(void)
1989 char buff[MAXPATHLEN];
1991 strcpy(last_selected_fname, "/media");
1993 scan_bios_plugins();
1997 menu_set_defconfig();
1998 menu_load_config(0);
2003 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2004 if (g_menubg_src_ptr == NULL)
2006 emu_make_path(buff, "skin/background.png", sizeof(buff));
2007 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2009 #ifndef __ARM_ARCH_7A__ /* XXX */
2010 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2011 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2013 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2017 void menu_notify_mode_change(int w, int h, int bpp)
2028 g_layer_w = w; g_layer_h = h;
2032 if (h > g_menuscreen_h || (240 < h && h <= 360))
2033 goto fractional_4_3;
2035 // 4:3 that prefers integer scaling
2036 imult = g_menuscreen_h / h;
2037 g_layer_w = w * imult;
2038 g_layer_h = h * imult;
2039 mult = (float)g_layer_w / (float)g_layer_h;
2040 if (mult < 1.25f || mult > 1.666f)
2041 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2042 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2047 mult = 240.0f / (float)h * 4.0f / 3.0f;
2050 g_layer_w = mult * (float)g_menuscreen_h;
2051 g_layer_h = g_menuscreen_h;
2052 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2055 case SCALE_FULLSCREEN:
2056 g_layer_w = g_menuscreen_w;
2057 g_layer_h = g_menuscreen_h;
2064 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2065 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2066 if (g_layer_x < 0) g_layer_x = 0;
2067 if (g_layer_y < 0) g_layer_y = 0;
2068 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2069 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2072 static void menu_leave_emu(void)
2074 if (GPU_close != NULL) {
2075 int ret = GPU_close();
2077 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2080 plat_video_menu_enter(ready_to_go);
2082 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2083 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2084 int x = max(0, g_menuscreen_w - last_psx_w);
2085 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2086 int w = min(g_menuscreen_w, last_psx_w);
2087 int h = min(g_menuscreen_h, last_psx_h);
2088 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2089 u16 *s = pl_vout_buf;
2091 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2092 menu_darken_bg(d, s, w, 0);
2096 cpu_clock = plat_cpu_clock_get();
2099 void menu_prepare_emu(void)
2101 R3000Acpu *prev_cpu = psxCpu;
2103 plat_video_menu_leave();
2105 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2107 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2108 if (psxCpu != prev_cpu)
2109 // note that this does not really reset, just clears drc caches
2112 // core doesn't care about Config.Cdda changes,
2113 // so handle them manually here
2118 apply_lcdrate(Config.PsxType);
2119 apply_filter(filter);
2120 plat_cpu_clock_apply(cpu_clock);
2122 // push config to GPU plugin
2123 plugin_call_rearmed_cbs();
2125 if (GPU_open != NULL) {
2126 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2128 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2134 void me_update_msg(const char *msg)
2136 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2137 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2139 menu_error_time = plat_get_ticks_ms();
2140 lprintf("msg: %s\n", menu_error_msg);