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"
25 #include "arm_utils.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"
37 #define array_size(x) (sizeof(x) / sizeof(x[0]))
72 static int last_psx_w, last_psx_h, last_psx_bpp;
73 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost;
74 static char rom_fname_reload[MAXPATHLEN];
75 static char last_selected_fname[MAXPATHLEN];
76 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
77 static int memcard1_sel, memcard2_sel;
81 extern int iUseReverb;
82 extern int iUseInterpolation;
84 extern int iSPUIRQWait;
88 static const char *bioses[24];
89 static const char *gpu_plugins[16];
90 static const char *spu_plugins[16];
91 static const char *memcards[32];
92 static int bios_sel, gpu_plugsel, spu_plugsel;
95 static int min(int x, int y) { return x < y ? x : y; }
96 static int max(int x, int y) { return x > y ? x : y; }
98 void emu_make_path(char *buff, const char *end, int size)
102 end_len = strlen(end);
103 pos = plat_get_root_dir(buff, size);
104 strncpy(buff + pos, end, size - pos);
106 if (pos + end_len > size - 1)
107 printf("Warning: path truncated: %s\n", buff);
110 static int emu_check_save_file(int slot)
112 int ret = emu_check_state(slot);
113 return ret == 0 ? 1 : 0;
116 static int emu_save_load_game(int load, int unused)
121 ret = emu_load_state(state_slot);
123 // reflect hle/bios mode from savestate
126 else if (bios_sel == 0 && bioses[1] != NULL)
127 // XXX: maybe find the right bios instead
131 ret = emu_save_state(state_slot);
136 // propagate menu settings to the emu vars
137 static void menu_sync_config(void)
139 static int allow_abs_only_old;
144 Config.PsxType = region - 1;
146 switch (in_type_sel1) {
147 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
148 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
149 default: in_type1 = PSE_PAD_TYPE_STANDARD;
151 switch (in_type_sel2) {
152 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
153 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
154 default: in_type2 = PSE_PAD_TYPE_STANDARD;
156 if (in_evdev_allow_abs_only != allow_abs_only_old) {
157 pandora_rescan_inputs();
158 allow_abs_only_old = in_evdev_allow_abs_only;
161 pl_frame_interval = Config.PsxType ? 20000 : 16667;
162 // used by P.E.Op.S. frameskip code
163 pl_rearmed_cbs.gpu_peops.fFrameRateHz = Config.PsxType ? 50.0f : 59.94f;
164 pl_rearmed_cbs.gpu_peops.dwFrameRateTicks =
165 (100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
167 iVolume = 768 + 128 * volume_boost;
170 static void menu_set_defconfig(void)
177 in_type_sel1 = in_type_sel2 = 0;
178 in_evdev_allow_abs_only = 0;
179 Config.Xa = Config.Cdda = Config.Sio =
180 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
181 Config.CdrReschedule = 0;
183 pl_rearmed_cbs.frameskip = 0;
184 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
185 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
188 iUseInterpolation = 1;
196 #define CE_CONFIG_STR(val) \
197 { #val, 0, Config.val }
199 #define CE_CONFIG_VAL(val) \
200 { #val, sizeof(Config.val), &Config.val }
202 #define CE_STR(val) \
205 #define CE_INTVAL(val) \
206 { #val, sizeof(val), &val }
208 #define CE_INTVAL_P(val) \
209 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
211 // 'versioned' var, used when defaults change
212 #define CE_INTVAL_V(val, ver) \
213 { #val #ver, sizeof(val), &val }
215 static const struct {
223 // CE_CONFIG_STR(Cdr),
228 CE_CONFIG_VAL(Debug),
229 CE_CONFIG_VAL(PsxOut),
230 CE_CONFIG_VAL(SpuIrq),
231 CE_CONFIG_VAL(RCntFix),
232 CE_CONFIG_VAL(VSyncWA),
234 CE_CONFIG_VAL(CdrReschedule),
237 CE_INTVAL(g_layer_x),
238 CE_INTVAL(g_layer_y),
239 CE_INTVAL(g_layer_w),
240 CE_INTVAL(g_layer_h),
242 CE_INTVAL(state_slot),
243 CE_INTVAL(cpu_clock),
245 CE_INTVAL(in_type_sel1),
246 CE_INTVAL(in_type_sel2),
247 CE_INTVAL_P(frameskip),
248 CE_INTVAL_P(gpu_peops.iUseDither),
249 CE_INTVAL_P(gpu_peops.dwActFixes),
250 CE_INTVAL(iUseReverb),
252 CE_INTVAL_V(iUseInterpolation, 2),
253 CE_INTVAL_V(iSPUIRQWait, 2),
254 CE_INTVAL(iUseTimer),
255 CE_INTVAL(warned_about_bios),
256 CE_INTVAL(in_evdev_allow_abs_only),
257 CE_INTVAL(volume_boost),
260 static char *get_cd_label(void)
262 static char trimlabel[33];
265 strncpy(trimlabel, CdromLabel, 32);
267 for (j = 31; j >= 0; j--)
268 if (trimlabel[j] == ' ')
274 static void make_cfg_fname(char *buf, size_t size, int is_game)
277 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
279 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
282 static void keys_write_all(FILE *f);
284 static int menu_write_config(int is_game)
286 char cfgfile[MAXPATHLEN];
290 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
291 f = fopen(cfgfile, "w");
293 printf("menu_write_config: failed to open: %s\n", cfgfile);
297 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
298 fprintf(f, "%s = ", config_data[i].name);
299 switch (config_data[i].len) {
301 fprintf(f, "%s\n", (char *)config_data[i].val);
304 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
307 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
310 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
313 printf("menu_write_config: unhandled len %d for %s\n",
314 config_data[i].len, config_data[i].name);
320 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
328 static void parse_str_val(char *cval, const char *src)
331 strncpy(cval, src, MAXPATHLEN);
332 cval[MAXPATHLEN - 1] = 0;
333 tmp = strchr(cval, '\n');
335 tmp = strchr(cval, '\r');
340 static void keys_load_all(const char *cfg);
342 static int menu_load_config(int is_game)
344 char cfgfile[MAXPATHLEN];
350 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
351 f = fopen(cfgfile, "r");
353 printf("menu_load_config: failed to open: %s\n", cfgfile);
357 fseek(f, 0, SEEK_END);
360 printf("bad size %ld: %s\n", size, cfgfile);
364 cfg = malloc(size + 1);
368 fseek(f, 0, SEEK_SET);
369 if (fread(cfg, 1, size, f) != size) {
370 printf("failed to read: %s\n", cfgfile);
375 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
379 tmp = strstr(cfg, config_data[i].name);
382 tmp += strlen(config_data[i].name);
383 if (strncmp(tmp, " = ", 3) != 0)
387 if (config_data[i].len == 0) {
388 parse_str_val(config_data[i].val, tmp);
393 val = strtoul(tmp, &tmp2, 16);
394 if (tmp2 == NULL || tmp == tmp2)
395 continue; // parse failed
397 switch (config_data[i].len) {
399 *(u8 *)config_data[i].val = val;
402 *(u16 *)config_data[i].val = val;
405 *(u32 *)config_data[i].val = val;
408 printf("menu_load_config: unhandled len %d for %s\n",
409 config_data[i].len, config_data[i].name);
415 char *tmp = strstr(cfg, "lastcdimg = ");
418 parse_str_val(last_selected_fname, tmp);
425 for (i = bios_sel = 0; bioses[i] != NULL; i++)
426 if (strcmp(Config.Bios, bioses[i]) == 0)
427 { bios_sel = i; break; }
429 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
430 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
431 { gpu_plugsel = i; break; }
433 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
434 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
435 { spu_plugsel = i; break; }
446 // rrrr rggg gggb bbbb
447 static unsigned short fname2color(const char *fname)
449 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
450 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
451 const char *ext = strrchr(fname, '.');
456 for (i = 0; i < array_size(cdimg_exts); i++)
457 if (strcasecmp(ext, cdimg_exts[i]) == 0)
459 for (i = 0; i < array_size(other_exts); i++)
460 if (strcasecmp(ext, other_exts[i]) == 0)
465 static void draw_savestate_bg(int slot);
467 static const char *filter_exts[] = {
468 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
471 #define MENU_ALIGN_LEFT
472 #define menu_init menu_init_common
473 #include "common/menu.c"
476 // a bit of black magic here
477 static void draw_savestate_bg(int slot)
479 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
481 char fname[MAXPATHLEN];
488 ret = get_state_filename(fname, sizeof(fname), slot);
492 f = gzopen(fname, "rb");
496 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
497 fprintf(stderr, "gzseek failed\n");
502 gpu = malloc(sizeof(*gpu));
508 ret = gzread(f, gpu, sizeof(*gpu));
510 if (ret != sizeof(*gpu)) {
511 fprintf(stderr, "gzread failed\n");
515 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
517 if (gpu->ulStatus & 0x800000)
518 goto out; // disabled
520 x = gpu->ulControl[5] & 0x3ff;
521 y = (gpu->ulControl[5] >> 10) & 0x1ff;
522 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
523 w = psx_widths[(gpu->ulStatus >> 16) & 7];
524 tmp = gpu->ulControl[7];
525 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
526 if (gpu->ulStatus & 0x80000) // doubleheight
529 x = max(0, g_menuscreen_w - w) & ~3;
530 y = max(0, g_menuscreen_h / 2 - h / 2);
531 w = min(g_menuscreen_w, w);
532 h = min(g_menuscreen_h, h);
533 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
535 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
536 if (gpu->ulStatus & 0x200000)
537 bgr888_to_rgb565(d, s, w * 3);
539 bgr555_to_rgb565(d, s, w * 2);
545 // ---------- pandora specific -----------
547 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
548 static char **pnd_filter_list;
550 static int get_cpu_clock(void)
554 f = fopen("/proc/pandora/cpu_mhz_max", "r");
556 fscanf(f, "%d", &ret);
562 static void apply_cpu_clock(void)
566 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
567 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
568 pnd_script_base, cpu_clock);
573 static void apply_filter(int which)
579 if (pnd_filter_list == NULL || which == old)
582 for (i = 0; i < which; i++)
583 if (pnd_filter_list[i] == NULL)
586 if (pnd_filter_list[i] == NULL)
589 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
594 static void apply_lcdrate(int pal)
602 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
603 pnd_script_base, pal ? 50 : 60);
608 static menu_entry e_menu_gfx_options[];
610 static void pnd_menu_init(void)
618 cpu_clock_st = cpu_clock = get_cpu_clock();
620 dir = opendir("/etc/pandora/conf/dss_fir");
622 perror("filter opendir");
635 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
644 mfilters = calloc(count + 1, sizeof(mfilters[0]));
645 if (mfilters == NULL)
649 for (i = 0; (ent = readdir(dir)); ) {
652 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
655 len = strlen(ent->d_name);
657 // skip pre-HF5 extra files
658 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
660 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
663 // have to cut "_up_h" for pre-HF5
664 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
667 if (len > sizeof(buff) - 1)
670 strncpy(buff, ent->d_name, len);
672 mfilters[i] = strdup(buff);
673 if (mfilters[i] != NULL)
678 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
679 e_menu_gfx_options[i].data = (void *)mfilters;
680 pnd_filter_list = mfilters;
683 void menu_finish(void)
685 cpu_clock = cpu_clock_st;
689 // -------------- key config --------------
691 me_bind_action me_ctrl_actions[] =
693 { "UP ", 1 << DKEY_UP},
694 { "DOWN ", 1 << DKEY_DOWN },
695 { "LEFT ", 1 << DKEY_LEFT },
696 { "RIGHT ", 1 << DKEY_RIGHT },
697 { "TRIANGLE", 1 << DKEY_TRIANGLE },
698 { "CIRCLE ", 1 << DKEY_CIRCLE },
699 { "CROSS ", 1 << DKEY_CROSS },
700 { "SQUARE ", 1 << DKEY_SQUARE },
701 { "L1 ", 1 << DKEY_L1 },
702 { "R1 ", 1 << DKEY_R1 },
703 { "L2 ", 1 << DKEY_L2 },
704 { "R2 ", 1 << DKEY_R2 },
705 { "L3 ", 1 << DKEY_L3 },
706 { "R3 ", 1 << DKEY_R3 },
707 { "START ", 1 << DKEY_START },
708 { "SELECT ", 1 << DKEY_SELECT },
712 me_bind_action emuctrl_actions[] =
714 { "Save State ", 1 << SACTION_SAVE_STATE },
715 { "Load State ", 1 << SACTION_LOAD_STATE },
716 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
717 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
718 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
719 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
720 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
721 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
722 { "Gun A button ", 1 << SACTION_GUN_A },
723 { "Gun B button ", 1 << SACTION_GUN_B },
724 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
728 static char *mystrip(char *str)
733 for (i = 0; i < len; i++)
734 if (str[i] != ' ') break;
735 if (i > 0) memmove(str, str + i, len - i + 1);
738 for (i = len - 1; i >= 0; i--)
739 if (str[i] != ' ') break;
745 static void get_line(char *d, size_t size, const char *s)
750 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
761 static void keys_write_all(FILE *f)
765 for (d = 0; d < IN_MAX_DEVS; d++)
767 const int *binds = in_get_dev_binds(d);
768 const char *name = in_get_dev_name(d, 0, 0);
771 if (binds == NULL || name == NULL)
774 fprintf(f, "binddev = %s\n", name);
775 in_get_config(d, IN_CFG_BIND_COUNT, &count);
777 for (k = 0; k < count; k++)
782 act[0] = act[31] = 0;
783 name = in_get_key_name(d, k);
785 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
786 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
787 mask = me_ctrl_actions[i].mask;
789 strncpy(act, me_ctrl_actions[i].name, 31);
790 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
793 mask = me_ctrl_actions[i].mask << 16;
795 strncpy(act, me_ctrl_actions[i].name, 31);
796 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
801 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
802 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
803 mask = emuctrl_actions[i].mask;
805 strncpy(act, emuctrl_actions[i].name, 31);
806 fprintf(f, "bind %s = %s\n", name, mystrip(act));
814 static int parse_bind_val(const char *val, int *type)
818 *type = IN_BINDTYPE_NONE;
822 if (strncasecmp(val, "player", 6) == 0)
824 int player, shift = 0;
825 player = atoi(val + 6) - 1;
827 if ((unsigned int)player > 1)
832 *type = IN_BINDTYPE_PLAYER12;
833 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
834 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
835 return me_ctrl_actions[i].mask << shift;
838 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
839 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
840 *type = IN_BINDTYPE_EMU;
841 return emuctrl_actions[i].mask;
848 static void keys_load_all(const char *cfg)
850 char dev[256], key[128], *act;
856 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
859 get_line(dev, sizeof(dev), p);
860 dev_id = in_config_parse_dev(dev);
862 printf("input: can't handle dev: %s\n", dev);
866 in_unbind_all(dev_id, -1, -1);
867 while ((p = strstr(p, "bind"))) {
868 if (strncmp(p, "binddev = ", 10) == 0)
873 printf("input: parse error: %16s..\n", p);
877 get_line(key, sizeof(key), p);
878 act = strchr(key, '=');
880 printf("parse failed: %16s..\n", p);
888 bind = parse_bind_val(act, &bindtype);
889 if (bind != -1 && bind != 0) {
890 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
891 in_config_bind_key(dev_id, key, bind, bindtype);
894 lprintf("config: unhandled action \"%s\"\n", act);
900 static int key_config_loop_wrap(int id, int keys)
903 case MA_CTRL_PLAYER1:
904 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
906 case MA_CTRL_PLAYER2:
907 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
910 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
918 static const char *mgn_dev_name(int id, int *offs)
920 const char *name = NULL;
923 if (id == MA_CTRL_DEV_FIRST)
926 for (; it < IN_MAX_DEVS; it++) {
927 name = in_get_dev_name(it, 1, 1);
936 static const char *mgn_saveloadcfg(int id, int *offs)
941 static int mh_savecfg(int id, int keys)
943 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
944 me_update_msg("config saved");
946 me_update_msg("failed to write config");
951 static int mh_input_rescan(int id, int keys)
953 //menu_sync_config();
954 pandora_rescan_inputs();
955 me_update_msg("rescan complete.");
960 static const char *men_in_type_sel[] = {
961 "Standard (SCPH-1080)",
962 "Analog (SCPH-1150)",
966 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
967 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
969 static menu_entry e_menu_keyconfig[] =
971 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
972 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
973 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
975 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
976 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
977 mee_onoff_h ("Nubs as buttons", 0, in_evdev_allow_abs_only, 1, h_nub_btns),
978 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
979 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
980 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
981 mee_handler ("Rescan devices", mh_input_rescan),
983 mee_label ("Input devices:"),
984 mee_label_mk (MA_CTRL_DEV_FIRST, 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),
989 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
990 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
994 static int menu_loop_keyconfig(int id, int keys)
998 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
999 me_loop(e_menu_keyconfig, &sel);
1003 // ------------ gfx options menu ------------
1005 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
1006 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1007 "using d-pad or move it using R+d-pad";
1008 static const char *men_dummy[] = { NULL };
1010 static int menu_loop_cscaler(int id, int keys)
1014 scaling = SCALE_CUSTOM;
1016 omap_enable_layer(1);
1021 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1022 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1023 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1026 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1027 if (inp & PBTN_UP) g_layer_y--;
1028 if (inp & PBTN_DOWN) g_layer_y++;
1029 if (inp & PBTN_LEFT) g_layer_x--;
1030 if (inp & PBTN_RIGHT) g_layer_x++;
1031 if (!(inp & PBTN_R)) {
1032 if (inp & PBTN_UP) g_layer_h += 2;
1033 if (inp & PBTN_DOWN) g_layer_h -= 2;
1034 if (inp & PBTN_LEFT) g_layer_w += 2;
1035 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1037 if (inp & (PBTN_MOK|PBTN_MBACK))
1040 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1041 if (g_layer_x < 0) g_layer_x = 0;
1042 if (g_layer_x > 640) g_layer_x = 640;
1043 if (g_layer_y < 0) g_layer_y = 0;
1044 if (g_layer_y > 420) g_layer_y = 420;
1045 if (g_layer_w < 160) g_layer_w = 160;
1046 if (g_layer_h < 60) g_layer_h = 60;
1047 if (g_layer_x + g_layer_w > 800)
1048 g_layer_w = 800 - g_layer_x;
1049 if (g_layer_y + g_layer_h > 480)
1050 g_layer_h = 480 - g_layer_y;
1051 omap_enable_layer(1);
1055 omap_enable_layer(0);
1060 static menu_entry e_menu_gfx_options[] =
1062 mee_enum ("Scaler", 0, scaling, men_scaler),
1063 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1064 // mee_onoff ("Vsync", 0, vsync, 1),
1065 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1069 static int menu_loop_gfx_options(int id, int keys)
1073 me_loop(e_menu_gfx_options, &sel);
1078 // ------------ bios/plugins ------------
1080 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1081 static const char h_gpu_0[] = "Needed for Chrono Cross";
1082 static const char h_gpu_1[] = "Capcom fighting games";
1083 static const char h_gpu_2[] = "Black screens in Lunar";
1084 static const char h_gpu_3[] = "Compatibility mode";
1085 static const char h_gpu_6[] = "Pandemonium 2";
1086 static const char h_gpu_7[] = "Skip every second frame";
1087 static const char h_gpu_8[] = "Needed by Dark Forces";
1088 static const char h_gpu_9[] = "better g-colors, worse textures";
1089 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1091 static menu_entry e_menu_plugin_gpu[] =
1093 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1094 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1095 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1096 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1097 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1098 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1099 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1100 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1101 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1102 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1106 static int menu_loop_plugin_gpu(int id, int keys)
1109 me_loop(e_menu_plugin_gpu, &sel);
1113 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1114 static const char h_spu_volboost[] = "Large values cause distortion";
1115 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1116 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1118 static menu_entry e_menu_plugin_spu[] =
1120 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1121 mee_onoff ("Reverb", 0, iUseReverb, 2),
1122 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1123 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1124 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1125 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1129 static int menu_loop_plugin_spu(int id, int keys)
1132 me_loop(e_menu_plugin_spu, &sel);
1136 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1137 "and can't be changed there. Must save config and reload\n"
1138 "the game for change to take effect";
1139 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1140 "for plugin change to take effect";
1141 static const char h_gpu[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1142 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1144 static menu_entry e_menu_plugin_options[] =
1146 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1147 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1148 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1149 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu, h_gpu),
1150 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1154 static menu_entry e_menu_main2[];
1156 static int menu_loop_plugin_options(int id, int keys)
1159 me_loop(e_menu_plugin_options, &sel);
1161 // sync BIOS/plugins
1162 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1163 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1164 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1165 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1170 // ------------ adv options menu ------------
1172 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1173 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1174 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1175 "(green: normal, red: fmod, blue: noise)";
1176 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1177 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1178 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1179 "(proper .cue/.bin dump is needed otherwise)";
1180 static const char h_cfg_sio[] = "You should not need this, breaks games";
1181 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1182 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1183 "(timing hack, breaks other games)";
1184 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1185 "(timing hack, breaks other games)";
1186 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1187 "(CD timing hack, breaks FMVs)";
1188 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1189 "Might be useful to overcome some dynarec bugs";
1191 static menu_entry e_menu_adv_options[] =
1193 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1194 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1195 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1196 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1197 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1198 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1199 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1200 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1201 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1202 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1203 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1207 static int menu_loop_adv_options(int id, int keys)
1210 me_loop(e_menu_adv_options, &sel);
1214 // ------------ options menu ------------
1216 static int mh_restore_defaults(int id, int keys)
1218 menu_set_defconfig();
1219 me_update_msg("defaults restored");
1223 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1225 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1226 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1227 "loading state or both";
1229 static const char h_restore_def[] = "Switches back to default / recommended\n"
1231 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1233 static menu_entry e_menu_options[] =
1235 // mee_range ("Save slot", 0, state_slot, 0, 9),
1236 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1237 mee_onoff_h ("Frameskip", 0, pl_rearmed_cbs.frameskip, 1, h_frameskip),
1238 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1239 mee_enum ("Region", 0, region, men_region),
1240 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1241 mee_handler ("[Display]", menu_loop_gfx_options),
1242 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1243 mee_handler ("[Advanced]", menu_loop_adv_options),
1244 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1245 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1246 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1250 static int menu_loop_options(int id, int keys)
1255 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1256 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1257 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1259 me_loop(e_menu_options, &sel);
1264 // ------------ debug menu ------------
1266 static void draw_frame_debug(GPUFreeze_t *gpuf)
1268 int w = min(g_menuscreen_w, 1024);
1269 int h = min(g_menuscreen_h, 512);
1270 u16 *d = g_menuscreen_ptr;
1271 u16 *s = (u16 *)gpuf->psxVRam;
1275 gpuf->ulFreezeVersion = 1;
1276 if (GPU_freeze != NULL)
1277 GPU_freeze(1, gpuf);
1279 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1280 bgr555_to_rgb565(d, s, w * 2);
1282 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1283 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1284 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1285 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1286 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1289 static void debug_menu_loop(void)
1294 gpuf = malloc(sizeof(*gpuf));
1301 draw_frame_debug(gpuf);
1304 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1305 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1306 if (inp & PBTN_MBACK)
1313 // --------- memcard manager ---------
1315 static void draw_mc_icon(int dx, int dy, const u16 *s)
1320 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1322 for (y = 0; y < 16; y++, s += 16) {
1323 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1324 for (x = 0; x < 16; x++) {
1326 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1327 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1333 static void draw_mc_bg(void)
1335 McdBlock *blocks1, *blocks2;
1339 blocks1 = malloc(15 * sizeof(blocks1[0]));
1340 blocks2 = malloc(15 * sizeof(blocks1[0]));
1341 if (blocks1 == NULL || blocks2 == NULL)
1344 for (i = 0; i < 15; i++) {
1345 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1346 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1351 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1353 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1357 maxicons = g_menuscreen_h / 32;
1360 row2 = g_menuscreen_w / 2;
1361 for (i = 0; i < maxicons; i++) {
1362 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1363 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1365 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1366 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1369 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1377 static void handle_memcard_sel(void)
1380 if (memcard1_sel != 0)
1381 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1383 if (memcard2_sel != 0)
1384 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1385 LoadMcds(Config.Mcd1, Config.Mcd2);
1389 static menu_entry e_memcard_options[] =
1391 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1392 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1396 static int menu_loop_memcards(int id, int keys)
1402 memcard1_sel = memcard2_sel = 0;
1403 p = strrchr(Config.Mcd1, '/');
1405 for (i = 0; memcards[i] != NULL; i++)
1406 if (strcmp(p + 1, memcards[i]) == 0)
1407 { memcard1_sel = i; break; }
1408 p = strrchr(Config.Mcd2, '/');
1410 for (i = 0; memcards[i] != NULL; i++)
1411 if (strcmp(p + 1, memcards[i]) == 0)
1412 { memcard2_sel = i; break; }
1414 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1416 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1421 // --------- main menu help ----------
1423 static void menu_bios_warn(void)
1426 static const char msg[] =
1427 "You don't seem to have copied any BIOS files to\n"
1428 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1429 "While many games work fine with fake (HLE) BIOS,\n"
1430 "others (like MGS and FF8) require BIOS to work.\n"
1431 "After copying the file, you'll also need to\n"
1432 "select it in the emu's options->[BIOS/Plugins]\n\n"
1433 "The file is usually named SCPH1001.BIN, but\n"
1434 "other not compressed files can be used too.\n\n"
1435 "Press (B) or (X) to continue";
1439 draw_menu_message(msg, NULL);
1441 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1442 if (inp & (PBTN_MBACK|PBTN_MOK))
1447 // ------------ main menu ------------
1451 static void draw_frame_main(void)
1453 if (CdromId[0] != 0) {
1455 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1456 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1457 Config.HLE ? "HLE" : "BIOS");
1458 smalltext_out16(4, 1, buff, 0x105f);
1462 static void draw_frame_credits(void)
1464 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1467 static const char credits_text[] =
1469 "(C) 1999-2003 PCSX Team\n"
1470 "(C) 2005-2009 PCSX-df Team\n"
1471 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1472 "GPU and SPU code by Pete Bernert\n"
1473 " and the P.E.Op.S. team\n"
1474 "ARM recompiler (C) 2009-2011 Ari64\n"
1475 "PCSX4ALL plugins by PCSX4ALL team\n"
1476 " Chui, Franxis, Unai\n\n"
1477 "integration, optimization and\n"
1478 " frontend (C) 2010-2011 notaz\n";
1480 static int reset_game(void)
1483 if (bios_sel == 0 && !Config.HLE)
1489 if (CheckCdrom() != -1) {
1495 static int reload_plugins(const char *cdimg)
1497 pl_fbdev_buf = NULL;
1501 set_cd_image(cdimg);
1503 pcnt_hook_plugins();
1505 if (OpenPlugins() == -1) {
1506 me_update_msg("failed to open plugins");
1509 plugin_call_rearmed_cbs();
1512 CdromLabel[0] = '\0';
1517 static int run_bios(void)
1523 if (reload_plugins(NULL) != 0)
1531 static int run_exe(void)
1535 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1540 if (reload_plugins(NULL) != 0)
1544 if (Load(fname) != 0) {
1545 me_update_msg("exe load failed, bad file?");
1554 static int run_cd_image(const char *fname)
1557 reload_plugins(fname);
1559 if (CheckCdrom() == -1) {
1560 // Only check the CD if we are starting the console with a CD
1562 me_update_msg("unsupported/invalid CD image");
1568 // Read main executable directly from CDRom and start it
1569 if (LoadCdrom() == -1) {
1571 me_update_msg("failed to load CD image");
1579 static int romsel_run(void)
1581 int prev_gpu, prev_spu;
1584 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1588 printf("selected file: %s\n", fname);
1590 new_dynarec_clear_full();
1592 if (run_cd_image(fname) != 0)
1595 prev_gpu = gpu_plugsel;
1596 prev_spu = spu_plugsel;
1597 if (menu_load_config(1) != 0)
1598 menu_load_config(0);
1600 // check for plugin changes, have to repeat
1601 // loading if game config changed plugins to reload them
1602 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1603 printf("plugin change detected, reloading plugins..\n");
1604 if (run_cd_image(fname) != 0)
1608 strcpy(last_selected_fname, rom_fname_reload);
1612 static int swap_cd_image(void)
1616 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1620 printf("selected file: %s\n", fname);
1623 CdromLabel[0] = '\0';
1625 set_cd_image(fname);
1626 if (ReloadCdromPlugin() < 0) {
1627 me_update_msg("failed to load cdr plugin");
1630 if (CDR_open() < 0) {
1631 me_update_msg("failed to open cdr plugin");
1635 SetCdOpenCaseTime(time(NULL) + 2);
1638 strcpy(last_selected_fname, rom_fname_reload);
1642 static int main_menu_handler(int id, int keys)
1646 case MA_MAIN_RESUME_GAME:
1650 case MA_MAIN_SAVE_STATE:
1652 return menu_loop_savestate(0);
1654 case MA_MAIN_LOAD_STATE:
1656 return menu_loop_savestate(1);
1658 case MA_MAIN_RESET_GAME:
1659 if (ready_to_go && reset_game() == 0)
1662 case MA_MAIN_LOAD_ROM:
1663 if (romsel_run() == 0)
1666 case MA_MAIN_SWAP_CD:
1667 if (swap_cd_image() == 0)
1670 case MA_MAIN_RUN_BIOS:
1671 if (run_bios() == 0)
1674 case MA_MAIN_RUN_EXE:
1678 case MA_MAIN_CREDITS:
1679 draw_menu_message(credits_text, draw_frame_credits);
1680 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1686 lprintf("%s: something unknown selected\n", __FUNCTION__);
1693 static menu_entry e_menu_main2[] =
1695 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1696 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1697 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1698 mee_handler ("Memcard manager", menu_loop_memcards),
1702 static int main_menu2_handler(int id, int keys)
1706 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1707 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1709 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1712 static const char h_extra[] = "Change CD, manage memcards..\n";
1714 static menu_entry e_menu_main[] =
1718 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1719 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1720 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1721 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1722 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1723 mee_handler ("Options", menu_loop_options),
1724 mee_handler ("Controls", menu_loop_keyconfig),
1725 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1726 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1727 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1731 // ----------------------------
1733 static void menu_leave_emu(void);
1735 void menu_loop(void)
1741 if (bioses[1] == NULL && !warned_about_bios) {
1743 warned_about_bios = 1;
1746 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1747 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1748 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1749 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1751 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1754 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1755 } while (!ready_to_go);
1757 /* wait until menu, ok, back is released */
1758 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1761 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1766 static int qsort_strcmp(const void *p1, const void *p2)
1768 char * const *s1 = (char * const *)p1;
1769 char * const *s2 = (char * const *)p2;
1770 return strcasecmp(*s1, *s2);
1773 static void scan_bios_plugins(void)
1775 char fname[MAXPATHLEN];
1777 int bios_i, gpu_i, spu_i, mc_i;
1782 gpu_plugins[0] = "builtin_gpu";
1783 spu_plugins[0] = "builtin_spu";
1784 memcards[0] = "(none)";
1785 bios_i = gpu_i = spu_i = mc_i = 1;
1787 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1788 dir = opendir(fname);
1790 perror("scan_bios_plugins bios opendir");
1805 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1808 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1809 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1810 printf("bad BIOS file: %s\n", ent->d_name);
1814 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1815 bioses[bios_i++] = strdup(ent->d_name);
1819 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1825 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1826 dir = opendir(fname);
1828 perror("scan_bios_plugins plugins opendir");
1842 p = strstr(ent->d_name, ".so");
1846 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1847 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1849 fprintf(stderr, "%s\n", dlerror());
1853 // now what do we have here?
1854 tmp = dlsym(h, "GPUinit");
1857 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1858 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1862 tmp = dlsym(h, "SPUinit");
1865 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1866 spu_plugins[spu_i++] = strdup(ent->d_name);
1870 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1877 dir = opendir("." MEMCARD_DIR);
1879 perror("scan_bios_plugins memcards opendir");
1894 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1897 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1898 if (stat(fname, &st) != 0) {
1899 printf("bad memcard file: %s\n", ent->d_name);
1903 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1904 memcards[mc_i++] = strdup(ent->d_name);
1908 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1912 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1917 void menu_init(void)
1919 char buff[MAXPATHLEN];
1921 strcpy(last_selected_fname, "/media");
1923 scan_bios_plugins();
1927 menu_set_defconfig();
1928 menu_load_config(0);
1933 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1934 if (g_menubg_src_ptr == NULL)
1936 emu_make_path(buff, "skin/background.png", sizeof(buff));
1937 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1940 void menu_notify_mode_change(int w, int h, int bpp)
1946 if (scaling == SCALE_1_1) {
1947 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1948 g_layer_w = w; g_layer_h = h;
1952 static void menu_leave_emu(void)
1954 if (GPU_close != NULL) {
1955 int ret = GPU_close();
1957 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1960 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1961 if (pl_fbdev_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1962 int x = max(0, g_menuscreen_w - last_psx_w);
1963 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1964 int w = min(g_menuscreen_w, last_psx_w);
1965 int h = min(g_menuscreen_h, last_psx_h);
1966 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1967 u16 *s = pl_fbdev_buf;
1969 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1970 menu_darken_bg(d, s, w, 0);
1974 cpu_clock = get_cpu_clock();
1976 plat_video_menu_enter(ready_to_go);
1979 void menu_prepare_emu(void)
1981 R3000Acpu *prev_cpu = psxCpu;
1983 plat_video_menu_leave();
1987 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
1990 g_layer_x = 80; g_layer_y = 0;
1991 g_layer_w = 640; g_layer_h = 480;
1993 case SCALE_FULLSCREEN:
1994 g_layer_x = 0; g_layer_y = 0;
1995 g_layer_w = 800; g_layer_h = 480;
2001 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2002 if (psxCpu != prev_cpu)
2003 // note that this does not really reset, just clears drc caches
2006 // core doesn't care about Config.Cdda changes,
2007 // so handle them manually here
2012 apply_lcdrate(Config.PsxType);
2013 apply_filter(filter);
2016 // push config to GPU plugin
2017 plugin_call_rearmed_cbs();
2019 if (GPU_open != NULL) {
2020 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2022 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2028 void me_update_msg(const char *msg)
2030 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2031 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2033 menu_error_time = plat_get_ticks_ms();
2034 lprintf("msg: %s\n", menu_error_msg);