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/cdriso.h"
32 #include "../libpcsxcore/psemu_plugin_defs.h"
33 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
34 #include "../plugins/dfinput/main.h"
37 #define array_size(x) (sizeof(x) / sizeof(x[0]))
48 MA_MAIN_SWAP_CD_MULTI,
78 static int last_psx_w, last_psx_h, last_psx_bpp;
79 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
80 static char rom_fname_reload[MAXPATHLEN];
81 static char last_selected_fname[MAXPATHLEN];
82 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
84 static int memcard1_sel, memcard2_sel;
86 int analog_deadzone; // for Caanoo
88 #ifdef __ARM_ARCH_7A__
89 #define DEFAULT_PSX_CLOCK 57
90 #define DEFAULT_PSX_CLOCK_S "57"
92 #define DEFAULT_PSX_CLOCK 50
93 #define DEFAULT_PSX_CLOCK_S "50"
97 extern int iUseReverb;
98 extern int iUseInterpolation;
100 extern int iSPUIRQWait;
101 extern int iUseTimer;
104 static const char *bioses[24];
105 static const char *gpu_plugins[16];
106 static const char *spu_plugins[16];
107 static const char *memcards[32];
108 static int bios_sel, gpu_plugsel, spu_plugsel;
111 static int min(int x, int y) { return x < y ? x : y; }
112 static int max(int x, int y) { return x > y ? x : y; }
114 void emu_make_path(char *buff, const char *end, int size)
118 end_len = strlen(end);
119 pos = plat_get_root_dir(buff, size);
120 strncpy(buff + pos, end, size - pos);
122 if (pos + end_len > size - 1)
123 printf("Warning: path truncated: %s\n", buff);
126 static int emu_check_save_file(int slot)
128 int ret = emu_check_state(slot);
129 return ret == 0 ? 1 : 0;
132 static int emu_save_load_game(int load, int unused)
137 ret = emu_load_state(state_slot);
139 // reflect hle/bios mode from savestate
142 else if (bios_sel == 0 && bioses[1] != NULL)
143 // XXX: maybe find the right bios instead
147 ret = emu_save_state(state_slot);
152 // propagate menu settings to the emu vars
153 static void menu_sync_config(void)
155 static int allow_abs_only_old;
160 Config.PsxType = region - 1;
162 cycle_multiplier = 10000 / psx_clock;
164 switch (in_type_sel1) {
165 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
166 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
167 default: in_type1 = PSE_PAD_TYPE_STANDARD;
169 switch (in_type_sel2) {
170 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
171 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
172 default: in_type2 = PSE_PAD_TYPE_STANDARD;
174 if (in_evdev_allow_abs_only != allow_abs_only_old) {
176 allow_abs_only_old = in_evdev_allow_abs_only;
179 iVolume = 768 + 128 * volume_boost;
180 pl_rearmed_cbs.frameskip = frameskip - 1;
181 pl_timing_prepare(Config.PsxType);
184 static void menu_set_defconfig(void)
186 emu_set_default_config();
192 analog_deadzone = 50;
193 psx_clock = DEFAULT_PSX_CLOCK;
196 in_type_sel1 = in_type_sel2 = 0;
197 in_evdev_allow_abs_only = 0;
202 #define CE_CONFIG_STR(val) \
203 { #val, 0, Config.val }
205 #define CE_CONFIG_VAL(val) \
206 { #val, sizeof(Config.val), &Config.val }
208 #define CE_STR(val) \
211 #define CE_INTVAL(val) \
212 { #val, sizeof(val), &val }
214 #define CE_INTVAL_P(val) \
215 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
217 // 'versioned' var, used when defaults change
218 #define CE_INTVAL_V(val, ver) \
219 { #val #ver, sizeof(val), &val }
221 #define CE_INTVAL_PV(val, ver) \
222 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
224 static const struct {
232 // CE_CONFIG_STR(Cdr),
237 CE_CONFIG_VAL(Debug),
238 CE_CONFIG_VAL(PsxOut),
239 CE_CONFIG_VAL(SpuIrq),
240 CE_CONFIG_VAL(RCntFix),
241 CE_CONFIG_VAL(VSyncWA),
243 CE_CONFIG_VAL(CdrReschedule),
245 CE_INTVAL_V(scaling, 2),
246 CE_INTVAL(g_layer_x),
247 CE_INTVAL(g_layer_y),
248 CE_INTVAL(g_layer_w),
249 CE_INTVAL(g_layer_h),
251 CE_INTVAL(state_slot),
252 CE_INTVAL(cpu_clock),
254 CE_INTVAL(in_type_sel1),
255 CE_INTVAL(in_type_sel2),
256 CE_INTVAL(analog_deadzone),
257 CE_INTVAL_V(frameskip, 2),
258 CE_INTVAL_P(gpu_peops.iUseDither),
259 CE_INTVAL_P(gpu_peops.dwActFixes),
260 CE_INTVAL_P(gpu_unai.abe_hack),
261 CE_INTVAL_P(gpu_unai.no_light),
262 CE_INTVAL_P(gpu_unai.no_blend),
263 CE_INTVAL_V(iUseReverb, 3),
264 CE_INTVAL_V(iXAPitch, 3),
265 CE_INTVAL_V(iUseInterpolation, 3),
266 CE_INTVAL_V(iSPUIRQWait, 3),
267 CE_INTVAL_V(iUseTimer, 3),
268 CE_INTVAL(warned_about_bios),
269 CE_INTVAL(in_evdev_allow_abs_only),
270 CE_INTVAL(volume_boost),
271 CE_INTVAL(psx_clock),
272 CE_INTVAL(new_dynarec_hacks),
273 CE_INTVAL(in_enable_vibration),
276 static char *get_cd_label(void)
278 static char trimlabel[33];
281 strncpy(trimlabel, CdromLabel, 32);
283 for (j = 31; j >= 0; j--)
284 if (trimlabel[j] == ' ')
290 static void make_cfg_fname(char *buf, size_t size, int is_game)
293 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
295 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
298 static void keys_write_all(FILE *f);
300 static int menu_write_config(int is_game)
302 char cfgfile[MAXPATHLEN];
306 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
307 f = fopen(cfgfile, "w");
309 printf("menu_write_config: failed to open: %s\n", cfgfile);
313 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
314 fprintf(f, "%s = ", config_data[i].name);
315 switch (config_data[i].len) {
317 fprintf(f, "%s\n", (char *)config_data[i].val);
320 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
323 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
326 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
329 printf("menu_write_config: unhandled len %d for %s\n",
330 config_data[i].len, config_data[i].name);
336 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
344 static void parse_str_val(char *cval, const char *src)
347 strncpy(cval, src, MAXPATHLEN);
348 cval[MAXPATHLEN - 1] = 0;
349 tmp = strchr(cval, '\n');
351 tmp = strchr(cval, '\r');
356 static void keys_load_all(const char *cfg);
358 static int menu_load_config(int is_game)
360 char cfgfile[MAXPATHLEN];
366 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
367 f = fopen(cfgfile, "r");
369 printf("menu_load_config: failed to open: %s\n", cfgfile);
373 fseek(f, 0, SEEK_END);
376 printf("bad size %ld: %s\n", size, cfgfile);
380 cfg = malloc(size + 1);
384 fseek(f, 0, SEEK_SET);
385 if (fread(cfg, 1, size, f) != size) {
386 printf("failed to read: %s\n", cfgfile);
391 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
395 tmp = strstr(cfg, config_data[i].name);
398 tmp += strlen(config_data[i].name);
399 if (strncmp(tmp, " = ", 3) != 0)
403 if (config_data[i].len == 0) {
404 parse_str_val(config_data[i].val, tmp);
409 val = strtoul(tmp, &tmp2, 16);
410 if (tmp2 == NULL || tmp == tmp2)
411 continue; // parse failed
413 switch (config_data[i].len) {
415 *(u8 *)config_data[i].val = val;
418 *(u16 *)config_data[i].val = val;
421 *(u32 *)config_data[i].val = val;
424 printf("menu_load_config: unhandled len %d for %s\n",
425 config_data[i].len, config_data[i].name);
431 char *tmp = strstr(cfg, "lastcdimg = ");
434 parse_str_val(last_selected_fname, tmp);
449 for (i = bios_sel = 0; bioses[i] != NULL; i++)
450 if (strcmp(Config.Bios, bioses[i]) == 0)
451 { bios_sel = i; break; }
453 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
454 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
455 { gpu_plugsel = i; break; }
457 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
458 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
459 { spu_plugsel = i; break; }
464 // rrrr rggg gggb bbbb
465 static unsigned short fname2color(const char *fname)
467 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
468 ".bz", ".znx", ".pbp", ".cbn" };
469 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
470 ".table", ".index", ".sbi" };
471 const char *ext = strrchr(fname, '.');
476 for (i = 0; i < array_size(cdimg_exts); i++)
477 if (strcasecmp(ext, cdimg_exts[i]) == 0)
479 for (i = 0; i < array_size(other_exts); i++)
480 if (strcasecmp(ext, other_exts[i]) == 0)
485 static void draw_savestate_bg(int slot);
487 static const char *filter_exts[] = {
488 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
491 #define MENU_ALIGN_LEFT
492 #ifdef __ARM_ARCH_7A__ // assume hires device
498 #define menu_init menu_init_common
499 #include "common/menu.c"
502 // a bit of black magic here
503 static void draw_savestate_bg(int slot)
505 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
507 char fname[MAXPATHLEN];
514 ret = get_state_filename(fname, sizeof(fname), slot);
518 f = gzopen(fname, "rb");
522 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
523 fprintf(stderr, "gzseek failed\n");
528 gpu = malloc(sizeof(*gpu));
534 ret = gzread(f, gpu, sizeof(*gpu));
536 if (ret != sizeof(*gpu)) {
537 fprintf(stderr, "gzread failed\n");
541 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
543 if (gpu->ulStatus & 0x800000)
544 goto out; // disabled
546 x = gpu->ulControl[5] & 0x3ff;
547 y = (gpu->ulControl[5] >> 10) & 0x1ff;
548 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
549 w = psx_widths[(gpu->ulStatus >> 16) & 7];
550 tmp = gpu->ulControl[7];
551 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
552 if (gpu->ulStatus & 0x80000) // doubleheight
555 x = max(0, g_menuscreen_w - w) & ~3;
556 y = max(0, g_menuscreen_h / 2 - h / 2);
557 w = min(g_menuscreen_w, w);
558 h = min(g_menuscreen_h, h);
559 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
561 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
562 if (gpu->ulStatus & 0x200000)
563 bgr888_to_rgb565(d, s, w * 3);
565 bgr555_to_rgb565(d, s, w * 2);
566 #ifndef __ARM_ARCH_7A__
567 // better darken this on small screens
568 menu_darken_bg(d, d, w * 2, 0);
576 // ---------- XXX: pandora specific -----------
578 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
579 static char **pnd_filter_list;
581 static void apply_filter(int which)
587 if (pnd_filter_list == NULL || which == old)
590 for (i = 0; i < which; i++)
591 if (pnd_filter_list[i] == NULL)
594 if (pnd_filter_list[i] == NULL)
597 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
602 static void apply_lcdrate(int pal)
610 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
611 pnd_script_base, pal ? 50 : 60);
616 static menu_entry e_menu_gfx_options[];
618 static void pnd_menu_init(void)
626 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
628 dir = opendir("/etc/pandora/conf/dss_fir");
630 perror("filter opendir");
643 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
652 mfilters = calloc(count + 1, sizeof(mfilters[0]));
653 if (mfilters == NULL)
657 for (i = 0; (ent = readdir(dir)); ) {
660 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
663 len = strlen(ent->d_name);
665 // skip pre-HF5 extra files
666 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
668 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
671 // have to cut "_up_h" for pre-HF5
672 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
675 if (len > sizeof(buff) - 1)
678 strncpy(buff, ent->d_name, len);
680 mfilters[i] = strdup(buff);
681 if (mfilters[i] != NULL)
686 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
687 e_menu_gfx_options[i].data = (void *)mfilters;
688 pnd_filter_list = mfilters;
691 void menu_finish(void)
693 plat_cpu_clock_apply(cpu_clock_st);
696 // -------------- key config --------------
698 me_bind_action me_ctrl_actions[] =
700 { "UP ", 1 << DKEY_UP},
701 { "DOWN ", 1 << DKEY_DOWN },
702 { "LEFT ", 1 << DKEY_LEFT },
703 { "RIGHT ", 1 << DKEY_RIGHT },
704 { "TRIANGLE", 1 << DKEY_TRIANGLE },
705 { "CIRCLE ", 1 << DKEY_CIRCLE },
706 { "CROSS ", 1 << DKEY_CROSS },
707 { "SQUARE ", 1 << DKEY_SQUARE },
708 { "L1 ", 1 << DKEY_L1 },
709 { "R1 ", 1 << DKEY_R1 },
710 { "L2 ", 1 << DKEY_L2 },
711 { "R2 ", 1 << DKEY_R2 },
712 { "L3 ", 1 << DKEY_L3 },
713 { "R3 ", 1 << DKEY_R3 },
714 { "START ", 1 << DKEY_START },
715 { "SELECT ", 1 << DKEY_SELECT },
719 me_bind_action emuctrl_actions[] =
721 { "Save State ", 1 << SACTION_SAVE_STATE },
722 { "Load State ", 1 << SACTION_LOAD_STATE },
723 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
724 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
725 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
726 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
727 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
728 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
729 { "Gun A button ", 1 << SACTION_GUN_A },
730 { "Gun B button ", 1 << SACTION_GUN_B },
731 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
732 #ifndef __ARM_ARCH_7A__ /* XXX */
733 { "Volume Up ", 1 << SACTION_VOLUME_UP },
734 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
739 static char *mystrip(char *str)
744 for (i = 0; i < len; i++)
745 if (str[i] != ' ') break;
746 if (i > 0) memmove(str, str + i, len - i + 1);
749 for (i = len - 1; i >= 0; i--)
750 if (str[i] != ' ') break;
756 static void get_line(char *d, size_t size, const char *s)
761 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
772 static void keys_write_all(FILE *f)
776 for (d = 0; d < IN_MAX_DEVS; d++)
778 const int *binds = in_get_dev_binds(d);
779 const char *name = in_get_dev_name(d, 0, 0);
782 if (binds == NULL || name == NULL)
785 fprintf(f, "binddev = %s\n", name);
786 in_get_config(d, IN_CFG_BIND_COUNT, &count);
788 for (k = 0; k < count; k++)
793 act[0] = act[31] = 0;
794 name = in_get_key_name(d, k);
796 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
797 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
798 mask = me_ctrl_actions[i].mask;
800 strncpy(act, me_ctrl_actions[i].name, 31);
801 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
804 mask = me_ctrl_actions[i].mask << 16;
806 strncpy(act, me_ctrl_actions[i].name, 31);
807 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
812 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
813 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
814 mask = emuctrl_actions[i].mask;
816 strncpy(act, emuctrl_actions[i].name, 31);
817 fprintf(f, "bind %s = %s\n", name, mystrip(act));
825 static int parse_bind_val(const char *val, int *type)
829 *type = IN_BINDTYPE_NONE;
833 if (strncasecmp(val, "player", 6) == 0)
835 int player, shift = 0;
836 player = atoi(val + 6) - 1;
838 if ((unsigned int)player > 1)
843 *type = IN_BINDTYPE_PLAYER12;
844 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
845 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
846 return me_ctrl_actions[i].mask << shift;
849 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
850 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
851 *type = IN_BINDTYPE_EMU;
852 return emuctrl_actions[i].mask;
859 static void keys_load_all(const char *cfg)
861 char dev[256], key[128], *act;
867 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
870 get_line(dev, sizeof(dev), p);
871 dev_id = in_config_parse_dev(dev);
873 printf("input: can't handle dev: %s\n", dev);
877 in_unbind_all(dev_id, -1, -1);
878 while ((p = strstr(p, "bind"))) {
879 if (strncmp(p, "binddev = ", 10) == 0)
884 printf("input: parse error: %16s..\n", p);
888 get_line(key, sizeof(key), p);
889 act = strchr(key, '=');
891 printf("parse failed: %16s..\n", p);
899 bind = parse_bind_val(act, &bindtype);
900 if (bind != -1 && bind != 0) {
901 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
902 in_config_bind_key(dev_id, key, bind, bindtype);
905 lprintf("config: unhandled action \"%s\"\n", act);
911 static int key_config_loop_wrap(int id, int keys)
914 case MA_CTRL_PLAYER1:
915 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
917 case MA_CTRL_PLAYER2:
918 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
921 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
929 static const char *mgn_dev_name(int id, int *offs)
931 const char *name = NULL;
934 if (id == MA_CTRL_DEV_FIRST)
937 for (; it < IN_MAX_DEVS; it++) {
938 name = in_get_dev_name(it, 1, 1);
947 static const char *mgn_saveloadcfg(int id, int *offs)
952 static int mh_savecfg(int id, int keys)
954 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
955 me_update_msg("config saved");
957 me_update_msg("failed to write config");
962 static int mh_input_rescan(int id, int keys)
964 //menu_sync_config();
966 me_update_msg("rescan complete.");
971 static const char *men_in_type_sel[] = {
972 "Standard (SCPH-1080)",
973 "Analog (SCPH-1150)",
977 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
978 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
979 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
981 static menu_entry e_menu_keyconfig[] =
983 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
984 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
985 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
987 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
988 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
989 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
990 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
991 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
992 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
993 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
994 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
995 mee_handler ("Rescan devices", mh_input_rescan),
997 mee_label ("Input devices:"),
998 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
999 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1000 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1001 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1002 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1003 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1004 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1008 static int menu_loop_keyconfig(int id, int keys)
1012 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1013 me_loop(e_menu_keyconfig, &sel);
1017 // ------------ gfx options menu ------------
1019 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1020 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1021 "using d-pad or move it using R+d-pad";
1022 static const char *men_dummy[] = { NULL };
1024 static int menu_loop_cscaler(int id, int keys)
1028 scaling = SCALE_CUSTOM;
1030 omap_enable_layer(1);
1035 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1036 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1037 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1040 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1041 if (inp & PBTN_UP) g_layer_y--;
1042 if (inp & PBTN_DOWN) g_layer_y++;
1043 if (inp & PBTN_LEFT) g_layer_x--;
1044 if (inp & PBTN_RIGHT) g_layer_x++;
1045 if (!(inp & PBTN_R)) {
1046 if (inp & PBTN_UP) g_layer_h += 2;
1047 if (inp & PBTN_DOWN) g_layer_h -= 2;
1048 if (inp & PBTN_LEFT) g_layer_w += 2;
1049 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1051 if (inp & (PBTN_MOK|PBTN_MBACK))
1054 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1055 if (g_layer_x < 0) g_layer_x = 0;
1056 if (g_layer_x > 640) g_layer_x = 640;
1057 if (g_layer_y < 0) g_layer_y = 0;
1058 if (g_layer_y > 420) g_layer_y = 420;
1059 if (g_layer_w < 160) g_layer_w = 160;
1060 if (g_layer_h < 60) g_layer_h = 60;
1061 if (g_layer_x + g_layer_w > 800)
1062 g_layer_w = 800 - g_layer_x;
1063 if (g_layer_y + g_layer_h > 480)
1064 g_layer_h = 480 - g_layer_y;
1065 omap_enable_layer(1);
1069 omap_enable_layer(0);
1074 static menu_entry e_menu_gfx_options[] =
1076 mee_enum ("Scaler", 0, scaling, men_scaler),
1077 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1078 // mee_onoff ("Vsync", 0, vsync, 1),
1079 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1083 static int menu_loop_gfx_options(int id, int keys)
1087 me_loop(e_menu_gfx_options, &sel);
1092 // ------------ bios/plugins ------------
1094 static menu_entry e_menu_plugin_gpu_unai[] =
1096 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1097 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1098 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1102 static int menu_loop_plugin_gpu_unai(int id, int keys)
1105 me_loop(e_menu_plugin_gpu_unai, &sel);
1109 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1110 static const char h_gpu_0[] = "Needed for Chrono Cross";
1111 static const char h_gpu_1[] = "Capcom fighting games";
1112 static const char h_gpu_2[] = "Black screens in Lunar";
1113 static const char h_gpu_3[] = "Compatibility mode";
1114 static const char h_gpu_6[] = "Pandemonium 2";
1115 static const char h_gpu_7[] = "Skip every second frame";
1116 static const char h_gpu_8[] = "Needed by Dark Forces";
1117 static const char h_gpu_9[] = "better g-colors, worse textures";
1118 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1120 static menu_entry e_menu_plugin_gpu_peops[] =
1122 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1123 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1124 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1125 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1126 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1127 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1128 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1129 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1130 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1131 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1135 static int menu_loop_plugin_gpu_peops(int id, int keys)
1138 me_loop(e_menu_plugin_gpu_peops, &sel);
1142 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1143 static const char h_spu_volboost[] = "Large values cause distortion";
1144 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1145 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1147 static menu_entry e_menu_plugin_spu[] =
1149 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1150 mee_onoff ("Reverb", 0, iUseReverb, 2),
1151 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1152 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1153 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1154 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1158 static int menu_loop_plugin_spu(int id, int keys)
1161 me_loop(e_menu_plugin_spu, &sel);
1165 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1166 "savestates and can't be changed there. Must save\n"
1167 "config and reload the game for change to take effect";
1168 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1169 "for plugin change to take effect";
1170 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1171 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1172 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1174 static menu_entry e_menu_plugin_options[] =
1176 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1177 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1178 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1179 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1180 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1181 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1185 static menu_entry e_menu_main2[];
1187 static int menu_loop_plugin_options(int id, int keys)
1190 me_loop(e_menu_plugin_options, &sel);
1192 // sync BIOS/plugins
1193 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1194 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1195 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1196 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1201 // ------------ adv options menu ------------
1203 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1204 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1205 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1206 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1208 static menu_entry e_menu_speed_hacks[] =
1210 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1211 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1212 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1213 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1217 static int menu_loop_speed_hacks(int id, int keys)
1220 me_loop(e_menu_speed_hacks, &sel);
1224 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1225 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1226 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1227 "(green: normal, red: fmod, blue: noise)";
1228 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1229 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1230 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1231 "(proper .cue/.bin dump is needed otherwise)";
1232 static const char h_cfg_sio[] = "You should not need this, breaks games";
1233 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1234 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1235 "(timing hack, breaks other games)";
1236 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1237 "(timing hack, breaks other games)";
1238 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1239 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1240 "Might be useful to overcome some dynarec bugs";
1241 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1242 "must reload game for any change to take effect";
1244 static menu_entry e_menu_adv_options[] =
1246 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1247 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1248 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1249 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1250 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1251 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1252 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1253 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1254 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1255 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1256 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1257 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1261 static int menu_loop_adv_options(int id, int keys)
1264 me_loop(e_menu_adv_options, &sel);
1268 // ------------ options menu ------------
1270 static int mh_restore_defaults(int id, int keys)
1272 menu_set_defconfig();
1273 me_update_msg("defaults restored");
1277 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1278 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1280 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1281 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1282 "loading state or both";
1284 static const char h_restore_def[] = "Switches back to default / recommended\n"
1286 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1288 static menu_entry e_menu_options[] =
1290 // mee_range ("Save slot", 0, state_slot, 0, 9),
1291 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1292 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1293 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1294 mee_enum ("Region", 0, region, men_region),
1295 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1296 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1297 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1298 mee_handler ("[Advanced]", menu_loop_adv_options),
1299 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1300 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1301 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1305 static int menu_loop_options(int id, int keys)
1310 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1311 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1312 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1314 me_loop(e_menu_options, &sel);
1319 // ------------ debug menu ------------
1321 static void draw_frame_debug(GPUFreeze_t *gpuf)
1323 int w = min(g_menuscreen_w, 1024);
1324 int h = min(g_menuscreen_h, 512);
1325 u16 *d = g_menuscreen_ptr;
1326 u16 *s = (u16 *)gpuf->psxVRam;
1330 gpuf->ulFreezeVersion = 1;
1331 if (GPU_freeze != NULL)
1332 GPU_freeze(1, gpuf);
1334 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1335 bgr555_to_rgb565(d, s, w * 2);
1337 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1338 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1339 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1340 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1341 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1344 static void debug_menu_loop(void)
1349 gpuf = malloc(sizeof(*gpuf));
1356 draw_frame_debug(gpuf);
1359 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1360 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1361 if (inp & PBTN_MBACK)
1368 // --------- memcard manager ---------
1370 static void draw_mc_icon(int dx, int dy, const u16 *s)
1375 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1377 for (y = 0; y < 16; y++, s += 16) {
1378 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1379 for (x = 0; x < 16; x++) {
1381 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1382 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1388 static void draw_mc_bg(void)
1390 McdBlock *blocks1, *blocks2;
1394 blocks1 = malloc(15 * sizeof(blocks1[0]));
1395 blocks2 = malloc(15 * sizeof(blocks1[0]));
1396 if (blocks1 == NULL || blocks2 == NULL)
1399 for (i = 0; i < 15; i++) {
1400 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1401 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1406 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1408 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1412 maxicons = g_menuscreen_h / 32;
1415 row2 = g_menuscreen_w / 2;
1416 for (i = 0; i < maxicons; i++) {
1417 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1418 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1420 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1421 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1424 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1432 static void handle_memcard_sel(void)
1435 if (memcard1_sel != 0)
1436 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1438 if (memcard2_sel != 0)
1439 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1440 LoadMcds(Config.Mcd1, Config.Mcd2);
1444 static menu_entry e_memcard_options[] =
1446 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1447 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1451 static int menu_loop_memcards(int id, int keys)
1457 memcard1_sel = memcard2_sel = 0;
1458 p = strrchr(Config.Mcd1, '/');
1460 for (i = 0; memcards[i] != NULL; i++)
1461 if (strcmp(p + 1, memcards[i]) == 0)
1462 { memcard1_sel = i; break; }
1463 p = strrchr(Config.Mcd2, '/');
1465 for (i = 0; memcards[i] != NULL; i++)
1466 if (strcmp(p + 1, memcards[i]) == 0)
1467 { memcard2_sel = i; break; }
1469 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1471 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1476 // --------- main menu help ----------
1478 static void menu_bios_warn(void)
1481 static const char msg[] =
1482 "You don't seem to have copied any BIOS\n"
1484 #ifdef __ARM_ARCH_7A__ // XXX
1485 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1487 "pcsx_rearmed/bios/\n\n"
1489 "While many games work fine with fake\n"
1490 "(HLE) BIOS, others (like MGS and FF8)\n"
1491 "require BIOS to work.\n"
1492 "After copying the file, you'll also need\n"
1493 "to select it in the emu's menu:\n"
1494 "options->[BIOS/Plugins]\n\n"
1495 "The file is usually named SCPH1001.BIN,\n"
1496 "but other not compressed files can be\n"
1498 "Press (B) or (X) to continue";
1502 draw_menu_message(msg, NULL);
1504 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1505 if (inp & (PBTN_MBACK|PBTN_MOK))
1510 // ------------ main menu ------------
1514 static void draw_frame_main(void)
1521 if (CdromId[0] != 0) {
1522 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1523 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1524 Config.HLE ? "HLE" : "BIOS");
1525 smalltext_out16(4, 1, buff, 0x105f);
1530 tmp = localtime(<ime);
1531 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1532 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1533 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1537 static void draw_frame_credits(void)
1539 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1542 static const char credits_text[] =
1544 "(C) 1999-2003 PCSX Team\n"
1545 "(C) 2005-2009 PCSX-df Team\n"
1546 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1547 "GPU and SPU code by Pete Bernert\n"
1548 " and the P.E.Op.S. team\n"
1549 "ARM recompiler (C) 2009-2011 Ari64\n"
1550 "PCSX4ALL plugins by PCSX4ALL team\n"
1551 " Chui, Franxis, Unai\n\n"
1552 "integration, optimization and\n"
1553 " frontend (C) 2010-2011 notaz\n";
1555 static int reset_game(void)
1558 if (bios_sel == 0 && !Config.HLE)
1564 if (CheckCdrom() != -1) {
1570 static int reload_plugins(const char *cdimg)
1576 set_cd_image(cdimg);
1578 pcnt_hook_plugins();
1580 if (OpenPlugins() == -1) {
1581 me_update_msg("failed to open plugins");
1584 plugin_call_rearmed_cbs();
1586 cdrIsoMultidiskCount = 1;
1588 CdromLabel[0] = '\0';
1593 static int run_bios(void)
1599 if (reload_plugins(NULL) != 0)
1607 static int run_exe(void)
1611 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1616 if (reload_plugins(NULL) != 0)
1620 if (Load(fname) != 0) {
1621 me_update_msg("exe load failed, bad file?");
1630 static int run_cd_image(const char *fname)
1633 reload_plugins(fname);
1635 // always autodetect, menu_sync_config will override as needed
1638 if (CheckCdrom() == -1) {
1639 // Only check the CD if we are starting the console with a CD
1641 me_update_msg("unsupported/invalid CD image");
1647 // Read main executable directly from CDRom and start it
1648 if (LoadCdrom() == -1) {
1650 me_update_msg("failed to load CD image");
1655 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1660 static int romsel_run(void)
1662 int prev_gpu, prev_spu;
1665 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1669 printf("selected file: %s\n", fname);
1671 new_dynarec_clear_full();
1673 if (run_cd_image(fname) != 0)
1676 prev_gpu = gpu_plugsel;
1677 prev_spu = spu_plugsel;
1678 if (menu_load_config(1) != 0)
1679 menu_load_config(0);
1681 // check for plugin changes, have to repeat
1682 // loading if game config changed plugins to reload them
1683 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1684 printf("plugin change detected, reloading plugins..\n");
1685 if (run_cd_image(fname) != 0)
1690 printf("note: running without BIOS, expect compatibility problems\n");
1692 strcpy(last_selected_fname, rom_fname_reload);
1696 static int swap_cd_image(void)
1700 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1704 printf("selected file: %s\n", fname);
1707 CdromLabel[0] = '\0';
1709 set_cd_image(fname);
1710 if (ReloadCdromPlugin() < 0) {
1711 me_update_msg("failed to load cdr plugin");
1714 if (CDR_open() < 0) {
1715 me_update_msg("failed to open cdr plugin");
1719 SetCdOpenCaseTime(time(NULL) + 2);
1722 strcpy(last_selected_fname, rom_fname_reload);
1726 static int swap_cd_multidisk(void)
1728 cdrIsoMultidiskSelect++;
1730 CdromLabel[0] = '\0';
1733 if (CDR_open() < 0) {
1734 me_update_msg("failed to open cdr plugin");
1738 SetCdOpenCaseTime(time(NULL) + 2);
1744 static int main_menu_handler(int id, int keys)
1748 case MA_MAIN_RESUME_GAME:
1752 case MA_MAIN_SAVE_STATE:
1754 return menu_loop_savestate(0);
1756 case MA_MAIN_LOAD_STATE:
1758 return menu_loop_savestate(1);
1760 case MA_MAIN_RESET_GAME:
1761 if (ready_to_go && reset_game() == 0)
1764 case MA_MAIN_LOAD_ROM:
1765 if (romsel_run() == 0)
1768 case MA_MAIN_SWAP_CD:
1769 if (swap_cd_image() == 0)
1772 case MA_MAIN_SWAP_CD_MULTI:
1773 if (swap_cd_multidisk() == 0)
1776 case MA_MAIN_RUN_BIOS:
1777 if (run_bios() == 0)
1780 case MA_MAIN_RUN_EXE:
1784 case MA_MAIN_CREDITS:
1785 draw_menu_message(credits_text, draw_frame_credits);
1786 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1792 lprintf("%s: something unknown selected\n", __FUNCTION__);
1799 static menu_entry e_menu_main2[] =
1801 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1802 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1803 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1804 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1805 mee_handler ("Memcard manager", menu_loop_memcards),
1809 static int main_menu2_handler(int id, int keys)
1813 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1814 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1815 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1817 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1820 static const char h_extra[] = "Change CD, manage memcards..\n";
1822 static menu_entry e_menu_main[] =
1826 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1827 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1828 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1829 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1830 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1831 mee_handler ("Options", menu_loop_options),
1832 mee_handler ("Controls", menu_loop_keyconfig),
1833 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1834 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1835 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1839 // ----------------------------
1841 static void menu_leave_emu(void);
1843 void menu_loop(void)
1849 if (bioses[1] == NULL && !warned_about_bios) {
1851 warned_about_bios = 1;
1854 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1855 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1856 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1857 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1859 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1862 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1863 } while (!ready_to_go);
1865 /* wait until menu, ok, back is released */
1866 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1869 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1874 static int qsort_strcmp(const void *p1, const void *p2)
1876 char * const *s1 = (char * const *)p1;
1877 char * const *s2 = (char * const *)p2;
1878 return strcasecmp(*s1, *s2);
1881 static void scan_bios_plugins(void)
1883 char fname[MAXPATHLEN];
1885 int bios_i, gpu_i, spu_i, mc_i;
1890 gpu_plugins[0] = "builtin_gpu";
1891 spu_plugins[0] = "builtin_spu";
1892 memcards[0] = "(none)";
1893 bios_i = gpu_i = spu_i = mc_i = 1;
1895 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1896 dir = opendir(fname);
1898 perror("scan_bios_plugins bios opendir");
1913 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1916 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1917 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1918 printf("bad BIOS file: %s\n", ent->d_name);
1922 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1923 bioses[bios_i++] = strdup(ent->d_name);
1927 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1933 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1934 dir = opendir(fname);
1936 perror("scan_bios_plugins plugins opendir");
1950 p = strstr(ent->d_name, ".so");
1954 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1955 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1957 fprintf(stderr, "%s\n", dlerror());
1961 // now what do we have here?
1962 tmp = dlsym(h, "GPUinit");
1965 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1966 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1970 tmp = dlsym(h, "SPUinit");
1973 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1974 spu_plugins[spu_i++] = strdup(ent->d_name);
1978 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1985 dir = opendir("." MEMCARD_DIR);
1987 perror("scan_bios_plugins memcards opendir");
2002 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2005 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2006 if (stat(fname, &st) != 0) {
2007 printf("bad memcard file: %s\n", ent->d_name);
2011 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2012 memcards[mc_i++] = strdup(ent->d_name);
2016 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2020 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2025 void menu_init(void)
2027 char buff[MAXPATHLEN];
2029 strcpy(last_selected_fname, "/media");
2031 scan_bios_plugins();
2035 menu_set_defconfig();
2036 menu_load_config(0);
2041 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2042 if (g_menubg_src_ptr == NULL)
2044 emu_make_path(buff, "skin/background.png", sizeof(buff));
2045 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2047 #ifndef __ARM_ARCH_7A__ /* XXX */
2048 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2049 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2051 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2052 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2056 void menu_notify_mode_change(int w, int h, int bpp)
2067 g_layer_w = w; g_layer_h = h;
2071 if (h > g_menuscreen_h || (240 < h && h <= 360))
2072 goto fractional_4_3;
2074 // 4:3 that prefers integer scaling
2075 imult = g_menuscreen_h / h;
2076 g_layer_w = w * imult;
2077 g_layer_h = h * imult;
2078 mult = (float)g_layer_w / (float)g_layer_h;
2079 if (mult < 1.25f || mult > 1.666f)
2080 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2081 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2086 mult = 240.0f / (float)h * 4.0f / 3.0f;
2089 g_layer_w = mult * (float)g_menuscreen_h;
2090 g_layer_h = g_menuscreen_h;
2091 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2094 case SCALE_FULLSCREEN:
2095 g_layer_w = g_menuscreen_w;
2096 g_layer_h = g_menuscreen_h;
2103 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2104 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2105 if (g_layer_x < 0) g_layer_x = 0;
2106 if (g_layer_y < 0) g_layer_y = 0;
2107 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2108 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2111 static void menu_leave_emu(void)
2113 if (GPU_close != NULL) {
2114 int ret = GPU_close();
2116 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2119 plat_video_menu_enter(ready_to_go);
2121 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2122 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2123 int x = max(0, g_menuscreen_w - last_psx_w);
2124 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2125 int w = min(g_menuscreen_w, last_psx_w);
2126 int h = min(g_menuscreen_h, last_psx_h);
2127 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2128 u16 *s = pl_vout_buf;
2130 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2131 menu_darken_bg(d, s, w, 0);
2135 cpu_clock = plat_cpu_clock_get();
2138 void menu_prepare_emu(void)
2140 R3000Acpu *prev_cpu = psxCpu;
2142 plat_video_menu_leave();
2144 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2146 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2147 if (psxCpu != prev_cpu)
2148 // note that this does not really reset, just clears drc caches
2151 // core doesn't care about Config.Cdda changes,
2152 // so handle them manually here
2157 apply_lcdrate(Config.PsxType);
2158 apply_filter(filter);
2159 plat_cpu_clock_apply(cpu_clock);
2161 // push config to GPU plugin
2162 plugin_call_rearmed_cbs();
2164 if (GPU_open != NULL) {
2165 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2167 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2173 void me_update_msg(const char *msg)
2175 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2176 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2178 menu_error_time = plat_get_ticks_ms();
2179 lprintf("msg: %s\n", menu_error_msg);