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;
80 static int memcard1_sel, memcard2_sel;
81 int g_opts, analog_deadzone;
84 extern int iUseReverb;
85 extern int iUseInterpolation;
87 extern int iSPUIRQWait;
91 static const char *bioses[24];
92 static const char *gpu_plugins[16];
93 static const char *spu_plugins[16];
94 static const char *memcards[32];
95 static int bios_sel, gpu_plugsel, spu_plugsel;
98 static int min(int x, int y) { return x < y ? x : y; }
99 static int max(int x, int y) { return x > y ? x : y; }
101 void emu_make_path(char *buff, const char *end, int size)
105 end_len = strlen(end);
106 pos = plat_get_root_dir(buff, size);
107 strncpy(buff + pos, end, size - pos);
109 if (pos + end_len > size - 1)
110 printf("Warning: path truncated: %s\n", buff);
113 static int emu_check_save_file(int slot)
115 int ret = emu_check_state(slot);
116 return ret == 0 ? 1 : 0;
119 static int emu_save_load_game(int load, int unused)
124 ret = emu_load_state(state_slot);
126 // reflect hle/bios mode from savestate
129 else if (bios_sel == 0 && bioses[1] != NULL)
130 // XXX: maybe find the right bios instead
134 ret = emu_save_state(state_slot);
139 // propagate menu settings to the emu vars
140 static void menu_sync_config(void)
142 static int allow_abs_only_old;
147 Config.PsxType = region - 1;
149 switch (in_type_sel1) {
150 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
151 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
152 default: in_type1 = PSE_PAD_TYPE_STANDARD;
154 switch (in_type_sel2) {
155 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
156 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
157 default: in_type2 = PSE_PAD_TYPE_STANDARD;
159 if (in_evdev_allow_abs_only != allow_abs_only_old) {
160 plat_rescan_inputs();
161 allow_abs_only_old = in_evdev_allow_abs_only;
164 iVolume = 768 + 128 * volume_boost;
165 pl_rearmed_cbs.frameskip = frameskip - 1;
166 pl_timing_prepare(Config.PsxType);
169 static void menu_set_defconfig(void)
175 analog_deadzone = 70;
178 in_type_sel1 = in_type_sel2 = 0;
179 in_evdev_allow_abs_only = 0;
180 Config.Xa = Config.Cdda = Config.Sio =
181 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
182 Config.CdrReschedule = 0;
184 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
185 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
186 pl_rearmed_cbs.gpu_unai.abe_hack =
187 pl_rearmed_cbs.gpu_unai.no_light =
188 pl_rearmed_cbs.gpu_unai.no_blend = 0;
191 iUseInterpolation = 1;
195 #ifndef __ARM_ARCH_7A__ /* XXX */
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),
273 static char *get_cd_label(void)
275 static char trimlabel[33];
278 strncpy(trimlabel, CdromLabel, 32);
280 for (j = 31; j >= 0; j--)
281 if (trimlabel[j] == ' ')
287 static void make_cfg_fname(char *buf, size_t size, int is_game)
290 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
292 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
295 static void keys_write_all(FILE *f);
297 static int menu_write_config(int is_game)
299 char cfgfile[MAXPATHLEN];
303 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
304 f = fopen(cfgfile, "w");
306 printf("menu_write_config: failed to open: %s\n", cfgfile);
310 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
311 fprintf(f, "%s = ", config_data[i].name);
312 switch (config_data[i].len) {
314 fprintf(f, "%s\n", (char *)config_data[i].val);
317 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
320 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
323 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
326 printf("menu_write_config: unhandled len %d for %s\n",
327 config_data[i].len, config_data[i].name);
333 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
341 static void parse_str_val(char *cval, const char *src)
344 strncpy(cval, src, MAXPATHLEN);
345 cval[MAXPATHLEN - 1] = 0;
346 tmp = strchr(cval, '\n');
348 tmp = strchr(cval, '\r');
353 static void keys_load_all(const char *cfg);
355 static int menu_load_config(int is_game)
357 char cfgfile[MAXPATHLEN];
363 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
364 f = fopen(cfgfile, "r");
366 printf("menu_load_config: failed to open: %s\n", cfgfile);
370 fseek(f, 0, SEEK_END);
373 printf("bad size %ld: %s\n", size, cfgfile);
377 cfg = malloc(size + 1);
381 fseek(f, 0, SEEK_SET);
382 if (fread(cfg, 1, size, f) != size) {
383 printf("failed to read: %s\n", cfgfile);
388 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
392 tmp = strstr(cfg, config_data[i].name);
395 tmp += strlen(config_data[i].name);
396 if (strncmp(tmp, " = ", 3) != 0)
400 if (config_data[i].len == 0) {
401 parse_str_val(config_data[i].val, tmp);
406 val = strtoul(tmp, &tmp2, 16);
407 if (tmp2 == NULL || tmp == tmp2)
408 continue; // parse failed
410 switch (config_data[i].len) {
412 *(u8 *)config_data[i].val = val;
415 *(u16 *)config_data[i].val = val;
418 *(u32 *)config_data[i].val = val;
421 printf("menu_load_config: unhandled len %d for %s\n",
422 config_data[i].len, config_data[i].name);
428 char *tmp = strstr(cfg, "lastcdimg = ");
431 parse_str_val(last_selected_fname, tmp);
438 for (i = bios_sel = 0; bioses[i] != NULL; i++)
439 if (strcmp(Config.Bios, bioses[i]) == 0)
440 { bios_sel = i; break; }
442 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
443 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
444 { gpu_plugsel = i; break; }
446 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
447 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
448 { 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", ".bz", ".znx", ".pbp" };
463 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
464 const char *ext = strrchr(fname, '.');
469 for (i = 0; i < array_size(cdimg_exts); i++)
470 if (strcasecmp(ext, cdimg_exts[i]) == 0)
472 for (i = 0; i < array_size(other_exts); i++)
473 if (strcasecmp(ext, other_exts[i]) == 0)
478 static void draw_savestate_bg(int slot);
480 static const char *filter_exts[] = {
481 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
484 #define MENU_ALIGN_LEFT
485 #ifdef __ARM_ARCH_7A__ // assume hires device
491 #define menu_init menu_init_common
492 #include "common/menu.c"
495 // a bit of black magic here
496 static void draw_savestate_bg(int slot)
498 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
500 char fname[MAXPATHLEN];
507 ret = get_state_filename(fname, sizeof(fname), slot);
511 f = gzopen(fname, "rb");
515 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
516 fprintf(stderr, "gzseek failed\n");
521 gpu = malloc(sizeof(*gpu));
527 ret = gzread(f, gpu, sizeof(*gpu));
529 if (ret != sizeof(*gpu)) {
530 fprintf(stderr, "gzread failed\n");
534 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
536 if (gpu->ulStatus & 0x800000)
537 goto out; // disabled
539 x = gpu->ulControl[5] & 0x3ff;
540 y = (gpu->ulControl[5] >> 10) & 0x1ff;
541 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
542 w = psx_widths[(gpu->ulStatus >> 16) & 7];
543 tmp = gpu->ulControl[7];
544 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
545 if (gpu->ulStatus & 0x80000) // doubleheight
548 x = max(0, g_menuscreen_w - w) & ~3;
549 y = max(0, g_menuscreen_h / 2 - h / 2);
550 w = min(g_menuscreen_w, w);
551 h = min(g_menuscreen_h, h);
552 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
554 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
555 if (gpu->ulStatus & 0x200000)
556 bgr888_to_rgb565(d, s, w * 3);
558 bgr555_to_rgb565(d, s, w * 2);
559 #ifndef __ARM_ARCH_7A__
560 // better darken this on small screens
561 menu_darken_bg(d, d, w * 2, 0);
569 // ---------- XXX: pandora specific -----------
571 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
572 static char **pnd_filter_list;
574 static void apply_filter(int which)
580 if (pnd_filter_list == NULL || which == old)
583 for (i = 0; i < which; i++)
584 if (pnd_filter_list[i] == NULL)
587 if (pnd_filter_list[i] == NULL)
590 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
595 static void apply_lcdrate(int pal)
603 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
604 pnd_script_base, pal ? 50 : 60);
609 static menu_entry e_menu_gfx_options[];
611 static void pnd_menu_init(void)
619 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
621 dir = opendir("/etc/pandora/conf/dss_fir");
623 perror("filter opendir");
636 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
645 mfilters = calloc(count + 1, sizeof(mfilters[0]));
646 if (mfilters == NULL)
650 for (i = 0; (ent = readdir(dir)); ) {
653 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
656 len = strlen(ent->d_name);
658 // skip pre-HF5 extra files
659 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
661 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
664 // have to cut "_up_h" for pre-HF5
665 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
668 if (len > sizeof(buff) - 1)
671 strncpy(buff, ent->d_name, len);
673 mfilters[i] = strdup(buff);
674 if (mfilters[i] != NULL)
679 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
680 e_menu_gfx_options[i].data = (void *)mfilters;
681 pnd_filter_list = mfilters;
684 void menu_finish(void)
686 plat_cpu_clock_apply(cpu_clock_st);
689 // -------------- key config --------------
691 me_bind_action me_ctrl_actions[] =
693 { "UP ", 1 << DKEY_UP},
694 { "DOWN ", 1 << DKEY_DOWN },
695 { "LEFT ", 1 << DKEY_LEFT },
696 { "RIGHT ", 1 << DKEY_RIGHT },
697 { "TRIANGLE", 1 << DKEY_TRIANGLE },
698 { "CIRCLE ", 1 << DKEY_CIRCLE },
699 { "CROSS ", 1 << DKEY_CROSS },
700 { "SQUARE ", 1 << DKEY_SQUARE },
701 { "L1 ", 1 << DKEY_L1 },
702 { "R1 ", 1 << DKEY_R1 },
703 { "L2 ", 1 << DKEY_L2 },
704 { "R2 ", 1 << DKEY_R2 },
705 { "L3 ", 1 << DKEY_L3 },
706 { "R3 ", 1 << DKEY_R3 },
707 { "START ", 1 << DKEY_START },
708 { "SELECT ", 1 << DKEY_SELECT },
712 me_bind_action emuctrl_actions[] =
714 { "Save State ", 1 << SACTION_SAVE_STATE },
715 { "Load State ", 1 << SACTION_LOAD_STATE },
716 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
717 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
718 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
719 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
720 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
721 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
722 { "Gun A button ", 1 << SACTION_GUN_A },
723 { "Gun B button ", 1 << SACTION_GUN_B },
724 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
728 static char *mystrip(char *str)
733 for (i = 0; i < len; i++)
734 if (str[i] != ' ') break;
735 if (i > 0) memmove(str, str + i, len - i + 1);
738 for (i = len - 1; i >= 0; i--)
739 if (str[i] != ' ') break;
745 static void get_line(char *d, size_t size, const char *s)
750 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
761 static void keys_write_all(FILE *f)
765 for (d = 0; d < IN_MAX_DEVS; d++)
767 const int *binds = in_get_dev_binds(d);
768 const char *name = in_get_dev_name(d, 0, 0);
771 if (binds == NULL || name == NULL)
774 fprintf(f, "binddev = %s\n", name);
775 in_get_config(d, IN_CFG_BIND_COUNT, &count);
777 for (k = 0; k < count; k++)
782 act[0] = act[31] = 0;
783 name = in_get_key_name(d, k);
785 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
786 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
787 mask = me_ctrl_actions[i].mask;
789 strncpy(act, me_ctrl_actions[i].name, 31);
790 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
793 mask = me_ctrl_actions[i].mask << 16;
795 strncpy(act, me_ctrl_actions[i].name, 31);
796 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
801 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
802 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
803 mask = emuctrl_actions[i].mask;
805 strncpy(act, emuctrl_actions[i].name, 31);
806 fprintf(f, "bind %s = %s\n", name, mystrip(act));
814 static int parse_bind_val(const char *val, int *type)
818 *type = IN_BINDTYPE_NONE;
822 if (strncasecmp(val, "player", 6) == 0)
824 int player, shift = 0;
825 player = atoi(val + 6) - 1;
827 if ((unsigned int)player > 1)
832 *type = IN_BINDTYPE_PLAYER12;
833 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
834 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
835 return me_ctrl_actions[i].mask << shift;
838 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
839 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
840 *type = IN_BINDTYPE_EMU;
841 return emuctrl_actions[i].mask;
848 static void keys_load_all(const char *cfg)
850 char dev[256], key[128], *act;
856 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
859 get_line(dev, sizeof(dev), p);
860 dev_id = in_config_parse_dev(dev);
862 printf("input: can't handle dev: %s\n", dev);
866 in_unbind_all(dev_id, -1, -1);
867 while ((p = strstr(p, "bind"))) {
868 if (strncmp(p, "binddev = ", 10) == 0)
873 printf("input: parse error: %16s..\n", p);
877 get_line(key, sizeof(key), p);
878 act = strchr(key, '=');
880 printf("parse failed: %16s..\n", p);
888 bind = parse_bind_val(act, &bindtype);
889 if (bind != -1 && bind != 0) {
890 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
891 in_config_bind_key(dev_id, key, bind, bindtype);
894 lprintf("config: unhandled action \"%s\"\n", act);
900 static int key_config_loop_wrap(int id, int keys)
903 case MA_CTRL_PLAYER1:
904 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
906 case MA_CTRL_PLAYER2:
907 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
910 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
918 static const char *mgn_dev_name(int id, int *offs)
920 const char *name = NULL;
923 if (id == MA_CTRL_DEV_FIRST)
926 for (; it < IN_MAX_DEVS; it++) {
927 name = in_get_dev_name(it, 1, 1);
936 static const char *mgn_saveloadcfg(int id, int *offs)
941 static int mh_savecfg(int id, int keys)
943 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
944 me_update_msg("config saved");
946 me_update_msg("failed to write config");
951 static int mh_input_rescan(int id, int keys)
953 //menu_sync_config();
954 plat_rescan_inputs();
955 me_update_msg("rescan complete.");
960 static const char *men_in_type_sel[] = {
961 "Standard (SCPH-1080)",
962 "Analog (SCPH-1150)",
966 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
967 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
969 static menu_entry e_menu_keyconfig[] =
971 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
972 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
973 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
975 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
976 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
977 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
978 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
979 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
980 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
981 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
982 mee_handler ("Rescan devices", mh_input_rescan),
984 mee_label ("Input devices:"),
985 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
986 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
987 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
988 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
989 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
990 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
991 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
995 static int menu_loop_keyconfig(int id, int keys)
999 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1000 me_loop(e_menu_keyconfig, &sel);
1004 // ------------ gfx options menu ------------
1006 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1007 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1008 "using d-pad or move it using R+d-pad";
1009 static const char *men_dummy[] = { NULL };
1011 static int menu_loop_cscaler(int id, int keys)
1015 scaling = SCALE_CUSTOM;
1017 omap_enable_layer(1);
1022 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1023 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1024 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1027 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1028 if (inp & PBTN_UP) g_layer_y--;
1029 if (inp & PBTN_DOWN) g_layer_y++;
1030 if (inp & PBTN_LEFT) g_layer_x--;
1031 if (inp & PBTN_RIGHT) g_layer_x++;
1032 if (!(inp & PBTN_R)) {
1033 if (inp & PBTN_UP) g_layer_h += 2;
1034 if (inp & PBTN_DOWN) g_layer_h -= 2;
1035 if (inp & PBTN_LEFT) g_layer_w += 2;
1036 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1038 if (inp & (PBTN_MOK|PBTN_MBACK))
1041 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1042 if (g_layer_x < 0) g_layer_x = 0;
1043 if (g_layer_x > 640) g_layer_x = 640;
1044 if (g_layer_y < 0) g_layer_y = 0;
1045 if (g_layer_y > 420) g_layer_y = 420;
1046 if (g_layer_w < 160) g_layer_w = 160;
1047 if (g_layer_h < 60) g_layer_h = 60;
1048 if (g_layer_x + g_layer_w > 800)
1049 g_layer_w = 800 - g_layer_x;
1050 if (g_layer_y + g_layer_h > 480)
1051 g_layer_h = 480 - g_layer_y;
1052 omap_enable_layer(1);
1056 omap_enable_layer(0);
1061 static menu_entry e_menu_gfx_options[] =
1063 mee_enum ("Scaler", 0, scaling, men_scaler),
1064 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1065 // mee_onoff ("Vsync", 0, vsync, 1),
1066 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1070 static int menu_loop_gfx_options(int id, int keys)
1074 me_loop(e_menu_gfx_options, &sel);
1079 // ------------ bios/plugins ------------
1081 static menu_entry e_menu_plugin_gpu_unai[] =
1083 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1084 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1085 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1089 static int menu_loop_plugin_gpu_unai(int id, int keys)
1092 me_loop(e_menu_plugin_gpu_unai, &sel);
1096 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1097 static const char h_gpu_0[] = "Needed for Chrono Cross";
1098 static const char h_gpu_1[] = "Capcom fighting games";
1099 static const char h_gpu_2[] = "Black screens in Lunar";
1100 static const char h_gpu_3[] = "Compatibility mode";
1101 static const char h_gpu_6[] = "Pandemonium 2";
1102 static const char h_gpu_7[] = "Skip every second frame";
1103 static const char h_gpu_8[] = "Needed by Dark Forces";
1104 static const char h_gpu_9[] = "better g-colors, worse textures";
1105 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1107 static menu_entry e_menu_plugin_gpu_peops[] =
1109 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1110 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1111 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1112 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1113 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1114 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1115 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1116 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1117 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1118 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1122 static int menu_loop_plugin_gpu_peops(int id, int keys)
1125 me_loop(e_menu_plugin_gpu_peops, &sel);
1129 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1130 static const char h_spu_volboost[] = "Large values cause distortion";
1131 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1132 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1134 static menu_entry e_menu_plugin_spu[] =
1136 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1137 mee_onoff ("Reverb", 0, iUseReverb, 2),
1138 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1139 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1140 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1141 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1145 static int menu_loop_plugin_spu(int id, int keys)
1148 me_loop(e_menu_plugin_spu, &sel);
1152 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1153 "savestates and can't be changed there. Must save\n"
1154 "config and reload the game for change to take effect";
1155 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1156 "for plugin change to take effect";
1157 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1158 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1159 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1161 static menu_entry e_menu_plugin_options[] =
1163 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1164 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1165 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1166 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1167 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1168 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1172 static menu_entry e_menu_main2[];
1174 static int menu_loop_plugin_options(int id, int keys)
1177 me_loop(e_menu_plugin_options, &sel);
1179 // sync BIOS/plugins
1180 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1181 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1182 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1183 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1188 // ------------ adv options menu ------------
1190 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1191 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1192 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1193 "(green: normal, red: fmod, blue: noise)";
1194 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1195 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1196 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1197 "(proper .cue/.bin dump is needed otherwise)";
1198 static const char h_cfg_sio[] = "You should not need this, breaks games";
1199 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1200 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1201 "(timing hack, breaks other games)";
1202 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1203 "(timing hack, breaks other games)";
1204 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1205 "(CD timing hack, breaks FMVs)";
1206 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1207 "Might be useful to overcome some dynarec bugs";
1209 static menu_entry e_menu_adv_options[] =
1211 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1212 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1213 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1214 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1215 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1216 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1217 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1218 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1219 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1220 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1221 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1225 static int menu_loop_adv_options(int id, int keys)
1228 me_loop(e_menu_adv_options, &sel);
1232 // ------------ options menu ------------
1234 static int mh_restore_defaults(int id, int keys)
1236 menu_set_defconfig();
1237 me_update_msg("defaults restored");
1241 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1242 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1244 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1245 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1246 "loading state or both";
1248 static const char h_restore_def[] = "Switches back to default / recommended\n"
1250 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1252 static menu_entry e_menu_options[] =
1254 // mee_range ("Save slot", 0, state_slot, 0, 9),
1255 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1256 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1257 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1258 mee_enum ("Region", 0, region, men_region),
1259 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1260 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1261 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1262 mee_handler ("[Advanced]", menu_loop_adv_options),
1263 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1264 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1265 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1269 static int menu_loop_options(int id, int keys)
1274 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1275 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1276 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1278 me_loop(e_menu_options, &sel);
1283 // ------------ debug menu ------------
1285 static void draw_frame_debug(GPUFreeze_t *gpuf)
1287 int w = min(g_menuscreen_w, 1024);
1288 int h = min(g_menuscreen_h, 512);
1289 u16 *d = g_menuscreen_ptr;
1290 u16 *s = (u16 *)gpuf->psxVRam;
1294 gpuf->ulFreezeVersion = 1;
1295 if (GPU_freeze != NULL)
1296 GPU_freeze(1, gpuf);
1298 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1299 bgr555_to_rgb565(d, s, w * 2);
1301 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1302 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1303 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1304 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1305 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1308 static void debug_menu_loop(void)
1313 gpuf = malloc(sizeof(*gpuf));
1320 draw_frame_debug(gpuf);
1323 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1324 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1325 if (inp & PBTN_MBACK)
1332 // --------- memcard manager ---------
1334 static void draw_mc_icon(int dx, int dy, const u16 *s)
1339 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1341 for (y = 0; y < 16; y++, s += 16) {
1342 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1343 for (x = 0; x < 16; x++) {
1345 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1346 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1352 static void draw_mc_bg(void)
1354 McdBlock *blocks1, *blocks2;
1358 blocks1 = malloc(15 * sizeof(blocks1[0]));
1359 blocks2 = malloc(15 * sizeof(blocks1[0]));
1360 if (blocks1 == NULL || blocks2 == NULL)
1363 for (i = 0; i < 15; i++) {
1364 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1365 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1370 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1372 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1376 maxicons = g_menuscreen_h / 32;
1379 row2 = g_menuscreen_w / 2;
1380 for (i = 0; i < maxicons; i++) {
1381 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1382 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1384 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1385 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1388 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1396 static void handle_memcard_sel(void)
1399 if (memcard1_sel != 0)
1400 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1402 if (memcard2_sel != 0)
1403 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1404 LoadMcds(Config.Mcd1, Config.Mcd2);
1408 static menu_entry e_memcard_options[] =
1410 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1411 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1415 static int menu_loop_memcards(int id, int keys)
1421 memcard1_sel = memcard2_sel = 0;
1422 p = strrchr(Config.Mcd1, '/');
1424 for (i = 0; memcards[i] != NULL; i++)
1425 if (strcmp(p + 1, memcards[i]) == 0)
1426 { memcard1_sel = i; break; }
1427 p = strrchr(Config.Mcd2, '/');
1429 for (i = 0; memcards[i] != NULL; i++)
1430 if (strcmp(p + 1, memcards[i]) == 0)
1431 { memcard2_sel = i; break; }
1433 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1435 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1440 // --------- main menu help ----------
1442 static void menu_bios_warn(void)
1445 static const char msg[] =
1446 "You don't seem to have copied any BIOS files to\n"
1447 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1448 "While many games work fine with fake (HLE) BIOS,\n"
1449 "others (like MGS and FF8) require BIOS to work.\n"
1450 "After copying the file, you'll also need to\n"
1451 "select it in the emu's options->[BIOS/Plugins]\n\n"
1452 "The file is usually named SCPH1001.BIN, but\n"
1453 "other not compressed files can be used too.\n\n"
1454 "Press (B) or (X) to continue";
1458 draw_menu_message(msg, NULL);
1460 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1461 if (inp & (PBTN_MBACK|PBTN_MOK))
1466 // ------------ main menu ------------
1470 static void draw_frame_main(void)
1477 if (CdromId[0] != 0) {
1478 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1479 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1480 Config.HLE ? "HLE" : "BIOS");
1481 smalltext_out16(4, 1, buff, 0x105f);
1486 tmp = localtime(<ime);
1487 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1488 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1489 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1493 static void draw_frame_credits(void)
1495 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1498 static const char credits_text[] =
1500 "(C) 1999-2003 PCSX Team\n"
1501 "(C) 2005-2009 PCSX-df Team\n"
1502 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1503 "GPU and SPU code by Pete Bernert\n"
1504 " and the P.E.Op.S. team\n"
1505 "ARM recompiler (C) 2009-2011 Ari64\n"
1506 "PCSX4ALL plugins by PCSX4ALL team\n"
1507 " Chui, Franxis, Unai\n\n"
1508 "integration, optimization and\n"
1509 " frontend (C) 2010-2011 notaz\n";
1511 static int reset_game(void)
1514 if (bios_sel == 0 && !Config.HLE)
1520 if (CheckCdrom() != -1) {
1526 static int reload_plugins(const char *cdimg)
1532 set_cd_image(cdimg);
1534 pcnt_hook_plugins();
1536 if (OpenPlugins() == -1) {
1537 me_update_msg("failed to open plugins");
1540 plugin_call_rearmed_cbs();
1543 CdromLabel[0] = '\0';
1548 static int run_bios(void)
1554 if (reload_plugins(NULL) != 0)
1562 static int run_exe(void)
1566 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1571 if (reload_plugins(NULL) != 0)
1575 if (Load(fname) != 0) {
1576 me_update_msg("exe load failed, bad file?");
1585 static int run_cd_image(const char *fname)
1588 reload_plugins(fname);
1590 // always autodetect, menu_sync_config will override as needed
1593 if (CheckCdrom() == -1) {
1594 // Only check the CD if we are starting the console with a CD
1596 me_update_msg("unsupported/invalid CD image");
1602 // Read main executable directly from CDRom and start it
1603 if (LoadCdrom() == -1) {
1605 me_update_msg("failed to load CD image");
1613 static int romsel_run(void)
1615 int prev_gpu, prev_spu;
1618 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1622 printf("selected file: %s\n", fname);
1624 new_dynarec_clear_full();
1626 if (run_cd_image(fname) != 0)
1629 prev_gpu = gpu_plugsel;
1630 prev_spu = spu_plugsel;
1631 if (menu_load_config(1) != 0)
1632 menu_load_config(0);
1634 // check for plugin changes, have to repeat
1635 // loading if game config changed plugins to reload them
1636 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1637 printf("plugin change detected, reloading plugins..\n");
1638 if (run_cd_image(fname) != 0)
1642 strcpy(last_selected_fname, rom_fname_reload);
1646 static int swap_cd_image(void)
1650 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1654 printf("selected file: %s\n", fname);
1657 CdromLabel[0] = '\0';
1659 set_cd_image(fname);
1660 if (ReloadCdromPlugin() < 0) {
1661 me_update_msg("failed to load cdr plugin");
1664 if (CDR_open() < 0) {
1665 me_update_msg("failed to open cdr plugin");
1669 SetCdOpenCaseTime(time(NULL) + 2);
1672 strcpy(last_selected_fname, rom_fname_reload);
1676 static int main_menu_handler(int id, int keys)
1680 case MA_MAIN_RESUME_GAME:
1684 case MA_MAIN_SAVE_STATE:
1686 return menu_loop_savestate(0);
1688 case MA_MAIN_LOAD_STATE:
1690 return menu_loop_savestate(1);
1692 case MA_MAIN_RESET_GAME:
1693 if (ready_to_go && reset_game() == 0)
1696 case MA_MAIN_LOAD_ROM:
1697 if (romsel_run() == 0)
1700 case MA_MAIN_SWAP_CD:
1701 if (swap_cd_image() == 0)
1704 case MA_MAIN_RUN_BIOS:
1705 if (run_bios() == 0)
1708 case MA_MAIN_RUN_EXE:
1712 case MA_MAIN_CREDITS:
1713 draw_menu_message(credits_text, draw_frame_credits);
1714 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1720 lprintf("%s: something unknown selected\n", __FUNCTION__);
1727 static menu_entry e_menu_main2[] =
1729 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1730 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1731 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1732 mee_handler ("Memcard manager", menu_loop_memcards),
1736 static int main_menu2_handler(int id, int keys)
1740 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1741 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1743 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1746 static const char h_extra[] = "Change CD, manage memcards..\n";
1748 static menu_entry e_menu_main[] =
1752 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1753 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1754 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1755 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1756 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1757 mee_handler ("Options", menu_loop_options),
1758 mee_handler ("Controls", menu_loop_keyconfig),
1759 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1760 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1761 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1765 // ----------------------------
1767 static void menu_leave_emu(void);
1769 void menu_loop(void)
1775 if (bioses[1] == NULL && !warned_about_bios) {
1777 warned_about_bios = 1;
1780 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1781 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1782 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1783 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1785 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1788 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1789 } while (!ready_to_go);
1791 /* wait until menu, ok, back is released */
1792 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1795 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1800 static int qsort_strcmp(const void *p1, const void *p2)
1802 char * const *s1 = (char * const *)p1;
1803 char * const *s2 = (char * const *)p2;
1804 return strcasecmp(*s1, *s2);
1807 static void scan_bios_plugins(void)
1809 char fname[MAXPATHLEN];
1811 int bios_i, gpu_i, spu_i, mc_i;
1816 gpu_plugins[0] = "builtin_gpu";
1817 spu_plugins[0] = "builtin_spu";
1818 memcards[0] = "(none)";
1819 bios_i = gpu_i = spu_i = mc_i = 1;
1821 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1822 dir = opendir(fname);
1824 perror("scan_bios_plugins bios opendir");
1839 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1842 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1843 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1844 printf("bad BIOS file: %s\n", ent->d_name);
1848 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1849 bioses[bios_i++] = strdup(ent->d_name);
1853 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1859 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1860 dir = opendir(fname);
1862 perror("scan_bios_plugins plugins opendir");
1876 p = strstr(ent->d_name, ".so");
1880 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1881 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1883 fprintf(stderr, "%s\n", dlerror());
1887 // now what do we have here?
1888 tmp = dlsym(h, "GPUinit");
1891 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1892 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1896 tmp = dlsym(h, "SPUinit");
1899 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1900 spu_plugins[spu_i++] = strdup(ent->d_name);
1904 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1911 dir = opendir("." MEMCARD_DIR);
1913 perror("scan_bios_plugins memcards opendir");
1928 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1931 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1932 if (stat(fname, &st) != 0) {
1933 printf("bad memcard file: %s\n", ent->d_name);
1937 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1938 memcards[mc_i++] = strdup(ent->d_name);
1942 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1946 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1951 void menu_init(void)
1953 char buff[MAXPATHLEN];
1955 strcpy(last_selected_fname, "/media");
1957 scan_bios_plugins();
1961 menu_set_defconfig();
1962 menu_load_config(0);
1967 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1968 if (g_menubg_src_ptr == NULL)
1970 emu_make_path(buff, "skin/background.png", sizeof(buff));
1971 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1973 #ifndef __ARM_ARCH_7A__ /* XXX */
1974 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
1975 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
1977 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
1981 void menu_notify_mode_change(int w, int h, int bpp)
1992 g_layer_w = w; g_layer_h = h;
1996 mult = 240.0f / (float)h * 4.0f / 3.0f;
1999 g_layer_w = mult * (float)g_menuscreen_h;
2000 g_layer_h = g_menuscreen_h;
2001 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2005 // 4:3 that prefers integer scaling
2006 imult = g_menuscreen_h / h;
2007 g_layer_w = w * imult;
2008 g_layer_h = h * imult;
2009 mult = (float)g_layer_w / (float)g_layer_h;
2010 if (mult < 1.25f || mult > 1.666f)
2011 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2012 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2015 case SCALE_FULLSCREEN:
2016 g_layer_w = g_menuscreen_w;
2017 g_layer_h = g_menuscreen_h;
2024 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2025 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2026 if (g_layer_x < 0) g_layer_x = 0;
2027 if (g_layer_y < 0) g_layer_y = 0;
2028 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2029 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2032 static void menu_leave_emu(void)
2034 if (GPU_close != NULL) {
2035 int ret = GPU_close();
2037 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2040 plat_video_menu_enter(ready_to_go);
2042 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2043 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2044 int x = max(0, g_menuscreen_w - last_psx_w);
2045 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2046 int w = min(g_menuscreen_w, last_psx_w);
2047 int h = min(g_menuscreen_h, last_psx_h);
2048 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2049 u16 *s = pl_vout_buf;
2051 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2052 menu_darken_bg(d, s, w, 0);
2056 cpu_clock = plat_cpu_clock_get();
2059 void menu_prepare_emu(void)
2061 R3000Acpu *prev_cpu = psxCpu;
2063 plat_video_menu_leave();
2065 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2067 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2068 if (psxCpu != prev_cpu)
2069 // note that this does not really reset, just clears drc caches
2072 // core doesn't care about Config.Cdda changes,
2073 // so handle them manually here
2078 apply_lcdrate(Config.PsxType);
2079 apply_filter(filter);
2080 plat_cpu_clock_apply(cpu_clock);
2082 // push config to GPU plugin
2083 plugin_call_rearmed_cbs();
2085 if (GPU_open != NULL) {
2086 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2088 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2094 void me_update_msg(const char *msg)
2096 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2097 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2099 menu_error_time = plat_get_ticks_ms();
2100 lprintf("msg: %s\n", menu_error_msg);