2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
4 * This work is licensed under the terms of any of these licenses
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
21 #include "plugin_lib.h"
26 #include "common/plat.h"
27 #include "common/input.h"
28 #include "linux/in_evdev.h"
29 #include "../libpcsxcore/misc.h"
30 #include "../libpcsxcore/cdrom.h"
31 #include "../libpcsxcore/psemu_plugin_defs.h"
32 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
33 #include "../plugins/dfinput/main.h"
36 #define array_size(x) (sizeof(x) / sizeof(x[0]))
75 static int last_psx_w, last_psx_h, last_psx_bpp;
76 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
77 static char rom_fname_reload[MAXPATHLEN];
78 static char last_selected_fname[MAXPATHLEN];
79 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
80 static int memcard1_sel, memcard2_sel;
81 int g_opts, analog_deadzone;
84 extern int iUseReverb;
85 extern int iUseInterpolation;
87 extern int iSPUIRQWait;
91 static const char *bioses[24];
92 static const char *gpu_plugins[16];
93 static const char *spu_plugins[16];
94 static const char *memcards[32];
95 static int bios_sel, gpu_plugsel, spu_plugsel;
98 static int min(int x, int y) { return x < y ? x : y; }
99 static int max(int x, int y) { return x > y ? x : y; }
101 void emu_make_path(char *buff, const char *end, int size)
105 end_len = strlen(end);
106 pos = plat_get_root_dir(buff, size);
107 strncpy(buff + pos, end, size - pos);
109 if (pos + end_len > size - 1)
110 printf("Warning: path truncated: %s\n", buff);
113 static int emu_check_save_file(int slot)
115 int ret = emu_check_state(slot);
116 return ret == 0 ? 1 : 0;
119 static int emu_save_load_game(int load, int unused)
124 ret = emu_load_state(state_slot);
126 // reflect hle/bios mode from savestate
129 else if (bios_sel == 0 && bioses[1] != NULL)
130 // XXX: maybe find the right bios instead
134 ret = emu_save_state(state_slot);
139 // propagate menu settings to the emu vars
140 static void menu_sync_config(void)
142 static int allow_abs_only_old;
147 Config.PsxType = region - 1;
149 switch (in_type_sel1) {
150 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
151 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
152 default: in_type1 = PSE_PAD_TYPE_STANDARD;
154 switch (in_type_sel2) {
155 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
156 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
157 default: in_type2 = PSE_PAD_TYPE_STANDARD;
159 if (in_evdev_allow_abs_only != allow_abs_only_old) {
160 plat_rescan_inputs();
161 allow_abs_only_old = in_evdev_allow_abs_only;
164 iVolume = 768 + 128 * volume_boost;
165 pl_rearmed_cbs.frameskip = frameskip - 1;
166 pl_timing_prepare(Config.PsxType);
169 static void menu_set_defconfig(void)
175 analog_deadzone = 50;
178 in_type_sel1 = in_type_sel2 = 0;
179 in_evdev_allow_abs_only = 0;
180 Config.Xa = Config.Cdda = Config.Sio =
181 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
182 Config.CdrReschedule = 0;
184 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
185 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
186 pl_rearmed_cbs.gpu_unai.abe_hack =
187 pl_rearmed_cbs.gpu_unai.no_light =
188 pl_rearmed_cbs.gpu_unai.no_blend = 0;
191 iUseInterpolation = 1;
199 #define CE_CONFIG_STR(val) \
200 { #val, 0, Config.val }
202 #define CE_CONFIG_VAL(val) \
203 { #val, sizeof(Config.val), &Config.val }
205 #define CE_STR(val) \
208 #define CE_INTVAL(val) \
209 { #val, sizeof(val), &val }
211 #define CE_INTVAL_P(val) \
212 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
214 // 'versioned' var, used when defaults change
215 #define CE_INTVAL_V(val, ver) \
216 { #val #ver, sizeof(val), &val }
218 #define CE_INTVAL_PV(val, ver) \
219 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
221 static const struct {
229 // CE_CONFIG_STR(Cdr),
234 CE_CONFIG_VAL(Debug),
235 CE_CONFIG_VAL(PsxOut),
236 CE_CONFIG_VAL(SpuIrq),
237 CE_CONFIG_VAL(RCntFix),
238 CE_CONFIG_VAL(VSyncWA),
240 CE_CONFIG_VAL(CdrReschedule),
242 CE_INTVAL_V(scaling, 2),
243 CE_INTVAL(g_layer_x),
244 CE_INTVAL(g_layer_y),
245 CE_INTVAL(g_layer_w),
246 CE_INTVAL(g_layer_h),
248 CE_INTVAL(state_slot),
249 CE_INTVAL(cpu_clock),
251 CE_INTVAL(in_type_sel1),
252 CE_INTVAL(in_type_sel2),
253 CE_INTVAL(analog_deadzone),
254 CE_INTVAL_V(frameskip, 2),
255 CE_INTVAL_P(gpu_peops.iUseDither),
256 CE_INTVAL_P(gpu_peops.dwActFixes),
257 CE_INTVAL_P(gpu_unai.abe_hack),
258 CE_INTVAL_P(gpu_unai.no_light),
259 CE_INTVAL_P(gpu_unai.no_blend),
260 CE_INTVAL_V(iUseReverb, 3),
261 CE_INTVAL_V(iXAPitch, 3),
262 CE_INTVAL_V(iUseInterpolation, 3),
263 CE_INTVAL_V(iSPUIRQWait, 3),
264 CE_INTVAL_V(iUseTimer, 3),
265 CE_INTVAL(warned_about_bios),
266 CE_INTVAL(in_evdev_allow_abs_only),
267 CE_INTVAL(volume_boost),
270 static char *get_cd_label(void)
272 static char trimlabel[33];
275 strncpy(trimlabel, CdromLabel, 32);
277 for (j = 31; j >= 0; j--)
278 if (trimlabel[j] == ' ')
284 static void make_cfg_fname(char *buf, size_t size, int is_game)
287 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
289 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
292 static void keys_write_all(FILE *f);
294 static int menu_write_config(int is_game)
296 char cfgfile[MAXPATHLEN];
300 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
301 f = fopen(cfgfile, "w");
303 printf("menu_write_config: failed to open: %s\n", cfgfile);
307 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
308 fprintf(f, "%s = ", config_data[i].name);
309 switch (config_data[i].len) {
311 fprintf(f, "%s\n", (char *)config_data[i].val);
314 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
317 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
320 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
323 printf("menu_write_config: unhandled len %d for %s\n",
324 config_data[i].len, config_data[i].name);
330 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
338 static void parse_str_val(char *cval, const char *src)
341 strncpy(cval, src, MAXPATHLEN);
342 cval[MAXPATHLEN - 1] = 0;
343 tmp = strchr(cval, '\n');
345 tmp = strchr(cval, '\r');
350 static void keys_load_all(const char *cfg);
352 static int menu_load_config(int is_game)
354 char cfgfile[MAXPATHLEN];
360 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
361 f = fopen(cfgfile, "r");
363 printf("menu_load_config: failed to open: %s\n", cfgfile);
367 fseek(f, 0, SEEK_END);
370 printf("bad size %ld: %s\n", size, cfgfile);
374 cfg = malloc(size + 1);
378 fseek(f, 0, SEEK_SET);
379 if (fread(cfg, 1, size, f) != size) {
380 printf("failed to read: %s\n", cfgfile);
385 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
389 tmp = strstr(cfg, config_data[i].name);
392 tmp += strlen(config_data[i].name);
393 if (strncmp(tmp, " = ", 3) != 0)
397 if (config_data[i].len == 0) {
398 parse_str_val(config_data[i].val, tmp);
403 val = strtoul(tmp, &tmp2, 16);
404 if (tmp2 == NULL || tmp == tmp2)
405 continue; // parse failed
407 switch (config_data[i].len) {
409 *(u8 *)config_data[i].val = val;
412 *(u16 *)config_data[i].val = val;
415 *(u32 *)config_data[i].val = val;
418 printf("menu_load_config: unhandled len %d for %s\n",
419 config_data[i].len, config_data[i].name);
425 char *tmp = strstr(cfg, "lastcdimg = ");
428 parse_str_val(last_selected_fname, tmp);
435 for (i = bios_sel = 0; bioses[i] != NULL; i++)
436 if (strcmp(Config.Bios, bioses[i]) == 0)
437 { bios_sel = i; break; }
439 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
440 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
441 { gpu_plugsel = i; break; }
443 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
444 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
445 { spu_plugsel = i; break; }
456 // rrrr rggg gggb bbbb
457 static unsigned short fname2color(const char *fname)
459 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
460 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
461 const char *ext = strrchr(fname, '.');
466 for (i = 0; i < array_size(cdimg_exts); i++)
467 if (strcasecmp(ext, cdimg_exts[i]) == 0)
469 for (i = 0; i < array_size(other_exts); i++)
470 if (strcasecmp(ext, other_exts[i]) == 0)
475 static void draw_savestate_bg(int slot);
477 static const char *filter_exts[] = {
478 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
481 #define MENU_ALIGN_LEFT
482 #ifdef __ARM_ARCH_7A__ // assume hires device
488 #define menu_init menu_init_common
489 #include "common/menu.c"
492 // a bit of black magic here
493 static void draw_savestate_bg(int slot)
495 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
497 char fname[MAXPATHLEN];
504 ret = get_state_filename(fname, sizeof(fname), slot);
508 f = gzopen(fname, "rb");
512 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
513 fprintf(stderr, "gzseek failed\n");
518 gpu = malloc(sizeof(*gpu));
524 ret = gzread(f, gpu, sizeof(*gpu));
526 if (ret != sizeof(*gpu)) {
527 fprintf(stderr, "gzread failed\n");
531 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
533 if (gpu->ulStatus & 0x800000)
534 goto out; // disabled
536 x = gpu->ulControl[5] & 0x3ff;
537 y = (gpu->ulControl[5] >> 10) & 0x1ff;
538 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
539 w = psx_widths[(gpu->ulStatus >> 16) & 7];
540 tmp = gpu->ulControl[7];
541 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
542 if (gpu->ulStatus & 0x80000) // doubleheight
545 x = max(0, g_menuscreen_w - w) & ~3;
546 y = max(0, g_menuscreen_h / 2 - h / 2);
547 w = min(g_menuscreen_w, w);
548 h = min(g_menuscreen_h, h);
549 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
551 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
552 if (gpu->ulStatus & 0x200000)
553 bgr888_to_rgb565(d, s, w * 3);
555 bgr555_to_rgb565(d, s, w * 2);
556 #ifndef __ARM_ARCH_7A__
557 // better darken this on small screens
558 menu_darken_bg(d, d, w * 2, 0);
566 // ---------- XXX: pandora specific -----------
568 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
569 static char **pnd_filter_list;
571 static void apply_filter(int which)
577 if (pnd_filter_list == NULL || which == old)
580 for (i = 0; i < which; i++)
581 if (pnd_filter_list[i] == NULL)
584 if (pnd_filter_list[i] == NULL)
587 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
592 static void apply_lcdrate(int pal)
600 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
601 pnd_script_base, pal ? 50 : 60);
606 static menu_entry e_menu_gfx_options[];
608 static void pnd_menu_init(void)
616 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
618 dir = opendir("/etc/pandora/conf/dss_fir");
620 perror("filter opendir");
633 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
642 mfilters = calloc(count + 1, sizeof(mfilters[0]));
643 if (mfilters == NULL)
647 for (i = 0; (ent = readdir(dir)); ) {
650 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
653 len = strlen(ent->d_name);
655 // skip pre-HF5 extra files
656 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
658 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
661 // have to cut "_up_h" for pre-HF5
662 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
665 if (len > sizeof(buff) - 1)
668 strncpy(buff, ent->d_name, len);
670 mfilters[i] = strdup(buff);
671 if (mfilters[i] != NULL)
676 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
677 e_menu_gfx_options[i].data = (void *)mfilters;
678 pnd_filter_list = mfilters;
681 void menu_finish(void)
683 plat_cpu_clock_apply(cpu_clock_st);
686 // -------------- key config --------------
688 me_bind_action me_ctrl_actions[] =
690 { "UP ", 1 << DKEY_UP},
691 { "DOWN ", 1 << DKEY_DOWN },
692 { "LEFT ", 1 << DKEY_LEFT },
693 { "RIGHT ", 1 << DKEY_RIGHT },
694 { "TRIANGLE", 1 << DKEY_TRIANGLE },
695 { "CIRCLE ", 1 << DKEY_CIRCLE },
696 { "CROSS ", 1 << DKEY_CROSS },
697 { "SQUARE ", 1 << DKEY_SQUARE },
698 { "L1 ", 1 << DKEY_L1 },
699 { "R1 ", 1 << DKEY_R1 },
700 { "L2 ", 1 << DKEY_L2 },
701 { "R2 ", 1 << DKEY_R2 },
702 { "L3 ", 1 << DKEY_L3 },
703 { "R3 ", 1 << DKEY_R3 },
704 { "START ", 1 << DKEY_START },
705 { "SELECT ", 1 << DKEY_SELECT },
709 me_bind_action emuctrl_actions[] =
711 { "Save State ", 1 << SACTION_SAVE_STATE },
712 { "Load State ", 1 << SACTION_LOAD_STATE },
713 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
714 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
715 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
716 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
717 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
718 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
719 { "Gun A button ", 1 << SACTION_GUN_A },
720 { "Gun B button ", 1 << SACTION_GUN_B },
721 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
725 static char *mystrip(char *str)
730 for (i = 0; i < len; i++)
731 if (str[i] != ' ') break;
732 if (i > 0) memmove(str, str + i, len - i + 1);
735 for (i = len - 1; i >= 0; i--)
736 if (str[i] != ' ') break;
742 static void get_line(char *d, size_t size, const char *s)
747 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
758 static void keys_write_all(FILE *f)
762 for (d = 0; d < IN_MAX_DEVS; d++)
764 const int *binds = in_get_dev_binds(d);
765 const char *name = in_get_dev_name(d, 0, 0);
768 if (binds == NULL || name == NULL)
771 fprintf(f, "binddev = %s\n", name);
772 in_get_config(d, IN_CFG_BIND_COUNT, &count);
774 for (k = 0; k < count; k++)
779 act[0] = act[31] = 0;
780 name = in_get_key_name(d, k);
782 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
783 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
784 mask = me_ctrl_actions[i].mask;
786 strncpy(act, me_ctrl_actions[i].name, 31);
787 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
790 mask = me_ctrl_actions[i].mask << 16;
792 strncpy(act, me_ctrl_actions[i].name, 31);
793 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
798 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
799 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
800 mask = emuctrl_actions[i].mask;
802 strncpy(act, emuctrl_actions[i].name, 31);
803 fprintf(f, "bind %s = %s\n", name, mystrip(act));
811 static int parse_bind_val(const char *val, int *type)
815 *type = IN_BINDTYPE_NONE;
819 if (strncasecmp(val, "player", 6) == 0)
821 int player, shift = 0;
822 player = atoi(val + 6) - 1;
824 if ((unsigned int)player > 1)
829 *type = IN_BINDTYPE_PLAYER12;
830 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
831 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
832 return me_ctrl_actions[i].mask << shift;
835 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
836 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
837 *type = IN_BINDTYPE_EMU;
838 return emuctrl_actions[i].mask;
845 static void keys_load_all(const char *cfg)
847 char dev[256], key[128], *act;
853 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
856 get_line(dev, sizeof(dev), p);
857 dev_id = in_config_parse_dev(dev);
859 printf("input: can't handle dev: %s\n", dev);
863 in_unbind_all(dev_id, -1, -1);
864 while ((p = strstr(p, "bind"))) {
865 if (strncmp(p, "binddev = ", 10) == 0)
870 printf("input: parse error: %16s..\n", p);
874 get_line(key, sizeof(key), p);
875 act = strchr(key, '=');
877 printf("parse failed: %16s..\n", p);
885 bind = parse_bind_val(act, &bindtype);
886 if (bind != -1 && bind != 0) {
887 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
888 in_config_bind_key(dev_id, key, bind, bindtype);
891 lprintf("config: unhandled action \"%s\"\n", act);
897 static int key_config_loop_wrap(int id, int keys)
900 case MA_CTRL_PLAYER1:
901 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
903 case MA_CTRL_PLAYER2:
904 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
907 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
915 static const char *mgn_dev_name(int id, int *offs)
917 const char *name = NULL;
920 if (id == MA_CTRL_DEV_FIRST)
923 for (; it < IN_MAX_DEVS; it++) {
924 name = in_get_dev_name(it, 1, 1);
933 static const char *mgn_saveloadcfg(int id, int *offs)
938 static int mh_savecfg(int id, int keys)
940 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
941 me_update_msg("config saved");
943 me_update_msg("failed to write config");
948 static int mh_input_rescan(int id, int keys)
950 //menu_sync_config();
951 plat_rescan_inputs();
952 me_update_msg("rescan complete.");
957 static const char *men_in_type_sel[] = {
958 "Standard (SCPH-1080)",
959 "Analog (SCPH-1150)",
963 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
964 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
966 static menu_entry e_menu_keyconfig[] =
968 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
969 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
970 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
972 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
973 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
974 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
975 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
976 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
977 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
978 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
979 mee_handler ("Rescan devices", mh_input_rescan),
981 mee_label ("Input devices:"),
982 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
983 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
984 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
985 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
986 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
987 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
988 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
992 static int menu_loop_keyconfig(int id, int keys)
996 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
997 me_loop(e_menu_keyconfig, &sel);
1001 // ------------ gfx options menu ------------
1003 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1004 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1005 "using d-pad or move it using R+d-pad";
1006 static const char *men_dummy[] = { NULL };
1008 static int menu_loop_cscaler(int id, int keys)
1012 scaling = SCALE_CUSTOM;
1014 omap_enable_layer(1);
1019 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1020 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1021 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1024 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1025 if (inp & PBTN_UP) g_layer_y--;
1026 if (inp & PBTN_DOWN) g_layer_y++;
1027 if (inp & PBTN_LEFT) g_layer_x--;
1028 if (inp & PBTN_RIGHT) g_layer_x++;
1029 if (!(inp & PBTN_R)) {
1030 if (inp & PBTN_UP) g_layer_h += 2;
1031 if (inp & PBTN_DOWN) g_layer_h -= 2;
1032 if (inp & PBTN_LEFT) g_layer_w += 2;
1033 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1035 if (inp & (PBTN_MOK|PBTN_MBACK))
1038 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1039 if (g_layer_x < 0) g_layer_x = 0;
1040 if (g_layer_x > 640) g_layer_x = 640;
1041 if (g_layer_y < 0) g_layer_y = 0;
1042 if (g_layer_y > 420) g_layer_y = 420;
1043 if (g_layer_w < 160) g_layer_w = 160;
1044 if (g_layer_h < 60) g_layer_h = 60;
1045 if (g_layer_x + g_layer_w > 800)
1046 g_layer_w = 800 - g_layer_x;
1047 if (g_layer_y + g_layer_h > 480)
1048 g_layer_h = 480 - g_layer_y;
1049 omap_enable_layer(1);
1053 omap_enable_layer(0);
1058 static menu_entry e_menu_gfx_options[] =
1060 mee_enum ("Scaler", 0, scaling, men_scaler),
1061 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1062 // mee_onoff ("Vsync", 0, vsync, 1),
1063 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1067 static int menu_loop_gfx_options(int id, int keys)
1071 me_loop(e_menu_gfx_options, &sel);
1076 // ------------ bios/plugins ------------
1078 static menu_entry e_menu_plugin_gpu_unai[] =
1080 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1081 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1082 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1086 static int menu_loop_plugin_gpu_unai(int id, int keys)
1089 me_loop(e_menu_plugin_gpu_unai, &sel);
1093 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1094 static const char h_gpu_0[] = "Needed for Chrono Cross";
1095 static const char h_gpu_1[] = "Capcom fighting games";
1096 static const char h_gpu_2[] = "Black screens in Lunar";
1097 static const char h_gpu_3[] = "Compatibility mode";
1098 static const char h_gpu_6[] = "Pandemonium 2";
1099 static const char h_gpu_7[] = "Skip every second frame";
1100 static const char h_gpu_8[] = "Needed by Dark Forces";
1101 static const char h_gpu_9[] = "better g-colors, worse textures";
1102 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1104 static menu_entry e_menu_plugin_gpu_peops[] =
1106 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1107 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1108 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1109 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1110 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1111 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1112 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1113 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1114 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1115 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1119 static int menu_loop_plugin_gpu_peops(int id, int keys)
1122 me_loop(e_menu_plugin_gpu_peops, &sel);
1126 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1127 static const char h_spu_volboost[] = "Large values cause distortion";
1128 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1129 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1131 static menu_entry e_menu_plugin_spu[] =
1133 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1134 mee_onoff ("Reverb", 0, iUseReverb, 2),
1135 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1136 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1137 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1138 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1142 static int menu_loop_plugin_spu(int id, int keys)
1145 me_loop(e_menu_plugin_spu, &sel);
1149 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1150 "savestates and can't be changed there. Must save\n"
1151 "config and reload the game for change to take effect";
1152 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1153 "for plugin change to take effect";
1154 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1155 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1156 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1158 static menu_entry e_menu_plugin_options[] =
1160 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1161 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1162 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1163 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1164 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1165 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1169 static menu_entry e_menu_main2[];
1171 static int menu_loop_plugin_options(int id, int keys)
1174 me_loop(e_menu_plugin_options, &sel);
1176 // sync BIOS/plugins
1177 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1178 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1179 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1180 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1185 // ------------ adv options menu ------------
1187 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1188 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1189 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1190 "(green: normal, red: fmod, blue: noise)";
1191 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1192 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1193 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1194 "(proper .cue/.bin dump is needed otherwise)";
1195 static const char h_cfg_sio[] = "You should not need this, breaks games";
1196 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1197 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1198 "(timing hack, breaks other games)";
1199 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1200 "(timing hack, breaks other games)";
1201 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1202 "(CD timing hack, breaks FMVs)";
1203 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1204 "Might be useful to overcome some dynarec bugs";
1206 static menu_entry e_menu_adv_options[] =
1208 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1209 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1210 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1211 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1212 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1213 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1214 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1215 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1216 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1217 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1218 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1222 static int menu_loop_adv_options(int id, int keys)
1225 me_loop(e_menu_adv_options, &sel);
1229 // ------------ options menu ------------
1231 static int mh_restore_defaults(int id, int keys)
1233 menu_set_defconfig();
1234 me_update_msg("defaults restored");
1238 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1239 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1241 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1242 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1243 "loading state or both";
1245 static const char h_restore_def[] = "Switches back to default / recommended\n"
1247 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1249 static menu_entry e_menu_options[] =
1251 // mee_range ("Save slot", 0, state_slot, 0, 9),
1252 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1253 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1254 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1255 mee_enum ("Region", 0, region, men_region),
1256 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1257 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1258 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1259 mee_handler ("[Advanced]", menu_loop_adv_options),
1260 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1261 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1262 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1266 static int menu_loop_options(int id, int keys)
1271 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1272 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1273 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1275 me_loop(e_menu_options, &sel);
1280 // ------------ debug menu ------------
1282 static void draw_frame_debug(GPUFreeze_t *gpuf)
1284 int w = min(g_menuscreen_w, 1024);
1285 int h = min(g_menuscreen_h, 512);
1286 u16 *d = g_menuscreen_ptr;
1287 u16 *s = (u16 *)gpuf->psxVRam;
1291 gpuf->ulFreezeVersion = 1;
1292 if (GPU_freeze != NULL)
1293 GPU_freeze(1, gpuf);
1295 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1296 bgr555_to_rgb565(d, s, w * 2);
1298 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1299 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1300 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1301 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1302 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1305 static void debug_menu_loop(void)
1310 gpuf = malloc(sizeof(*gpuf));
1317 draw_frame_debug(gpuf);
1320 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1321 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1322 if (inp & PBTN_MBACK)
1329 // --------- memcard manager ---------
1331 static void draw_mc_icon(int dx, int dy, const u16 *s)
1336 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1338 for (y = 0; y < 16; y++, s += 16) {
1339 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1340 for (x = 0; x < 16; x++) {
1342 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1343 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1349 static void draw_mc_bg(void)
1351 McdBlock *blocks1, *blocks2;
1355 blocks1 = malloc(15 * sizeof(blocks1[0]));
1356 blocks2 = malloc(15 * sizeof(blocks1[0]));
1357 if (blocks1 == NULL || blocks2 == NULL)
1360 for (i = 0; i < 15; i++) {
1361 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1362 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1367 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1369 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1373 maxicons = g_menuscreen_h / 32;
1376 row2 = g_menuscreen_w / 2;
1377 for (i = 0; i < maxicons; i++) {
1378 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1379 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1381 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1382 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1385 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1393 static void handle_memcard_sel(void)
1396 if (memcard1_sel != 0)
1397 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1399 if (memcard2_sel != 0)
1400 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1401 LoadMcds(Config.Mcd1, Config.Mcd2);
1405 static menu_entry e_memcard_options[] =
1407 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1408 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1412 static int menu_loop_memcards(int id, int keys)
1418 memcard1_sel = memcard2_sel = 0;
1419 p = strrchr(Config.Mcd1, '/');
1421 for (i = 0; memcards[i] != NULL; i++)
1422 if (strcmp(p + 1, memcards[i]) == 0)
1423 { memcard1_sel = i; break; }
1424 p = strrchr(Config.Mcd2, '/');
1426 for (i = 0; memcards[i] != NULL; i++)
1427 if (strcmp(p + 1, memcards[i]) == 0)
1428 { memcard2_sel = i; break; }
1430 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1432 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1437 // --------- main menu help ----------
1439 static void menu_bios_warn(void)
1442 static const char msg[] =
1443 "You don't seem to have copied any BIOS files to\n"
1444 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1445 "While many games work fine with fake (HLE) BIOS,\n"
1446 "others (like MGS and FF8) require BIOS to work.\n"
1447 "After copying the file, you'll also need to\n"
1448 "select it in the emu's options->[BIOS/Plugins]\n\n"
1449 "The file is usually named SCPH1001.BIN, but\n"
1450 "other not compressed files can be used too.\n\n"
1451 "Press (B) or (X) to continue";
1455 draw_menu_message(msg, NULL);
1457 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1458 if (inp & (PBTN_MBACK|PBTN_MOK))
1463 // ------------ main menu ------------
1467 static void draw_frame_main(void)
1474 if (CdromId[0] != 0) {
1475 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1476 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1477 Config.HLE ? "HLE" : "BIOS");
1478 smalltext_out16(4, 1, buff, 0x105f);
1483 tmp = localtime(<ime);
1484 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1485 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1486 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1490 static void draw_frame_credits(void)
1492 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1495 static const char credits_text[] =
1497 "(C) 1999-2003 PCSX Team\n"
1498 "(C) 2005-2009 PCSX-df Team\n"
1499 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1500 "GPU and SPU code by Pete Bernert\n"
1501 " and the P.E.Op.S. team\n"
1502 "ARM recompiler (C) 2009-2011 Ari64\n"
1503 "PCSX4ALL plugins by PCSX4ALL team\n"
1504 " Chui, Franxis, Unai\n\n"
1505 "integration, optimization and\n"
1506 " frontend (C) 2010-2011 notaz\n";
1508 static int reset_game(void)
1511 if (bios_sel == 0 && !Config.HLE)
1517 if (CheckCdrom() != -1) {
1523 static int reload_plugins(const char *cdimg)
1529 set_cd_image(cdimg);
1531 pcnt_hook_plugins();
1533 if (OpenPlugins() == -1) {
1534 me_update_msg("failed to open plugins");
1537 plugin_call_rearmed_cbs();
1540 CdromLabel[0] = '\0';
1545 static int run_bios(void)
1551 if (reload_plugins(NULL) != 0)
1559 static int run_exe(void)
1563 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1568 if (reload_plugins(NULL) != 0)
1572 if (Load(fname) != 0) {
1573 me_update_msg("exe load failed, bad file?");
1582 static int run_cd_image(const char *fname)
1585 reload_plugins(fname);
1587 // always autodetect, menu_sync_config will override as needed
1590 if (CheckCdrom() == -1) {
1591 // Only check the CD if we are starting the console with a CD
1593 me_update_msg("unsupported/invalid CD image");
1599 // Read main executable directly from CDRom and start it
1600 if (LoadCdrom() == -1) {
1602 me_update_msg("failed to load CD image");
1610 static int romsel_run(void)
1612 int prev_gpu, prev_spu;
1615 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1619 printf("selected file: %s\n", fname);
1621 new_dynarec_clear_full();
1623 if (run_cd_image(fname) != 0)
1626 prev_gpu = gpu_plugsel;
1627 prev_spu = spu_plugsel;
1628 if (menu_load_config(1) != 0)
1629 menu_load_config(0);
1631 // check for plugin changes, have to repeat
1632 // loading if game config changed plugins to reload them
1633 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1634 printf("plugin change detected, reloading plugins..\n");
1635 if (run_cd_image(fname) != 0)
1639 strcpy(last_selected_fname, rom_fname_reload);
1643 static int swap_cd_image(void)
1647 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1651 printf("selected file: %s\n", fname);
1654 CdromLabel[0] = '\0';
1656 set_cd_image(fname);
1657 if (ReloadCdromPlugin() < 0) {
1658 me_update_msg("failed to load cdr plugin");
1661 if (CDR_open() < 0) {
1662 me_update_msg("failed to open cdr plugin");
1666 SetCdOpenCaseTime(time(NULL) + 2);
1669 strcpy(last_selected_fname, rom_fname_reload);
1673 static int main_menu_handler(int id, int keys)
1677 case MA_MAIN_RESUME_GAME:
1681 case MA_MAIN_SAVE_STATE:
1683 return menu_loop_savestate(0);
1685 case MA_MAIN_LOAD_STATE:
1687 return menu_loop_savestate(1);
1689 case MA_MAIN_RESET_GAME:
1690 if (ready_to_go && reset_game() == 0)
1693 case MA_MAIN_LOAD_ROM:
1694 if (romsel_run() == 0)
1697 case MA_MAIN_SWAP_CD:
1698 if (swap_cd_image() == 0)
1701 case MA_MAIN_RUN_BIOS:
1702 if (run_bios() == 0)
1705 case MA_MAIN_RUN_EXE:
1709 case MA_MAIN_CREDITS:
1710 draw_menu_message(credits_text, draw_frame_credits);
1711 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1717 lprintf("%s: something unknown selected\n", __FUNCTION__);
1724 static menu_entry e_menu_main2[] =
1726 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1727 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1728 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1729 mee_handler ("Memcard manager", menu_loop_memcards),
1733 static int main_menu2_handler(int id, int keys)
1737 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1738 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1740 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1743 static const char h_extra[] = "Change CD, manage memcards..\n";
1745 static menu_entry e_menu_main[] =
1749 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1750 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1751 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1752 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1753 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1754 mee_handler ("Options", menu_loop_options),
1755 mee_handler ("Controls", menu_loop_keyconfig),
1756 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1757 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1758 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1762 // ----------------------------
1764 static void menu_leave_emu(void);
1766 void menu_loop(void)
1772 if (bioses[1] == NULL && !warned_about_bios) {
1774 warned_about_bios = 1;
1777 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1778 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1779 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1780 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1782 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1785 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1786 } while (!ready_to_go);
1788 /* wait until menu, ok, back is released */
1789 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1792 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1797 static int qsort_strcmp(const void *p1, const void *p2)
1799 char * const *s1 = (char * const *)p1;
1800 char * const *s2 = (char * const *)p2;
1801 return strcasecmp(*s1, *s2);
1804 static void scan_bios_plugins(void)
1806 char fname[MAXPATHLEN];
1808 int bios_i, gpu_i, spu_i, mc_i;
1813 gpu_plugins[0] = "builtin_gpu";
1814 spu_plugins[0] = "builtin_spu";
1815 memcards[0] = "(none)";
1816 bios_i = gpu_i = spu_i = mc_i = 1;
1818 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1819 dir = opendir(fname);
1821 perror("scan_bios_plugins bios opendir");
1836 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1839 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1840 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1841 printf("bad BIOS file: %s\n", ent->d_name);
1845 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1846 bioses[bios_i++] = strdup(ent->d_name);
1850 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1856 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1857 dir = opendir(fname);
1859 perror("scan_bios_plugins plugins opendir");
1873 p = strstr(ent->d_name, ".so");
1877 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1878 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1880 fprintf(stderr, "%s\n", dlerror());
1884 // now what do we have here?
1885 tmp = dlsym(h, "GPUinit");
1888 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1889 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1893 tmp = dlsym(h, "SPUinit");
1896 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1897 spu_plugins[spu_i++] = strdup(ent->d_name);
1901 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1908 dir = opendir("." MEMCARD_DIR);
1910 perror("scan_bios_plugins memcards opendir");
1925 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1928 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1929 if (stat(fname, &st) != 0) {
1930 printf("bad memcard file: %s\n", ent->d_name);
1934 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1935 memcards[mc_i++] = strdup(ent->d_name);
1939 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1943 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1948 void menu_init(void)
1950 char buff[MAXPATHLEN];
1952 strcpy(last_selected_fname, "/media");
1954 scan_bios_plugins();
1958 menu_set_defconfig();
1959 menu_load_config(0);
1964 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1965 if (g_menubg_src_ptr == NULL)
1967 emu_make_path(buff, "skin/background.png", sizeof(buff));
1968 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1970 #ifndef __ARM_ARCH_7A__ /* XXX */
1971 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
1972 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
1974 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
1978 void menu_notify_mode_change(int w, int h, int bpp)
1989 g_layer_w = w; g_layer_h = h;
1993 mult = 240.0f / (float)h * 4.0f / 3.0f;
1996 g_layer_w = mult * (float)g_menuscreen_h;
1997 g_layer_h = g_menuscreen_h;
1998 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2002 // 4:3 that prefers integer scaling
2003 imult = g_menuscreen_h / h;
2004 g_layer_w = w * imult;
2005 g_layer_h = h * imult;
2006 mult = (float)g_layer_w / (float)g_layer_h;
2007 if (mult < 1.25f || mult > 1.666f)
2008 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2009 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2012 case SCALE_FULLSCREEN:
2013 g_layer_w = g_menuscreen_w;
2014 g_layer_h = g_menuscreen_h;
2021 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2022 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2023 if (g_layer_x < 0) g_layer_x = 0;
2024 if (g_layer_y < 0) g_layer_y = 0;
2025 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2026 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2029 static void menu_leave_emu(void)
2031 if (GPU_close != NULL) {
2032 int ret = GPU_close();
2034 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2037 plat_video_menu_enter(ready_to_go);
2039 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2040 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2041 int x = max(0, g_menuscreen_w - last_psx_w);
2042 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2043 int w = min(g_menuscreen_w, last_psx_w);
2044 int h = min(g_menuscreen_h, last_psx_h);
2045 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2046 u16 *s = pl_vout_buf;
2048 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2049 menu_darken_bg(d, s, w, 0);
2053 cpu_clock = plat_cpu_clock_get();
2056 void menu_prepare_emu(void)
2058 R3000Acpu *prev_cpu = psxCpu;
2060 plat_video_menu_leave();
2062 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2064 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2065 if (psxCpu != prev_cpu)
2066 // note that this does not really reset, just clears drc caches
2069 // core doesn't care about Config.Cdda changes,
2070 // so handle them manually here
2075 apply_lcdrate(Config.PsxType);
2076 apply_filter(filter);
2077 plat_cpu_clock_apply(cpu_clock);
2079 // push config to GPU plugin
2080 plugin_call_rearmed_cbs();
2082 if (GPU_open != NULL) {
2083 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2085 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2091 void me_update_msg(const char *msg)
2093 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2094 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2096 menu_error_time = plat_get_ticks_ms();
2097 lprintf("msg: %s\n", menu_error_msg);