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 iVolume = 768 + 128 * volume_boost;
162 pl_timing_prepare(Config.PsxType);
165 static void menu_set_defconfig(void)
172 in_type_sel1 = in_type_sel2 = 0;
173 in_evdev_allow_abs_only = 0;
174 Config.Xa = Config.Cdda = Config.Sio =
175 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
176 Config.CdrReschedule = 0;
178 pl_rearmed_cbs.frameskip = 0;
179 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
180 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
181 pl_rearmed_cbs.gpu_unai.abe_hack =
182 pl_rearmed_cbs.gpu_unai.no_light =
183 pl_rearmed_cbs.gpu_unai.no_blend = 0;
186 iUseInterpolation = 1;
194 #define CE_CONFIG_STR(val) \
195 { #val, 0, Config.val }
197 #define CE_CONFIG_VAL(val) \
198 { #val, sizeof(Config.val), &Config.val }
200 #define CE_STR(val) \
203 #define CE_INTVAL(val) \
204 { #val, sizeof(val), &val }
206 #define CE_INTVAL_P(val) \
207 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
209 // 'versioned' var, used when defaults change
210 #define CE_INTVAL_V(val, ver) \
211 { #val #ver, sizeof(val), &val }
213 static const struct {
221 // CE_CONFIG_STR(Cdr),
226 CE_CONFIG_VAL(Debug),
227 CE_CONFIG_VAL(PsxOut),
228 CE_CONFIG_VAL(SpuIrq),
229 CE_CONFIG_VAL(RCntFix),
230 CE_CONFIG_VAL(VSyncWA),
232 CE_CONFIG_VAL(CdrReschedule),
235 CE_INTVAL(g_layer_x),
236 CE_INTVAL(g_layer_y),
237 CE_INTVAL(g_layer_w),
238 CE_INTVAL(g_layer_h),
240 CE_INTVAL(state_slot),
241 CE_INTVAL(cpu_clock),
243 CE_INTVAL(in_type_sel1),
244 CE_INTVAL(in_type_sel2),
245 CE_INTVAL_P(frameskip),
246 CE_INTVAL_P(gpu_peops.iUseDither),
247 CE_INTVAL_P(gpu_peops.dwActFixes),
248 CE_INTVAL_P(gpu_unai.abe_hack),
249 CE_INTVAL_P(gpu_unai.no_light),
250 CE_INTVAL_P(gpu_unai.no_blend),
251 CE_INTVAL(iUseReverb),
253 CE_INTVAL_V(iUseInterpolation, 2),
254 CE_INTVAL_V(iSPUIRQWait, 2),
255 CE_INTVAL(iUseTimer),
256 CE_INTVAL(warned_about_bios),
257 CE_INTVAL(in_evdev_allow_abs_only),
258 CE_INTVAL(volume_boost),
261 static char *get_cd_label(void)
263 static char trimlabel[33];
266 strncpy(trimlabel, CdromLabel, 32);
268 for (j = 31; j >= 0; j--)
269 if (trimlabel[j] == ' ')
275 static void make_cfg_fname(char *buf, size_t size, int is_game)
278 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
280 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
283 static void keys_write_all(FILE *f);
285 static int menu_write_config(int is_game)
287 char cfgfile[MAXPATHLEN];
291 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
292 f = fopen(cfgfile, "w");
294 printf("menu_write_config: failed to open: %s\n", cfgfile);
298 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
299 fprintf(f, "%s = ", config_data[i].name);
300 switch (config_data[i].len) {
302 fprintf(f, "%s\n", (char *)config_data[i].val);
305 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
308 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
311 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
314 printf("menu_write_config: unhandled len %d for %s\n",
315 config_data[i].len, config_data[i].name);
321 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
329 static void parse_str_val(char *cval, const char *src)
332 strncpy(cval, src, MAXPATHLEN);
333 cval[MAXPATHLEN - 1] = 0;
334 tmp = strchr(cval, '\n');
336 tmp = strchr(cval, '\r');
341 static void keys_load_all(const char *cfg);
343 static int menu_load_config(int is_game)
345 char cfgfile[MAXPATHLEN];
351 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
352 f = fopen(cfgfile, "r");
354 printf("menu_load_config: failed to open: %s\n", cfgfile);
358 fseek(f, 0, SEEK_END);
361 printf("bad size %ld: %s\n", size, cfgfile);
365 cfg = malloc(size + 1);
369 fseek(f, 0, SEEK_SET);
370 if (fread(cfg, 1, size, f) != size) {
371 printf("failed to read: %s\n", cfgfile);
376 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
380 tmp = strstr(cfg, config_data[i].name);
383 tmp += strlen(config_data[i].name);
384 if (strncmp(tmp, " = ", 3) != 0)
388 if (config_data[i].len == 0) {
389 parse_str_val(config_data[i].val, tmp);
394 val = strtoul(tmp, &tmp2, 16);
395 if (tmp2 == NULL || tmp == tmp2)
396 continue; // parse failed
398 switch (config_data[i].len) {
400 *(u8 *)config_data[i].val = val;
403 *(u16 *)config_data[i].val = val;
406 *(u32 *)config_data[i].val = val;
409 printf("menu_load_config: unhandled len %d for %s\n",
410 config_data[i].len, config_data[i].name);
416 char *tmp = strstr(cfg, "lastcdimg = ");
419 parse_str_val(last_selected_fname, tmp);
426 for (i = bios_sel = 0; bioses[i] != NULL; i++)
427 if (strcmp(Config.Bios, bioses[i]) == 0)
428 { bios_sel = i; break; }
430 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
431 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
432 { gpu_plugsel = i; break; }
434 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
435 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
436 { spu_plugsel = i; break; }
447 // rrrr rggg gggb bbbb
448 static unsigned short fname2color(const char *fname)
450 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
451 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
452 const char *ext = strrchr(fname, '.');
457 for (i = 0; i < array_size(cdimg_exts); i++)
458 if (strcasecmp(ext, cdimg_exts[i]) == 0)
460 for (i = 0; i < array_size(other_exts); i++)
461 if (strcasecmp(ext, other_exts[i]) == 0)
466 static void draw_savestate_bg(int slot);
468 static const char *filter_exts[] = {
469 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
472 #define MENU_ALIGN_LEFT
473 #define menu_init menu_init_common
474 #include "common/menu.c"
477 // a bit of black magic here
478 static void draw_savestate_bg(int slot)
480 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
482 char fname[MAXPATHLEN];
489 ret = get_state_filename(fname, sizeof(fname), slot);
493 f = gzopen(fname, "rb");
497 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
498 fprintf(stderr, "gzseek failed\n");
503 gpu = malloc(sizeof(*gpu));
509 ret = gzread(f, gpu, sizeof(*gpu));
511 if (ret != sizeof(*gpu)) {
512 fprintf(stderr, "gzread failed\n");
516 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
518 if (gpu->ulStatus & 0x800000)
519 goto out; // disabled
521 x = gpu->ulControl[5] & 0x3ff;
522 y = (gpu->ulControl[5] >> 10) & 0x1ff;
523 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
524 w = psx_widths[(gpu->ulStatus >> 16) & 7];
525 tmp = gpu->ulControl[7];
526 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
527 if (gpu->ulStatus & 0x80000) // doubleheight
530 x = max(0, g_menuscreen_w - w) & ~3;
531 y = max(0, g_menuscreen_h / 2 - h / 2);
532 w = min(g_menuscreen_w, w);
533 h = min(g_menuscreen_h, h);
534 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
536 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
537 if (gpu->ulStatus & 0x200000)
538 bgr888_to_rgb565(d, s, w * 3);
540 bgr555_to_rgb565(d, s, w * 2);
546 // ---------- pandora specific -----------
548 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
549 static char **pnd_filter_list;
551 static int get_cpu_clock(void)
555 f = fopen("/proc/pandora/cpu_mhz_max", "r");
557 fscanf(f, "%d", &ret);
563 static void apply_cpu_clock(void)
567 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
568 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
569 pnd_script_base, cpu_clock);
574 static void apply_filter(int which)
580 if (pnd_filter_list == NULL || which == old)
583 for (i = 0; i < which; i++)
584 if (pnd_filter_list[i] == NULL)
587 if (pnd_filter_list[i] == NULL)
590 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
595 static void apply_lcdrate(int pal)
603 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
604 pnd_script_base, pal ? 50 : 60);
609 static menu_entry e_menu_gfx_options[];
611 static void pnd_menu_init(void)
619 cpu_clock_st = cpu_clock = get_cpu_clock();
621 dir = opendir("/etc/pandora/conf/dss_fir");
623 perror("filter opendir");
636 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
645 mfilters = calloc(count + 1, sizeof(mfilters[0]));
646 if (mfilters == NULL)
650 for (i = 0; (ent = readdir(dir)); ) {
653 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
656 len = strlen(ent->d_name);
658 // skip pre-HF5 extra files
659 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
661 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
664 // have to cut "_up_h" for pre-HF5
665 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
668 if (len > sizeof(buff) - 1)
671 strncpy(buff, ent->d_name, len);
673 mfilters[i] = strdup(buff);
674 if (mfilters[i] != NULL)
679 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
680 e_menu_gfx_options[i].data = (void *)mfilters;
681 pnd_filter_list = mfilters;
684 void menu_finish(void)
686 cpu_clock = cpu_clock_st;
690 // -------------- key config --------------
692 me_bind_action me_ctrl_actions[] =
694 { "UP ", 1 << DKEY_UP},
695 { "DOWN ", 1 << DKEY_DOWN },
696 { "LEFT ", 1 << DKEY_LEFT },
697 { "RIGHT ", 1 << DKEY_RIGHT },
698 { "TRIANGLE", 1 << DKEY_TRIANGLE },
699 { "CIRCLE ", 1 << DKEY_CIRCLE },
700 { "CROSS ", 1 << DKEY_CROSS },
701 { "SQUARE ", 1 << DKEY_SQUARE },
702 { "L1 ", 1 << DKEY_L1 },
703 { "R1 ", 1 << DKEY_R1 },
704 { "L2 ", 1 << DKEY_L2 },
705 { "R2 ", 1 << DKEY_R2 },
706 { "L3 ", 1 << DKEY_L3 },
707 { "R3 ", 1 << DKEY_R3 },
708 { "START ", 1 << DKEY_START },
709 { "SELECT ", 1 << DKEY_SELECT },
713 me_bind_action emuctrl_actions[] =
715 { "Save State ", 1 << SACTION_SAVE_STATE },
716 { "Load State ", 1 << SACTION_LOAD_STATE },
717 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
718 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
719 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
720 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
721 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
722 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
723 { "Gun A button ", 1 << SACTION_GUN_A },
724 { "Gun B button ", 1 << SACTION_GUN_B },
725 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
729 static char *mystrip(char *str)
734 for (i = 0; i < len; i++)
735 if (str[i] != ' ') break;
736 if (i > 0) memmove(str, str + i, len - i + 1);
739 for (i = len - 1; i >= 0; i--)
740 if (str[i] != ' ') break;
746 static void get_line(char *d, size_t size, const char *s)
751 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
762 static void keys_write_all(FILE *f)
766 for (d = 0; d < IN_MAX_DEVS; d++)
768 const int *binds = in_get_dev_binds(d);
769 const char *name = in_get_dev_name(d, 0, 0);
772 if (binds == NULL || name == NULL)
775 fprintf(f, "binddev = %s\n", name);
776 in_get_config(d, IN_CFG_BIND_COUNT, &count);
778 for (k = 0; k < count; k++)
783 act[0] = act[31] = 0;
784 name = in_get_key_name(d, k);
786 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
787 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
788 mask = me_ctrl_actions[i].mask;
790 strncpy(act, me_ctrl_actions[i].name, 31);
791 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
794 mask = me_ctrl_actions[i].mask << 16;
796 strncpy(act, me_ctrl_actions[i].name, 31);
797 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
802 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
803 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
804 mask = emuctrl_actions[i].mask;
806 strncpy(act, emuctrl_actions[i].name, 31);
807 fprintf(f, "bind %s = %s\n", name, mystrip(act));
815 static int parse_bind_val(const char *val, int *type)
819 *type = IN_BINDTYPE_NONE;
823 if (strncasecmp(val, "player", 6) == 0)
825 int player, shift = 0;
826 player = atoi(val + 6) - 1;
828 if ((unsigned int)player > 1)
833 *type = IN_BINDTYPE_PLAYER12;
834 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
835 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
836 return me_ctrl_actions[i].mask << shift;
839 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
840 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
841 *type = IN_BINDTYPE_EMU;
842 return emuctrl_actions[i].mask;
849 static void keys_load_all(const char *cfg)
851 char dev[256], key[128], *act;
857 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
860 get_line(dev, sizeof(dev), p);
861 dev_id = in_config_parse_dev(dev);
863 printf("input: can't handle dev: %s\n", dev);
867 in_unbind_all(dev_id, -1, -1);
868 while ((p = strstr(p, "bind"))) {
869 if (strncmp(p, "binddev = ", 10) == 0)
874 printf("input: parse error: %16s..\n", p);
878 get_line(key, sizeof(key), p);
879 act = strchr(key, '=');
881 printf("parse failed: %16s..\n", p);
889 bind = parse_bind_val(act, &bindtype);
890 if (bind != -1 && bind != 0) {
891 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
892 in_config_bind_key(dev_id, key, bind, bindtype);
895 lprintf("config: unhandled action \"%s\"\n", act);
901 static int key_config_loop_wrap(int id, int keys)
904 case MA_CTRL_PLAYER1:
905 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
907 case MA_CTRL_PLAYER2:
908 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
911 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
919 static const char *mgn_dev_name(int id, int *offs)
921 const char *name = NULL;
924 if (id == MA_CTRL_DEV_FIRST)
927 for (; it < IN_MAX_DEVS; it++) {
928 name = in_get_dev_name(it, 1, 1);
937 static const char *mgn_saveloadcfg(int id, int *offs)
942 static int mh_savecfg(int id, int keys)
944 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
945 me_update_msg("config saved");
947 me_update_msg("failed to write config");
952 static int mh_input_rescan(int id, int keys)
954 //menu_sync_config();
955 pandora_rescan_inputs();
956 me_update_msg("rescan complete.");
961 static const char *men_in_type_sel[] = {
962 "Standard (SCPH-1080)",
963 "Analog (SCPH-1150)",
967 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
968 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
970 static menu_entry e_menu_keyconfig[] =
972 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
973 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
974 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
976 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
977 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
978 mee_onoff_h ("Nubs as buttons", 0, in_evdev_allow_abs_only, 1, h_nub_btns),
979 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
980 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
981 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
982 mee_handler ("Rescan devices", mh_input_rescan),
984 mee_label ("Input devices:"),
985 mee_label_mk (MA_CTRL_DEV_FIRST, 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),
991 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
995 static int menu_loop_keyconfig(int id, int keys)
999 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1000 me_loop(e_menu_keyconfig, &sel);
1004 // ------------ gfx options menu ------------
1006 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
1007 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1008 "using d-pad or move it using R+d-pad";
1009 static const char *men_dummy[] = { NULL };
1011 static int menu_loop_cscaler(int id, int keys)
1015 scaling = SCALE_CUSTOM;
1017 omap_enable_layer(1);
1022 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1023 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1024 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1027 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1028 if (inp & PBTN_UP) g_layer_y--;
1029 if (inp & PBTN_DOWN) g_layer_y++;
1030 if (inp & PBTN_LEFT) g_layer_x--;
1031 if (inp & PBTN_RIGHT) g_layer_x++;
1032 if (!(inp & PBTN_R)) {
1033 if (inp & PBTN_UP) g_layer_h += 2;
1034 if (inp & PBTN_DOWN) g_layer_h -= 2;
1035 if (inp & PBTN_LEFT) g_layer_w += 2;
1036 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1038 if (inp & (PBTN_MOK|PBTN_MBACK))
1041 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1042 if (g_layer_x < 0) g_layer_x = 0;
1043 if (g_layer_x > 640) g_layer_x = 640;
1044 if (g_layer_y < 0) g_layer_y = 0;
1045 if (g_layer_y > 420) g_layer_y = 420;
1046 if (g_layer_w < 160) g_layer_w = 160;
1047 if (g_layer_h < 60) g_layer_h = 60;
1048 if (g_layer_x + g_layer_w > 800)
1049 g_layer_w = 800 - g_layer_x;
1050 if (g_layer_y + g_layer_h > 480)
1051 g_layer_h = 480 - g_layer_y;
1052 omap_enable_layer(1);
1056 omap_enable_layer(0);
1061 static menu_entry e_menu_gfx_options[] =
1063 mee_enum ("Scaler", 0, scaling, men_scaler),
1064 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1065 // mee_onoff ("Vsync", 0, vsync, 1),
1066 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1070 static int menu_loop_gfx_options(int id, int keys)
1074 me_loop(e_menu_gfx_options, &sel);
1079 // ------------ bios/plugins ------------
1081 static menu_entry e_menu_plugin_gpu_unai[] =
1083 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1084 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1085 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1089 static int menu_loop_plugin_gpu_unai(int id, int keys)
1092 me_loop(e_menu_plugin_gpu_unai, &sel);
1096 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1097 static const char h_gpu_0[] = "Needed for Chrono Cross";
1098 static const char h_gpu_1[] = "Capcom fighting games";
1099 static const char h_gpu_2[] = "Black screens in Lunar";
1100 static const char h_gpu_3[] = "Compatibility mode";
1101 static const char h_gpu_6[] = "Pandemonium 2";
1102 static const char h_gpu_7[] = "Skip every second frame";
1103 static const char h_gpu_8[] = "Needed by Dark Forces";
1104 static const char h_gpu_9[] = "better g-colors, worse textures";
1105 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1107 static menu_entry e_menu_plugin_gpu_peops[] =
1109 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1110 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1111 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1112 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1113 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1114 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1115 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1116 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1117 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1118 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1122 static int menu_loop_plugin_gpu_peops(int id, int keys)
1125 me_loop(e_menu_plugin_gpu_peops, &sel);
1129 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1130 static const char h_spu_volboost[] = "Large values cause distortion";
1131 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1132 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1134 static menu_entry e_menu_plugin_spu[] =
1136 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1137 mee_onoff ("Reverb", 0, iUseReverb, 2),
1138 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1139 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1140 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1141 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1145 static int menu_loop_plugin_spu(int id, int keys)
1148 me_loop(e_menu_plugin_spu, &sel);
1152 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1153 "and can't be changed there. Must save config and reload\n"
1154 "the game for change to take effect";
1155 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1156 "for plugin change to take effect";
1157 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1158 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1159 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1161 static menu_entry e_menu_plugin_options[] =
1163 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1164 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1165 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1166 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1167 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1168 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1172 static menu_entry e_menu_main2[];
1174 static int menu_loop_plugin_options(int id, int keys)
1177 me_loop(e_menu_plugin_options, &sel);
1179 // sync BIOS/plugins
1180 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1181 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1182 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1183 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1188 // ------------ adv options menu ------------
1190 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1191 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1192 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1193 "(green: normal, red: fmod, blue: noise)";
1194 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1195 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1196 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1197 "(proper .cue/.bin dump is needed otherwise)";
1198 static const char h_cfg_sio[] = "You should not need this, breaks games";
1199 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1200 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1201 "(timing hack, breaks other games)";
1202 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1203 "(timing hack, breaks other games)";
1204 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1205 "(CD timing hack, breaks FMVs)";
1206 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1207 "Might be useful to overcome some dynarec bugs";
1209 static menu_entry e_menu_adv_options[] =
1211 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1212 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1213 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1214 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1215 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1216 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1217 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1218 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1219 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1220 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1221 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1225 static int menu_loop_adv_options(int id, int keys)
1228 me_loop(e_menu_adv_options, &sel);
1232 // ------------ options menu ------------
1234 static int mh_restore_defaults(int id, int keys)
1236 menu_set_defconfig();
1237 me_update_msg("defaults restored");
1241 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1243 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1244 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1245 "loading state or both";
1247 static const char h_restore_def[] = "Switches back to default / recommended\n"
1249 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1251 static menu_entry e_menu_options[] =
1253 // mee_range ("Save slot", 0, state_slot, 0, 9),
1254 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1255 mee_onoff_h ("Frameskip", 0, pl_rearmed_cbs.frameskip, 1, h_frameskip),
1256 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1257 mee_enum ("Region", 0, region, men_region),
1258 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1259 mee_handler ("[Display]", menu_loop_gfx_options),
1260 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1261 mee_handler ("[Advanced]", menu_loop_adv_options),
1262 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1263 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1264 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1268 static int menu_loop_options(int id, int keys)
1273 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1274 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1275 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1277 me_loop(e_menu_options, &sel);
1282 // ------------ debug menu ------------
1284 static void draw_frame_debug(GPUFreeze_t *gpuf)
1286 int w = min(g_menuscreen_w, 1024);
1287 int h = min(g_menuscreen_h, 512);
1288 u16 *d = g_menuscreen_ptr;
1289 u16 *s = (u16 *)gpuf->psxVRam;
1293 gpuf->ulFreezeVersion = 1;
1294 if (GPU_freeze != NULL)
1295 GPU_freeze(1, gpuf);
1297 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1298 bgr555_to_rgb565(d, s, w * 2);
1300 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1301 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1302 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1303 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1304 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1307 static void debug_menu_loop(void)
1312 gpuf = malloc(sizeof(*gpuf));
1319 draw_frame_debug(gpuf);
1322 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1323 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1324 if (inp & PBTN_MBACK)
1331 // --------- memcard manager ---------
1333 static void draw_mc_icon(int dx, int dy, const u16 *s)
1338 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1340 for (y = 0; y < 16; y++, s += 16) {
1341 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1342 for (x = 0; x < 16; x++) {
1344 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1345 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1351 static void draw_mc_bg(void)
1353 McdBlock *blocks1, *blocks2;
1357 blocks1 = malloc(15 * sizeof(blocks1[0]));
1358 blocks2 = malloc(15 * sizeof(blocks1[0]));
1359 if (blocks1 == NULL || blocks2 == NULL)
1362 for (i = 0; i < 15; i++) {
1363 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1364 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1369 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1371 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1375 maxicons = g_menuscreen_h / 32;
1378 row2 = g_menuscreen_w / 2;
1379 for (i = 0; i < maxicons; i++) {
1380 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1381 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1383 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1384 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1387 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1395 static void handle_memcard_sel(void)
1398 if (memcard1_sel != 0)
1399 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1401 if (memcard2_sel != 0)
1402 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1403 LoadMcds(Config.Mcd1, Config.Mcd2);
1407 static menu_entry e_memcard_options[] =
1409 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1410 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1414 static int menu_loop_memcards(int id, int keys)
1420 memcard1_sel = memcard2_sel = 0;
1421 p = strrchr(Config.Mcd1, '/');
1423 for (i = 0; memcards[i] != NULL; i++)
1424 if (strcmp(p + 1, memcards[i]) == 0)
1425 { memcard1_sel = i; break; }
1426 p = strrchr(Config.Mcd2, '/');
1428 for (i = 0; memcards[i] != NULL; i++)
1429 if (strcmp(p + 1, memcards[i]) == 0)
1430 { memcard2_sel = i; break; }
1432 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1434 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1439 // --------- main menu help ----------
1441 static void menu_bios_warn(void)
1444 static const char msg[] =
1445 "You don't seem to have copied any BIOS files to\n"
1446 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1447 "While many games work fine with fake (HLE) BIOS,\n"
1448 "others (like MGS and FF8) require BIOS to work.\n"
1449 "After copying the file, you'll also need to\n"
1450 "select it in the emu's options->[BIOS/Plugins]\n\n"
1451 "The file is usually named SCPH1001.BIN, but\n"
1452 "other not compressed files can be used too.\n\n"
1453 "Press (B) or (X) to continue";
1457 draw_menu_message(msg, NULL);
1459 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1460 if (inp & (PBTN_MBACK|PBTN_MOK))
1465 // ------------ main menu ------------
1469 static void draw_frame_main(void)
1471 if (CdromId[0] != 0) {
1473 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1474 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1475 Config.HLE ? "HLE" : "BIOS");
1476 smalltext_out16(4, 1, buff, 0x105f);
1480 static void draw_frame_credits(void)
1482 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1485 static const char credits_text[] =
1487 "(C) 1999-2003 PCSX Team\n"
1488 "(C) 2005-2009 PCSX-df Team\n"
1489 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1490 "GPU and SPU code by Pete Bernert\n"
1491 " and the P.E.Op.S. team\n"
1492 "ARM recompiler (C) 2009-2011 Ari64\n"
1493 "PCSX4ALL plugins by PCSX4ALL team\n"
1494 " Chui, Franxis, Unai\n\n"
1495 "integration, optimization and\n"
1496 " frontend (C) 2010-2011 notaz\n";
1498 static int reset_game(void)
1501 if (bios_sel == 0 && !Config.HLE)
1507 if (CheckCdrom() != -1) {
1513 static int reload_plugins(const char *cdimg)
1519 set_cd_image(cdimg);
1521 pcnt_hook_plugins();
1523 if (OpenPlugins() == -1) {
1524 me_update_msg("failed to open plugins");
1527 plugin_call_rearmed_cbs();
1530 CdromLabel[0] = '\0';
1535 static int run_bios(void)
1541 if (reload_plugins(NULL) != 0)
1549 static int run_exe(void)
1553 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1558 if (reload_plugins(NULL) != 0)
1562 if (Load(fname) != 0) {
1563 me_update_msg("exe load failed, bad file?");
1572 static int run_cd_image(const char *fname)
1575 reload_plugins(fname);
1577 if (CheckCdrom() == -1) {
1578 // Only check the CD if we are starting the console with a CD
1580 me_update_msg("unsupported/invalid CD image");
1586 // Read main executable directly from CDRom and start it
1587 if (LoadCdrom() == -1) {
1589 me_update_msg("failed to load CD image");
1597 static int romsel_run(void)
1599 int prev_gpu, prev_spu;
1602 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1606 printf("selected file: %s\n", fname);
1608 new_dynarec_clear_full();
1610 if (run_cd_image(fname) != 0)
1613 prev_gpu = gpu_plugsel;
1614 prev_spu = spu_plugsel;
1615 if (menu_load_config(1) != 0)
1616 menu_load_config(0);
1618 // check for plugin changes, have to repeat
1619 // loading if game config changed plugins to reload them
1620 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1621 printf("plugin change detected, reloading plugins..\n");
1622 if (run_cd_image(fname) != 0)
1626 strcpy(last_selected_fname, rom_fname_reload);
1630 static int swap_cd_image(void)
1634 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1638 printf("selected file: %s\n", fname);
1641 CdromLabel[0] = '\0';
1643 set_cd_image(fname);
1644 if (ReloadCdromPlugin() < 0) {
1645 me_update_msg("failed to load cdr plugin");
1648 if (CDR_open() < 0) {
1649 me_update_msg("failed to open cdr plugin");
1653 SetCdOpenCaseTime(time(NULL) + 2);
1656 strcpy(last_selected_fname, rom_fname_reload);
1660 static int main_menu_handler(int id, int keys)
1664 case MA_MAIN_RESUME_GAME:
1668 case MA_MAIN_SAVE_STATE:
1670 return menu_loop_savestate(0);
1672 case MA_MAIN_LOAD_STATE:
1674 return menu_loop_savestate(1);
1676 case MA_MAIN_RESET_GAME:
1677 if (ready_to_go && reset_game() == 0)
1680 case MA_MAIN_LOAD_ROM:
1681 if (romsel_run() == 0)
1684 case MA_MAIN_SWAP_CD:
1685 if (swap_cd_image() == 0)
1688 case MA_MAIN_RUN_BIOS:
1689 if (run_bios() == 0)
1692 case MA_MAIN_RUN_EXE:
1696 case MA_MAIN_CREDITS:
1697 draw_menu_message(credits_text, draw_frame_credits);
1698 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1704 lprintf("%s: something unknown selected\n", __FUNCTION__);
1711 static menu_entry e_menu_main2[] =
1713 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1714 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1715 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1716 mee_handler ("Memcard manager", menu_loop_memcards),
1720 static int main_menu2_handler(int id, int keys)
1724 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1725 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1727 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1730 static const char h_extra[] = "Change CD, manage memcards..\n";
1732 static menu_entry e_menu_main[] =
1736 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1737 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1738 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1739 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1740 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1741 mee_handler ("Options", menu_loop_options),
1742 mee_handler ("Controls", menu_loop_keyconfig),
1743 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1744 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1745 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1749 // ----------------------------
1751 static void menu_leave_emu(void);
1753 void menu_loop(void)
1759 if (bioses[1] == NULL && !warned_about_bios) {
1761 warned_about_bios = 1;
1764 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1765 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1766 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1767 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1769 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1772 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1773 } while (!ready_to_go);
1775 /* wait until menu, ok, back is released */
1776 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1779 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1784 static int qsort_strcmp(const void *p1, const void *p2)
1786 char * const *s1 = (char * const *)p1;
1787 char * const *s2 = (char * const *)p2;
1788 return strcasecmp(*s1, *s2);
1791 static void scan_bios_plugins(void)
1793 char fname[MAXPATHLEN];
1795 int bios_i, gpu_i, spu_i, mc_i;
1800 gpu_plugins[0] = "builtin_gpu";
1801 spu_plugins[0] = "builtin_spu";
1802 memcards[0] = "(none)";
1803 bios_i = gpu_i = spu_i = mc_i = 1;
1805 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1806 dir = opendir(fname);
1808 perror("scan_bios_plugins bios opendir");
1823 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1826 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1827 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1828 printf("bad BIOS file: %s\n", ent->d_name);
1832 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1833 bioses[bios_i++] = strdup(ent->d_name);
1837 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1843 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1844 dir = opendir(fname);
1846 perror("scan_bios_plugins plugins opendir");
1860 p = strstr(ent->d_name, ".so");
1864 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1865 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1867 fprintf(stderr, "%s\n", dlerror());
1871 // now what do we have here?
1872 tmp = dlsym(h, "GPUinit");
1875 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1876 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1880 tmp = dlsym(h, "SPUinit");
1883 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1884 spu_plugins[spu_i++] = strdup(ent->d_name);
1888 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1895 dir = opendir("." MEMCARD_DIR);
1897 perror("scan_bios_plugins memcards opendir");
1912 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1915 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1916 if (stat(fname, &st) != 0) {
1917 printf("bad memcard file: %s\n", ent->d_name);
1921 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1922 memcards[mc_i++] = strdup(ent->d_name);
1926 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1930 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1935 void menu_init(void)
1937 char buff[MAXPATHLEN];
1939 strcpy(last_selected_fname, "/media");
1941 scan_bios_plugins();
1945 menu_set_defconfig();
1946 menu_load_config(0);
1951 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1952 if (g_menubg_src_ptr == NULL)
1954 emu_make_path(buff, "skin/background.png", sizeof(buff));
1955 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1958 void menu_notify_mode_change(int w, int h, int bpp)
1964 if (scaling == SCALE_1_1) {
1965 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1966 g_layer_w = w; g_layer_h = h;
1970 static void menu_leave_emu(void)
1972 if (GPU_close != NULL) {
1973 int ret = GPU_close();
1975 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1978 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1979 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1980 int x = max(0, g_menuscreen_w - last_psx_w);
1981 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1982 int w = min(g_menuscreen_w, last_psx_w);
1983 int h = min(g_menuscreen_h, last_psx_h);
1984 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1985 u16 *s = pl_vout_buf;
1987 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1988 menu_darken_bg(d, s, w, 0);
1992 cpu_clock = get_cpu_clock();
1994 plat_video_menu_enter(ready_to_go);
1997 void menu_prepare_emu(void)
1999 R3000Acpu *prev_cpu = psxCpu;
2001 plat_video_menu_leave();
2005 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2008 g_layer_x = 80; g_layer_y = 0;
2009 g_layer_w = 640; g_layer_h = 480;
2011 case SCALE_FULLSCREEN:
2012 g_layer_x = 0; g_layer_y = 0;
2013 g_layer_w = 800; g_layer_h = 480;
2019 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2020 if (psxCpu != prev_cpu)
2021 // note that this does not really reset, just clears drc caches
2024 // core doesn't care about Config.Cdda changes,
2025 // so handle them manually here
2030 apply_lcdrate(Config.PsxType);
2031 apply_filter(filter);
2034 // push config to GPU plugin
2035 plugin_call_rearmed_cbs();
2037 if (GPU_open != NULL) {
2038 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2040 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2046 void me_update_msg(const char *msg)
2048 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2049 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2051 menu_error_time = plat_get_ticks_ms();
2052 lprintf("msg: %s\n", menu_error_msg);