2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
21 #include "plugin_lib.h"
26 #include "common/plat.h"
27 #include "common/input.h"
28 #include "linux/in_evdev.h"
29 #include "../libpcsxcore/misc.h"
30 #include "../libpcsxcore/cdrom.h"
31 #include "../libpcsxcore/psemu_plugin_defs.h"
32 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
33 #include "../plugins/dfinput/main.h"
36 #define array_size(x) (sizeof(x) / sizeof(x[0]))
75 static int last_psx_w, last_psx_h, last_psx_bpp;
76 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
77 static char rom_fname_reload[MAXPATHLEN];
78 static char last_selected_fname[MAXPATHLEN];
79 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
81 static int memcard1_sel, memcard2_sel;
82 int g_opts, analog_deadzone;
84 #ifdef __ARM_ARCH_7A__
85 #define DEFAULT_PSX_CLOCK 57
86 #define DEFAULT_PSX_CLOCK_S "57"
88 #define DEFAULT_PSX_CLOCK 50
89 #define DEFAULT_PSX_CLOCK_S "50"
93 extern int iUseReverb;
94 extern int iUseInterpolation;
96 extern int iSPUIRQWait;
100 static const char *bioses[24];
101 static const char *gpu_plugins[16];
102 static const char *spu_plugins[16];
103 static const char *memcards[32];
104 static int bios_sel, gpu_plugsel, spu_plugsel;
107 static int min(int x, int y) { return x < y ? x : y; }
108 static int max(int x, int y) { return x > y ? x : y; }
110 void emu_make_path(char *buff, const char *end, int size)
114 end_len = strlen(end);
115 pos = plat_get_root_dir(buff, size);
116 strncpy(buff + pos, end, size - pos);
118 if (pos + end_len > size - 1)
119 printf("Warning: path truncated: %s\n", buff);
122 static int emu_check_save_file(int slot)
124 int ret = emu_check_state(slot);
125 return ret == 0 ? 1 : 0;
128 static int emu_save_load_game(int load, int unused)
133 ret = emu_load_state(state_slot);
135 // reflect hle/bios mode from savestate
138 else if (bios_sel == 0 && bioses[1] != NULL)
139 // XXX: maybe find the right bios instead
143 ret = emu_save_state(state_slot);
148 // propagate menu settings to the emu vars
149 static void menu_sync_config(void)
151 static int allow_abs_only_old;
156 Config.PsxType = region - 1;
158 cycle_multiplier = 10000 / psx_clock;
160 switch (in_type_sel1) {
161 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
162 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
163 default: in_type1 = PSE_PAD_TYPE_STANDARD;
165 switch (in_type_sel2) {
166 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
167 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
168 default: in_type2 = PSE_PAD_TYPE_STANDARD;
170 if (in_evdev_allow_abs_only != allow_abs_only_old) {
171 plat_rescan_inputs();
172 allow_abs_only_old = in_evdev_allow_abs_only;
175 iVolume = 768 + 128 * volume_boost;
176 pl_rearmed_cbs.frameskip = frameskip - 1;
177 pl_timing_prepare(Config.PsxType);
180 static void menu_set_defconfig(void)
186 analog_deadzone = 50;
187 psx_clock = DEFAULT_PSX_CLOCK;
188 new_dynarec_hacks = 0;
191 in_type_sel1 = in_type_sel2 = 0;
192 in_evdev_allow_abs_only = 0;
193 Config.Xa = Config.Cdda = Config.Sio =
194 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
195 Config.CdrReschedule = 0;
197 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
198 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
199 pl_rearmed_cbs.gpu_unai.abe_hack =
200 pl_rearmed_cbs.gpu_unai.no_light =
201 pl_rearmed_cbs.gpu_unai.no_blend = 0;
204 iUseInterpolation = 1;
208 #ifndef __ARM_ARCH_7A__ /* XXX */
210 iUseInterpolation = 0;
216 #define CE_CONFIG_STR(val) \
217 { #val, 0, Config.val }
219 #define CE_CONFIG_VAL(val) \
220 { #val, sizeof(Config.val), &Config.val }
222 #define CE_STR(val) \
225 #define CE_INTVAL(val) \
226 { #val, sizeof(val), &val }
228 #define CE_INTVAL_P(val) \
229 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
231 // 'versioned' var, used when defaults change
232 #define CE_INTVAL_V(val, ver) \
233 { #val #ver, sizeof(val), &val }
235 #define CE_INTVAL_PV(val, ver) \
236 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
238 static const struct {
246 // CE_CONFIG_STR(Cdr),
251 CE_CONFIG_VAL(Debug),
252 CE_CONFIG_VAL(PsxOut),
253 CE_CONFIG_VAL(SpuIrq),
254 CE_CONFIG_VAL(RCntFix),
255 CE_CONFIG_VAL(VSyncWA),
257 CE_CONFIG_VAL(CdrReschedule),
259 CE_INTVAL_V(scaling, 2),
260 CE_INTVAL(g_layer_x),
261 CE_INTVAL(g_layer_y),
262 CE_INTVAL(g_layer_w),
263 CE_INTVAL(g_layer_h),
265 CE_INTVAL(state_slot),
266 CE_INTVAL(cpu_clock),
268 CE_INTVAL(in_type_sel1),
269 CE_INTVAL(in_type_sel2),
270 CE_INTVAL(analog_deadzone),
271 CE_INTVAL_V(frameskip, 2),
272 CE_INTVAL_P(gpu_peops.iUseDither),
273 CE_INTVAL_P(gpu_peops.dwActFixes),
274 CE_INTVAL_P(gpu_unai.abe_hack),
275 CE_INTVAL_P(gpu_unai.no_light),
276 CE_INTVAL_P(gpu_unai.no_blend),
277 CE_INTVAL_V(iUseReverb, 3),
278 CE_INTVAL_V(iXAPitch, 3),
279 CE_INTVAL_V(iUseInterpolation, 3),
280 CE_INTVAL_V(iSPUIRQWait, 3),
281 CE_INTVAL_V(iUseTimer, 3),
282 CE_INTVAL(warned_about_bios),
283 CE_INTVAL(in_evdev_allow_abs_only),
284 CE_INTVAL(volume_boost),
285 CE_INTVAL(psx_clock),
286 CE_INTVAL(new_dynarec_hacks),
289 static char *get_cd_label(void)
291 static char trimlabel[33];
294 strncpy(trimlabel, CdromLabel, 32);
296 for (j = 31; j >= 0; j--)
297 if (trimlabel[j] == ' ')
303 static void make_cfg_fname(char *buf, size_t size, int is_game)
306 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
308 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
311 static void keys_write_all(FILE *f);
313 static int menu_write_config(int is_game)
315 char cfgfile[MAXPATHLEN];
319 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
320 f = fopen(cfgfile, "w");
322 printf("menu_write_config: failed to open: %s\n", cfgfile);
326 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
327 fprintf(f, "%s = ", config_data[i].name);
328 switch (config_data[i].len) {
330 fprintf(f, "%s\n", (char *)config_data[i].val);
333 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
336 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
339 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
342 printf("menu_write_config: unhandled len %d for %s\n",
343 config_data[i].len, config_data[i].name);
349 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
357 static void parse_str_val(char *cval, const char *src)
360 strncpy(cval, src, MAXPATHLEN);
361 cval[MAXPATHLEN - 1] = 0;
362 tmp = strchr(cval, '\n');
364 tmp = strchr(cval, '\r');
369 static void keys_load_all(const char *cfg);
371 static int menu_load_config(int is_game)
373 char cfgfile[MAXPATHLEN];
379 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
380 f = fopen(cfgfile, "r");
382 printf("menu_load_config: failed to open: %s\n", cfgfile);
386 fseek(f, 0, SEEK_END);
389 printf("bad size %ld: %s\n", size, cfgfile);
393 cfg = malloc(size + 1);
397 fseek(f, 0, SEEK_SET);
398 if (fread(cfg, 1, size, f) != size) {
399 printf("failed to read: %s\n", cfgfile);
404 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
408 tmp = strstr(cfg, config_data[i].name);
411 tmp += strlen(config_data[i].name);
412 if (strncmp(tmp, " = ", 3) != 0)
416 if (config_data[i].len == 0) {
417 parse_str_val(config_data[i].val, tmp);
422 val = strtoul(tmp, &tmp2, 16);
423 if (tmp2 == NULL || tmp == tmp2)
424 continue; // parse failed
426 switch (config_data[i].len) {
428 *(u8 *)config_data[i].val = val;
431 *(u16 *)config_data[i].val = val;
434 *(u32 *)config_data[i].val = val;
437 printf("menu_load_config: unhandled len %d for %s\n",
438 config_data[i].len, config_data[i].name);
444 char *tmp = strstr(cfg, "lastcdimg = ");
447 parse_str_val(last_selected_fname, tmp);
462 for (i = bios_sel = 0; bioses[i] != NULL; i++)
463 if (strcmp(Config.Bios, bioses[i]) == 0)
464 { bios_sel = i; break; }
466 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
467 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
468 { gpu_plugsel = i; break; }
470 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
471 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
472 { spu_plugsel = i; break; }
477 // rrrr rggg gggb bbbb
478 static unsigned short fname2color(const char *fname)
480 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
481 ".bz", ".znx", ".pbp", ".cbn" };
482 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
483 ".table", ".index", ".sbi" };
484 const char *ext = strrchr(fname, '.');
489 for (i = 0; i < array_size(cdimg_exts); i++)
490 if (strcasecmp(ext, cdimg_exts[i]) == 0)
492 for (i = 0; i < array_size(other_exts); i++)
493 if (strcasecmp(ext, other_exts[i]) == 0)
498 static void draw_savestate_bg(int slot);
500 static const char *filter_exts[] = {
501 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
504 #define MENU_ALIGN_LEFT
505 #ifdef __ARM_ARCH_7A__ // assume hires device
511 #define menu_init menu_init_common
512 #include "common/menu.c"
515 // a bit of black magic here
516 static void draw_savestate_bg(int slot)
518 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
520 char fname[MAXPATHLEN];
527 ret = get_state_filename(fname, sizeof(fname), slot);
531 f = gzopen(fname, "rb");
535 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
536 fprintf(stderr, "gzseek failed\n");
541 gpu = malloc(sizeof(*gpu));
547 ret = gzread(f, gpu, sizeof(*gpu));
549 if (ret != sizeof(*gpu)) {
550 fprintf(stderr, "gzread failed\n");
554 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
556 if (gpu->ulStatus & 0x800000)
557 goto out; // disabled
559 x = gpu->ulControl[5] & 0x3ff;
560 y = (gpu->ulControl[5] >> 10) & 0x1ff;
561 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
562 w = psx_widths[(gpu->ulStatus >> 16) & 7];
563 tmp = gpu->ulControl[7];
564 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
565 if (gpu->ulStatus & 0x80000) // doubleheight
568 x = max(0, g_menuscreen_w - w) & ~3;
569 y = max(0, g_menuscreen_h / 2 - h / 2);
570 w = min(g_menuscreen_w, w);
571 h = min(g_menuscreen_h, h);
572 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
574 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
575 if (gpu->ulStatus & 0x200000)
576 bgr888_to_rgb565(d, s, w * 3);
578 bgr555_to_rgb565(d, s, w * 2);
579 #ifndef __ARM_ARCH_7A__
580 // better darken this on small screens
581 menu_darken_bg(d, d, w * 2, 0);
589 // ---------- XXX: pandora specific -----------
591 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
592 static char **pnd_filter_list;
594 static void apply_filter(int which)
600 if (pnd_filter_list == NULL || which == old)
603 for (i = 0; i < which; i++)
604 if (pnd_filter_list[i] == NULL)
607 if (pnd_filter_list[i] == NULL)
610 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
615 static void apply_lcdrate(int pal)
623 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
624 pnd_script_base, pal ? 50 : 60);
629 static menu_entry e_menu_gfx_options[];
631 static void pnd_menu_init(void)
639 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
641 dir = opendir("/etc/pandora/conf/dss_fir");
643 perror("filter opendir");
656 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
665 mfilters = calloc(count + 1, sizeof(mfilters[0]));
666 if (mfilters == NULL)
670 for (i = 0; (ent = readdir(dir)); ) {
673 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
676 len = strlen(ent->d_name);
678 // skip pre-HF5 extra files
679 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
681 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
684 // have to cut "_up_h" for pre-HF5
685 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
688 if (len > sizeof(buff) - 1)
691 strncpy(buff, ent->d_name, len);
693 mfilters[i] = strdup(buff);
694 if (mfilters[i] != NULL)
699 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
700 e_menu_gfx_options[i].data = (void *)mfilters;
701 pnd_filter_list = mfilters;
704 void menu_finish(void)
706 plat_cpu_clock_apply(cpu_clock_st);
709 // -------------- key config --------------
711 me_bind_action me_ctrl_actions[] =
713 { "UP ", 1 << DKEY_UP},
714 { "DOWN ", 1 << DKEY_DOWN },
715 { "LEFT ", 1 << DKEY_LEFT },
716 { "RIGHT ", 1 << DKEY_RIGHT },
717 { "TRIANGLE", 1 << DKEY_TRIANGLE },
718 { "CIRCLE ", 1 << DKEY_CIRCLE },
719 { "CROSS ", 1 << DKEY_CROSS },
720 { "SQUARE ", 1 << DKEY_SQUARE },
721 { "L1 ", 1 << DKEY_L1 },
722 { "R1 ", 1 << DKEY_R1 },
723 { "L2 ", 1 << DKEY_L2 },
724 { "R2 ", 1 << DKEY_R2 },
725 { "L3 ", 1 << DKEY_L3 },
726 { "R3 ", 1 << DKEY_R3 },
727 { "START ", 1 << DKEY_START },
728 { "SELECT ", 1 << DKEY_SELECT },
732 me_bind_action emuctrl_actions[] =
734 { "Save State ", 1 << SACTION_SAVE_STATE },
735 { "Load State ", 1 << SACTION_LOAD_STATE },
736 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
737 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
738 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
739 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
740 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
741 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
742 { "Gun A button ", 1 << SACTION_GUN_A },
743 { "Gun B button ", 1 << SACTION_GUN_B },
744 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
748 static char *mystrip(char *str)
753 for (i = 0; i < len; i++)
754 if (str[i] != ' ') break;
755 if (i > 0) memmove(str, str + i, len - i + 1);
758 for (i = len - 1; i >= 0; i--)
759 if (str[i] != ' ') break;
765 static void get_line(char *d, size_t size, const char *s)
770 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
781 static void keys_write_all(FILE *f)
785 for (d = 0; d < IN_MAX_DEVS; d++)
787 const int *binds = in_get_dev_binds(d);
788 const char *name = in_get_dev_name(d, 0, 0);
791 if (binds == NULL || name == NULL)
794 fprintf(f, "binddev = %s\n", name);
795 in_get_config(d, IN_CFG_BIND_COUNT, &count);
797 for (k = 0; k < count; k++)
802 act[0] = act[31] = 0;
803 name = in_get_key_name(d, k);
805 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
806 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
807 mask = me_ctrl_actions[i].mask;
809 strncpy(act, me_ctrl_actions[i].name, 31);
810 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
813 mask = me_ctrl_actions[i].mask << 16;
815 strncpy(act, me_ctrl_actions[i].name, 31);
816 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
821 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
822 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
823 mask = emuctrl_actions[i].mask;
825 strncpy(act, emuctrl_actions[i].name, 31);
826 fprintf(f, "bind %s = %s\n", name, mystrip(act));
834 static int parse_bind_val(const char *val, int *type)
838 *type = IN_BINDTYPE_NONE;
842 if (strncasecmp(val, "player", 6) == 0)
844 int player, shift = 0;
845 player = atoi(val + 6) - 1;
847 if ((unsigned int)player > 1)
852 *type = IN_BINDTYPE_PLAYER12;
853 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
854 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
855 return me_ctrl_actions[i].mask << shift;
858 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
859 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
860 *type = IN_BINDTYPE_EMU;
861 return emuctrl_actions[i].mask;
868 static void keys_load_all(const char *cfg)
870 char dev[256], key[128], *act;
876 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
879 get_line(dev, sizeof(dev), p);
880 dev_id = in_config_parse_dev(dev);
882 printf("input: can't handle dev: %s\n", dev);
886 in_unbind_all(dev_id, -1, -1);
887 while ((p = strstr(p, "bind"))) {
888 if (strncmp(p, "binddev = ", 10) == 0)
893 printf("input: parse error: %16s..\n", p);
897 get_line(key, sizeof(key), p);
898 act = strchr(key, '=');
900 printf("parse failed: %16s..\n", p);
908 bind = parse_bind_val(act, &bindtype);
909 if (bind != -1 && bind != 0) {
910 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
911 in_config_bind_key(dev_id, key, bind, bindtype);
914 lprintf("config: unhandled action \"%s\"\n", act);
920 static int key_config_loop_wrap(int id, int keys)
923 case MA_CTRL_PLAYER1:
924 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
926 case MA_CTRL_PLAYER2:
927 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
930 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
938 static const char *mgn_dev_name(int id, int *offs)
940 const char *name = NULL;
943 if (id == MA_CTRL_DEV_FIRST)
946 for (; it < IN_MAX_DEVS; it++) {
947 name = in_get_dev_name(it, 1, 1);
956 static const char *mgn_saveloadcfg(int id, int *offs)
961 static int mh_savecfg(int id, int keys)
963 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
964 me_update_msg("config saved");
966 me_update_msg("failed to write config");
971 static int mh_input_rescan(int id, int keys)
973 //menu_sync_config();
974 plat_rescan_inputs();
975 me_update_msg("rescan complete.");
980 static const char *men_in_type_sel[] = {
981 "Standard (SCPH-1080)",
982 "Analog (SCPH-1150)",
986 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
987 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
989 static menu_entry e_menu_keyconfig[] =
991 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
992 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
993 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
995 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
996 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
997 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
998 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
999 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1000 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1001 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1002 mee_handler ("Rescan devices", mh_input_rescan),
1004 mee_label ("Input devices:"),
1005 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1006 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1007 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1008 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1009 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1010 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1011 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1015 static int menu_loop_keyconfig(int id, int keys)
1019 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1020 me_loop(e_menu_keyconfig, &sel);
1024 // ------------ gfx options menu ------------
1026 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1027 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1028 "using d-pad or move it using R+d-pad";
1029 static const char *men_dummy[] = { NULL };
1031 static int menu_loop_cscaler(int id, int keys)
1035 scaling = SCALE_CUSTOM;
1037 omap_enable_layer(1);
1042 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1043 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1044 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1047 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1048 if (inp & PBTN_UP) g_layer_y--;
1049 if (inp & PBTN_DOWN) g_layer_y++;
1050 if (inp & PBTN_LEFT) g_layer_x--;
1051 if (inp & PBTN_RIGHT) g_layer_x++;
1052 if (!(inp & PBTN_R)) {
1053 if (inp & PBTN_UP) g_layer_h += 2;
1054 if (inp & PBTN_DOWN) g_layer_h -= 2;
1055 if (inp & PBTN_LEFT) g_layer_w += 2;
1056 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1058 if (inp & (PBTN_MOK|PBTN_MBACK))
1061 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1062 if (g_layer_x < 0) g_layer_x = 0;
1063 if (g_layer_x > 640) g_layer_x = 640;
1064 if (g_layer_y < 0) g_layer_y = 0;
1065 if (g_layer_y > 420) g_layer_y = 420;
1066 if (g_layer_w < 160) g_layer_w = 160;
1067 if (g_layer_h < 60) g_layer_h = 60;
1068 if (g_layer_x + g_layer_w > 800)
1069 g_layer_w = 800 - g_layer_x;
1070 if (g_layer_y + g_layer_h > 480)
1071 g_layer_h = 480 - g_layer_y;
1072 omap_enable_layer(1);
1076 omap_enable_layer(0);
1081 static menu_entry e_menu_gfx_options[] =
1083 mee_enum ("Scaler", 0, scaling, men_scaler),
1084 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1085 // mee_onoff ("Vsync", 0, vsync, 1),
1086 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1090 static int menu_loop_gfx_options(int id, int keys)
1094 me_loop(e_menu_gfx_options, &sel);
1099 // ------------ bios/plugins ------------
1101 static menu_entry e_menu_plugin_gpu_unai[] =
1103 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1104 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1105 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1109 static int menu_loop_plugin_gpu_unai(int id, int keys)
1112 me_loop(e_menu_plugin_gpu_unai, &sel);
1116 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1117 static const char h_gpu_0[] = "Needed for Chrono Cross";
1118 static const char h_gpu_1[] = "Capcom fighting games";
1119 static const char h_gpu_2[] = "Black screens in Lunar";
1120 static const char h_gpu_3[] = "Compatibility mode";
1121 static const char h_gpu_6[] = "Pandemonium 2";
1122 static const char h_gpu_7[] = "Skip every second frame";
1123 static const char h_gpu_8[] = "Needed by Dark Forces";
1124 static const char h_gpu_9[] = "better g-colors, worse textures";
1125 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1127 static menu_entry e_menu_plugin_gpu_peops[] =
1129 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1130 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1131 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1132 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1133 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1134 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1135 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1136 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1137 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1138 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1142 static int menu_loop_plugin_gpu_peops(int id, int keys)
1145 me_loop(e_menu_plugin_gpu_peops, &sel);
1149 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1150 static const char h_spu_volboost[] = "Large values cause distortion";
1151 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1152 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1154 static menu_entry e_menu_plugin_spu[] =
1156 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1157 mee_onoff ("Reverb", 0, iUseReverb, 2),
1158 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1159 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1160 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1161 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1165 static int menu_loop_plugin_spu(int id, int keys)
1168 me_loop(e_menu_plugin_spu, &sel);
1172 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1173 "savestates and can't be changed there. Must save\n"
1174 "config and reload the game for change to take effect";
1175 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1176 "for plugin change to take effect";
1177 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1178 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1179 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1181 static menu_entry e_menu_plugin_options[] =
1183 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1184 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1185 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1186 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1187 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1188 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1192 static menu_entry e_menu_main2[];
1194 static int menu_loop_plugin_options(int id, int keys)
1197 me_loop(e_menu_plugin_options, &sel);
1199 // sync BIOS/plugins
1200 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1201 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1202 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1203 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1208 // ------------ adv options menu ------------
1210 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1211 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1212 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1213 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1215 static menu_entry e_menu_speed_hacks[] =
1217 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1218 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1219 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1220 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1224 static int menu_loop_speed_hacks(int id, int keys)
1227 me_loop(e_menu_speed_hacks, &sel);
1231 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1232 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1233 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1234 "(green: normal, red: fmod, blue: noise)";
1235 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1236 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1237 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1238 "(proper .cue/.bin dump is needed otherwise)";
1239 static const char h_cfg_sio[] = "You should not need this, breaks games";
1240 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1241 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1242 "(timing hack, breaks other games)";
1243 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1244 "(timing hack, breaks other games)";
1245 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1246 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1247 "Might be useful to overcome some dynarec bugs";
1248 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1249 "must reload game for any change to take effect";
1251 static menu_entry e_menu_adv_options[] =
1253 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1254 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1255 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1256 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1257 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1258 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1259 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1260 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1261 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1262 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1263 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1264 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1268 static int menu_loop_adv_options(int id, int keys)
1271 me_loop(e_menu_adv_options, &sel);
1275 // ------------ options menu ------------
1277 static int mh_restore_defaults(int id, int keys)
1279 menu_set_defconfig();
1280 me_update_msg("defaults restored");
1284 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1285 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1287 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1288 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1289 "loading state or both";
1291 static const char h_restore_def[] = "Switches back to default / recommended\n"
1293 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1295 static menu_entry e_menu_options[] =
1297 // mee_range ("Save slot", 0, state_slot, 0, 9),
1298 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1299 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1300 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1301 mee_enum ("Region", 0, region, men_region),
1302 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1303 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1304 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1305 mee_handler ("[Advanced]", menu_loop_adv_options),
1306 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1307 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1308 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1312 static int menu_loop_options(int id, int keys)
1317 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1318 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1319 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1321 me_loop(e_menu_options, &sel);
1326 // ------------ debug menu ------------
1328 static void draw_frame_debug(GPUFreeze_t *gpuf)
1330 int w = min(g_menuscreen_w, 1024);
1331 int h = min(g_menuscreen_h, 512);
1332 u16 *d = g_menuscreen_ptr;
1333 u16 *s = (u16 *)gpuf->psxVRam;
1337 gpuf->ulFreezeVersion = 1;
1338 if (GPU_freeze != NULL)
1339 GPU_freeze(1, gpuf);
1341 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1342 bgr555_to_rgb565(d, s, w * 2);
1344 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1345 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1346 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1347 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1348 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1351 static void debug_menu_loop(void)
1356 gpuf = malloc(sizeof(*gpuf));
1363 draw_frame_debug(gpuf);
1366 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1367 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1368 if (inp & PBTN_MBACK)
1375 // --------- memcard manager ---------
1377 static void draw_mc_icon(int dx, int dy, const u16 *s)
1382 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1384 for (y = 0; y < 16; y++, s += 16) {
1385 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1386 for (x = 0; x < 16; x++) {
1388 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1389 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1395 static void draw_mc_bg(void)
1397 McdBlock *blocks1, *blocks2;
1401 blocks1 = malloc(15 * sizeof(blocks1[0]));
1402 blocks2 = malloc(15 * sizeof(blocks1[0]));
1403 if (blocks1 == NULL || blocks2 == NULL)
1406 for (i = 0; i < 15; i++) {
1407 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1408 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1413 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1415 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1419 maxicons = g_menuscreen_h / 32;
1422 row2 = g_menuscreen_w / 2;
1423 for (i = 0; i < maxicons; i++) {
1424 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1425 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1427 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1428 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1431 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1439 static void handle_memcard_sel(void)
1442 if (memcard1_sel != 0)
1443 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1445 if (memcard2_sel != 0)
1446 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1447 LoadMcds(Config.Mcd1, Config.Mcd2);
1451 static menu_entry e_memcard_options[] =
1453 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1454 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1458 static int menu_loop_memcards(int id, int keys)
1464 memcard1_sel = memcard2_sel = 0;
1465 p = strrchr(Config.Mcd1, '/');
1467 for (i = 0; memcards[i] != NULL; i++)
1468 if (strcmp(p + 1, memcards[i]) == 0)
1469 { memcard1_sel = i; break; }
1470 p = strrchr(Config.Mcd2, '/');
1472 for (i = 0; memcards[i] != NULL; i++)
1473 if (strcmp(p + 1, memcards[i]) == 0)
1474 { memcard2_sel = i; break; }
1476 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1478 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1483 // --------- main menu help ----------
1485 static void menu_bios_warn(void)
1488 static const char msg[] =
1489 "You don't seem to have copied any BIOS\n"
1491 #ifdef __ARM_ARCH_7A__ // XXX
1492 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1494 "pcsx_rearmed/bios/\n\n"
1496 "While many games work fine with fake\n"
1497 "(HLE) BIOS, others (like MGS and FF8)\n"
1498 "require BIOS to work.\n"
1499 "After copying the file, you'll also need\n"
1500 "to select it in the emu's menu:\n"
1501 "options->[BIOS/Plugins]\n\n"
1502 "The file is usually named SCPH1001.BIN,\n"
1503 "but other not compressed files can be\n"
1505 "Press (B) or (X) to continue";
1509 draw_menu_message(msg, NULL);
1511 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1512 if (inp & (PBTN_MBACK|PBTN_MOK))
1517 // ------------ main menu ------------
1521 static void draw_frame_main(void)
1528 if (CdromId[0] != 0) {
1529 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1530 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1531 Config.HLE ? "HLE" : "BIOS");
1532 smalltext_out16(4, 1, buff, 0x105f);
1537 tmp = localtime(<ime);
1538 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1539 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1540 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1544 static void draw_frame_credits(void)
1546 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1549 static const char credits_text[] =
1551 "(C) 1999-2003 PCSX Team\n"
1552 "(C) 2005-2009 PCSX-df Team\n"
1553 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1554 "GPU and SPU code by Pete Bernert\n"
1555 " and the P.E.Op.S. team\n"
1556 "ARM recompiler (C) 2009-2011 Ari64\n"
1557 "PCSX4ALL plugins by PCSX4ALL team\n"
1558 " Chui, Franxis, Unai\n\n"
1559 "integration, optimization and\n"
1560 " frontend (C) 2010-2011 notaz\n";
1562 static int reset_game(void)
1565 if (bios_sel == 0 && !Config.HLE)
1571 if (CheckCdrom() != -1) {
1577 static int reload_plugins(const char *cdimg)
1583 set_cd_image(cdimg);
1585 pcnt_hook_plugins();
1587 if (OpenPlugins() == -1) {
1588 me_update_msg("failed to open plugins");
1591 plugin_call_rearmed_cbs();
1594 CdromLabel[0] = '\0';
1599 static int run_bios(void)
1605 if (reload_plugins(NULL) != 0)
1613 static int run_exe(void)
1617 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1622 if (reload_plugins(NULL) != 0)
1626 if (Load(fname) != 0) {
1627 me_update_msg("exe load failed, bad file?");
1636 static int run_cd_image(const char *fname)
1639 reload_plugins(fname);
1641 // always autodetect, menu_sync_config will override as needed
1644 if (CheckCdrom() == -1) {
1645 // Only check the CD if we are starting the console with a CD
1647 me_update_msg("unsupported/invalid CD image");
1653 // Read main executable directly from CDRom and start it
1654 if (LoadCdrom() == -1) {
1656 me_update_msg("failed to load CD image");
1664 static int romsel_run(void)
1666 int prev_gpu, prev_spu;
1669 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1673 printf("selected file: %s\n", fname);
1675 new_dynarec_clear_full();
1677 if (run_cd_image(fname) != 0)
1680 prev_gpu = gpu_plugsel;
1681 prev_spu = spu_plugsel;
1682 if (menu_load_config(1) != 0)
1683 menu_load_config(0);
1685 // check for plugin changes, have to repeat
1686 // loading if game config changed plugins to reload them
1687 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1688 printf("plugin change detected, reloading plugins..\n");
1689 if (run_cd_image(fname) != 0)
1694 printf("note: running without BIOS, expect compatibility problems\n");
1696 strcpy(last_selected_fname, rom_fname_reload);
1700 static int swap_cd_image(void)
1704 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1708 printf("selected file: %s\n", fname);
1711 CdromLabel[0] = '\0';
1713 set_cd_image(fname);
1714 if (ReloadCdromPlugin() < 0) {
1715 me_update_msg("failed to load cdr plugin");
1718 if (CDR_open() < 0) {
1719 me_update_msg("failed to open cdr plugin");
1723 SetCdOpenCaseTime(time(NULL) + 2);
1726 strcpy(last_selected_fname, rom_fname_reload);
1730 static int main_menu_handler(int id, int keys)
1734 case MA_MAIN_RESUME_GAME:
1738 case MA_MAIN_SAVE_STATE:
1740 return menu_loop_savestate(0);
1742 case MA_MAIN_LOAD_STATE:
1744 return menu_loop_savestate(1);
1746 case MA_MAIN_RESET_GAME:
1747 if (ready_to_go && reset_game() == 0)
1750 case MA_MAIN_LOAD_ROM:
1751 if (romsel_run() == 0)
1754 case MA_MAIN_SWAP_CD:
1755 if (swap_cd_image() == 0)
1758 case MA_MAIN_RUN_BIOS:
1759 if (run_bios() == 0)
1762 case MA_MAIN_RUN_EXE:
1766 case MA_MAIN_CREDITS:
1767 draw_menu_message(credits_text, draw_frame_credits);
1768 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1774 lprintf("%s: something unknown selected\n", __FUNCTION__);
1781 static menu_entry e_menu_main2[] =
1783 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1784 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1785 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1786 mee_handler ("Memcard manager", menu_loop_memcards),
1790 static int main_menu2_handler(int id, int keys)
1794 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1795 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1797 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1800 static const char h_extra[] = "Change CD, manage memcards..\n";
1802 static menu_entry e_menu_main[] =
1806 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1807 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1808 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1809 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1810 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1811 mee_handler ("Options", menu_loop_options),
1812 mee_handler ("Controls", menu_loop_keyconfig),
1813 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1814 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1815 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1819 // ----------------------------
1821 static void menu_leave_emu(void);
1823 void menu_loop(void)
1829 if (bioses[1] == NULL && !warned_about_bios) {
1831 warned_about_bios = 1;
1834 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1835 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1836 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1837 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1839 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1842 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1843 } while (!ready_to_go);
1845 /* wait until menu, ok, back is released */
1846 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1849 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1854 static int qsort_strcmp(const void *p1, const void *p2)
1856 char * const *s1 = (char * const *)p1;
1857 char * const *s2 = (char * const *)p2;
1858 return strcasecmp(*s1, *s2);
1861 static void scan_bios_plugins(void)
1863 char fname[MAXPATHLEN];
1865 int bios_i, gpu_i, spu_i, mc_i;
1870 gpu_plugins[0] = "builtin_gpu";
1871 spu_plugins[0] = "builtin_spu";
1872 memcards[0] = "(none)";
1873 bios_i = gpu_i = spu_i = mc_i = 1;
1875 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1876 dir = opendir(fname);
1878 perror("scan_bios_plugins bios opendir");
1893 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1896 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1897 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1898 printf("bad BIOS file: %s\n", ent->d_name);
1902 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1903 bioses[bios_i++] = strdup(ent->d_name);
1907 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1913 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1914 dir = opendir(fname);
1916 perror("scan_bios_plugins plugins opendir");
1930 p = strstr(ent->d_name, ".so");
1934 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1935 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1937 fprintf(stderr, "%s\n", dlerror());
1941 // now what do we have here?
1942 tmp = dlsym(h, "GPUinit");
1945 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1946 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1950 tmp = dlsym(h, "SPUinit");
1953 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1954 spu_plugins[spu_i++] = strdup(ent->d_name);
1958 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1965 dir = opendir("." MEMCARD_DIR);
1967 perror("scan_bios_plugins memcards opendir");
1982 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1985 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1986 if (stat(fname, &st) != 0) {
1987 printf("bad memcard file: %s\n", ent->d_name);
1991 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1992 memcards[mc_i++] = strdup(ent->d_name);
1996 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2000 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2005 void menu_init(void)
2007 char buff[MAXPATHLEN];
2009 strcpy(last_selected_fname, "/media");
2011 scan_bios_plugins();
2015 menu_set_defconfig();
2016 menu_load_config(0);
2021 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2022 if (g_menubg_src_ptr == NULL)
2024 emu_make_path(buff, "skin/background.png", sizeof(buff));
2025 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2027 #ifndef __ARM_ARCH_7A__ /* XXX */
2028 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2029 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2031 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2035 void menu_notify_mode_change(int w, int h, int bpp)
2046 g_layer_w = w; g_layer_h = h;
2050 if (h > g_menuscreen_h || (240 < h && h <= 360))
2051 goto fractional_4_3;
2053 // 4:3 that prefers integer scaling
2054 imult = g_menuscreen_h / h;
2055 g_layer_w = w * imult;
2056 g_layer_h = h * imult;
2057 mult = (float)g_layer_w / (float)g_layer_h;
2058 if (mult < 1.25f || mult > 1.666f)
2059 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2060 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2065 mult = 240.0f / (float)h * 4.0f / 3.0f;
2068 g_layer_w = mult * (float)g_menuscreen_h;
2069 g_layer_h = g_menuscreen_h;
2070 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2073 case SCALE_FULLSCREEN:
2074 g_layer_w = g_menuscreen_w;
2075 g_layer_h = g_menuscreen_h;
2082 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2083 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2084 if (g_layer_x < 0) g_layer_x = 0;
2085 if (g_layer_y < 0) g_layer_y = 0;
2086 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2087 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2090 static void menu_leave_emu(void)
2092 if (GPU_close != NULL) {
2093 int ret = GPU_close();
2095 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2098 plat_video_menu_enter(ready_to_go);
2100 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2101 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2102 int x = max(0, g_menuscreen_w - last_psx_w);
2103 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2104 int w = min(g_menuscreen_w, last_psx_w);
2105 int h = min(g_menuscreen_h, last_psx_h);
2106 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2107 u16 *s = pl_vout_buf;
2109 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2110 menu_darken_bg(d, s, w, 0);
2114 cpu_clock = plat_cpu_clock_get();
2117 void menu_prepare_emu(void)
2119 R3000Acpu *prev_cpu = psxCpu;
2121 plat_video_menu_leave();
2123 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2125 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2126 if (psxCpu != prev_cpu)
2127 // note that this does not really reset, just clears drc caches
2130 // core doesn't care about Config.Cdda changes,
2131 // so handle them manually here
2136 apply_lcdrate(Config.PsxType);
2137 apply_filter(filter);
2138 plat_cpu_clock_apply(cpu_clock);
2140 // push config to GPU plugin
2141 plugin_call_rearmed_cbs();
2143 if (GPU_open != NULL) {
2144 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2146 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2152 void me_update_msg(const char *msg)
2154 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2155 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2157 menu_error_time = plat_get_ticks_ms();
2158 lprintf("msg: %s\n", menu_error_msg);