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 #define DEFAULT_PSX_CLOCK 50
85 #define DEFAULT_PSX_CLOCK_S "50"
88 extern int iUseReverb;
89 extern int iUseInterpolation;
91 extern int iSPUIRQWait;
95 static const char *bioses[24];
96 static const char *gpu_plugins[16];
97 static const char *spu_plugins[16];
98 static const char *memcards[32];
99 static int bios_sel, gpu_plugsel, spu_plugsel;
102 static int min(int x, int y) { return x < y ? x : y; }
103 static int max(int x, int y) { return x > y ? x : y; }
105 void emu_make_path(char *buff, const char *end, int size)
109 end_len = strlen(end);
110 pos = plat_get_root_dir(buff, size);
111 strncpy(buff + pos, end, size - pos);
113 if (pos + end_len > size - 1)
114 printf("Warning: path truncated: %s\n", buff);
117 static int emu_check_save_file(int slot)
119 int ret = emu_check_state(slot);
120 return ret == 0 ? 1 : 0;
123 static int emu_save_load_game(int load, int unused)
128 ret = emu_load_state(state_slot);
130 // reflect hle/bios mode from savestate
133 else if (bios_sel == 0 && bioses[1] != NULL)
134 // XXX: maybe find the right bios instead
138 ret = emu_save_state(state_slot);
143 // propagate menu settings to the emu vars
144 static void menu_sync_config(void)
146 static int allow_abs_only_old;
151 Config.PsxType = region - 1;
153 cycle_multiplier = 10000 / psx_clock;
155 switch (in_type_sel1) {
156 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
157 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
158 default: in_type1 = PSE_PAD_TYPE_STANDARD;
160 switch (in_type_sel2) {
161 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
162 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
163 default: in_type2 = PSE_PAD_TYPE_STANDARD;
165 if (in_evdev_allow_abs_only != allow_abs_only_old) {
166 plat_rescan_inputs();
167 allow_abs_only_old = in_evdev_allow_abs_only;
170 iVolume = 768 + 128 * volume_boost;
171 pl_rearmed_cbs.frameskip = frameskip - 1;
172 pl_timing_prepare(Config.PsxType);
175 static void menu_set_defconfig(void)
181 analog_deadzone = 70;
182 psx_clock = DEFAULT_PSX_CLOCK;
185 in_type_sel1 = in_type_sel2 = 0;
186 in_evdev_allow_abs_only = 0;
187 Config.Xa = Config.Cdda = Config.Sio =
188 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
189 Config.CdrReschedule = 0;
191 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
192 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
193 pl_rearmed_cbs.gpu_unai.abe_hack =
194 pl_rearmed_cbs.gpu_unai.no_light =
195 pl_rearmed_cbs.gpu_unai.no_blend = 0;
198 iUseInterpolation = 1;
202 #ifndef __ARM_ARCH_7A__ /* XXX */
204 iUseInterpolation = 0;
210 #define CE_CONFIG_STR(val) \
211 { #val, 0, Config.val }
213 #define CE_CONFIG_VAL(val) \
214 { #val, sizeof(Config.val), &Config.val }
216 #define CE_STR(val) \
219 #define CE_INTVAL(val) \
220 { #val, sizeof(val), &val }
222 #define CE_INTVAL_P(val) \
223 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
225 // 'versioned' var, used when defaults change
226 #define CE_INTVAL_V(val, ver) \
227 { #val #ver, sizeof(val), &val }
229 #define CE_INTVAL_PV(val, ver) \
230 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
232 static const struct {
240 // CE_CONFIG_STR(Cdr),
245 CE_CONFIG_VAL(Debug),
246 CE_CONFIG_VAL(PsxOut),
247 CE_CONFIG_VAL(SpuIrq),
248 CE_CONFIG_VAL(RCntFix),
249 CE_CONFIG_VAL(VSyncWA),
251 CE_CONFIG_VAL(CdrReschedule),
253 CE_INTVAL_V(scaling, 2),
254 CE_INTVAL(g_layer_x),
255 CE_INTVAL(g_layer_y),
256 CE_INTVAL(g_layer_w),
257 CE_INTVAL(g_layer_h),
259 CE_INTVAL(state_slot),
260 CE_INTVAL(cpu_clock),
262 CE_INTVAL(in_type_sel1),
263 CE_INTVAL(in_type_sel2),
264 CE_INTVAL(analog_deadzone),
265 CE_INTVAL_V(frameskip, 2),
266 CE_INTVAL_P(gpu_peops.iUseDither),
267 CE_INTVAL_P(gpu_peops.dwActFixes),
268 CE_INTVAL_P(gpu_unai.abe_hack),
269 CE_INTVAL_P(gpu_unai.no_light),
270 CE_INTVAL_P(gpu_unai.no_blend),
271 CE_INTVAL_V(iUseReverb, 3),
272 CE_INTVAL_V(iXAPitch, 3),
273 CE_INTVAL_V(iUseInterpolation, 3),
274 CE_INTVAL_V(iSPUIRQWait, 3),
275 CE_INTVAL_V(iUseTimer, 3),
276 CE_INTVAL(warned_about_bios),
277 CE_INTVAL(in_evdev_allow_abs_only),
278 CE_INTVAL(volume_boost),
279 CE_INTVAL(psx_clock),
282 static char *get_cd_label(void)
284 static char trimlabel[33];
287 strncpy(trimlabel, CdromLabel, 32);
289 for (j = 31; j >= 0; j--)
290 if (trimlabel[j] == ' ')
296 static void make_cfg_fname(char *buf, size_t size, int is_game)
299 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
301 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
304 static void keys_write_all(FILE *f);
306 static int menu_write_config(int is_game)
308 char cfgfile[MAXPATHLEN];
312 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
313 f = fopen(cfgfile, "w");
315 printf("menu_write_config: failed to open: %s\n", cfgfile);
319 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
320 fprintf(f, "%s = ", config_data[i].name);
321 switch (config_data[i].len) {
323 fprintf(f, "%s\n", (char *)config_data[i].val);
326 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
329 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
332 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
335 printf("menu_write_config: unhandled len %d for %s\n",
336 config_data[i].len, config_data[i].name);
342 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
350 static void parse_str_val(char *cval, const char *src)
353 strncpy(cval, src, MAXPATHLEN);
354 cval[MAXPATHLEN - 1] = 0;
355 tmp = strchr(cval, '\n');
357 tmp = strchr(cval, '\r');
362 static void keys_load_all(const char *cfg);
364 static int menu_load_config(int is_game)
366 char cfgfile[MAXPATHLEN];
372 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
373 f = fopen(cfgfile, "r");
375 printf("menu_load_config: failed to open: %s\n", cfgfile);
379 fseek(f, 0, SEEK_END);
382 printf("bad size %ld: %s\n", size, cfgfile);
386 cfg = malloc(size + 1);
390 fseek(f, 0, SEEK_SET);
391 if (fread(cfg, 1, size, f) != size) {
392 printf("failed to read: %s\n", cfgfile);
397 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
401 tmp = strstr(cfg, config_data[i].name);
404 tmp += strlen(config_data[i].name);
405 if (strncmp(tmp, " = ", 3) != 0)
409 if (config_data[i].len == 0) {
410 parse_str_val(config_data[i].val, tmp);
415 val = strtoul(tmp, &tmp2, 16);
416 if (tmp2 == NULL || tmp == tmp2)
417 continue; // parse failed
419 switch (config_data[i].len) {
421 *(u8 *)config_data[i].val = val;
424 *(u16 *)config_data[i].val = val;
427 *(u32 *)config_data[i].val = val;
430 printf("menu_load_config: unhandled len %d for %s\n",
431 config_data[i].len, config_data[i].name);
437 char *tmp = strstr(cfg, "lastcdimg = ");
440 parse_str_val(last_selected_fname, tmp);
447 for (i = bios_sel = 0; bioses[i] != NULL; i++)
448 if (strcmp(Config.Bios, bioses[i]) == 0)
449 { bios_sel = i; break; }
451 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
452 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
453 { gpu_plugsel = i; break; }
455 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
456 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
457 { spu_plugsel = i; break; }
468 // rrrr rggg gggb bbbb
469 static unsigned short fname2color(const char *fname)
471 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
472 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
473 const char *ext = strrchr(fname, '.');
478 for (i = 0; i < array_size(cdimg_exts); i++)
479 if (strcasecmp(ext, cdimg_exts[i]) == 0)
481 for (i = 0; i < array_size(other_exts); i++)
482 if (strcasecmp(ext, other_exts[i]) == 0)
487 static void draw_savestate_bg(int slot);
489 static const char *filter_exts[] = {
490 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
493 #define MENU_ALIGN_LEFT
494 #ifdef __ARM_ARCH_7A__ // assume hires device
500 #define menu_init menu_init_common
501 #include "common/menu.c"
504 // a bit of black magic here
505 static void draw_savestate_bg(int slot)
507 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
509 char fname[MAXPATHLEN];
516 ret = get_state_filename(fname, sizeof(fname), slot);
520 f = gzopen(fname, "rb");
524 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
525 fprintf(stderr, "gzseek failed\n");
530 gpu = malloc(sizeof(*gpu));
536 ret = gzread(f, gpu, sizeof(*gpu));
538 if (ret != sizeof(*gpu)) {
539 fprintf(stderr, "gzread failed\n");
543 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
545 if (gpu->ulStatus & 0x800000)
546 goto out; // disabled
548 x = gpu->ulControl[5] & 0x3ff;
549 y = (gpu->ulControl[5] >> 10) & 0x1ff;
550 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
551 w = psx_widths[(gpu->ulStatus >> 16) & 7];
552 tmp = gpu->ulControl[7];
553 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
554 if (gpu->ulStatus & 0x80000) // doubleheight
557 x = max(0, g_menuscreen_w - w) & ~3;
558 y = max(0, g_menuscreen_h / 2 - h / 2);
559 w = min(g_menuscreen_w, w);
560 h = min(g_menuscreen_h, h);
561 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
563 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
564 if (gpu->ulStatus & 0x200000)
565 bgr888_to_rgb565(d, s, w * 3);
567 bgr555_to_rgb565(d, s, w * 2);
568 #ifndef __ARM_ARCH_7A__
569 // better darken this on small screens
570 menu_darken_bg(d, d, w * 2, 0);
578 // ---------- XXX: pandora specific -----------
580 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
581 static char **pnd_filter_list;
583 static void apply_filter(int which)
589 if (pnd_filter_list == NULL || which == old)
592 for (i = 0; i < which; i++)
593 if (pnd_filter_list[i] == NULL)
596 if (pnd_filter_list[i] == NULL)
599 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
604 static void apply_lcdrate(int pal)
612 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
613 pnd_script_base, pal ? 50 : 60);
618 static menu_entry e_menu_gfx_options[];
620 static void pnd_menu_init(void)
628 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
630 dir = opendir("/etc/pandora/conf/dss_fir");
632 perror("filter opendir");
645 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
654 mfilters = calloc(count + 1, sizeof(mfilters[0]));
655 if (mfilters == NULL)
659 for (i = 0; (ent = readdir(dir)); ) {
662 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
665 len = strlen(ent->d_name);
667 // skip pre-HF5 extra files
668 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
670 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
673 // have to cut "_up_h" for pre-HF5
674 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
677 if (len > sizeof(buff) - 1)
680 strncpy(buff, ent->d_name, len);
682 mfilters[i] = strdup(buff);
683 if (mfilters[i] != NULL)
688 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
689 e_menu_gfx_options[i].data = (void *)mfilters;
690 pnd_filter_list = mfilters;
693 void menu_finish(void)
695 plat_cpu_clock_apply(cpu_clock_st);
698 // -------------- key config --------------
700 me_bind_action me_ctrl_actions[] =
702 { "UP ", 1 << DKEY_UP},
703 { "DOWN ", 1 << DKEY_DOWN },
704 { "LEFT ", 1 << DKEY_LEFT },
705 { "RIGHT ", 1 << DKEY_RIGHT },
706 { "TRIANGLE", 1 << DKEY_TRIANGLE },
707 { "CIRCLE ", 1 << DKEY_CIRCLE },
708 { "CROSS ", 1 << DKEY_CROSS },
709 { "SQUARE ", 1 << DKEY_SQUARE },
710 { "L1 ", 1 << DKEY_L1 },
711 { "R1 ", 1 << DKEY_R1 },
712 { "L2 ", 1 << DKEY_L2 },
713 { "R2 ", 1 << DKEY_R2 },
714 { "L3 ", 1 << DKEY_L3 },
715 { "R3 ", 1 << DKEY_R3 },
716 { "START ", 1 << DKEY_START },
717 { "SELECT ", 1 << DKEY_SELECT },
721 me_bind_action emuctrl_actions[] =
723 { "Save State ", 1 << SACTION_SAVE_STATE },
724 { "Load State ", 1 << SACTION_LOAD_STATE },
725 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
726 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
727 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
728 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
729 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
730 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
731 { "Gun A button ", 1 << SACTION_GUN_A },
732 { "Gun B button ", 1 << SACTION_GUN_B },
733 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
737 static char *mystrip(char *str)
742 for (i = 0; i < len; i++)
743 if (str[i] != ' ') break;
744 if (i > 0) memmove(str, str + i, len - i + 1);
747 for (i = len - 1; i >= 0; i--)
748 if (str[i] != ' ') break;
754 static void get_line(char *d, size_t size, const char *s)
759 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
770 static void keys_write_all(FILE *f)
774 for (d = 0; d < IN_MAX_DEVS; d++)
776 const int *binds = in_get_dev_binds(d);
777 const char *name = in_get_dev_name(d, 0, 0);
780 if (binds == NULL || name == NULL)
783 fprintf(f, "binddev = %s\n", name);
784 in_get_config(d, IN_CFG_BIND_COUNT, &count);
786 for (k = 0; k < count; k++)
791 act[0] = act[31] = 0;
792 name = in_get_key_name(d, k);
794 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
795 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
796 mask = me_ctrl_actions[i].mask;
798 strncpy(act, me_ctrl_actions[i].name, 31);
799 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
802 mask = me_ctrl_actions[i].mask << 16;
804 strncpy(act, me_ctrl_actions[i].name, 31);
805 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
810 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
811 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
812 mask = emuctrl_actions[i].mask;
814 strncpy(act, emuctrl_actions[i].name, 31);
815 fprintf(f, "bind %s = %s\n", name, mystrip(act));
823 static int parse_bind_val(const char *val, int *type)
827 *type = IN_BINDTYPE_NONE;
831 if (strncasecmp(val, "player", 6) == 0)
833 int player, shift = 0;
834 player = atoi(val + 6) - 1;
836 if ((unsigned int)player > 1)
841 *type = IN_BINDTYPE_PLAYER12;
842 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
843 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
844 return me_ctrl_actions[i].mask << shift;
847 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
848 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
849 *type = IN_BINDTYPE_EMU;
850 return emuctrl_actions[i].mask;
857 static void keys_load_all(const char *cfg)
859 char dev[256], key[128], *act;
865 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
868 get_line(dev, sizeof(dev), p);
869 dev_id = in_config_parse_dev(dev);
871 printf("input: can't handle dev: %s\n", dev);
875 in_unbind_all(dev_id, -1, -1);
876 while ((p = strstr(p, "bind"))) {
877 if (strncmp(p, "binddev = ", 10) == 0)
882 printf("input: parse error: %16s..\n", p);
886 get_line(key, sizeof(key), p);
887 act = strchr(key, '=');
889 printf("parse failed: %16s..\n", p);
897 bind = parse_bind_val(act, &bindtype);
898 if (bind != -1 && bind != 0) {
899 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
900 in_config_bind_key(dev_id, key, bind, bindtype);
903 lprintf("config: unhandled action \"%s\"\n", act);
909 static int key_config_loop_wrap(int id, int keys)
912 case MA_CTRL_PLAYER1:
913 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
915 case MA_CTRL_PLAYER2:
916 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
919 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
927 static const char *mgn_dev_name(int id, int *offs)
929 const char *name = NULL;
932 if (id == MA_CTRL_DEV_FIRST)
935 for (; it < IN_MAX_DEVS; it++) {
936 name = in_get_dev_name(it, 1, 1);
945 static const char *mgn_saveloadcfg(int id, int *offs)
950 static int mh_savecfg(int id, int keys)
952 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
953 me_update_msg("config saved");
955 me_update_msg("failed to write config");
960 static int mh_input_rescan(int id, int keys)
962 //menu_sync_config();
963 plat_rescan_inputs();
964 me_update_msg("rescan complete.");
969 static const char *men_in_type_sel[] = {
970 "Standard (SCPH-1080)",
971 "Analog (SCPH-1150)",
975 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
976 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
978 static menu_entry e_menu_keyconfig[] =
980 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
981 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
982 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
984 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
985 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
986 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
987 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
988 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
989 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
990 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
991 mee_handler ("Rescan devices", mh_input_rescan),
993 mee_label ("Input devices:"),
994 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
995 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
996 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
997 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
998 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
999 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1000 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1004 static int menu_loop_keyconfig(int id, int keys)
1008 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1009 me_loop(e_menu_keyconfig, &sel);
1013 // ------------ gfx options menu ------------
1015 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1016 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1017 "using d-pad or move it using R+d-pad";
1018 static const char *men_dummy[] = { NULL };
1020 static int menu_loop_cscaler(int id, int keys)
1024 scaling = SCALE_CUSTOM;
1026 omap_enable_layer(1);
1031 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1032 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1033 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1036 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1037 if (inp & PBTN_UP) g_layer_y--;
1038 if (inp & PBTN_DOWN) g_layer_y++;
1039 if (inp & PBTN_LEFT) g_layer_x--;
1040 if (inp & PBTN_RIGHT) g_layer_x++;
1041 if (!(inp & PBTN_R)) {
1042 if (inp & PBTN_UP) g_layer_h += 2;
1043 if (inp & PBTN_DOWN) g_layer_h -= 2;
1044 if (inp & PBTN_LEFT) g_layer_w += 2;
1045 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1047 if (inp & (PBTN_MOK|PBTN_MBACK))
1050 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1051 if (g_layer_x < 0) g_layer_x = 0;
1052 if (g_layer_x > 640) g_layer_x = 640;
1053 if (g_layer_y < 0) g_layer_y = 0;
1054 if (g_layer_y > 420) g_layer_y = 420;
1055 if (g_layer_w < 160) g_layer_w = 160;
1056 if (g_layer_h < 60) g_layer_h = 60;
1057 if (g_layer_x + g_layer_w > 800)
1058 g_layer_w = 800 - g_layer_x;
1059 if (g_layer_y + g_layer_h > 480)
1060 g_layer_h = 480 - g_layer_y;
1061 omap_enable_layer(1);
1065 omap_enable_layer(0);
1070 static menu_entry e_menu_gfx_options[] =
1072 mee_enum ("Scaler", 0, scaling, men_scaler),
1073 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1074 // mee_onoff ("Vsync", 0, vsync, 1),
1075 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1079 static int menu_loop_gfx_options(int id, int keys)
1083 me_loop(e_menu_gfx_options, &sel);
1088 // ------------ bios/plugins ------------
1090 static menu_entry e_menu_plugin_gpu_unai[] =
1092 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1093 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1094 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1098 static int menu_loop_plugin_gpu_unai(int id, int keys)
1101 me_loop(e_menu_plugin_gpu_unai, &sel);
1105 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1106 static const char h_gpu_0[] = "Needed for Chrono Cross";
1107 static const char h_gpu_1[] = "Capcom fighting games";
1108 static const char h_gpu_2[] = "Black screens in Lunar";
1109 static const char h_gpu_3[] = "Compatibility mode";
1110 static const char h_gpu_6[] = "Pandemonium 2";
1111 static const char h_gpu_7[] = "Skip every second frame";
1112 static const char h_gpu_8[] = "Needed by Dark Forces";
1113 static const char h_gpu_9[] = "better g-colors, worse textures";
1114 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1116 static menu_entry e_menu_plugin_gpu_peops[] =
1118 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1119 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1120 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1121 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1122 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1123 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1124 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1125 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1126 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1127 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1131 static int menu_loop_plugin_gpu_peops(int id, int keys)
1134 me_loop(e_menu_plugin_gpu_peops, &sel);
1138 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1139 static const char h_spu_volboost[] = "Large values cause distortion";
1140 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1141 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1143 static menu_entry e_menu_plugin_spu[] =
1145 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1146 mee_onoff ("Reverb", 0, iUseReverb, 2),
1147 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1148 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1149 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1150 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1154 static int menu_loop_plugin_spu(int id, int keys)
1157 me_loop(e_menu_plugin_spu, &sel);
1161 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1162 "savestates and can't be changed there. Must save\n"
1163 "config and reload the game for change to take effect";
1164 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1165 "for plugin change to take effect";
1166 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1167 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1168 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1170 static menu_entry e_menu_plugin_options[] =
1172 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1173 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1174 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1175 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1176 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1177 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1181 static menu_entry e_menu_main2[];
1183 static int menu_loop_plugin_options(int id, int keys)
1186 me_loop(e_menu_plugin_options, &sel);
1188 // sync BIOS/plugins
1189 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1190 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1191 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1192 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1197 // ------------ adv options menu ------------
1199 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1200 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1201 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1202 "(green: normal, red: fmod, blue: noise)";
1203 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1204 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1205 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1206 "(proper .cue/.bin dump is needed otherwise)";
1207 static const char h_cfg_sio[] = "You should not need this, breaks games";
1208 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1209 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1210 "(timing hack, breaks other games)";
1211 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1212 "(timing hack, breaks other games)";
1213 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1214 "(CD timing hack, breaks FMVs)";
1215 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1216 "(may break games, must reload game to take effect)";
1217 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1218 "Might be useful to overcome some dynarec bugs";
1220 static menu_entry e_menu_adv_options[] =
1222 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1223 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1224 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1225 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1226 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1227 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1228 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1229 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1230 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1231 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1232 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1233 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1237 static int menu_loop_adv_options(int id, int keys)
1240 me_loop(e_menu_adv_options, &sel);
1244 // ------------ options menu ------------
1246 static int mh_restore_defaults(int id, int keys)
1248 menu_set_defconfig();
1249 me_update_msg("defaults restored");
1253 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1254 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1256 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1257 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1258 "loading state or both";
1260 static const char h_restore_def[] = "Switches back to default / recommended\n"
1262 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1264 static menu_entry e_menu_options[] =
1266 // mee_range ("Save slot", 0, state_slot, 0, 9),
1267 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1268 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1269 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1270 mee_enum ("Region", 0, region, men_region),
1271 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1272 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1273 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1274 mee_handler ("[Advanced]", menu_loop_adv_options),
1275 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1276 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1277 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1281 static int menu_loop_options(int id, int keys)
1286 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1287 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1288 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1290 me_loop(e_menu_options, &sel);
1295 // ------------ debug menu ------------
1297 static void draw_frame_debug(GPUFreeze_t *gpuf)
1299 int w = min(g_menuscreen_w, 1024);
1300 int h = min(g_menuscreen_h, 512);
1301 u16 *d = g_menuscreen_ptr;
1302 u16 *s = (u16 *)gpuf->psxVRam;
1306 gpuf->ulFreezeVersion = 1;
1307 if (GPU_freeze != NULL)
1308 GPU_freeze(1, gpuf);
1310 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1311 bgr555_to_rgb565(d, s, w * 2);
1313 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1314 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1315 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1316 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1317 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1320 static void debug_menu_loop(void)
1325 gpuf = malloc(sizeof(*gpuf));
1332 draw_frame_debug(gpuf);
1335 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1336 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1337 if (inp & PBTN_MBACK)
1344 // --------- memcard manager ---------
1346 static void draw_mc_icon(int dx, int dy, const u16 *s)
1351 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1353 for (y = 0; y < 16; y++, s += 16) {
1354 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1355 for (x = 0; x < 16; x++) {
1357 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1358 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1364 static void draw_mc_bg(void)
1366 McdBlock *blocks1, *blocks2;
1370 blocks1 = malloc(15 * sizeof(blocks1[0]));
1371 blocks2 = malloc(15 * sizeof(blocks1[0]));
1372 if (blocks1 == NULL || blocks2 == NULL)
1375 for (i = 0; i < 15; i++) {
1376 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1377 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1382 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1384 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1388 maxicons = g_menuscreen_h / 32;
1391 row2 = g_menuscreen_w / 2;
1392 for (i = 0; i < maxicons; i++) {
1393 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1394 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1396 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1397 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1400 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1408 static void handle_memcard_sel(void)
1411 if (memcard1_sel != 0)
1412 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1414 if (memcard2_sel != 0)
1415 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1416 LoadMcds(Config.Mcd1, Config.Mcd2);
1420 static menu_entry e_memcard_options[] =
1422 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1423 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1427 static int menu_loop_memcards(int id, int keys)
1433 memcard1_sel = memcard2_sel = 0;
1434 p = strrchr(Config.Mcd1, '/');
1436 for (i = 0; memcards[i] != NULL; i++)
1437 if (strcmp(p + 1, memcards[i]) == 0)
1438 { memcard1_sel = i; break; }
1439 p = strrchr(Config.Mcd2, '/');
1441 for (i = 0; memcards[i] != NULL; i++)
1442 if (strcmp(p + 1, memcards[i]) == 0)
1443 { memcard2_sel = i; break; }
1445 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1447 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1452 // --------- main menu help ----------
1454 static void menu_bios_warn(void)
1457 static const char msg[] =
1458 "You don't seem to have copied any BIOS files to\n"
1459 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1460 "While many games work fine with fake (HLE) BIOS,\n"
1461 "others (like MGS and FF8) require BIOS to work.\n"
1462 "After copying the file, you'll also need to\n"
1463 "select it in the emu's options->[BIOS/Plugins]\n\n"
1464 "The file is usually named SCPH1001.BIN, but\n"
1465 "other not compressed files can be used too.\n\n"
1466 "Press (B) or (X) to continue";
1470 draw_menu_message(msg, NULL);
1472 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1473 if (inp & (PBTN_MBACK|PBTN_MOK))
1478 // ------------ main menu ------------
1482 static void draw_frame_main(void)
1489 if (CdromId[0] != 0) {
1490 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1491 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1492 Config.HLE ? "HLE" : "BIOS");
1493 smalltext_out16(4, 1, buff, 0x105f);
1498 tmp = localtime(<ime);
1499 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1500 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1501 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1505 static void draw_frame_credits(void)
1507 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1510 static const char credits_text[] =
1512 "(C) 1999-2003 PCSX Team\n"
1513 "(C) 2005-2009 PCSX-df Team\n"
1514 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1515 "GPU and SPU code by Pete Bernert\n"
1516 " and the P.E.Op.S. team\n"
1517 "ARM recompiler (C) 2009-2011 Ari64\n"
1518 "PCSX4ALL plugins by PCSX4ALL team\n"
1519 " Chui, Franxis, Unai\n\n"
1520 "integration, optimization and\n"
1521 " frontend (C) 2010-2011 notaz\n";
1523 static int reset_game(void)
1526 if (bios_sel == 0 && !Config.HLE)
1532 if (CheckCdrom() != -1) {
1538 static int reload_plugins(const char *cdimg)
1544 set_cd_image(cdimg);
1546 pcnt_hook_plugins();
1548 if (OpenPlugins() == -1) {
1549 me_update_msg("failed to open plugins");
1552 plugin_call_rearmed_cbs();
1555 CdromLabel[0] = '\0';
1560 static int run_bios(void)
1566 if (reload_plugins(NULL) != 0)
1574 static int run_exe(void)
1578 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1583 if (reload_plugins(NULL) != 0)
1587 if (Load(fname) != 0) {
1588 me_update_msg("exe load failed, bad file?");
1597 static int run_cd_image(const char *fname)
1600 reload_plugins(fname);
1602 // always autodetect, menu_sync_config will override as needed
1605 if (CheckCdrom() == -1) {
1606 // Only check the CD if we are starting the console with a CD
1608 me_update_msg("unsupported/invalid CD image");
1614 // Read main executable directly from CDRom and start it
1615 if (LoadCdrom() == -1) {
1617 me_update_msg("failed to load CD image");
1625 static int romsel_run(void)
1627 int prev_gpu, prev_spu;
1630 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1634 printf("selected file: %s\n", fname);
1636 new_dynarec_clear_full();
1638 if (run_cd_image(fname) != 0)
1641 prev_gpu = gpu_plugsel;
1642 prev_spu = spu_plugsel;
1643 if (menu_load_config(1) != 0)
1644 menu_load_config(0);
1646 // check for plugin changes, have to repeat
1647 // loading if game config changed plugins to reload them
1648 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1649 printf("plugin change detected, reloading plugins..\n");
1650 if (run_cd_image(fname) != 0)
1654 strcpy(last_selected_fname, rom_fname_reload);
1658 static int swap_cd_image(void)
1662 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1666 printf("selected file: %s\n", fname);
1669 CdromLabel[0] = '\0';
1671 set_cd_image(fname);
1672 if (ReloadCdromPlugin() < 0) {
1673 me_update_msg("failed to load cdr plugin");
1676 if (CDR_open() < 0) {
1677 me_update_msg("failed to open cdr plugin");
1681 SetCdOpenCaseTime(time(NULL) + 2);
1684 strcpy(last_selected_fname, rom_fname_reload);
1688 static int main_menu_handler(int id, int keys)
1692 case MA_MAIN_RESUME_GAME:
1696 case MA_MAIN_SAVE_STATE:
1698 return menu_loop_savestate(0);
1700 case MA_MAIN_LOAD_STATE:
1702 return menu_loop_savestate(1);
1704 case MA_MAIN_RESET_GAME:
1705 if (ready_to_go && reset_game() == 0)
1708 case MA_MAIN_LOAD_ROM:
1709 if (romsel_run() == 0)
1712 case MA_MAIN_SWAP_CD:
1713 if (swap_cd_image() == 0)
1716 case MA_MAIN_RUN_BIOS:
1717 if (run_bios() == 0)
1720 case MA_MAIN_RUN_EXE:
1724 case MA_MAIN_CREDITS:
1725 draw_menu_message(credits_text, draw_frame_credits);
1726 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1732 lprintf("%s: something unknown selected\n", __FUNCTION__);
1739 static menu_entry e_menu_main2[] =
1741 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1742 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1743 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1744 mee_handler ("Memcard manager", menu_loop_memcards),
1748 static int main_menu2_handler(int id, int keys)
1752 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1753 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1755 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1758 static const char h_extra[] = "Change CD, manage memcards..\n";
1760 static menu_entry e_menu_main[] =
1764 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1765 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1766 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1767 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1768 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1769 mee_handler ("Options", menu_loop_options),
1770 mee_handler ("Controls", menu_loop_keyconfig),
1771 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1772 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1773 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1777 // ----------------------------
1779 static void menu_leave_emu(void);
1781 void menu_loop(void)
1787 if (bioses[1] == NULL && !warned_about_bios) {
1789 warned_about_bios = 1;
1792 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1793 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1794 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1795 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1797 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1800 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1801 } while (!ready_to_go);
1803 /* wait until menu, ok, back is released */
1804 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1807 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1812 static int qsort_strcmp(const void *p1, const void *p2)
1814 char * const *s1 = (char * const *)p1;
1815 char * const *s2 = (char * const *)p2;
1816 return strcasecmp(*s1, *s2);
1819 static void scan_bios_plugins(void)
1821 char fname[MAXPATHLEN];
1823 int bios_i, gpu_i, spu_i, mc_i;
1828 gpu_plugins[0] = "builtin_gpu";
1829 spu_plugins[0] = "builtin_spu";
1830 memcards[0] = "(none)";
1831 bios_i = gpu_i = spu_i = mc_i = 1;
1833 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1834 dir = opendir(fname);
1836 perror("scan_bios_plugins bios opendir");
1851 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1854 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1855 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1856 printf("bad BIOS file: %s\n", ent->d_name);
1860 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1861 bioses[bios_i++] = strdup(ent->d_name);
1865 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1871 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1872 dir = opendir(fname);
1874 perror("scan_bios_plugins plugins opendir");
1888 p = strstr(ent->d_name, ".so");
1892 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1893 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1895 fprintf(stderr, "%s\n", dlerror());
1899 // now what do we have here?
1900 tmp = dlsym(h, "GPUinit");
1903 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1904 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1908 tmp = dlsym(h, "SPUinit");
1911 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1912 spu_plugins[spu_i++] = strdup(ent->d_name);
1916 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1923 dir = opendir("." MEMCARD_DIR);
1925 perror("scan_bios_plugins memcards opendir");
1940 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1943 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1944 if (stat(fname, &st) != 0) {
1945 printf("bad memcard file: %s\n", ent->d_name);
1949 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1950 memcards[mc_i++] = strdup(ent->d_name);
1954 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1958 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1963 void menu_init(void)
1965 char buff[MAXPATHLEN];
1967 strcpy(last_selected_fname, "/media");
1969 scan_bios_plugins();
1973 menu_set_defconfig();
1974 menu_load_config(0);
1979 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1980 if (g_menubg_src_ptr == NULL)
1982 emu_make_path(buff, "skin/background.png", sizeof(buff));
1983 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1985 #ifndef __ARM_ARCH_7A__ /* XXX */
1986 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
1987 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
1989 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
1993 void menu_notify_mode_change(int w, int h, int bpp)
2004 g_layer_w = w; g_layer_h = h;
2008 mult = 240.0f / (float)h * 4.0f / 3.0f;
2011 g_layer_w = mult * (float)g_menuscreen_h;
2012 g_layer_h = g_menuscreen_h;
2013 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2017 // 4:3 that prefers integer scaling
2018 imult = g_menuscreen_h / h;
2019 g_layer_w = w * imult;
2020 g_layer_h = h * imult;
2021 mult = (float)g_layer_w / (float)g_layer_h;
2022 if (mult < 1.25f || mult > 1.666f)
2023 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2024 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2027 case SCALE_FULLSCREEN:
2028 g_layer_w = g_menuscreen_w;
2029 g_layer_h = g_menuscreen_h;
2036 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2037 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2038 if (g_layer_x < 0) g_layer_x = 0;
2039 if (g_layer_y < 0) g_layer_y = 0;
2040 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2041 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2044 static void menu_leave_emu(void)
2046 if (GPU_close != NULL) {
2047 int ret = GPU_close();
2049 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2052 plat_video_menu_enter(ready_to_go);
2054 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2055 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2056 int x = max(0, g_menuscreen_w - last_psx_w);
2057 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2058 int w = min(g_menuscreen_w, last_psx_w);
2059 int h = min(g_menuscreen_h, last_psx_h);
2060 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2061 u16 *s = pl_vout_buf;
2063 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2064 menu_darken_bg(d, s, w, 0);
2068 cpu_clock = plat_cpu_clock_get();
2071 void menu_prepare_emu(void)
2073 R3000Acpu *prev_cpu = psxCpu;
2075 plat_video_menu_leave();
2077 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2079 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2080 if (psxCpu != prev_cpu)
2081 // note that this does not really reset, just clears drc caches
2084 // core doesn't care about Config.Cdda changes,
2085 // so handle them manually here
2090 apply_lcdrate(Config.PsxType);
2091 apply_filter(filter);
2092 plat_cpu_clock_apply(cpu_clock);
2094 // push config to GPU plugin
2095 plugin_call_rearmed_cbs();
2097 if (GPU_open != NULL) {
2098 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2100 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2106 void me_update_msg(const char *msg)
2108 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2109 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2111 menu_error_time = plat_get_ticks_ms();
2112 lprintf("msg: %s\n", menu_error_msg);