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]))
73 static int last_psx_w, last_psx_h, last_psx_bpp;
74 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
75 static char rom_fname_reload[MAXPATHLEN];
76 static char last_selected_fname[MAXPATHLEN];
77 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
78 static int memcard1_sel, memcard2_sel;
82 extern int iUseReverb;
83 extern int iUseInterpolation;
85 extern int iSPUIRQWait;
89 static const char *bioses[24];
90 static const char *gpu_plugins[16];
91 static const char *spu_plugins[16];
92 static const char *memcards[32];
93 static int bios_sel, gpu_plugsel, spu_plugsel;
96 static int min(int x, int y) { return x < y ? x : y; }
97 static int max(int x, int y) { return x > y ? x : y; }
99 void emu_make_path(char *buff, const char *end, int size)
103 end_len = strlen(end);
104 pos = plat_get_root_dir(buff, size);
105 strncpy(buff + pos, end, size - pos);
107 if (pos + end_len > size - 1)
108 printf("Warning: path truncated: %s\n", buff);
111 static int emu_check_save_file(int slot)
113 int ret = emu_check_state(slot);
114 return ret == 0 ? 1 : 0;
117 static int emu_save_load_game(int load, int unused)
122 ret = emu_load_state(state_slot);
124 // reflect hle/bios mode from savestate
127 else if (bios_sel == 0 && bioses[1] != NULL)
128 // XXX: maybe find the right bios instead
132 ret = emu_save_state(state_slot);
137 // propagate menu settings to the emu vars
138 static void menu_sync_config(void)
140 static int allow_abs_only_old;
145 Config.PsxType = region - 1;
147 switch (in_type_sel1) {
148 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
149 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
150 default: in_type1 = PSE_PAD_TYPE_STANDARD;
152 switch (in_type_sel2) {
153 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
154 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
155 default: in_type2 = PSE_PAD_TYPE_STANDARD;
157 if (in_evdev_allow_abs_only != allow_abs_only_old) {
158 pandora_rescan_inputs();
159 allow_abs_only_old = in_evdev_allow_abs_only;
162 iVolume = 768 + 128 * volume_boost;
163 pl_rearmed_cbs.frameskip = frameskip - 1;
164 pl_timing_prepare(Config.PsxType);
167 static void menu_set_defconfig(void)
175 in_type_sel1 = in_type_sel2 = 0;
176 in_evdev_allow_abs_only = 0;
177 Config.Xa = Config.Cdda = Config.Sio =
178 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
179 Config.CdrReschedule = 0;
181 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
182 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
183 pl_rearmed_cbs.gpu_unai.abe_hack =
184 pl_rearmed_cbs.gpu_unai.no_light =
185 pl_rearmed_cbs.gpu_unai.no_blend = 0;
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 #define CE_INTVAL_PV(val, ver) \
216 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
218 static const struct {
226 // CE_CONFIG_STR(Cdr),
231 CE_CONFIG_VAL(Debug),
232 CE_CONFIG_VAL(PsxOut),
233 CE_CONFIG_VAL(SpuIrq),
234 CE_CONFIG_VAL(RCntFix),
235 CE_CONFIG_VAL(VSyncWA),
237 CE_CONFIG_VAL(CdrReschedule),
239 CE_INTVAL_V(scaling, 2),
240 CE_INTVAL(g_layer_x),
241 CE_INTVAL(g_layer_y),
242 CE_INTVAL(g_layer_w),
243 CE_INTVAL(g_layer_h),
245 CE_INTVAL(state_slot),
246 CE_INTVAL(cpu_clock),
248 CE_INTVAL(in_type_sel1),
249 CE_INTVAL(in_type_sel2),
250 CE_INTVAL_V(frameskip, 2),
251 CE_INTVAL_P(gpu_peops.iUseDither),
252 CE_INTVAL_P(gpu_peops.dwActFixes),
253 CE_INTVAL_P(gpu_unai.abe_hack),
254 CE_INTVAL_P(gpu_unai.no_light),
255 CE_INTVAL_P(gpu_unai.no_blend),
256 CE_INTVAL(iUseReverb),
258 CE_INTVAL_V(iUseInterpolation, 2),
259 CE_INTVAL_V(iSPUIRQWait, 2),
260 CE_INTVAL(iUseTimer),
261 CE_INTVAL(warned_about_bios),
262 CE_INTVAL(in_evdev_allow_abs_only),
263 CE_INTVAL(volume_boost),
266 static char *get_cd_label(void)
268 static char trimlabel[33];
271 strncpy(trimlabel, CdromLabel, 32);
273 for (j = 31; j >= 0; j--)
274 if (trimlabel[j] == ' ')
280 static void make_cfg_fname(char *buf, size_t size, int is_game)
283 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
285 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
288 static void keys_write_all(FILE *f);
290 static int menu_write_config(int is_game)
292 char cfgfile[MAXPATHLEN];
296 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
297 f = fopen(cfgfile, "w");
299 printf("menu_write_config: failed to open: %s\n", cfgfile);
303 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
304 fprintf(f, "%s = ", config_data[i].name);
305 switch (config_data[i].len) {
307 fprintf(f, "%s\n", (char *)config_data[i].val);
310 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
313 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
316 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
319 printf("menu_write_config: unhandled len %d for %s\n",
320 config_data[i].len, config_data[i].name);
326 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
334 static void parse_str_val(char *cval, const char *src)
337 strncpy(cval, src, MAXPATHLEN);
338 cval[MAXPATHLEN - 1] = 0;
339 tmp = strchr(cval, '\n');
341 tmp = strchr(cval, '\r');
346 static void keys_load_all(const char *cfg);
348 static int menu_load_config(int is_game)
350 char cfgfile[MAXPATHLEN];
356 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
357 f = fopen(cfgfile, "r");
359 printf("menu_load_config: failed to open: %s\n", cfgfile);
363 fseek(f, 0, SEEK_END);
366 printf("bad size %ld: %s\n", size, cfgfile);
370 cfg = malloc(size + 1);
374 fseek(f, 0, SEEK_SET);
375 if (fread(cfg, 1, size, f) != size) {
376 printf("failed to read: %s\n", cfgfile);
381 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
385 tmp = strstr(cfg, config_data[i].name);
388 tmp += strlen(config_data[i].name);
389 if (strncmp(tmp, " = ", 3) != 0)
393 if (config_data[i].len == 0) {
394 parse_str_val(config_data[i].val, tmp);
399 val = strtoul(tmp, &tmp2, 16);
400 if (tmp2 == NULL || tmp == tmp2)
401 continue; // parse failed
403 switch (config_data[i].len) {
405 *(u8 *)config_data[i].val = val;
408 *(u16 *)config_data[i].val = val;
411 *(u32 *)config_data[i].val = val;
414 printf("menu_load_config: unhandled len %d for %s\n",
415 config_data[i].len, config_data[i].name);
421 char *tmp = strstr(cfg, "lastcdimg = ");
424 parse_str_val(last_selected_fname, tmp);
431 for (i = bios_sel = 0; bioses[i] != NULL; i++)
432 if (strcmp(Config.Bios, bioses[i]) == 0)
433 { bios_sel = i; break; }
435 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
436 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
437 { gpu_plugsel = i; break; }
439 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
440 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
441 { spu_plugsel = i; break; }
452 // rrrr rggg gggb bbbb
453 static unsigned short fname2color(const char *fname)
455 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
456 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
457 const char *ext = strrchr(fname, '.');
462 for (i = 0; i < array_size(cdimg_exts); i++)
463 if (strcasecmp(ext, cdimg_exts[i]) == 0)
465 for (i = 0; i < array_size(other_exts); i++)
466 if (strcasecmp(ext, other_exts[i]) == 0)
471 static void draw_savestate_bg(int slot);
473 static const char *filter_exts[] = {
474 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
477 #define MENU_ALIGN_LEFT
478 #define menu_init menu_init_common
479 #include "common/menu.c"
482 // a bit of black magic here
483 static void draw_savestate_bg(int slot)
485 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
487 char fname[MAXPATHLEN];
494 ret = get_state_filename(fname, sizeof(fname), slot);
498 f = gzopen(fname, "rb");
502 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
503 fprintf(stderr, "gzseek failed\n");
508 gpu = malloc(sizeof(*gpu));
514 ret = gzread(f, gpu, sizeof(*gpu));
516 if (ret != sizeof(*gpu)) {
517 fprintf(stderr, "gzread failed\n");
521 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
523 if (gpu->ulStatus & 0x800000)
524 goto out; // disabled
526 x = gpu->ulControl[5] & 0x3ff;
527 y = (gpu->ulControl[5] >> 10) & 0x1ff;
528 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
529 w = psx_widths[(gpu->ulStatus >> 16) & 7];
530 tmp = gpu->ulControl[7];
531 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
532 if (gpu->ulStatus & 0x80000) // doubleheight
535 x = max(0, g_menuscreen_w - w) & ~3;
536 y = max(0, g_menuscreen_h / 2 - h / 2);
537 w = min(g_menuscreen_w, w);
538 h = min(g_menuscreen_h, h);
539 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
541 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
542 if (gpu->ulStatus & 0x200000)
543 bgr888_to_rgb565(d, s, w * 3);
545 bgr555_to_rgb565(d, s, w * 2);
551 // ---------- pandora specific -----------
553 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
554 static char **pnd_filter_list;
556 static int get_cpu_clock(void)
560 f = fopen("/proc/pandora/cpu_mhz_max", "r");
562 fscanf(f, "%d", &ret);
568 static void apply_cpu_clock(void)
572 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
573 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
574 pnd_script_base, cpu_clock);
579 static void apply_filter(int which)
585 if (pnd_filter_list == NULL || which == old)
588 for (i = 0; i < which; i++)
589 if (pnd_filter_list[i] == NULL)
592 if (pnd_filter_list[i] == NULL)
595 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
600 static void apply_lcdrate(int pal)
608 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
609 pnd_script_base, pal ? 50 : 60);
614 static int get_bat_capacity(void)
618 f = fopen("/sys/class/power_supply/bq27500-0/capacity", "r");
620 fscanf(f, "%d", &ret);
626 static menu_entry e_menu_gfx_options[];
628 static void pnd_menu_init(void)
636 cpu_clock_st = cpu_clock = get_cpu_clock();
638 dir = opendir("/etc/pandora/conf/dss_fir");
640 perror("filter opendir");
653 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
662 mfilters = calloc(count + 1, sizeof(mfilters[0]));
663 if (mfilters == NULL)
667 for (i = 0; (ent = readdir(dir)); ) {
670 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
673 len = strlen(ent->d_name);
675 // skip pre-HF5 extra files
676 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
678 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
681 // have to cut "_up_h" for pre-HF5
682 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
685 if (len > sizeof(buff) - 1)
688 strncpy(buff, ent->d_name, len);
690 mfilters[i] = strdup(buff);
691 if (mfilters[i] != NULL)
696 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
697 e_menu_gfx_options[i].data = (void *)mfilters;
698 pnd_filter_list = mfilters;
701 void menu_finish(void)
703 cpu_clock = cpu_clock_st;
707 // -------------- key config --------------
709 me_bind_action me_ctrl_actions[] =
711 { "UP ", 1 << DKEY_UP},
712 { "DOWN ", 1 << DKEY_DOWN },
713 { "LEFT ", 1 << DKEY_LEFT },
714 { "RIGHT ", 1 << DKEY_RIGHT },
715 { "TRIANGLE", 1 << DKEY_TRIANGLE },
716 { "CIRCLE ", 1 << DKEY_CIRCLE },
717 { "CROSS ", 1 << DKEY_CROSS },
718 { "SQUARE ", 1 << DKEY_SQUARE },
719 { "L1 ", 1 << DKEY_L1 },
720 { "R1 ", 1 << DKEY_R1 },
721 { "L2 ", 1 << DKEY_L2 },
722 { "R2 ", 1 << DKEY_R2 },
723 { "L3 ", 1 << DKEY_L3 },
724 { "R3 ", 1 << DKEY_R3 },
725 { "START ", 1 << DKEY_START },
726 { "SELECT ", 1 << DKEY_SELECT },
730 me_bind_action emuctrl_actions[] =
732 { "Save State ", 1 << SACTION_SAVE_STATE },
733 { "Load State ", 1 << SACTION_LOAD_STATE },
734 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
735 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
736 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
737 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
738 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
739 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
740 { "Gun A button ", 1 << SACTION_GUN_A },
741 { "Gun B button ", 1 << SACTION_GUN_B },
742 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
746 static char *mystrip(char *str)
751 for (i = 0; i < len; i++)
752 if (str[i] != ' ') break;
753 if (i > 0) memmove(str, str + i, len - i + 1);
756 for (i = len - 1; i >= 0; i--)
757 if (str[i] != ' ') break;
763 static void get_line(char *d, size_t size, const char *s)
768 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
779 static void keys_write_all(FILE *f)
783 for (d = 0; d < IN_MAX_DEVS; d++)
785 const int *binds = in_get_dev_binds(d);
786 const char *name = in_get_dev_name(d, 0, 0);
789 if (binds == NULL || name == NULL)
792 fprintf(f, "binddev = %s\n", name);
793 in_get_config(d, IN_CFG_BIND_COUNT, &count);
795 for (k = 0; k < count; k++)
800 act[0] = act[31] = 0;
801 name = in_get_key_name(d, k);
803 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
804 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
805 mask = me_ctrl_actions[i].mask;
807 strncpy(act, me_ctrl_actions[i].name, 31);
808 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
811 mask = me_ctrl_actions[i].mask << 16;
813 strncpy(act, me_ctrl_actions[i].name, 31);
814 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
819 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
820 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
821 mask = emuctrl_actions[i].mask;
823 strncpy(act, emuctrl_actions[i].name, 31);
824 fprintf(f, "bind %s = %s\n", name, mystrip(act));
832 static int parse_bind_val(const char *val, int *type)
836 *type = IN_BINDTYPE_NONE;
840 if (strncasecmp(val, "player", 6) == 0)
842 int player, shift = 0;
843 player = atoi(val + 6) - 1;
845 if ((unsigned int)player > 1)
850 *type = IN_BINDTYPE_PLAYER12;
851 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
852 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
853 return me_ctrl_actions[i].mask << shift;
856 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
857 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
858 *type = IN_BINDTYPE_EMU;
859 return emuctrl_actions[i].mask;
866 static void keys_load_all(const char *cfg)
868 char dev[256], key[128], *act;
874 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
877 get_line(dev, sizeof(dev), p);
878 dev_id = in_config_parse_dev(dev);
880 printf("input: can't handle dev: %s\n", dev);
884 in_unbind_all(dev_id, -1, -1);
885 while ((p = strstr(p, "bind"))) {
886 if (strncmp(p, "binddev = ", 10) == 0)
891 printf("input: parse error: %16s..\n", p);
895 get_line(key, sizeof(key), p);
896 act = strchr(key, '=');
898 printf("parse failed: %16s..\n", p);
906 bind = parse_bind_val(act, &bindtype);
907 if (bind != -1 && bind != 0) {
908 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
909 in_config_bind_key(dev_id, key, bind, bindtype);
912 lprintf("config: unhandled action \"%s\"\n", act);
918 static int key_config_loop_wrap(int id, int keys)
921 case MA_CTRL_PLAYER1:
922 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
924 case MA_CTRL_PLAYER2:
925 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
928 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
936 static const char *mgn_dev_name(int id, int *offs)
938 const char *name = NULL;
941 if (id == MA_CTRL_DEV_FIRST)
944 for (; it < IN_MAX_DEVS; it++) {
945 name = in_get_dev_name(it, 1, 1);
954 static const char *mgn_saveloadcfg(int id, int *offs)
959 static int mh_savecfg(int id, int keys)
961 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
962 me_update_msg("config saved");
964 me_update_msg("failed to write config");
969 static int mh_input_rescan(int id, int keys)
971 //menu_sync_config();
972 pandora_rescan_inputs();
973 me_update_msg("rescan complete.");
978 static const char *men_in_type_sel[] = {
979 "Standard (SCPH-1080)",
980 "Analog (SCPH-1150)",
984 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
985 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
987 static menu_entry e_menu_keyconfig[] =
989 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
990 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
991 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
993 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
994 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
995 mee_onoff_h ("Nubs as buttons", 0, in_evdev_allow_abs_only, 1, h_nub_btns),
996 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
997 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
998 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
999 mee_handler ("Rescan devices", mh_input_rescan),
1001 mee_label ("Input devices:"),
1002 mee_label_mk (MA_CTRL_DEV_FIRST, 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),
1006 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1007 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1008 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1012 static int menu_loop_keyconfig(int id, int keys)
1016 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1017 me_loop(e_menu_keyconfig, &sel);
1021 // ------------ gfx options menu ------------
1023 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1024 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1025 "using d-pad or move it using R+d-pad";
1026 static const char *men_dummy[] = { NULL };
1028 static int menu_loop_cscaler(int id, int keys)
1032 scaling = SCALE_CUSTOM;
1034 omap_enable_layer(1);
1039 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1040 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1041 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1044 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1045 if (inp & PBTN_UP) g_layer_y--;
1046 if (inp & PBTN_DOWN) g_layer_y++;
1047 if (inp & PBTN_LEFT) g_layer_x--;
1048 if (inp & PBTN_RIGHT) g_layer_x++;
1049 if (!(inp & PBTN_R)) {
1050 if (inp & PBTN_UP) g_layer_h += 2;
1051 if (inp & PBTN_DOWN) g_layer_h -= 2;
1052 if (inp & PBTN_LEFT) g_layer_w += 2;
1053 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1055 if (inp & (PBTN_MOK|PBTN_MBACK))
1058 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1059 if (g_layer_x < 0) g_layer_x = 0;
1060 if (g_layer_x > 640) g_layer_x = 640;
1061 if (g_layer_y < 0) g_layer_y = 0;
1062 if (g_layer_y > 420) g_layer_y = 420;
1063 if (g_layer_w < 160) g_layer_w = 160;
1064 if (g_layer_h < 60) g_layer_h = 60;
1065 if (g_layer_x + g_layer_w > 800)
1066 g_layer_w = 800 - g_layer_x;
1067 if (g_layer_y + g_layer_h > 480)
1068 g_layer_h = 480 - g_layer_y;
1069 omap_enable_layer(1);
1073 omap_enable_layer(0);
1078 static menu_entry e_menu_gfx_options[] =
1080 mee_enum ("Scaler", 0, scaling, men_scaler),
1081 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1082 // mee_onoff ("Vsync", 0, vsync, 1),
1083 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1087 static int menu_loop_gfx_options(int id, int keys)
1091 me_loop(e_menu_gfx_options, &sel);
1096 // ------------ bios/plugins ------------
1098 static menu_entry e_menu_plugin_gpu_unai[] =
1100 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1101 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1102 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1106 static int menu_loop_plugin_gpu_unai(int id, int keys)
1109 me_loop(e_menu_plugin_gpu_unai, &sel);
1113 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1114 static const char h_gpu_0[] = "Needed for Chrono Cross";
1115 static const char h_gpu_1[] = "Capcom fighting games";
1116 static const char h_gpu_2[] = "Black screens in Lunar";
1117 static const char h_gpu_3[] = "Compatibility mode";
1118 static const char h_gpu_6[] = "Pandemonium 2";
1119 static const char h_gpu_7[] = "Skip every second frame";
1120 static const char h_gpu_8[] = "Needed by Dark Forces";
1121 static const char h_gpu_9[] = "better g-colors, worse textures";
1122 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1124 static menu_entry e_menu_plugin_gpu_peops[] =
1126 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1127 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1128 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1129 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1130 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1131 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1132 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1133 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1134 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1135 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1139 static int menu_loop_plugin_gpu_peops(int id, int keys)
1142 me_loop(e_menu_plugin_gpu_peops, &sel);
1146 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1147 static const char h_spu_volboost[] = "Large values cause distortion";
1148 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1149 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1151 static menu_entry e_menu_plugin_spu[] =
1153 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1154 mee_onoff ("Reverb", 0, iUseReverb, 2),
1155 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1156 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1157 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1158 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1162 static int menu_loop_plugin_spu(int id, int keys)
1165 me_loop(e_menu_plugin_spu, &sel);
1169 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1170 "and can't be changed there. Must save config and reload\n"
1171 "the game for change to take effect";
1172 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1173 "for plugin change to take effect";
1174 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1175 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1176 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1178 static menu_entry e_menu_plugin_options[] =
1180 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1181 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1182 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1183 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1184 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1185 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1189 static menu_entry e_menu_main2[];
1191 static int menu_loop_plugin_options(int id, int keys)
1194 me_loop(e_menu_plugin_options, &sel);
1196 // sync BIOS/plugins
1197 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1198 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1199 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1200 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1205 // ------------ adv options menu ------------
1207 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1208 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1209 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1210 "(green: normal, red: fmod, blue: noise)";
1211 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1212 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1213 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1214 "(proper .cue/.bin dump is needed otherwise)";
1215 static const char h_cfg_sio[] = "You should not need this, breaks games";
1216 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1217 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1218 "(timing hack, breaks other games)";
1219 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1220 "(timing hack, breaks other games)";
1221 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1222 "(CD timing hack, breaks FMVs)";
1223 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1224 "Might be useful to overcome some dynarec bugs";
1226 static menu_entry e_menu_adv_options[] =
1228 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1229 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1230 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1231 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1232 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1233 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1234 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1235 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1236 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1237 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
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 ("[Display]", 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, 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 if (CheckCdrom() == -1) {
1608 // Only check the CD if we are starting the console with a CD
1610 me_update_msg("unsupported/invalid CD image");
1616 // Read main executable directly from CDRom and start it
1617 if (LoadCdrom() == -1) {
1619 me_update_msg("failed to load CD image");
1627 static int romsel_run(void)
1629 int prev_gpu, prev_spu;
1632 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1636 printf("selected file: %s\n", fname);
1638 new_dynarec_clear_full();
1640 if (run_cd_image(fname) != 0)
1643 prev_gpu = gpu_plugsel;
1644 prev_spu = spu_plugsel;
1645 if (menu_load_config(1) != 0)
1646 menu_load_config(0);
1648 // check for plugin changes, have to repeat
1649 // loading if game config changed plugins to reload them
1650 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1651 printf("plugin change detected, reloading plugins..\n");
1652 if (run_cd_image(fname) != 0)
1656 strcpy(last_selected_fname, rom_fname_reload);
1660 static int swap_cd_image(void)
1664 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1668 printf("selected file: %s\n", fname);
1671 CdromLabel[0] = '\0';
1673 set_cd_image(fname);
1674 if (ReloadCdromPlugin() < 0) {
1675 me_update_msg("failed to load cdr plugin");
1678 if (CDR_open() < 0) {
1679 me_update_msg("failed to open cdr plugin");
1683 SetCdOpenCaseTime(time(NULL) + 2);
1686 strcpy(last_selected_fname, rom_fname_reload);
1690 static int main_menu_handler(int id, int keys)
1694 case MA_MAIN_RESUME_GAME:
1698 case MA_MAIN_SAVE_STATE:
1700 return menu_loop_savestate(0);
1702 case MA_MAIN_LOAD_STATE:
1704 return menu_loop_savestate(1);
1706 case MA_MAIN_RESET_GAME:
1707 if (ready_to_go && reset_game() == 0)
1710 case MA_MAIN_LOAD_ROM:
1711 if (romsel_run() == 0)
1714 case MA_MAIN_SWAP_CD:
1715 if (swap_cd_image() == 0)
1718 case MA_MAIN_RUN_BIOS:
1719 if (run_bios() == 0)
1722 case MA_MAIN_RUN_EXE:
1726 case MA_MAIN_CREDITS:
1727 draw_menu_message(credits_text, draw_frame_credits);
1728 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1734 lprintf("%s: something unknown selected\n", __FUNCTION__);
1741 static menu_entry e_menu_main2[] =
1743 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1744 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1745 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1746 mee_handler ("Memcard manager", menu_loop_memcards),
1750 static int main_menu2_handler(int id, int keys)
1754 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1755 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1757 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1760 static const char h_extra[] = "Change CD, manage memcards..\n";
1762 static menu_entry e_menu_main[] =
1766 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1767 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1768 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1769 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1770 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1771 mee_handler ("Options", menu_loop_options),
1772 mee_handler ("Controls", menu_loop_keyconfig),
1773 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1774 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1775 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1779 // ----------------------------
1781 static void menu_leave_emu(void);
1783 void menu_loop(void)
1789 if (bioses[1] == NULL && !warned_about_bios) {
1791 warned_about_bios = 1;
1794 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1795 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1796 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1797 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1799 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1802 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1803 } while (!ready_to_go);
1805 /* wait until menu, ok, back is released */
1806 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1809 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1814 static int qsort_strcmp(const void *p1, const void *p2)
1816 char * const *s1 = (char * const *)p1;
1817 char * const *s2 = (char * const *)p2;
1818 return strcasecmp(*s1, *s2);
1821 static void scan_bios_plugins(void)
1823 char fname[MAXPATHLEN];
1825 int bios_i, gpu_i, spu_i, mc_i;
1830 gpu_plugins[0] = "builtin_gpu";
1831 spu_plugins[0] = "builtin_spu";
1832 memcards[0] = "(none)";
1833 bios_i = gpu_i = spu_i = mc_i = 1;
1835 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1836 dir = opendir(fname);
1838 perror("scan_bios_plugins bios opendir");
1853 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1856 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1857 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1858 printf("bad BIOS file: %s\n", ent->d_name);
1862 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1863 bioses[bios_i++] = strdup(ent->d_name);
1867 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1873 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1874 dir = opendir(fname);
1876 perror("scan_bios_plugins plugins opendir");
1890 p = strstr(ent->d_name, ".so");
1894 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1895 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1897 fprintf(stderr, "%s\n", dlerror());
1901 // now what do we have here?
1902 tmp = dlsym(h, "GPUinit");
1905 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1906 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1910 tmp = dlsym(h, "SPUinit");
1913 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1914 spu_plugins[spu_i++] = strdup(ent->d_name);
1918 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1925 dir = opendir("." MEMCARD_DIR);
1927 perror("scan_bios_plugins memcards opendir");
1942 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1945 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1946 if (stat(fname, &st) != 0) {
1947 printf("bad memcard file: %s\n", ent->d_name);
1951 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1952 memcards[mc_i++] = strdup(ent->d_name);
1956 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1960 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1965 void menu_init(void)
1967 char buff[MAXPATHLEN];
1969 strcpy(last_selected_fname, "/media");
1971 scan_bios_plugins();
1975 menu_set_defconfig();
1976 menu_load_config(0);
1981 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1982 if (g_menubg_src_ptr == NULL)
1984 emu_make_path(buff, "skin/background.png", sizeof(buff));
1985 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1988 void menu_notify_mode_change(int w, int h, int bpp)
1999 g_layer_w = w; g_layer_h = h;
2003 mult = 240.0f / (float)h * 4.0f / 3.0f;
2006 g_layer_w = mult * (float)g_menuscreen_h;
2007 g_layer_h = g_menuscreen_h;
2008 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2012 // 4:3 that prefers integer scaling
2013 imult = g_menuscreen_h / h;
2014 g_layer_w = w * imult;
2015 g_layer_h = h * imult;
2016 mult = (float)g_layer_w / (float)g_layer_h;
2017 if (mult < 1.25f || mult > 1.666f)
2018 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2019 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2022 case SCALE_FULLSCREEN:
2023 g_layer_w = g_menuscreen_w;
2024 g_layer_h = g_menuscreen_h;
2031 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2032 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2033 if (g_layer_x < 0) g_layer_x = 0;
2034 if (g_layer_y < 0) g_layer_y = 0;
2035 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2036 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2039 static void menu_leave_emu(void)
2041 if (GPU_close != NULL) {
2042 int ret = GPU_close();
2044 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2047 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2048 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2049 int x = max(0, g_menuscreen_w - last_psx_w);
2050 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2051 int w = min(g_menuscreen_w, last_psx_w);
2052 int h = min(g_menuscreen_h, last_psx_h);
2053 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2054 u16 *s = pl_vout_buf;
2056 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2057 menu_darken_bg(d, s, w, 0);
2061 cpu_clock = get_cpu_clock();
2063 plat_video_menu_enter(ready_to_go);
2066 void menu_prepare_emu(void)
2068 R3000Acpu *prev_cpu = psxCpu;
2070 plat_video_menu_leave();
2072 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2074 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2075 if (psxCpu != prev_cpu)
2076 // note that this does not really reset, just clears drc caches
2079 // core doesn't care about Config.Cdda changes,
2080 // so handle them manually here
2085 apply_lcdrate(Config.PsxType);
2086 apply_filter(filter);
2089 // push config to GPU plugin
2090 plugin_call_rearmed_cbs();
2092 if (GPU_open != NULL) {
2093 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2095 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2101 void me_update_msg(const char *msg)
2103 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2104 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2106 menu_error_time = plat_get_ticks_ms();
2107 lprintf("msg: %s\n", menu_error_msg);