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 = 70;
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", ".bz", ".znx", ".pbp" };
481 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
482 const char *ext = strrchr(fname, '.');
487 for (i = 0; i < array_size(cdimg_exts); i++)
488 if (strcasecmp(ext, cdimg_exts[i]) == 0)
490 for (i = 0; i < array_size(other_exts); i++)
491 if (strcasecmp(ext, other_exts[i]) == 0)
496 static void draw_savestate_bg(int slot);
498 static const char *filter_exts[] = {
499 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
502 #define MENU_ALIGN_LEFT
503 #ifdef __ARM_ARCH_7A__ // assume hires device
509 #define menu_init menu_init_common
510 #include "common/menu.c"
513 // a bit of black magic here
514 static void draw_savestate_bg(int slot)
516 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
518 char fname[MAXPATHLEN];
525 ret = get_state_filename(fname, sizeof(fname), slot);
529 f = gzopen(fname, "rb");
533 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
534 fprintf(stderr, "gzseek failed\n");
539 gpu = malloc(sizeof(*gpu));
545 ret = gzread(f, gpu, sizeof(*gpu));
547 if (ret != sizeof(*gpu)) {
548 fprintf(stderr, "gzread failed\n");
552 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
554 if (gpu->ulStatus & 0x800000)
555 goto out; // disabled
557 x = gpu->ulControl[5] & 0x3ff;
558 y = (gpu->ulControl[5] >> 10) & 0x1ff;
559 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
560 w = psx_widths[(gpu->ulStatus >> 16) & 7];
561 tmp = gpu->ulControl[7];
562 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
563 if (gpu->ulStatus & 0x80000) // doubleheight
566 x = max(0, g_menuscreen_w - w) & ~3;
567 y = max(0, g_menuscreen_h / 2 - h / 2);
568 w = min(g_menuscreen_w, w);
569 h = min(g_menuscreen_h, h);
570 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
572 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
573 if (gpu->ulStatus & 0x200000)
574 bgr888_to_rgb565(d, s, w * 3);
576 bgr555_to_rgb565(d, s, w * 2);
577 #ifndef __ARM_ARCH_7A__
578 // better darken this on small screens
579 menu_darken_bg(d, d, w * 2, 0);
587 // ---------- XXX: pandora specific -----------
589 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
590 static char **pnd_filter_list;
592 static void apply_filter(int which)
598 if (pnd_filter_list == NULL || which == old)
601 for (i = 0; i < which; i++)
602 if (pnd_filter_list[i] == NULL)
605 if (pnd_filter_list[i] == NULL)
608 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
613 static void apply_lcdrate(int pal)
621 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
622 pnd_script_base, pal ? 50 : 60);
627 static menu_entry e_menu_gfx_options[];
629 static void pnd_menu_init(void)
637 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
639 dir = opendir("/etc/pandora/conf/dss_fir");
641 perror("filter opendir");
654 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
663 mfilters = calloc(count + 1, sizeof(mfilters[0]));
664 if (mfilters == NULL)
668 for (i = 0; (ent = readdir(dir)); ) {
671 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
674 len = strlen(ent->d_name);
676 // skip pre-HF5 extra files
677 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
679 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
682 // have to cut "_up_h" for pre-HF5
683 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
686 if (len > sizeof(buff) - 1)
689 strncpy(buff, ent->d_name, len);
691 mfilters[i] = strdup(buff);
692 if (mfilters[i] != NULL)
697 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
698 e_menu_gfx_options[i].data = (void *)mfilters;
699 pnd_filter_list = mfilters;
702 void menu_finish(void)
704 plat_cpu_clock_apply(cpu_clock_st);
707 // -------------- key config --------------
709 me_bind_action me_ctrl_actions[] =
711 { "UP ", 1 << DKEY_UP},
712 { "DOWN ", 1 << DKEY_DOWN },
713 { "LEFT ", 1 << DKEY_LEFT },
714 { "RIGHT ", 1 << DKEY_RIGHT },
715 { "TRIANGLE", 1 << DKEY_TRIANGLE },
716 { "CIRCLE ", 1 << DKEY_CIRCLE },
717 { "CROSS ", 1 << DKEY_CROSS },
718 { "SQUARE ", 1 << DKEY_SQUARE },
719 { "L1 ", 1 << DKEY_L1 },
720 { "R1 ", 1 << DKEY_R1 },
721 { "L2 ", 1 << DKEY_L2 },
722 { "R2 ", 1 << DKEY_R2 },
723 { "L3 ", 1 << DKEY_L3 },
724 { "R3 ", 1 << DKEY_R3 },
725 { "START ", 1 << DKEY_START },
726 { "SELECT ", 1 << DKEY_SELECT },
730 me_bind_action emuctrl_actions[] =
732 { "Save State ", 1 << SACTION_SAVE_STATE },
733 { "Load State ", 1 << SACTION_LOAD_STATE },
734 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
735 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
736 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
737 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
738 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
739 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
740 { "Gun A button ", 1 << SACTION_GUN_A },
741 { "Gun B button ", 1 << SACTION_GUN_B },
742 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
746 static char *mystrip(char *str)
751 for (i = 0; i < len; i++)
752 if (str[i] != ' ') break;
753 if (i > 0) memmove(str, str + i, len - i + 1);
756 for (i = len - 1; i >= 0; i--)
757 if (str[i] != ' ') break;
763 static void get_line(char *d, size_t size, const char *s)
768 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
779 static void keys_write_all(FILE *f)
783 for (d = 0; d < IN_MAX_DEVS; d++)
785 const int *binds = in_get_dev_binds(d);
786 const char *name = in_get_dev_name(d, 0, 0);
789 if (binds == NULL || name == NULL)
792 fprintf(f, "binddev = %s\n", name);
793 in_get_config(d, IN_CFG_BIND_COUNT, &count);
795 for (k = 0; k < count; k++)
800 act[0] = act[31] = 0;
801 name = in_get_key_name(d, k);
803 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
804 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
805 mask = me_ctrl_actions[i].mask;
807 strncpy(act, me_ctrl_actions[i].name, 31);
808 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
811 mask = me_ctrl_actions[i].mask << 16;
813 strncpy(act, me_ctrl_actions[i].name, 31);
814 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
819 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
820 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
821 mask = emuctrl_actions[i].mask;
823 strncpy(act, emuctrl_actions[i].name, 31);
824 fprintf(f, "bind %s = %s\n", name, mystrip(act));
832 static int parse_bind_val(const char *val, int *type)
836 *type = IN_BINDTYPE_NONE;
840 if (strncasecmp(val, "player", 6) == 0)
842 int player, shift = 0;
843 player = atoi(val + 6) - 1;
845 if ((unsigned int)player > 1)
850 *type = IN_BINDTYPE_PLAYER12;
851 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
852 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
853 return me_ctrl_actions[i].mask << shift;
856 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
857 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
858 *type = IN_BINDTYPE_EMU;
859 return emuctrl_actions[i].mask;
866 static void keys_load_all(const char *cfg)
868 char dev[256], key[128], *act;
874 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
877 get_line(dev, sizeof(dev), p);
878 dev_id = in_config_parse_dev(dev);
880 printf("input: can't handle dev: %s\n", dev);
884 in_unbind_all(dev_id, -1, -1);
885 while ((p = strstr(p, "bind"))) {
886 if (strncmp(p, "binddev = ", 10) == 0)
891 printf("input: parse error: %16s..\n", p);
895 get_line(key, sizeof(key), p);
896 act = strchr(key, '=');
898 printf("parse failed: %16s..\n", p);
906 bind = parse_bind_val(act, &bindtype);
907 if (bind != -1 && bind != 0) {
908 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
909 in_config_bind_key(dev_id, key, bind, bindtype);
912 lprintf("config: unhandled action \"%s\"\n", act);
918 static int key_config_loop_wrap(int id, int keys)
921 case MA_CTRL_PLAYER1:
922 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
924 case MA_CTRL_PLAYER2:
925 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
928 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
936 static const char *mgn_dev_name(int id, int *offs)
938 const char *name = NULL;
941 if (id == MA_CTRL_DEV_FIRST)
944 for (; it < IN_MAX_DEVS; it++) {
945 name = in_get_dev_name(it, 1, 1);
954 static const char *mgn_saveloadcfg(int id, int *offs)
959 static int mh_savecfg(int id, int keys)
961 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
962 me_update_msg("config saved");
964 me_update_msg("failed to write config");
969 static int mh_input_rescan(int id, int keys)
971 //menu_sync_config();
972 plat_rescan_inputs();
973 me_update_msg("rescan complete.");
978 static const char *men_in_type_sel[] = {
979 "Standard (SCPH-1080)",
980 "Analog (SCPH-1150)",
984 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
985 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
987 static menu_entry e_menu_keyconfig[] =
989 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
990 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
991 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
993 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
994 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
995 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
996 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
997 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
998 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
999 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1000 mee_handler ("Rescan devices", mh_input_rescan),
1002 mee_label ("Input devices:"),
1003 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1004 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1005 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1013 static int menu_loop_keyconfig(int id, int keys)
1017 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1018 me_loop(e_menu_keyconfig, &sel);
1022 // ------------ gfx options menu ------------
1024 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1025 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1026 "using d-pad or move it using R+d-pad";
1027 static const char *men_dummy[] = { NULL };
1029 static int menu_loop_cscaler(int id, int keys)
1033 scaling = SCALE_CUSTOM;
1035 omap_enable_layer(1);
1040 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1041 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1042 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1045 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1046 if (inp & PBTN_UP) g_layer_y--;
1047 if (inp & PBTN_DOWN) g_layer_y++;
1048 if (inp & PBTN_LEFT) g_layer_x--;
1049 if (inp & PBTN_RIGHT) g_layer_x++;
1050 if (!(inp & PBTN_R)) {
1051 if (inp & PBTN_UP) g_layer_h += 2;
1052 if (inp & PBTN_DOWN) g_layer_h -= 2;
1053 if (inp & PBTN_LEFT) g_layer_w += 2;
1054 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1056 if (inp & (PBTN_MOK|PBTN_MBACK))
1059 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1060 if (g_layer_x < 0) g_layer_x = 0;
1061 if (g_layer_x > 640) g_layer_x = 640;
1062 if (g_layer_y < 0) g_layer_y = 0;
1063 if (g_layer_y > 420) g_layer_y = 420;
1064 if (g_layer_w < 160) g_layer_w = 160;
1065 if (g_layer_h < 60) g_layer_h = 60;
1066 if (g_layer_x + g_layer_w > 800)
1067 g_layer_w = 800 - g_layer_x;
1068 if (g_layer_y + g_layer_h > 480)
1069 g_layer_h = 480 - g_layer_y;
1070 omap_enable_layer(1);
1074 omap_enable_layer(0);
1079 static menu_entry e_menu_gfx_options[] =
1081 mee_enum ("Scaler", 0, scaling, men_scaler),
1082 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1083 // mee_onoff ("Vsync", 0, vsync, 1),
1084 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1088 static int menu_loop_gfx_options(int id, int keys)
1092 me_loop(e_menu_gfx_options, &sel);
1097 // ------------ bios/plugins ------------
1099 static menu_entry e_menu_plugin_gpu_unai[] =
1101 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1102 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1103 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1107 static int menu_loop_plugin_gpu_unai(int id, int keys)
1110 me_loop(e_menu_plugin_gpu_unai, &sel);
1114 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1115 static const char h_gpu_0[] = "Needed for Chrono Cross";
1116 static const char h_gpu_1[] = "Capcom fighting games";
1117 static const char h_gpu_2[] = "Black screens in Lunar";
1118 static const char h_gpu_3[] = "Compatibility mode";
1119 static const char h_gpu_6[] = "Pandemonium 2";
1120 static const char h_gpu_7[] = "Skip every second frame";
1121 static const char h_gpu_8[] = "Needed by Dark Forces";
1122 static const char h_gpu_9[] = "better g-colors, worse textures";
1123 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1125 static menu_entry e_menu_plugin_gpu_peops[] =
1127 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1128 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1129 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1130 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1131 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1132 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1133 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1134 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1135 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1136 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1140 static int menu_loop_plugin_gpu_peops(int id, int keys)
1143 me_loop(e_menu_plugin_gpu_peops, &sel);
1147 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1148 static const char h_spu_volboost[] = "Large values cause distortion";
1149 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1150 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1152 static menu_entry e_menu_plugin_spu[] =
1154 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1155 mee_onoff ("Reverb", 0, iUseReverb, 2),
1156 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1157 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1158 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1159 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1163 static int menu_loop_plugin_spu(int id, int keys)
1166 me_loop(e_menu_plugin_spu, &sel);
1170 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1171 "savestates and can't be changed there. Must save\n"
1172 "config and reload the game for change to take effect";
1173 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1174 "for plugin change to take effect";
1175 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1176 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1177 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1179 static menu_entry e_menu_plugin_options[] =
1181 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1182 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1183 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1184 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1185 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1186 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1190 static menu_entry e_menu_main2[];
1192 static int menu_loop_plugin_options(int id, int keys)
1195 me_loop(e_menu_plugin_options, &sel);
1197 // sync BIOS/plugins
1198 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1199 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1200 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1201 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1206 // ------------ adv options menu ------------
1208 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1209 static const char h_cfg_nosmc[] = "Will cause crashes when loading";
1210 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1211 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1213 static menu_entry e_menu_speed_hacks[] =
1215 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1216 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1217 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1218 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1222 static int menu_loop_speed_hacks(int id, int keys)
1225 me_loop(e_menu_speed_hacks, &sel);
1229 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1230 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1231 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1232 "(green: normal, red: fmod, blue: noise)";
1233 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1234 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1235 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1236 "(proper .cue/.bin dump is needed otherwise)";
1237 static const char h_cfg_sio[] = "You should not need this, breaks games";
1238 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1239 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1240 "(timing hack, breaks other games)";
1241 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1242 "(timing hack, breaks other games)";
1243 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1244 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1245 "Might be useful to overcome some dynarec bugs";
1246 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1247 "must reload game for any change to take effect";
1249 static menu_entry e_menu_adv_options[] =
1251 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1252 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1253 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1254 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1255 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1256 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1257 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1258 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1259 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1260 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1261 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1262 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1266 static int menu_loop_adv_options(int id, int keys)
1269 me_loop(e_menu_adv_options, &sel);
1273 // ------------ options menu ------------
1275 static int mh_restore_defaults(int id, int keys)
1277 menu_set_defconfig();
1278 me_update_msg("defaults restored");
1282 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1283 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1285 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1286 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1287 "loading state or both";
1289 static const char h_restore_def[] = "Switches back to default / recommended\n"
1291 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1293 static menu_entry e_menu_options[] =
1295 // mee_range ("Save slot", 0, state_slot, 0, 9),
1296 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1297 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1298 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1299 mee_enum ("Region", 0, region, men_region),
1300 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1301 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1302 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1303 mee_handler ("[Advanced]", menu_loop_adv_options),
1304 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1305 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1306 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1310 static int menu_loop_options(int id, int keys)
1315 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1316 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1317 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1319 me_loop(e_menu_options, &sel);
1324 // ------------ debug menu ------------
1326 static void draw_frame_debug(GPUFreeze_t *gpuf)
1328 int w = min(g_menuscreen_w, 1024);
1329 int h = min(g_menuscreen_h, 512);
1330 u16 *d = g_menuscreen_ptr;
1331 u16 *s = (u16 *)gpuf->psxVRam;
1335 gpuf->ulFreezeVersion = 1;
1336 if (GPU_freeze != NULL)
1337 GPU_freeze(1, gpuf);
1339 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1340 bgr555_to_rgb565(d, s, w * 2);
1342 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1343 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1344 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1345 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1346 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1349 static void debug_menu_loop(void)
1354 gpuf = malloc(sizeof(*gpuf));
1361 draw_frame_debug(gpuf);
1364 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1365 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1366 if (inp & PBTN_MBACK)
1373 // --------- memcard manager ---------
1375 static void draw_mc_icon(int dx, int dy, const u16 *s)
1380 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1382 for (y = 0; y < 16; y++, s += 16) {
1383 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1384 for (x = 0; x < 16; x++) {
1386 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1387 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1393 static void draw_mc_bg(void)
1395 McdBlock *blocks1, *blocks2;
1399 blocks1 = malloc(15 * sizeof(blocks1[0]));
1400 blocks2 = malloc(15 * sizeof(blocks1[0]));
1401 if (blocks1 == NULL || blocks2 == NULL)
1404 for (i = 0; i < 15; i++) {
1405 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1406 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1411 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1413 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1417 maxicons = g_menuscreen_h / 32;
1420 row2 = g_menuscreen_w / 2;
1421 for (i = 0; i < maxicons; i++) {
1422 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1423 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1425 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1426 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1429 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1437 static void handle_memcard_sel(void)
1440 if (memcard1_sel != 0)
1441 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1443 if (memcard2_sel != 0)
1444 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1445 LoadMcds(Config.Mcd1, Config.Mcd2);
1449 static menu_entry e_memcard_options[] =
1451 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1452 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1456 static int menu_loop_memcards(int id, int keys)
1462 memcard1_sel = memcard2_sel = 0;
1463 p = strrchr(Config.Mcd1, '/');
1465 for (i = 0; memcards[i] != NULL; i++)
1466 if (strcmp(p + 1, memcards[i]) == 0)
1467 { memcard1_sel = i; break; }
1468 p = strrchr(Config.Mcd2, '/');
1470 for (i = 0; memcards[i] != NULL; i++)
1471 if (strcmp(p + 1, memcards[i]) == 0)
1472 { memcard2_sel = i; break; }
1474 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1476 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1481 // --------- main menu help ----------
1483 static void menu_bios_warn(void)
1486 static const char msg[] =
1487 "You don't seem to have copied any BIOS\n"
1489 #ifdef __ARM_ARCH_7A__ // XXX
1490 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1492 "pcsx_rearmed/bios/\n\n"
1494 "While many games work fine with fake\n"
1495 "(HLE) BIOS, others (like MGS and FF8)\n"
1496 "require BIOS to work.\n"
1497 "After copying the file, you'll also need\n"
1498 "to select it in the emu's menu:\n"
1499 "options->[BIOS/Plugins]\n\n"
1500 "The file is usually named SCPH1001.BIN,\n"
1501 "but other not compressed files can be\n"
1503 "Press (B) or (X) to continue";
1507 draw_menu_message(msg, NULL);
1509 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1510 if (inp & (PBTN_MBACK|PBTN_MOK))
1515 // ------------ main menu ------------
1519 static void draw_frame_main(void)
1526 if (CdromId[0] != 0) {
1527 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1528 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1529 Config.HLE ? "HLE" : "BIOS");
1530 smalltext_out16(4, 1, buff, 0x105f);
1535 tmp = localtime(<ime);
1536 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1537 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1538 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1542 static void draw_frame_credits(void)
1544 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1547 static const char credits_text[] =
1549 "(C) 1999-2003 PCSX Team\n"
1550 "(C) 2005-2009 PCSX-df Team\n"
1551 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1552 "GPU and SPU code by Pete Bernert\n"
1553 " and the P.E.Op.S. team\n"
1554 "ARM recompiler (C) 2009-2011 Ari64\n"
1555 "PCSX4ALL plugins by PCSX4ALL team\n"
1556 " Chui, Franxis, Unai\n\n"
1557 "integration, optimization and\n"
1558 " frontend (C) 2010-2011 notaz\n";
1560 static int reset_game(void)
1563 if (bios_sel == 0 && !Config.HLE)
1569 if (CheckCdrom() != -1) {
1575 static int reload_plugins(const char *cdimg)
1581 set_cd_image(cdimg);
1583 pcnt_hook_plugins();
1585 if (OpenPlugins() == -1) {
1586 me_update_msg("failed to open plugins");
1589 plugin_call_rearmed_cbs();
1592 CdromLabel[0] = '\0';
1597 static int run_bios(void)
1603 if (reload_plugins(NULL) != 0)
1611 static int run_exe(void)
1615 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1620 if (reload_plugins(NULL) != 0)
1624 if (Load(fname) != 0) {
1625 me_update_msg("exe load failed, bad file?");
1634 static int run_cd_image(const char *fname)
1637 reload_plugins(fname);
1639 // always autodetect, menu_sync_config will override as needed
1642 if (CheckCdrom() == -1) {
1643 // Only check the CD if we are starting the console with a CD
1645 me_update_msg("unsupported/invalid CD image");
1651 // Read main executable directly from CDRom and start it
1652 if (LoadCdrom() == -1) {
1654 me_update_msg("failed to load CD image");
1662 static int romsel_run(void)
1664 int prev_gpu, prev_spu;
1667 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1671 printf("selected file: %s\n", fname);
1673 new_dynarec_clear_full();
1675 if (run_cd_image(fname) != 0)
1678 prev_gpu = gpu_plugsel;
1679 prev_spu = spu_plugsel;
1680 if (menu_load_config(1) != 0)
1681 menu_load_config(0);
1683 // check for plugin changes, have to repeat
1684 // loading if game config changed plugins to reload them
1685 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1686 printf("plugin change detected, reloading plugins..\n");
1687 if (run_cd_image(fname) != 0)
1691 strcpy(last_selected_fname, rom_fname_reload);
1695 static int swap_cd_image(void)
1699 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1703 printf("selected file: %s\n", fname);
1706 CdromLabel[0] = '\0';
1708 set_cd_image(fname);
1709 if (ReloadCdromPlugin() < 0) {
1710 me_update_msg("failed to load cdr plugin");
1713 if (CDR_open() < 0) {
1714 me_update_msg("failed to open cdr plugin");
1718 SetCdOpenCaseTime(time(NULL) + 2);
1721 strcpy(last_selected_fname, rom_fname_reload);
1725 static int main_menu_handler(int id, int keys)
1729 case MA_MAIN_RESUME_GAME:
1733 case MA_MAIN_SAVE_STATE:
1735 return menu_loop_savestate(0);
1737 case MA_MAIN_LOAD_STATE:
1739 return menu_loop_savestate(1);
1741 case MA_MAIN_RESET_GAME:
1742 if (ready_to_go && reset_game() == 0)
1745 case MA_MAIN_LOAD_ROM:
1746 if (romsel_run() == 0)
1749 case MA_MAIN_SWAP_CD:
1750 if (swap_cd_image() == 0)
1753 case MA_MAIN_RUN_BIOS:
1754 if (run_bios() == 0)
1757 case MA_MAIN_RUN_EXE:
1761 case MA_MAIN_CREDITS:
1762 draw_menu_message(credits_text, draw_frame_credits);
1763 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1769 lprintf("%s: something unknown selected\n", __FUNCTION__);
1776 static menu_entry e_menu_main2[] =
1778 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1779 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1780 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1781 mee_handler ("Memcard manager", menu_loop_memcards),
1785 static int main_menu2_handler(int id, int keys)
1789 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1790 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1792 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1795 static const char h_extra[] = "Change CD, manage memcards..\n";
1797 static menu_entry e_menu_main[] =
1801 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1802 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1803 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1804 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1805 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1806 mee_handler ("Options", menu_loop_options),
1807 mee_handler ("Controls", menu_loop_keyconfig),
1808 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1809 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1810 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1814 // ----------------------------
1816 static void menu_leave_emu(void);
1818 void menu_loop(void)
1824 if (bioses[1] == NULL && !warned_about_bios) {
1826 warned_about_bios = 1;
1829 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1830 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1831 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1832 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1834 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1837 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1838 } while (!ready_to_go);
1840 /* wait until menu, ok, back is released */
1841 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1844 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1849 static int qsort_strcmp(const void *p1, const void *p2)
1851 char * const *s1 = (char * const *)p1;
1852 char * const *s2 = (char * const *)p2;
1853 return strcasecmp(*s1, *s2);
1856 static void scan_bios_plugins(void)
1858 char fname[MAXPATHLEN];
1860 int bios_i, gpu_i, spu_i, mc_i;
1865 gpu_plugins[0] = "builtin_gpu";
1866 spu_plugins[0] = "builtin_spu";
1867 memcards[0] = "(none)";
1868 bios_i = gpu_i = spu_i = mc_i = 1;
1870 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1871 dir = opendir(fname);
1873 perror("scan_bios_plugins bios opendir");
1888 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1891 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1892 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1893 printf("bad BIOS file: %s\n", ent->d_name);
1897 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1898 bioses[bios_i++] = strdup(ent->d_name);
1902 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1908 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1909 dir = opendir(fname);
1911 perror("scan_bios_plugins plugins opendir");
1925 p = strstr(ent->d_name, ".so");
1929 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1930 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1932 fprintf(stderr, "%s\n", dlerror());
1936 // now what do we have here?
1937 tmp = dlsym(h, "GPUinit");
1940 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1941 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1945 tmp = dlsym(h, "SPUinit");
1948 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1949 spu_plugins[spu_i++] = strdup(ent->d_name);
1953 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1960 dir = opendir("." MEMCARD_DIR);
1962 perror("scan_bios_plugins memcards opendir");
1977 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1980 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1981 if (stat(fname, &st) != 0) {
1982 printf("bad memcard file: %s\n", ent->d_name);
1986 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1987 memcards[mc_i++] = strdup(ent->d_name);
1991 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1995 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2000 void menu_init(void)
2002 char buff[MAXPATHLEN];
2004 strcpy(last_selected_fname, "/media");
2006 scan_bios_plugins();
2010 menu_set_defconfig();
2011 menu_load_config(0);
2016 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2017 if (g_menubg_src_ptr == NULL)
2019 emu_make_path(buff, "skin/background.png", sizeof(buff));
2020 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2022 #ifndef __ARM_ARCH_7A__ /* XXX */
2023 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2024 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2026 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2030 void menu_notify_mode_change(int w, int h, int bpp)
2041 g_layer_w = w; g_layer_h = h;
2045 if (h > g_menuscreen_h || (240 < h && h <= 360))
2046 goto fractional_4_3;
2048 // 4:3 that prefers integer scaling
2049 imult = g_menuscreen_h / h;
2050 g_layer_w = w * imult;
2051 g_layer_h = h * imult;
2052 mult = (float)g_layer_w / (float)g_layer_h;
2053 if (mult < 1.25f || mult > 1.666f)
2054 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2055 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2060 mult = 240.0f / (float)h * 4.0f / 3.0f;
2063 g_layer_w = mult * (float)g_menuscreen_h;
2064 g_layer_h = g_menuscreen_h;
2065 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2068 case SCALE_FULLSCREEN:
2069 g_layer_w = g_menuscreen_w;
2070 g_layer_h = g_menuscreen_h;
2077 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2078 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2079 if (g_layer_x < 0) g_layer_x = 0;
2080 if (g_layer_y < 0) g_layer_y = 0;
2081 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2082 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2085 static void menu_leave_emu(void)
2087 if (GPU_close != NULL) {
2088 int ret = GPU_close();
2090 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2093 plat_video_menu_enter(ready_to_go);
2095 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2096 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2097 int x = max(0, g_menuscreen_w - last_psx_w);
2098 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2099 int w = min(g_menuscreen_w, last_psx_w);
2100 int h = min(g_menuscreen_h, last_psx_h);
2101 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2102 u16 *s = pl_vout_buf;
2104 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2105 menu_darken_bg(d, s, w, 0);
2109 cpu_clock = plat_cpu_clock_get();
2112 void menu_prepare_emu(void)
2114 R3000Acpu *prev_cpu = psxCpu;
2116 plat_video_menu_leave();
2118 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2120 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2121 if (psxCpu != prev_cpu)
2122 // note that this does not really reset, just clears drc caches
2125 // core doesn't care about Config.Cdda changes,
2126 // so handle them manually here
2131 apply_lcdrate(Config.PsxType);
2132 apply_filter(filter);
2133 plat_cpu_clock_apply(cpu_clock);
2135 // push config to GPU plugin
2136 plugin_call_rearmed_cbs();
2138 if (GPU_open != NULL) {
2139 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2141 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2147 void me_update_msg(const char *msg)
2149 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2150 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2152 menu_error_time = plat_get_ticks_ms();
2153 lprintf("msg: %s\n", menu_error_msg);