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;
190 in_type_sel1 = in_type_sel2 = 0;
191 in_evdev_allow_abs_only = 0;
192 Config.Xa = Config.Cdda = Config.Sio =
193 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
194 Config.CdrReschedule = 0;
196 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
197 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
198 pl_rearmed_cbs.gpu_unai.abe_hack =
199 pl_rearmed_cbs.gpu_unai.no_light =
200 pl_rearmed_cbs.gpu_unai.no_blend = 0;
203 iUseInterpolation = 1;
207 #ifndef __ARM_ARCH_7A__ /* XXX */
209 iUseInterpolation = 0;
215 #define CE_CONFIG_STR(val) \
216 { #val, 0, Config.val }
218 #define CE_CONFIG_VAL(val) \
219 { #val, sizeof(Config.val), &Config.val }
221 #define CE_STR(val) \
224 #define CE_INTVAL(val) \
225 { #val, sizeof(val), &val }
227 #define CE_INTVAL_P(val) \
228 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
230 // 'versioned' var, used when defaults change
231 #define CE_INTVAL_V(val, ver) \
232 { #val #ver, sizeof(val), &val }
234 #define CE_INTVAL_PV(val, ver) \
235 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
237 static const struct {
245 // CE_CONFIG_STR(Cdr),
250 CE_CONFIG_VAL(Debug),
251 CE_CONFIG_VAL(PsxOut),
252 CE_CONFIG_VAL(SpuIrq),
253 CE_CONFIG_VAL(RCntFix),
254 CE_CONFIG_VAL(VSyncWA),
256 CE_CONFIG_VAL(CdrReschedule),
258 CE_INTVAL_V(scaling, 2),
259 CE_INTVAL(g_layer_x),
260 CE_INTVAL(g_layer_y),
261 CE_INTVAL(g_layer_w),
262 CE_INTVAL(g_layer_h),
264 CE_INTVAL(state_slot),
265 CE_INTVAL(cpu_clock),
267 CE_INTVAL(in_type_sel1),
268 CE_INTVAL(in_type_sel2),
269 CE_INTVAL(analog_deadzone),
270 CE_INTVAL_V(frameskip, 2),
271 CE_INTVAL_P(gpu_peops.iUseDither),
272 CE_INTVAL_P(gpu_peops.dwActFixes),
273 CE_INTVAL_P(gpu_unai.abe_hack),
274 CE_INTVAL_P(gpu_unai.no_light),
275 CE_INTVAL_P(gpu_unai.no_blend),
276 CE_INTVAL_V(iUseReverb, 3),
277 CE_INTVAL_V(iXAPitch, 3),
278 CE_INTVAL_V(iUseInterpolation, 3),
279 CE_INTVAL_V(iSPUIRQWait, 3),
280 CE_INTVAL_V(iUseTimer, 3),
281 CE_INTVAL(warned_about_bios),
282 CE_INTVAL(in_evdev_allow_abs_only),
283 CE_INTVAL(volume_boost),
284 CE_INTVAL(psx_clock),
287 static char *get_cd_label(void)
289 static char trimlabel[33];
292 strncpy(trimlabel, CdromLabel, 32);
294 for (j = 31; j >= 0; j--)
295 if (trimlabel[j] == ' ')
301 static void make_cfg_fname(char *buf, size_t size, int is_game)
304 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
306 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
309 static void keys_write_all(FILE *f);
311 static int menu_write_config(int is_game)
313 char cfgfile[MAXPATHLEN];
317 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
318 f = fopen(cfgfile, "w");
320 printf("menu_write_config: failed to open: %s\n", cfgfile);
324 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
325 fprintf(f, "%s = ", config_data[i].name);
326 switch (config_data[i].len) {
328 fprintf(f, "%s\n", (char *)config_data[i].val);
331 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
334 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
337 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
340 printf("menu_write_config: unhandled len %d for %s\n",
341 config_data[i].len, config_data[i].name);
347 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
355 static void parse_str_val(char *cval, const char *src)
358 strncpy(cval, src, MAXPATHLEN);
359 cval[MAXPATHLEN - 1] = 0;
360 tmp = strchr(cval, '\n');
362 tmp = strchr(cval, '\r');
367 static void keys_load_all(const char *cfg);
369 static int menu_load_config(int is_game)
371 char cfgfile[MAXPATHLEN];
377 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
378 f = fopen(cfgfile, "r");
380 printf("menu_load_config: failed to open: %s\n", cfgfile);
384 fseek(f, 0, SEEK_END);
387 printf("bad size %ld: %s\n", size, cfgfile);
391 cfg = malloc(size + 1);
395 fseek(f, 0, SEEK_SET);
396 if (fread(cfg, 1, size, f) != size) {
397 printf("failed to read: %s\n", cfgfile);
402 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
406 tmp = strstr(cfg, config_data[i].name);
409 tmp += strlen(config_data[i].name);
410 if (strncmp(tmp, " = ", 3) != 0)
414 if (config_data[i].len == 0) {
415 parse_str_val(config_data[i].val, tmp);
420 val = strtoul(tmp, &tmp2, 16);
421 if (tmp2 == NULL || tmp == tmp2)
422 continue; // parse failed
424 switch (config_data[i].len) {
426 *(u8 *)config_data[i].val = val;
429 *(u16 *)config_data[i].val = val;
432 *(u32 *)config_data[i].val = val;
435 printf("menu_load_config: unhandled len %d for %s\n",
436 config_data[i].len, config_data[i].name);
442 char *tmp = strstr(cfg, "lastcdimg = ");
445 parse_str_val(last_selected_fname, tmp);
460 for (i = bios_sel = 0; bioses[i] != NULL; i++)
461 if (strcmp(Config.Bios, bioses[i]) == 0)
462 { bios_sel = i; break; }
464 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
465 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
466 { gpu_plugsel = i; break; }
468 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
469 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
470 { spu_plugsel = i; break; }
475 // rrrr rggg gggb bbbb
476 static unsigned short fname2color(const char *fname)
478 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
479 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
480 const char *ext = strrchr(fname, '.');
485 for (i = 0; i < array_size(cdimg_exts); i++)
486 if (strcasecmp(ext, cdimg_exts[i]) == 0)
488 for (i = 0; i < array_size(other_exts); i++)
489 if (strcasecmp(ext, other_exts[i]) == 0)
494 static void draw_savestate_bg(int slot);
496 static const char *filter_exts[] = {
497 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
500 #define MENU_ALIGN_LEFT
501 #ifdef __ARM_ARCH_7A__ // assume hires device
507 #define menu_init menu_init_common
508 #include "common/menu.c"
511 // a bit of black magic here
512 static void draw_savestate_bg(int slot)
514 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
516 char fname[MAXPATHLEN];
523 ret = get_state_filename(fname, sizeof(fname), slot);
527 f = gzopen(fname, "rb");
531 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
532 fprintf(stderr, "gzseek failed\n");
537 gpu = malloc(sizeof(*gpu));
543 ret = gzread(f, gpu, sizeof(*gpu));
545 if (ret != sizeof(*gpu)) {
546 fprintf(stderr, "gzread failed\n");
550 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
552 if (gpu->ulStatus & 0x800000)
553 goto out; // disabled
555 x = gpu->ulControl[5] & 0x3ff;
556 y = (gpu->ulControl[5] >> 10) & 0x1ff;
557 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
558 w = psx_widths[(gpu->ulStatus >> 16) & 7];
559 tmp = gpu->ulControl[7];
560 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
561 if (gpu->ulStatus & 0x80000) // doubleheight
564 x = max(0, g_menuscreen_w - w) & ~3;
565 y = max(0, g_menuscreen_h / 2 - h / 2);
566 w = min(g_menuscreen_w, w);
567 h = min(g_menuscreen_h, h);
568 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
570 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
571 if (gpu->ulStatus & 0x200000)
572 bgr888_to_rgb565(d, s, w * 3);
574 bgr555_to_rgb565(d, s, w * 2);
575 #ifndef __ARM_ARCH_7A__
576 // better darken this on small screens
577 menu_darken_bg(d, d, w * 2, 0);
585 // ---------- XXX: pandora specific -----------
587 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
588 static char **pnd_filter_list;
590 static void apply_filter(int which)
596 if (pnd_filter_list == NULL || which == old)
599 for (i = 0; i < which; i++)
600 if (pnd_filter_list[i] == NULL)
603 if (pnd_filter_list[i] == NULL)
606 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
611 static void apply_lcdrate(int pal)
619 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
620 pnd_script_base, pal ? 50 : 60);
625 static menu_entry e_menu_gfx_options[];
627 static void pnd_menu_init(void)
635 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
637 dir = opendir("/etc/pandora/conf/dss_fir");
639 perror("filter opendir");
652 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
661 mfilters = calloc(count + 1, sizeof(mfilters[0]));
662 if (mfilters == NULL)
666 for (i = 0; (ent = readdir(dir)); ) {
669 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
672 len = strlen(ent->d_name);
674 // skip pre-HF5 extra files
675 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
677 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
680 // have to cut "_up_h" for pre-HF5
681 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
684 if (len > sizeof(buff) - 1)
687 strncpy(buff, ent->d_name, len);
689 mfilters[i] = strdup(buff);
690 if (mfilters[i] != NULL)
695 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
696 e_menu_gfx_options[i].data = (void *)mfilters;
697 pnd_filter_list = mfilters;
700 void menu_finish(void)
702 plat_cpu_clock_apply(cpu_clock_st);
705 // -------------- key config --------------
707 me_bind_action me_ctrl_actions[] =
709 { "UP ", 1 << DKEY_UP},
710 { "DOWN ", 1 << DKEY_DOWN },
711 { "LEFT ", 1 << DKEY_LEFT },
712 { "RIGHT ", 1 << DKEY_RIGHT },
713 { "TRIANGLE", 1 << DKEY_TRIANGLE },
714 { "CIRCLE ", 1 << DKEY_CIRCLE },
715 { "CROSS ", 1 << DKEY_CROSS },
716 { "SQUARE ", 1 << DKEY_SQUARE },
717 { "L1 ", 1 << DKEY_L1 },
718 { "R1 ", 1 << DKEY_R1 },
719 { "L2 ", 1 << DKEY_L2 },
720 { "R2 ", 1 << DKEY_R2 },
721 { "L3 ", 1 << DKEY_L3 },
722 { "R3 ", 1 << DKEY_R3 },
723 { "START ", 1 << DKEY_START },
724 { "SELECT ", 1 << DKEY_SELECT },
728 me_bind_action emuctrl_actions[] =
730 { "Save State ", 1 << SACTION_SAVE_STATE },
731 { "Load State ", 1 << SACTION_LOAD_STATE },
732 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
733 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
734 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
735 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
736 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
737 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
738 { "Gun A button ", 1 << SACTION_GUN_A },
739 { "Gun B button ", 1 << SACTION_GUN_B },
740 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
744 static char *mystrip(char *str)
749 for (i = 0; i < len; i++)
750 if (str[i] != ' ') break;
751 if (i > 0) memmove(str, str + i, len - i + 1);
754 for (i = len - 1; i >= 0; i--)
755 if (str[i] != ' ') break;
761 static void get_line(char *d, size_t size, const char *s)
766 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
777 static void keys_write_all(FILE *f)
781 for (d = 0; d < IN_MAX_DEVS; d++)
783 const int *binds = in_get_dev_binds(d);
784 const char *name = in_get_dev_name(d, 0, 0);
787 if (binds == NULL || name == NULL)
790 fprintf(f, "binddev = %s\n", name);
791 in_get_config(d, IN_CFG_BIND_COUNT, &count);
793 for (k = 0; k < count; k++)
798 act[0] = act[31] = 0;
799 name = in_get_key_name(d, k);
801 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
802 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
803 mask = me_ctrl_actions[i].mask;
805 strncpy(act, me_ctrl_actions[i].name, 31);
806 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
809 mask = me_ctrl_actions[i].mask << 16;
811 strncpy(act, me_ctrl_actions[i].name, 31);
812 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
817 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
818 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
819 mask = emuctrl_actions[i].mask;
821 strncpy(act, emuctrl_actions[i].name, 31);
822 fprintf(f, "bind %s = %s\n", name, mystrip(act));
830 static int parse_bind_val(const char *val, int *type)
834 *type = IN_BINDTYPE_NONE;
838 if (strncasecmp(val, "player", 6) == 0)
840 int player, shift = 0;
841 player = atoi(val + 6) - 1;
843 if ((unsigned int)player > 1)
848 *type = IN_BINDTYPE_PLAYER12;
849 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
850 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
851 return me_ctrl_actions[i].mask << shift;
854 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
855 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
856 *type = IN_BINDTYPE_EMU;
857 return emuctrl_actions[i].mask;
864 static void keys_load_all(const char *cfg)
866 char dev[256], key[128], *act;
872 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
875 get_line(dev, sizeof(dev), p);
876 dev_id = in_config_parse_dev(dev);
878 printf("input: can't handle dev: %s\n", dev);
882 in_unbind_all(dev_id, -1, -1);
883 while ((p = strstr(p, "bind"))) {
884 if (strncmp(p, "binddev = ", 10) == 0)
889 printf("input: parse error: %16s..\n", p);
893 get_line(key, sizeof(key), p);
894 act = strchr(key, '=');
896 printf("parse failed: %16s..\n", p);
904 bind = parse_bind_val(act, &bindtype);
905 if (bind != -1 && bind != 0) {
906 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
907 in_config_bind_key(dev_id, key, bind, bindtype);
910 lprintf("config: unhandled action \"%s\"\n", act);
916 static int key_config_loop_wrap(int id, int keys)
919 case MA_CTRL_PLAYER1:
920 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
922 case MA_CTRL_PLAYER2:
923 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
926 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
934 static const char *mgn_dev_name(int id, int *offs)
936 const char *name = NULL;
939 if (id == MA_CTRL_DEV_FIRST)
942 for (; it < IN_MAX_DEVS; it++) {
943 name = in_get_dev_name(it, 1, 1);
952 static const char *mgn_saveloadcfg(int id, int *offs)
957 static int mh_savecfg(int id, int keys)
959 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
960 me_update_msg("config saved");
962 me_update_msg("failed to write config");
967 static int mh_input_rescan(int id, int keys)
969 //menu_sync_config();
970 plat_rescan_inputs();
971 me_update_msg("rescan complete.");
976 static const char *men_in_type_sel[] = {
977 "Standard (SCPH-1080)",
978 "Analog (SCPH-1150)",
982 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
983 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
985 static menu_entry e_menu_keyconfig[] =
987 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
988 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
989 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
991 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
992 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
993 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
994 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
995 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
996 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
997 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
998 mee_handler ("Rescan devices", mh_input_rescan),
1000 mee_label ("Input devices:"),
1001 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1002 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1003 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1004 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
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),
1011 static int menu_loop_keyconfig(int id, int keys)
1015 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1016 me_loop(e_menu_keyconfig, &sel);
1020 // ------------ gfx options menu ------------
1022 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1023 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1024 "using d-pad or move it using R+d-pad";
1025 static const char *men_dummy[] = { NULL };
1027 static int menu_loop_cscaler(int id, int keys)
1031 scaling = SCALE_CUSTOM;
1033 omap_enable_layer(1);
1038 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1039 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1040 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1043 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1044 if (inp & PBTN_UP) g_layer_y--;
1045 if (inp & PBTN_DOWN) g_layer_y++;
1046 if (inp & PBTN_LEFT) g_layer_x--;
1047 if (inp & PBTN_RIGHT) g_layer_x++;
1048 if (!(inp & PBTN_R)) {
1049 if (inp & PBTN_UP) g_layer_h += 2;
1050 if (inp & PBTN_DOWN) g_layer_h -= 2;
1051 if (inp & PBTN_LEFT) g_layer_w += 2;
1052 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1054 if (inp & (PBTN_MOK|PBTN_MBACK))
1057 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1058 if (g_layer_x < 0) g_layer_x = 0;
1059 if (g_layer_x > 640) g_layer_x = 640;
1060 if (g_layer_y < 0) g_layer_y = 0;
1061 if (g_layer_y > 420) g_layer_y = 420;
1062 if (g_layer_w < 160) g_layer_w = 160;
1063 if (g_layer_h < 60) g_layer_h = 60;
1064 if (g_layer_x + g_layer_w > 800)
1065 g_layer_w = 800 - g_layer_x;
1066 if (g_layer_y + g_layer_h > 480)
1067 g_layer_h = 480 - g_layer_y;
1068 omap_enable_layer(1);
1072 omap_enable_layer(0);
1077 static menu_entry e_menu_gfx_options[] =
1079 mee_enum ("Scaler", 0, scaling, men_scaler),
1080 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1081 // mee_onoff ("Vsync", 0, vsync, 1),
1082 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1086 static int menu_loop_gfx_options(int id, int keys)
1090 me_loop(e_menu_gfx_options, &sel);
1095 // ------------ bios/plugins ------------
1097 static menu_entry e_menu_plugin_gpu_unai[] =
1099 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1100 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1101 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1105 static int menu_loop_plugin_gpu_unai(int id, int keys)
1108 me_loop(e_menu_plugin_gpu_unai, &sel);
1112 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1113 static const char h_gpu_0[] = "Needed for Chrono Cross";
1114 static const char h_gpu_1[] = "Capcom fighting games";
1115 static const char h_gpu_2[] = "Black screens in Lunar";
1116 static const char h_gpu_3[] = "Compatibility mode";
1117 static const char h_gpu_6[] = "Pandemonium 2";
1118 static const char h_gpu_7[] = "Skip every second frame";
1119 static const char h_gpu_8[] = "Needed by Dark Forces";
1120 static const char h_gpu_9[] = "better g-colors, worse textures";
1121 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1123 static menu_entry e_menu_plugin_gpu_peops[] =
1125 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1126 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1127 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1128 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1129 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1130 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1131 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1132 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1133 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1134 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1138 static int menu_loop_plugin_gpu_peops(int id, int keys)
1141 me_loop(e_menu_plugin_gpu_peops, &sel);
1145 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1146 static const char h_spu_volboost[] = "Large values cause distortion";
1147 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1148 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1150 static menu_entry e_menu_plugin_spu[] =
1152 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1153 mee_onoff ("Reverb", 0, iUseReverb, 2),
1154 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1155 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1156 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1157 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1161 static int menu_loop_plugin_spu(int id, int keys)
1164 me_loop(e_menu_plugin_spu, &sel);
1168 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1169 "savestates and can't be changed there. Must save\n"
1170 "config and reload the game for change to take effect";
1171 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1172 "for plugin change to take effect";
1173 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1174 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1175 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1177 static menu_entry e_menu_plugin_options[] =
1179 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1180 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1181 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1182 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1183 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1184 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1188 static menu_entry e_menu_main2[];
1190 static int menu_loop_plugin_options(int id, int keys)
1193 me_loop(e_menu_plugin_options, &sel);
1195 // sync BIOS/plugins
1196 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1197 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1198 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1199 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1204 // ------------ adv options menu ------------
1206 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1207 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1208 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1209 "(green: normal, red: fmod, blue: noise)";
1210 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1211 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1212 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1213 "(proper .cue/.bin dump is needed otherwise)";
1214 static const char h_cfg_sio[] = "You should not need this, breaks games";
1215 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1216 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1217 "(timing hack, breaks other games)";
1218 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1219 "(timing hack, breaks other games)";
1220 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1221 "(CD timing hack, breaks FMVs)";
1222 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1223 "(may break games, must reload game to take effect)";
1224 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1225 "Might be useful to overcome some dynarec bugs";
1227 static menu_entry e_menu_adv_options[] =
1229 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1230 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1231 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1232 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1233 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1234 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1235 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1236 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1237 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1238 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1239 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1240 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1244 static int menu_loop_adv_options(int id, int keys)
1247 me_loop(e_menu_adv_options, &sel);
1251 // ------------ options menu ------------
1253 static int mh_restore_defaults(int id, int keys)
1255 menu_set_defconfig();
1256 me_update_msg("defaults restored");
1260 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1261 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1263 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1264 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1265 "loading state or both";
1267 static const char h_restore_def[] = "Switches back to default / recommended\n"
1269 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1271 static menu_entry e_menu_options[] =
1273 // mee_range ("Save slot", 0, state_slot, 0, 9),
1274 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1275 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1276 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1277 mee_enum ("Region", 0, region, men_region),
1278 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1279 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1280 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1281 mee_handler ("[Advanced]", menu_loop_adv_options),
1282 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1283 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1284 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1288 static int menu_loop_options(int id, int keys)
1293 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1294 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1295 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1297 me_loop(e_menu_options, &sel);
1302 // ------------ debug menu ------------
1304 static void draw_frame_debug(GPUFreeze_t *gpuf)
1306 int w = min(g_menuscreen_w, 1024);
1307 int h = min(g_menuscreen_h, 512);
1308 u16 *d = g_menuscreen_ptr;
1309 u16 *s = (u16 *)gpuf->psxVRam;
1313 gpuf->ulFreezeVersion = 1;
1314 if (GPU_freeze != NULL)
1315 GPU_freeze(1, gpuf);
1317 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1318 bgr555_to_rgb565(d, s, w * 2);
1320 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1321 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1322 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1323 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1324 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1327 static void debug_menu_loop(void)
1332 gpuf = malloc(sizeof(*gpuf));
1339 draw_frame_debug(gpuf);
1342 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1343 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1344 if (inp & PBTN_MBACK)
1351 // --------- memcard manager ---------
1353 static void draw_mc_icon(int dx, int dy, const u16 *s)
1358 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1360 for (y = 0; y < 16; y++, s += 16) {
1361 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1362 for (x = 0; x < 16; x++) {
1364 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1365 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1371 static void draw_mc_bg(void)
1373 McdBlock *blocks1, *blocks2;
1377 blocks1 = malloc(15 * sizeof(blocks1[0]));
1378 blocks2 = malloc(15 * sizeof(blocks1[0]));
1379 if (blocks1 == NULL || blocks2 == NULL)
1382 for (i = 0; i < 15; i++) {
1383 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1384 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1389 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1391 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1395 maxicons = g_menuscreen_h / 32;
1398 row2 = g_menuscreen_w / 2;
1399 for (i = 0; i < maxicons; i++) {
1400 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1401 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1403 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1404 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1407 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1415 static void handle_memcard_sel(void)
1418 if (memcard1_sel != 0)
1419 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1421 if (memcard2_sel != 0)
1422 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1423 LoadMcds(Config.Mcd1, Config.Mcd2);
1427 static menu_entry e_memcard_options[] =
1429 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1430 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1434 static int menu_loop_memcards(int id, int keys)
1440 memcard1_sel = memcard2_sel = 0;
1441 p = strrchr(Config.Mcd1, '/');
1443 for (i = 0; memcards[i] != NULL; i++)
1444 if (strcmp(p + 1, memcards[i]) == 0)
1445 { memcard1_sel = i; break; }
1446 p = strrchr(Config.Mcd2, '/');
1448 for (i = 0; memcards[i] != NULL; i++)
1449 if (strcmp(p + 1, memcards[i]) == 0)
1450 { memcard2_sel = i; break; }
1452 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1454 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1459 // --------- main menu help ----------
1461 static void menu_bios_warn(void)
1464 static const char msg[] =
1465 "You don't seem to have copied any BIOS\n"
1467 #ifdef __ARM_ARCH_7A__ // XXX
1468 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1470 "pcsx_rearmed/bios/\n\n"
1472 "While many games work fine with fake\n"
1473 "(HLE) BIOS, others (like MGS and FF8)\n"
1474 "require BIOS to work.\n"
1475 "After copying the file, you'll also need\n"
1476 "to select it in the emu's menu:\n"
1477 "options->[BIOS/Plugins]\n\n"
1478 "The file is usually named SCPH1001.BIN,\n"
1479 "but other not compressed files can be\n"
1481 "Press (B) or (X) to continue";
1485 draw_menu_message(msg, NULL);
1487 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1488 if (inp & (PBTN_MBACK|PBTN_MOK))
1493 // ------------ main menu ------------
1497 static void draw_frame_main(void)
1504 if (CdromId[0] != 0) {
1505 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1506 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1507 Config.HLE ? "HLE" : "BIOS");
1508 smalltext_out16(4, 1, buff, 0x105f);
1513 tmp = localtime(<ime);
1514 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1515 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1516 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1520 static void draw_frame_credits(void)
1522 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1525 static const char credits_text[] =
1527 "(C) 1999-2003 PCSX Team\n"
1528 "(C) 2005-2009 PCSX-df Team\n"
1529 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1530 "GPU and SPU code by Pete Bernert\n"
1531 " and the P.E.Op.S. team\n"
1532 "ARM recompiler (C) 2009-2011 Ari64\n"
1533 "PCSX4ALL plugins by PCSX4ALL team\n"
1534 " Chui, Franxis, Unai\n\n"
1535 "integration, optimization and\n"
1536 " frontend (C) 2010-2011 notaz\n";
1538 static int reset_game(void)
1541 if (bios_sel == 0 && !Config.HLE)
1547 if (CheckCdrom() != -1) {
1553 static int reload_plugins(const char *cdimg)
1559 set_cd_image(cdimg);
1561 pcnt_hook_plugins();
1563 if (OpenPlugins() == -1) {
1564 me_update_msg("failed to open plugins");
1567 plugin_call_rearmed_cbs();
1570 CdromLabel[0] = '\0';
1575 static int run_bios(void)
1581 if (reload_plugins(NULL) != 0)
1589 static int run_exe(void)
1593 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1598 if (reload_plugins(NULL) != 0)
1602 if (Load(fname) != 0) {
1603 me_update_msg("exe load failed, bad file?");
1612 static int run_cd_image(const char *fname)
1615 reload_plugins(fname);
1617 // always autodetect, menu_sync_config will override as needed
1620 if (CheckCdrom() == -1) {
1621 // Only check the CD if we are starting the console with a CD
1623 me_update_msg("unsupported/invalid CD image");
1629 // Read main executable directly from CDRom and start it
1630 if (LoadCdrom() == -1) {
1632 me_update_msg("failed to load CD image");
1640 static int romsel_run(void)
1642 int prev_gpu, prev_spu;
1645 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1649 printf("selected file: %s\n", fname);
1651 new_dynarec_clear_full();
1653 if (run_cd_image(fname) != 0)
1656 prev_gpu = gpu_plugsel;
1657 prev_spu = spu_plugsel;
1658 if (menu_load_config(1) != 0)
1659 menu_load_config(0);
1661 // check for plugin changes, have to repeat
1662 // loading if game config changed plugins to reload them
1663 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1664 printf("plugin change detected, reloading plugins..\n");
1665 if (run_cd_image(fname) != 0)
1669 strcpy(last_selected_fname, rom_fname_reload);
1673 static int swap_cd_image(void)
1677 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1681 printf("selected file: %s\n", fname);
1684 CdromLabel[0] = '\0';
1686 set_cd_image(fname);
1687 if (ReloadCdromPlugin() < 0) {
1688 me_update_msg("failed to load cdr plugin");
1691 if (CDR_open() < 0) {
1692 me_update_msg("failed to open cdr plugin");
1696 SetCdOpenCaseTime(time(NULL) + 2);
1699 strcpy(last_selected_fname, rom_fname_reload);
1703 static int main_menu_handler(int id, int keys)
1707 case MA_MAIN_RESUME_GAME:
1711 case MA_MAIN_SAVE_STATE:
1713 return menu_loop_savestate(0);
1715 case MA_MAIN_LOAD_STATE:
1717 return menu_loop_savestate(1);
1719 case MA_MAIN_RESET_GAME:
1720 if (ready_to_go && reset_game() == 0)
1723 case MA_MAIN_LOAD_ROM:
1724 if (romsel_run() == 0)
1727 case MA_MAIN_SWAP_CD:
1728 if (swap_cd_image() == 0)
1731 case MA_MAIN_RUN_BIOS:
1732 if (run_bios() == 0)
1735 case MA_MAIN_RUN_EXE:
1739 case MA_MAIN_CREDITS:
1740 draw_menu_message(credits_text, draw_frame_credits);
1741 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1747 lprintf("%s: something unknown selected\n", __FUNCTION__);
1754 static menu_entry e_menu_main2[] =
1756 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1757 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1758 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1759 mee_handler ("Memcard manager", menu_loop_memcards),
1763 static int main_menu2_handler(int id, int keys)
1767 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1768 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1770 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1773 static const char h_extra[] = "Change CD, manage memcards..\n";
1775 static menu_entry e_menu_main[] =
1779 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1780 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1781 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1782 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1783 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1784 mee_handler ("Options", menu_loop_options),
1785 mee_handler ("Controls", menu_loop_keyconfig),
1786 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1787 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1788 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1792 // ----------------------------
1794 static void menu_leave_emu(void);
1796 void menu_loop(void)
1802 if (bioses[1] == NULL && !warned_about_bios) {
1804 warned_about_bios = 1;
1807 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1808 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1809 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1810 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1812 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1815 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1816 } while (!ready_to_go);
1818 /* wait until menu, ok, back is released */
1819 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1822 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1827 static int qsort_strcmp(const void *p1, const void *p2)
1829 char * const *s1 = (char * const *)p1;
1830 char * const *s2 = (char * const *)p2;
1831 return strcasecmp(*s1, *s2);
1834 static void scan_bios_plugins(void)
1836 char fname[MAXPATHLEN];
1838 int bios_i, gpu_i, spu_i, mc_i;
1843 gpu_plugins[0] = "builtin_gpu";
1844 spu_plugins[0] = "builtin_spu";
1845 memcards[0] = "(none)";
1846 bios_i = gpu_i = spu_i = mc_i = 1;
1848 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1849 dir = opendir(fname);
1851 perror("scan_bios_plugins bios opendir");
1866 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1869 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1870 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1871 printf("bad BIOS file: %s\n", ent->d_name);
1875 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1876 bioses[bios_i++] = strdup(ent->d_name);
1880 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1886 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1887 dir = opendir(fname);
1889 perror("scan_bios_plugins plugins opendir");
1903 p = strstr(ent->d_name, ".so");
1907 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1908 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1910 fprintf(stderr, "%s\n", dlerror());
1914 // now what do we have here?
1915 tmp = dlsym(h, "GPUinit");
1918 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1919 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1923 tmp = dlsym(h, "SPUinit");
1926 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1927 spu_plugins[spu_i++] = strdup(ent->d_name);
1931 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1938 dir = opendir("." MEMCARD_DIR);
1940 perror("scan_bios_plugins memcards opendir");
1955 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1958 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1959 if (stat(fname, &st) != 0) {
1960 printf("bad memcard file: %s\n", ent->d_name);
1964 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1965 memcards[mc_i++] = strdup(ent->d_name);
1969 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1973 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1978 void menu_init(void)
1980 char buff[MAXPATHLEN];
1982 strcpy(last_selected_fname, "/media");
1984 scan_bios_plugins();
1988 menu_set_defconfig();
1989 menu_load_config(0);
1994 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1995 if (g_menubg_src_ptr == NULL)
1997 emu_make_path(buff, "skin/background.png", sizeof(buff));
1998 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2000 #ifndef __ARM_ARCH_7A__ /* XXX */
2001 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2002 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2004 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2008 void menu_notify_mode_change(int w, int h, int bpp)
2019 g_layer_w = w; g_layer_h = h;
2023 if (h > g_menuscreen_h || (240 < h && h <= 360))
2024 goto fractional_4_3;
2026 // 4:3 that prefers integer scaling
2027 imult = g_menuscreen_h / h;
2028 g_layer_w = w * imult;
2029 g_layer_h = h * imult;
2030 mult = (float)g_layer_w / (float)g_layer_h;
2031 if (mult < 1.25f || mult > 1.666f)
2032 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2033 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2038 mult = 240.0f / (float)h * 4.0f / 3.0f;
2041 g_layer_w = mult * (float)g_menuscreen_h;
2042 g_layer_h = g_menuscreen_h;
2043 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2046 case SCALE_FULLSCREEN:
2047 g_layer_w = g_menuscreen_w;
2048 g_layer_h = g_menuscreen_h;
2055 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2056 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2057 if (g_layer_x < 0) g_layer_x = 0;
2058 if (g_layer_y < 0) g_layer_y = 0;
2059 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2060 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2063 static void menu_leave_emu(void)
2065 if (GPU_close != NULL) {
2066 int ret = GPU_close();
2068 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2071 plat_video_menu_enter(ready_to_go);
2073 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2074 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2075 int x = max(0, g_menuscreen_w - last_psx_w);
2076 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2077 int w = min(g_menuscreen_w, last_psx_w);
2078 int h = min(g_menuscreen_h, last_psx_h);
2079 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2080 u16 *s = pl_vout_buf;
2082 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2083 menu_darken_bg(d, s, w, 0);
2087 cpu_clock = plat_cpu_clock_get();
2090 void menu_prepare_emu(void)
2092 R3000Acpu *prev_cpu = psxCpu;
2094 plat_video_menu_leave();
2096 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2098 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2099 if (psxCpu != prev_cpu)
2100 // note that this does not really reset, just clears drc caches
2103 // core doesn't care about Config.Cdda changes,
2104 // so handle them manually here
2109 apply_lcdrate(Config.PsxType);
2110 apply_filter(filter);
2111 plat_cpu_clock_apply(cpu_clock);
2113 // push config to GPU plugin
2114 plugin_call_rearmed_cbs();
2116 if (GPU_open != NULL) {
2117 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2119 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2125 void me_update_msg(const char *msg)
2127 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2128 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2130 menu_error_time = plat_get_ticks_ms();
2131 lprintf("msg: %s\n", menu_error_msg);