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);
452 for (i = bios_sel = 0; bioses[i] != NULL; i++)
453 if (strcmp(Config.Bios, bioses[i]) == 0)
454 { bios_sel = i; break; }
456 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
457 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
458 { gpu_plugsel = i; break; }
460 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
461 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
462 { spu_plugsel = i; break; }
473 // rrrr rggg gggb bbbb
474 static unsigned short fname2color(const char *fname)
476 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
477 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
478 const char *ext = strrchr(fname, '.');
483 for (i = 0; i < array_size(cdimg_exts); i++)
484 if (strcasecmp(ext, cdimg_exts[i]) == 0)
486 for (i = 0; i < array_size(other_exts); i++)
487 if (strcasecmp(ext, other_exts[i]) == 0)
492 static void draw_savestate_bg(int slot);
494 static const char *filter_exts[] = {
495 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
498 #define MENU_ALIGN_LEFT
499 #ifdef __ARM_ARCH_7A__ // assume hires device
505 #define menu_init menu_init_common
506 #include "common/menu.c"
509 // a bit of black magic here
510 static void draw_savestate_bg(int slot)
512 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
514 char fname[MAXPATHLEN];
521 ret = get_state_filename(fname, sizeof(fname), slot);
525 f = gzopen(fname, "rb");
529 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
530 fprintf(stderr, "gzseek failed\n");
535 gpu = malloc(sizeof(*gpu));
541 ret = gzread(f, gpu, sizeof(*gpu));
543 if (ret != sizeof(*gpu)) {
544 fprintf(stderr, "gzread failed\n");
548 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
550 if (gpu->ulStatus & 0x800000)
551 goto out; // disabled
553 x = gpu->ulControl[5] & 0x3ff;
554 y = (gpu->ulControl[5] >> 10) & 0x1ff;
555 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
556 w = psx_widths[(gpu->ulStatus >> 16) & 7];
557 tmp = gpu->ulControl[7];
558 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
559 if (gpu->ulStatus & 0x80000) // doubleheight
562 x = max(0, g_menuscreen_w - w) & ~3;
563 y = max(0, g_menuscreen_h / 2 - h / 2);
564 w = min(g_menuscreen_w, w);
565 h = min(g_menuscreen_h, h);
566 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
568 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
569 if (gpu->ulStatus & 0x200000)
570 bgr888_to_rgb565(d, s, w * 3);
572 bgr555_to_rgb565(d, s, w * 2);
573 #ifndef __ARM_ARCH_7A__
574 // better darken this on small screens
575 menu_darken_bg(d, d, w * 2, 0);
583 // ---------- XXX: pandora specific -----------
585 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
586 static char **pnd_filter_list;
588 static void apply_filter(int which)
594 if (pnd_filter_list == NULL || which == old)
597 for (i = 0; i < which; i++)
598 if (pnd_filter_list[i] == NULL)
601 if (pnd_filter_list[i] == NULL)
604 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
609 static void apply_lcdrate(int pal)
617 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
618 pnd_script_base, pal ? 50 : 60);
623 static menu_entry e_menu_gfx_options[];
625 static void pnd_menu_init(void)
633 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
635 dir = opendir("/etc/pandora/conf/dss_fir");
637 perror("filter opendir");
650 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
659 mfilters = calloc(count + 1, sizeof(mfilters[0]));
660 if (mfilters == NULL)
664 for (i = 0; (ent = readdir(dir)); ) {
667 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
670 len = strlen(ent->d_name);
672 // skip pre-HF5 extra files
673 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
675 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
678 // have to cut "_up_h" for pre-HF5
679 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
682 if (len > sizeof(buff) - 1)
685 strncpy(buff, ent->d_name, len);
687 mfilters[i] = strdup(buff);
688 if (mfilters[i] != NULL)
693 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
694 e_menu_gfx_options[i].data = (void *)mfilters;
695 pnd_filter_list = mfilters;
698 void menu_finish(void)
700 plat_cpu_clock_apply(cpu_clock_st);
703 // -------------- key config --------------
705 me_bind_action me_ctrl_actions[] =
707 { "UP ", 1 << DKEY_UP},
708 { "DOWN ", 1 << DKEY_DOWN },
709 { "LEFT ", 1 << DKEY_LEFT },
710 { "RIGHT ", 1 << DKEY_RIGHT },
711 { "TRIANGLE", 1 << DKEY_TRIANGLE },
712 { "CIRCLE ", 1 << DKEY_CIRCLE },
713 { "CROSS ", 1 << DKEY_CROSS },
714 { "SQUARE ", 1 << DKEY_SQUARE },
715 { "L1 ", 1 << DKEY_L1 },
716 { "R1 ", 1 << DKEY_R1 },
717 { "L2 ", 1 << DKEY_L2 },
718 { "R2 ", 1 << DKEY_R2 },
719 { "L3 ", 1 << DKEY_L3 },
720 { "R3 ", 1 << DKEY_R3 },
721 { "START ", 1 << DKEY_START },
722 { "SELECT ", 1 << DKEY_SELECT },
726 me_bind_action emuctrl_actions[] =
728 { "Save State ", 1 << SACTION_SAVE_STATE },
729 { "Load State ", 1 << SACTION_LOAD_STATE },
730 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
731 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
732 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
733 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
734 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
735 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
736 { "Gun A button ", 1 << SACTION_GUN_A },
737 { "Gun B button ", 1 << SACTION_GUN_B },
738 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
742 static char *mystrip(char *str)
747 for (i = 0; i < len; i++)
748 if (str[i] != ' ') break;
749 if (i > 0) memmove(str, str + i, len - i + 1);
752 for (i = len - 1; i >= 0; i--)
753 if (str[i] != ' ') break;
759 static void get_line(char *d, size_t size, const char *s)
764 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
775 static void keys_write_all(FILE *f)
779 for (d = 0; d < IN_MAX_DEVS; d++)
781 const int *binds = in_get_dev_binds(d);
782 const char *name = in_get_dev_name(d, 0, 0);
785 if (binds == NULL || name == NULL)
788 fprintf(f, "binddev = %s\n", name);
789 in_get_config(d, IN_CFG_BIND_COUNT, &count);
791 for (k = 0; k < count; k++)
796 act[0] = act[31] = 0;
797 name = in_get_key_name(d, k);
799 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
800 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
801 mask = me_ctrl_actions[i].mask;
803 strncpy(act, me_ctrl_actions[i].name, 31);
804 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
807 mask = me_ctrl_actions[i].mask << 16;
809 strncpy(act, me_ctrl_actions[i].name, 31);
810 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
815 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
816 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
817 mask = emuctrl_actions[i].mask;
819 strncpy(act, emuctrl_actions[i].name, 31);
820 fprintf(f, "bind %s = %s\n", name, mystrip(act));
828 static int parse_bind_val(const char *val, int *type)
832 *type = IN_BINDTYPE_NONE;
836 if (strncasecmp(val, "player", 6) == 0)
838 int player, shift = 0;
839 player = atoi(val + 6) - 1;
841 if ((unsigned int)player > 1)
846 *type = IN_BINDTYPE_PLAYER12;
847 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
848 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
849 return me_ctrl_actions[i].mask << shift;
852 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
853 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
854 *type = IN_BINDTYPE_EMU;
855 return emuctrl_actions[i].mask;
862 static void keys_load_all(const char *cfg)
864 char dev[256], key[128], *act;
870 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
873 get_line(dev, sizeof(dev), p);
874 dev_id = in_config_parse_dev(dev);
876 printf("input: can't handle dev: %s\n", dev);
880 in_unbind_all(dev_id, -1, -1);
881 while ((p = strstr(p, "bind"))) {
882 if (strncmp(p, "binddev = ", 10) == 0)
887 printf("input: parse error: %16s..\n", p);
891 get_line(key, sizeof(key), p);
892 act = strchr(key, '=');
894 printf("parse failed: %16s..\n", p);
902 bind = parse_bind_val(act, &bindtype);
903 if (bind != -1 && bind != 0) {
904 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
905 in_config_bind_key(dev_id, key, bind, bindtype);
908 lprintf("config: unhandled action \"%s\"\n", act);
914 static int key_config_loop_wrap(int id, int keys)
917 case MA_CTRL_PLAYER1:
918 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
920 case MA_CTRL_PLAYER2:
921 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
924 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
932 static const char *mgn_dev_name(int id, int *offs)
934 const char *name = NULL;
937 if (id == MA_CTRL_DEV_FIRST)
940 for (; it < IN_MAX_DEVS; it++) {
941 name = in_get_dev_name(it, 1, 1);
950 static const char *mgn_saveloadcfg(int id, int *offs)
955 static int mh_savecfg(int id, int keys)
957 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
958 me_update_msg("config saved");
960 me_update_msg("failed to write config");
965 static int mh_input_rescan(int id, int keys)
967 //menu_sync_config();
968 plat_rescan_inputs();
969 me_update_msg("rescan complete.");
974 static const char *men_in_type_sel[] = {
975 "Standard (SCPH-1080)",
976 "Analog (SCPH-1150)",
980 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
981 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
983 static menu_entry e_menu_keyconfig[] =
985 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
986 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
987 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
989 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
990 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
991 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
992 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
993 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
994 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
995 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
996 mee_handler ("Rescan devices", mh_input_rescan),
998 mee_label ("Input devices:"),
999 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1000 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1001 mee_label_mk (MA_CTRL_DEV_NEXT, 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),
1009 static int menu_loop_keyconfig(int id, int keys)
1013 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1014 me_loop(e_menu_keyconfig, &sel);
1018 // ------------ gfx options menu ------------
1020 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1021 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1022 "using d-pad or move it using R+d-pad";
1023 static const char *men_dummy[] = { NULL };
1025 static int menu_loop_cscaler(int id, int keys)
1029 scaling = SCALE_CUSTOM;
1031 omap_enable_layer(1);
1036 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1037 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1038 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1041 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1042 if (inp & PBTN_UP) g_layer_y--;
1043 if (inp & PBTN_DOWN) g_layer_y++;
1044 if (inp & PBTN_LEFT) g_layer_x--;
1045 if (inp & PBTN_RIGHT) g_layer_x++;
1046 if (!(inp & PBTN_R)) {
1047 if (inp & PBTN_UP) g_layer_h += 2;
1048 if (inp & PBTN_DOWN) g_layer_h -= 2;
1049 if (inp & PBTN_LEFT) g_layer_w += 2;
1050 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1052 if (inp & (PBTN_MOK|PBTN_MBACK))
1055 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1056 if (g_layer_x < 0) g_layer_x = 0;
1057 if (g_layer_x > 640) g_layer_x = 640;
1058 if (g_layer_y < 0) g_layer_y = 0;
1059 if (g_layer_y > 420) g_layer_y = 420;
1060 if (g_layer_w < 160) g_layer_w = 160;
1061 if (g_layer_h < 60) g_layer_h = 60;
1062 if (g_layer_x + g_layer_w > 800)
1063 g_layer_w = 800 - g_layer_x;
1064 if (g_layer_y + g_layer_h > 480)
1065 g_layer_h = 480 - g_layer_y;
1066 omap_enable_layer(1);
1070 omap_enable_layer(0);
1075 static menu_entry e_menu_gfx_options[] =
1077 mee_enum ("Scaler", 0, scaling, men_scaler),
1078 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1079 // mee_onoff ("Vsync", 0, vsync, 1),
1080 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1084 static int menu_loop_gfx_options(int id, int keys)
1088 me_loop(e_menu_gfx_options, &sel);
1093 // ------------ bios/plugins ------------
1095 static menu_entry e_menu_plugin_gpu_unai[] =
1097 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1098 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1099 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1103 static int menu_loop_plugin_gpu_unai(int id, int keys)
1106 me_loop(e_menu_plugin_gpu_unai, &sel);
1110 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1111 static const char h_gpu_0[] = "Needed for Chrono Cross";
1112 static const char h_gpu_1[] = "Capcom fighting games";
1113 static const char h_gpu_2[] = "Black screens in Lunar";
1114 static const char h_gpu_3[] = "Compatibility mode";
1115 static const char h_gpu_6[] = "Pandemonium 2";
1116 static const char h_gpu_7[] = "Skip every second frame";
1117 static const char h_gpu_8[] = "Needed by Dark Forces";
1118 static const char h_gpu_9[] = "better g-colors, worse textures";
1119 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1121 static menu_entry e_menu_plugin_gpu_peops[] =
1123 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1124 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1125 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1126 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1127 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1128 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1129 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1130 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1131 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1132 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1136 static int menu_loop_plugin_gpu_peops(int id, int keys)
1139 me_loop(e_menu_plugin_gpu_peops, &sel);
1143 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1144 static const char h_spu_volboost[] = "Large values cause distortion";
1145 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1146 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1148 static menu_entry e_menu_plugin_spu[] =
1150 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1151 mee_onoff ("Reverb", 0, iUseReverb, 2),
1152 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1153 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1154 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1155 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1159 static int menu_loop_plugin_spu(int id, int keys)
1162 me_loop(e_menu_plugin_spu, &sel);
1166 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1167 "savestates and can't be changed there. Must save\n"
1168 "config and reload the game for change to take effect";
1169 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1170 "for plugin change to take effect";
1171 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1172 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1173 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1175 static menu_entry e_menu_plugin_options[] =
1177 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1178 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1179 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1180 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1181 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1182 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1186 static menu_entry e_menu_main2[];
1188 static int menu_loop_plugin_options(int id, int keys)
1191 me_loop(e_menu_plugin_options, &sel);
1193 // sync BIOS/plugins
1194 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1195 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1196 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1197 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1202 // ------------ adv options menu ------------
1204 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1205 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1206 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1207 "(green: normal, red: fmod, blue: noise)";
1208 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1209 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1210 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1211 "(proper .cue/.bin dump is needed otherwise)";
1212 static const char h_cfg_sio[] = "You should not need this, breaks games";
1213 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1214 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1215 "(timing hack, breaks other games)";
1216 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1217 "(timing hack, breaks other games)";
1218 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1219 "(CD timing hack, breaks FMVs)";
1220 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1221 "(may break games, must reload game to take effect)";
1222 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1223 "Might be useful to overcome some dynarec bugs";
1225 static menu_entry e_menu_adv_options[] =
1227 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1228 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1229 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1230 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1231 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1232 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1233 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1234 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1235 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1236 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1237 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1238 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1242 static int menu_loop_adv_options(int id, int keys)
1245 me_loop(e_menu_adv_options, &sel);
1249 // ------------ options menu ------------
1251 static int mh_restore_defaults(int id, int keys)
1253 menu_set_defconfig();
1254 me_update_msg("defaults restored");
1258 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1259 static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
1261 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1262 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1263 "loading state or both";
1265 static const char h_restore_def[] = "Switches back to default / recommended\n"
1267 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1269 static menu_entry e_menu_options[] =
1271 // mee_range ("Save slot", 0, state_slot, 0, 9),
1272 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1273 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1274 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1275 mee_enum ("Region", 0, region, men_region),
1276 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1277 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1278 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1279 mee_handler ("[Advanced]", menu_loop_adv_options),
1280 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1281 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1282 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1286 static int menu_loop_options(int id, int keys)
1291 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1292 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1293 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1295 me_loop(e_menu_options, &sel);
1300 // ------------ debug menu ------------
1302 static void draw_frame_debug(GPUFreeze_t *gpuf)
1304 int w = min(g_menuscreen_w, 1024);
1305 int h = min(g_menuscreen_h, 512);
1306 u16 *d = g_menuscreen_ptr;
1307 u16 *s = (u16 *)gpuf->psxVRam;
1311 gpuf->ulFreezeVersion = 1;
1312 if (GPU_freeze != NULL)
1313 GPU_freeze(1, gpuf);
1315 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1316 bgr555_to_rgb565(d, s, w * 2);
1318 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1319 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1320 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1321 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1322 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1325 static void debug_menu_loop(void)
1330 gpuf = malloc(sizeof(*gpuf));
1337 draw_frame_debug(gpuf);
1340 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1341 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1342 if (inp & PBTN_MBACK)
1349 // --------- memcard manager ---------
1351 static void draw_mc_icon(int dx, int dy, const u16 *s)
1356 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1358 for (y = 0; y < 16; y++, s += 16) {
1359 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1360 for (x = 0; x < 16; x++) {
1362 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1363 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1369 static void draw_mc_bg(void)
1371 McdBlock *blocks1, *blocks2;
1375 blocks1 = malloc(15 * sizeof(blocks1[0]));
1376 blocks2 = malloc(15 * sizeof(blocks1[0]));
1377 if (blocks1 == NULL || blocks2 == NULL)
1380 for (i = 0; i < 15; i++) {
1381 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1382 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1387 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1389 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1393 maxicons = g_menuscreen_h / 32;
1396 row2 = g_menuscreen_w / 2;
1397 for (i = 0; i < maxicons; i++) {
1398 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1399 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1401 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1402 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1405 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1413 static void handle_memcard_sel(void)
1416 if (memcard1_sel != 0)
1417 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1419 if (memcard2_sel != 0)
1420 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1421 LoadMcds(Config.Mcd1, Config.Mcd2);
1425 static menu_entry e_memcard_options[] =
1427 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1428 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1432 static int menu_loop_memcards(int id, int keys)
1438 memcard1_sel = memcard2_sel = 0;
1439 p = strrchr(Config.Mcd1, '/');
1441 for (i = 0; memcards[i] != NULL; i++)
1442 if (strcmp(p + 1, memcards[i]) == 0)
1443 { memcard1_sel = i; break; }
1444 p = strrchr(Config.Mcd2, '/');
1446 for (i = 0; memcards[i] != NULL; i++)
1447 if (strcmp(p + 1, memcards[i]) == 0)
1448 { memcard2_sel = i; break; }
1450 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1452 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1457 // --------- main menu help ----------
1459 static void menu_bios_warn(void)
1462 static const char msg[] =
1463 "You don't seem to have copied any BIOS files to\n"
1464 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1465 "While many games work fine with fake (HLE) BIOS,\n"
1466 "others (like MGS and FF8) require BIOS to work.\n"
1467 "After copying the file, you'll also need to\n"
1468 "select it in the emu's options->[BIOS/Plugins]\n\n"
1469 "The file is usually named SCPH1001.BIN, but\n"
1470 "other not compressed files can be used too.\n\n"
1471 "Press (B) or (X) to continue";
1475 draw_menu_message(msg, NULL);
1477 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1478 if (inp & (PBTN_MBACK|PBTN_MOK))
1483 // ------------ main menu ------------
1487 static void draw_frame_main(void)
1494 if (CdromId[0] != 0) {
1495 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1496 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1497 Config.HLE ? "HLE" : "BIOS");
1498 smalltext_out16(4, 1, buff, 0x105f);
1503 tmp = localtime(<ime);
1504 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1505 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1506 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1510 static void draw_frame_credits(void)
1512 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1515 static const char credits_text[] =
1517 "(C) 1999-2003 PCSX Team\n"
1518 "(C) 2005-2009 PCSX-df Team\n"
1519 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1520 "GPU and SPU code by Pete Bernert\n"
1521 " and the P.E.Op.S. team\n"
1522 "ARM recompiler (C) 2009-2011 Ari64\n"
1523 "PCSX4ALL plugins by PCSX4ALL team\n"
1524 " Chui, Franxis, Unai\n\n"
1525 "integration, optimization and\n"
1526 " frontend (C) 2010-2011 notaz\n";
1528 static int reset_game(void)
1531 if (bios_sel == 0 && !Config.HLE)
1537 if (CheckCdrom() != -1) {
1543 static int reload_plugins(const char *cdimg)
1549 set_cd_image(cdimg);
1551 pcnt_hook_plugins();
1553 if (OpenPlugins() == -1) {
1554 me_update_msg("failed to open plugins");
1557 plugin_call_rearmed_cbs();
1560 CdromLabel[0] = '\0';
1565 static int run_bios(void)
1571 if (reload_plugins(NULL) != 0)
1579 static int run_exe(void)
1583 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1588 if (reload_plugins(NULL) != 0)
1592 if (Load(fname) != 0) {
1593 me_update_msg("exe load failed, bad file?");
1602 static int run_cd_image(const char *fname)
1605 reload_plugins(fname);
1607 // always autodetect, menu_sync_config will override as needed
1610 if (CheckCdrom() == -1) {
1611 // Only check the CD if we are starting the console with a CD
1613 me_update_msg("unsupported/invalid CD image");
1619 // Read main executable directly from CDRom and start it
1620 if (LoadCdrom() == -1) {
1622 me_update_msg("failed to load CD image");
1630 static int romsel_run(void)
1632 int prev_gpu, prev_spu;
1635 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1639 printf("selected file: %s\n", fname);
1641 new_dynarec_clear_full();
1643 if (run_cd_image(fname) != 0)
1646 prev_gpu = gpu_plugsel;
1647 prev_spu = spu_plugsel;
1648 if (menu_load_config(1) != 0)
1649 menu_load_config(0);
1651 // check for plugin changes, have to repeat
1652 // loading if game config changed plugins to reload them
1653 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1654 printf("plugin change detected, reloading plugins..\n");
1655 if (run_cd_image(fname) != 0)
1659 strcpy(last_selected_fname, rom_fname_reload);
1663 static int swap_cd_image(void)
1667 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1671 printf("selected file: %s\n", fname);
1674 CdromLabel[0] = '\0';
1676 set_cd_image(fname);
1677 if (ReloadCdromPlugin() < 0) {
1678 me_update_msg("failed to load cdr plugin");
1681 if (CDR_open() < 0) {
1682 me_update_msg("failed to open cdr plugin");
1686 SetCdOpenCaseTime(time(NULL) + 2);
1689 strcpy(last_selected_fname, rom_fname_reload);
1693 static int main_menu_handler(int id, int keys)
1697 case MA_MAIN_RESUME_GAME:
1701 case MA_MAIN_SAVE_STATE:
1703 return menu_loop_savestate(0);
1705 case MA_MAIN_LOAD_STATE:
1707 return menu_loop_savestate(1);
1709 case MA_MAIN_RESET_GAME:
1710 if (ready_to_go && reset_game() == 0)
1713 case MA_MAIN_LOAD_ROM:
1714 if (romsel_run() == 0)
1717 case MA_MAIN_SWAP_CD:
1718 if (swap_cd_image() == 0)
1721 case MA_MAIN_RUN_BIOS:
1722 if (run_bios() == 0)
1725 case MA_MAIN_RUN_EXE:
1729 case MA_MAIN_CREDITS:
1730 draw_menu_message(credits_text, draw_frame_credits);
1731 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1737 lprintf("%s: something unknown selected\n", __FUNCTION__);
1744 static menu_entry e_menu_main2[] =
1746 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1747 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1748 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1749 mee_handler ("Memcard manager", menu_loop_memcards),
1753 static int main_menu2_handler(int id, int keys)
1757 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1758 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1760 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1763 static const char h_extra[] = "Change CD, manage memcards..\n";
1765 static menu_entry e_menu_main[] =
1769 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1770 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1771 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1772 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1773 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1774 mee_handler ("Options", menu_loop_options),
1775 mee_handler ("Controls", menu_loop_keyconfig),
1776 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1777 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1778 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1782 // ----------------------------
1784 static void menu_leave_emu(void);
1786 void menu_loop(void)
1792 if (bioses[1] == NULL && !warned_about_bios) {
1794 warned_about_bios = 1;
1797 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1798 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1799 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1800 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1802 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1805 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1806 } while (!ready_to_go);
1808 /* wait until menu, ok, back is released */
1809 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1812 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1817 static int qsort_strcmp(const void *p1, const void *p2)
1819 char * const *s1 = (char * const *)p1;
1820 char * const *s2 = (char * const *)p2;
1821 return strcasecmp(*s1, *s2);
1824 static void scan_bios_plugins(void)
1826 char fname[MAXPATHLEN];
1828 int bios_i, gpu_i, spu_i, mc_i;
1833 gpu_plugins[0] = "builtin_gpu";
1834 spu_plugins[0] = "builtin_spu";
1835 memcards[0] = "(none)";
1836 bios_i = gpu_i = spu_i = mc_i = 1;
1838 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1839 dir = opendir(fname);
1841 perror("scan_bios_plugins bios opendir");
1856 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1859 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1860 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1861 printf("bad BIOS file: %s\n", ent->d_name);
1865 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1866 bioses[bios_i++] = strdup(ent->d_name);
1870 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1876 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1877 dir = opendir(fname);
1879 perror("scan_bios_plugins plugins opendir");
1893 p = strstr(ent->d_name, ".so");
1897 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1898 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1900 fprintf(stderr, "%s\n", dlerror());
1904 // now what do we have here?
1905 tmp = dlsym(h, "GPUinit");
1908 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1909 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1913 tmp = dlsym(h, "SPUinit");
1916 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1917 spu_plugins[spu_i++] = strdup(ent->d_name);
1921 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1928 dir = opendir("." MEMCARD_DIR);
1930 perror("scan_bios_plugins memcards opendir");
1945 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1948 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1949 if (stat(fname, &st) != 0) {
1950 printf("bad memcard file: %s\n", ent->d_name);
1954 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1955 memcards[mc_i++] = strdup(ent->d_name);
1959 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1963 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1968 void menu_init(void)
1970 char buff[MAXPATHLEN];
1972 strcpy(last_selected_fname, "/media");
1974 scan_bios_plugins();
1978 menu_set_defconfig();
1979 menu_load_config(0);
1984 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1985 if (g_menubg_src_ptr == NULL)
1987 emu_make_path(buff, "skin/background.png", sizeof(buff));
1988 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1990 #ifndef __ARM_ARCH_7A__ /* XXX */
1991 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
1992 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
1994 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
1998 void menu_notify_mode_change(int w, int h, int bpp)
2009 g_layer_w = w; g_layer_h = h;
2013 mult = 240.0f / (float)h * 4.0f / 3.0f;
2016 g_layer_w = mult * (float)g_menuscreen_h;
2017 g_layer_h = g_menuscreen_h;
2018 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2022 // 4:3 that prefers integer scaling
2023 imult = g_menuscreen_h / h;
2024 g_layer_w = w * imult;
2025 g_layer_h = h * imult;
2026 mult = (float)g_layer_w / (float)g_layer_h;
2027 if (mult < 1.25f || mult > 1.666f)
2028 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2029 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2032 case SCALE_FULLSCREEN:
2033 g_layer_w = g_menuscreen_w;
2034 g_layer_h = g_menuscreen_h;
2041 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2042 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2043 if (g_layer_x < 0) g_layer_x = 0;
2044 if (g_layer_y < 0) g_layer_y = 0;
2045 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2046 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2049 static void menu_leave_emu(void)
2051 if (GPU_close != NULL) {
2052 int ret = GPU_close();
2054 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2057 plat_video_menu_enter(ready_to_go);
2059 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2060 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2061 int x = max(0, g_menuscreen_w - last_psx_w);
2062 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2063 int w = min(g_menuscreen_w, last_psx_w);
2064 int h = min(g_menuscreen_h, last_psx_h);
2065 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2066 u16 *s = pl_vout_buf;
2068 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2069 menu_darken_bg(d, s, w, 0);
2073 cpu_clock = plat_cpu_clock_get();
2076 void menu_prepare_emu(void)
2078 R3000Acpu *prev_cpu = psxCpu;
2080 plat_video_menu_leave();
2082 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2084 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2085 if (psxCpu != prev_cpu)
2086 // note that this does not really reset, just clears drc caches
2089 // core doesn't care about Config.Cdda changes,
2090 // so handle them manually here
2095 apply_lcdrate(Config.PsxType);
2096 apply_filter(filter);
2097 plat_cpu_clock_apply(cpu_clock);
2099 // push config to GPU plugin
2100 plugin_call_rearmed_cbs();
2102 if (GPU_open != NULL) {
2103 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2105 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2111 void me_update_msg(const char *msg)
2113 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2114 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2116 menu_error_time = plat_get_ticks_ms();
2117 lprintf("msg: %s\n", menu_error_msg);