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/pad.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;
74 static char rom_fname_reload[MAXPATHLEN];
75 static char last_selected_fname[MAXPATHLEN];
76 static int warned_about_bios, region, in_type_sel;
77 static int memcard1_sel, memcard2_sel;
81 extern int iUseReverb;
82 extern int iUseInterpolation;
84 extern int iSPUIRQWait;
87 static const char *bioses[24];
88 static const char *gpu_plugins[16];
89 static const char *spu_plugins[16];
90 static const char *memcards[32];
91 static int bios_sel, gpu_plugsel, spu_plugsel;
94 static int min(int x, int y) { return x < y ? x : y; }
95 static int max(int x, int y) { return x > y ? x : y; }
97 void emu_make_path(char *buff, const char *end, int size)
101 end_len = strlen(end);
102 pos = plat_get_root_dir(buff, size);
103 strncpy(buff + pos, end, size - pos);
105 if (pos + end_len > size - 1)
106 printf("Warning: path truncated: %s\n", buff);
109 static int emu_check_save_file(int slot)
111 int ret = emu_check_state(slot);
112 return ret == 0 ? 1 : 0;
115 static int emu_save_load_game(int load, int unused)
120 ret = emu_load_state(state_slot);
122 // reflect hle/bios mode from savestate
125 else if (bios_sel == 0 && bioses[1] != NULL)
126 // XXX: maybe find the right bios instead
130 ret = emu_save_state(state_slot);
135 // propagate menu settings to the emu vars
136 static void menu_sync_config(void)
138 static int allow_abs_only_old;
143 Config.PsxType = region - 1;
145 in_type = in_type_sel ? PSE_PAD_TYPE_ANALOGPAD : PSE_PAD_TYPE_STANDARD;
146 if (in_evdev_allow_abs_only != allow_abs_only_old) {
147 pandora_rescan_inputs();
148 allow_abs_only_old = in_evdev_allow_abs_only;
151 pl_frame_interval = Config.PsxType ? 20000 : 16667;
152 // used by P.E.Op.S. frameskip code
153 pl_rearmed_cbs.gpu_peops.fFrameRateHz = Config.PsxType ? 50.0f : 59.94f;
154 pl_rearmed_cbs.gpu_peops.dwFrameRateTicks =
155 (100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
158 static void menu_set_defconfig(void)
165 in_evdev_allow_abs_only = 0;
166 Config.Xa = Config.Cdda = Config.Sio =
167 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
168 Config.CdrReschedule = 0;
170 pl_rearmed_cbs.frameskip = 0;
171 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
172 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
175 iUseInterpolation = 1;
183 #define CE_CONFIG_STR(val) \
184 { #val, 0, Config.val }
186 #define CE_CONFIG_VAL(val) \
187 { #val, sizeof(Config.val), &Config.val }
189 #define CE_STR(val) \
192 #define CE_INTVAL(val) \
193 { #val, sizeof(val), &val }
195 #define CE_INTVAL_P(val) \
196 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
198 // 'versioned' var, used when defaults change
199 #define CE_INTVAL_V(val, ver) \
200 { #val #ver, sizeof(val), &val }
202 static const struct {
210 // CE_CONFIG_STR(Cdr),
215 CE_CONFIG_VAL(Debug),
216 CE_CONFIG_VAL(PsxOut),
217 CE_CONFIG_VAL(SpuIrq),
218 CE_CONFIG_VAL(RCntFix),
219 CE_CONFIG_VAL(VSyncWA),
221 CE_CONFIG_VAL(CdrReschedule),
224 CE_INTVAL(g_layer_x),
225 CE_INTVAL(g_layer_y),
226 CE_INTVAL(g_layer_w),
227 CE_INTVAL(g_layer_h),
229 CE_INTVAL(state_slot),
230 CE_INTVAL(cpu_clock),
232 CE_INTVAL(in_type_sel),
233 CE_INTVAL_P(frameskip),
234 CE_INTVAL_P(gpu_peops.iUseDither),
235 CE_INTVAL_P(gpu_peops.dwActFixes),
236 CE_INTVAL(iUseReverb),
238 CE_INTVAL_V(iUseInterpolation, 2),
239 CE_INTVAL_V(iSPUIRQWait, 2),
240 CE_INTVAL(iUseTimer),
241 CE_INTVAL(warned_about_bios),
242 CE_INTVAL(in_evdev_allow_abs_only),
245 static char *get_cd_label(void)
247 static char trimlabel[33];
250 strncpy(trimlabel, CdromLabel, 32);
252 for (j = 31; j >= 0; j--)
253 if (trimlabel[j] == ' ')
259 static void make_cfg_fname(char *buf, size_t size, int is_game)
262 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
264 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
267 static void keys_write_all(FILE *f);
269 static int menu_write_config(int is_game)
271 char cfgfile[MAXPATHLEN];
275 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
276 f = fopen(cfgfile, "w");
278 printf("menu_write_config: failed to open: %s\n", cfgfile);
282 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
283 fprintf(f, "%s = ", config_data[i].name);
284 switch (config_data[i].len) {
286 fprintf(f, "%s\n", (char *)config_data[i].val);
289 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
292 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
295 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
298 printf("menu_write_config: unhandled len %d for %s\n",
299 config_data[i].len, config_data[i].name);
305 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
313 static void parse_str_val(char *cval, const char *src)
316 strncpy(cval, src, MAXPATHLEN);
317 cval[MAXPATHLEN - 1] = 0;
318 tmp = strchr(cval, '\n');
320 tmp = strchr(cval, '\r');
325 static void keys_load_all(const char *cfg);
327 static int menu_load_config(int is_game)
329 char cfgfile[MAXPATHLEN];
335 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
336 f = fopen(cfgfile, "r");
338 printf("menu_load_config: failed to open: %s\n", cfgfile);
342 fseek(f, 0, SEEK_END);
345 printf("bad size %ld: %s\n", size, cfgfile);
349 cfg = malloc(size + 1);
353 fseek(f, 0, SEEK_SET);
354 if (fread(cfg, 1, size, f) != size) {
355 printf("failed to read: %s\n", cfgfile);
360 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
364 tmp = strstr(cfg, config_data[i].name);
367 tmp += strlen(config_data[i].name);
368 if (strncmp(tmp, " = ", 3) != 0)
372 if (config_data[i].len == 0) {
373 parse_str_val(config_data[i].val, tmp);
378 val = strtoul(tmp, &tmp2, 16);
379 if (tmp2 == NULL || tmp == tmp2)
380 continue; // parse failed
382 switch (config_data[i].len) {
384 *(u8 *)config_data[i].val = val;
387 *(u16 *)config_data[i].val = val;
390 *(u32 *)config_data[i].val = val;
393 printf("menu_load_config: unhandled len %d for %s\n",
394 config_data[i].len, config_data[i].name);
400 char *tmp = strstr(cfg, "lastcdimg = ");
403 parse_str_val(last_selected_fname, tmp);
410 for (i = bios_sel = 0; bioses[i] != NULL; i++)
411 if (strcmp(Config.Bios, bioses[i]) == 0)
412 { bios_sel = i; break; }
414 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
415 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
416 { gpu_plugsel = i; break; }
418 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
419 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
420 { spu_plugsel = i; break; }
431 // rrrr rggg gggb bbbb
432 static unsigned short fname2color(const char *fname)
434 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
435 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
436 const char *ext = strrchr(fname, '.');
441 for (i = 0; i < array_size(cdimg_exts); i++)
442 if (strcasecmp(ext, cdimg_exts[i]) == 0)
444 for (i = 0; i < array_size(other_exts); i++)
445 if (strcasecmp(ext, other_exts[i]) == 0)
450 static void draw_savestate_bg(int slot);
452 static const char *filter_exts[] = {
453 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
456 #define MENU_ALIGN_LEFT
457 #define menu_init menu_init_common
458 #include "common/menu.c"
461 // a bit of black magic here
462 static void draw_savestate_bg(int slot)
464 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
466 char fname[MAXPATHLEN];
473 ret = get_state_filename(fname, sizeof(fname), slot);
477 f = gzopen(fname, "rb");
481 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
482 fprintf(stderr, "gzseek failed\n");
487 gpu = malloc(sizeof(*gpu));
493 ret = gzread(f, gpu, sizeof(*gpu));
495 if (ret != sizeof(*gpu)) {
496 fprintf(stderr, "gzread failed\n");
500 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
502 if (gpu->ulStatus & 0x800000)
503 goto out; // disabled
505 x = gpu->ulControl[5] & 0x3ff;
506 y = (gpu->ulControl[5] >> 10) & 0x1ff;
507 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
508 w = psx_widths[(gpu->ulStatus >> 16) & 7];
509 tmp = gpu->ulControl[7];
510 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
511 if (gpu->ulStatus & 0x80000) // doubleheight
514 x = max(0, g_menuscreen_w - w) & ~3;
515 y = max(0, g_menuscreen_h / 2 - h / 2);
516 w = min(g_menuscreen_w, w);
517 h = min(g_menuscreen_h, h);
518 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
520 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
521 if (gpu->ulStatus & 0x200000)
522 bgr888_to_rgb565(d, s, w * 3);
524 bgr555_to_rgb565(d, s, w * 2);
530 // ---------- pandora specific -----------
532 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
533 static char **pnd_filter_list;
535 static int get_cpu_clock(void)
539 f = fopen("/proc/pandora/cpu_mhz_max", "r");
541 fscanf(f, "%d", &ret);
547 static void apply_cpu_clock(void)
551 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
552 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
553 pnd_script_base, cpu_clock);
558 static void apply_filter(int which)
564 if (pnd_filter_list == NULL || which == old)
567 for (i = 0; i < which; i++)
568 if (pnd_filter_list[i] == NULL)
571 if (pnd_filter_list[i] == NULL)
574 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
579 static void apply_lcdrate(int pal)
587 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
588 pnd_script_base, pal ? 50 : 60);
593 static menu_entry e_menu_gfx_options[];
595 static void pnd_menu_init(void)
603 cpu_clock_st = cpu_clock = get_cpu_clock();
605 dir = opendir("/etc/pandora/conf/dss_fir");
607 perror("filter opendir");
620 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
629 mfilters = calloc(count + 1, sizeof(mfilters[0]));
630 if (mfilters == NULL)
634 for (i = 0; (ent = readdir(dir)); ) {
637 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
640 len = strlen(ent->d_name);
642 // skip pre-HF5 extra files
643 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
645 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
648 // have to cut "_up_h" for pre-HF5
649 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
652 if (len > sizeof(buff) - 1)
655 strncpy(buff, ent->d_name, len);
657 mfilters[i] = strdup(buff);
658 if (mfilters[i] != NULL)
663 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
664 e_menu_gfx_options[i].data = (void *)mfilters;
665 pnd_filter_list = mfilters;
668 void menu_finish(void)
670 cpu_clock = cpu_clock_st;
674 // -------------- key config --------------
676 me_bind_action me_ctrl_actions[] =
678 { "UP ", 1 << DKEY_UP},
679 { "DOWN ", 1 << DKEY_DOWN },
680 { "LEFT ", 1 << DKEY_LEFT },
681 { "RIGHT ", 1 << DKEY_RIGHT },
682 { "TRIANGLE", 1 << DKEY_TRIANGLE },
683 { "CIRCLE ", 1 << DKEY_CIRCLE },
684 { "CROSS ", 1 << DKEY_CROSS },
685 { "SQUARE ", 1 << DKEY_SQUARE },
686 { "L1 ", 1 << DKEY_L1 },
687 { "R1 ", 1 << DKEY_R1 },
688 { "L2 ", 1 << DKEY_L2 },
689 { "R2 ", 1 << DKEY_R2 },
690 { "L3 ", 1 << DKEY_L3 },
691 { "R3 ", 1 << DKEY_R3 },
692 { "START ", 1 << DKEY_START },
693 { "SELECT ", 1 << DKEY_SELECT },
697 me_bind_action emuctrl_actions[] =
699 { "Save State ", 1 << SACTION_SAVE_STATE },
700 { "Load State ", 1 << SACTION_LOAD_STATE },
701 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
702 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
703 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
704 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
705 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
709 static char *mystrip(char *str)
714 for (i = 0; i < len; i++)
715 if (str[i] != ' ') break;
716 if (i > 0) memmove(str, str + i, len - i + 1);
719 for (i = len - 1; i >= 0; i--)
720 if (str[i] != ' ') break;
726 static void get_line(char *d, size_t size, const char *s)
731 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
742 static void keys_write_all(FILE *f)
746 for (d = 0; d < IN_MAX_DEVS; d++)
748 const int *binds = in_get_dev_binds(d);
749 const char *name = in_get_dev_name(d, 0, 0);
752 if (binds == NULL || name == NULL)
755 fprintf(f, "binddev = %s\n", name);
756 in_get_config(d, IN_CFG_BIND_COUNT, &count);
758 for (k = 0; k < count; k++)
763 act[0] = act[31] = 0;
764 name = in_get_key_name(d, k);
766 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
767 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
768 mask = me_ctrl_actions[i].mask;
770 strncpy(act, me_ctrl_actions[i].name, 31);
771 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
774 mask = me_ctrl_actions[i].mask << 16;
776 strncpy(act, me_ctrl_actions[i].name, 31);
777 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
782 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
783 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
784 mask = emuctrl_actions[i].mask;
786 strncpy(act, emuctrl_actions[i].name, 31);
787 fprintf(f, "bind %s = %s\n", name, mystrip(act));
795 static int parse_bind_val(const char *val, int *type)
799 *type = IN_BINDTYPE_NONE;
803 if (strncasecmp(val, "player", 6) == 0)
805 int player, shift = 0;
806 player = atoi(val + 6) - 1;
808 if ((unsigned int)player > 1)
813 *type = IN_BINDTYPE_PLAYER12;
814 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
815 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
816 return me_ctrl_actions[i].mask << shift;
819 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
820 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
821 *type = IN_BINDTYPE_EMU;
822 return emuctrl_actions[i].mask;
829 static void keys_load_all(const char *cfg)
831 char dev[256], key[128], *act;
837 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
840 get_line(dev, sizeof(dev), p);
841 dev_id = in_config_parse_dev(dev);
843 printf("input: can't handle dev: %s\n", dev);
847 in_unbind_all(dev_id, -1, -1);
848 while ((p = strstr(p, "bind"))) {
849 if (strncmp(p, "binddev = ", 10) == 0)
854 printf("input: parse error: %16s..\n", p);
858 get_line(key, sizeof(key), p);
859 act = strchr(key, '=');
861 printf("parse failed: %16s..\n", p);
869 bind = parse_bind_val(act, &bindtype);
870 if (bind != -1 && bind != 0) {
871 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
872 in_config_bind_key(dev_id, key, bind, bindtype);
875 lprintf("config: unhandled action \"%s\"\n", act);
881 static int key_config_loop_wrap(int id, int keys)
884 case MA_CTRL_PLAYER1:
885 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
887 case MA_CTRL_PLAYER2:
888 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
891 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
899 static const char *mgn_dev_name(int id, int *offs)
901 const char *name = NULL;
904 if (id == MA_CTRL_DEV_FIRST)
907 for (; it < IN_MAX_DEVS; it++) {
908 name = in_get_dev_name(it, 1, 1);
917 static const char *mgn_saveloadcfg(int id, int *offs)
922 static int mh_savecfg(int id, int keys)
924 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
925 me_update_msg("config saved");
927 me_update_msg("failed to write config");
932 static int mh_input_rescan(int id, int keys)
934 //menu_sync_config();
935 pandora_rescan_inputs();
936 me_update_msg("rescan complete.");
941 static const char *men_in_type_sel[] = { "Standard (SCPH-1080)", "Analog (SCPH-1150)", NULL };
942 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
944 static menu_entry e_menu_keyconfig[] =
946 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
947 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
948 mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
950 mee_enum ("Controller", 0, in_type_sel, men_in_type_sel),
951 mee_onoff_h ("Nubs as buttons", 0, in_evdev_allow_abs_only, 1, h_nub_btns),
952 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
953 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
954 mee_handler ("Rescan devices", mh_input_rescan),
956 mee_label ("Input devices:"),
957 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
958 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
959 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
960 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
961 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
962 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
963 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
967 static int menu_loop_keyconfig(int id, int keys)
971 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
972 me_loop(e_menu_keyconfig, &sel);
976 // ------------ gfx options menu ------------
978 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
979 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
980 "using d-pad or move it using R+d-pad";
981 static const char *men_dummy[] = { NULL };
983 static int menu_loop_cscaler(int id, int keys)
987 scaling = SCALE_CUSTOM;
989 omap_enable_layer(1);
994 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
995 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
996 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
999 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1000 if (inp & PBTN_UP) g_layer_y--;
1001 if (inp & PBTN_DOWN) g_layer_y++;
1002 if (inp & PBTN_LEFT) g_layer_x--;
1003 if (inp & PBTN_RIGHT) g_layer_x++;
1004 if (!(inp & PBTN_R)) {
1005 if (inp & PBTN_UP) g_layer_h += 2;
1006 if (inp & PBTN_DOWN) g_layer_h -= 2;
1007 if (inp & PBTN_LEFT) g_layer_w += 2;
1008 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1010 if (inp & (PBTN_MOK|PBTN_MBACK))
1013 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1014 if (g_layer_x < 0) g_layer_x = 0;
1015 if (g_layer_x > 640) g_layer_x = 640;
1016 if (g_layer_y < 0) g_layer_y = 0;
1017 if (g_layer_y > 420) g_layer_y = 420;
1018 if (g_layer_w < 160) g_layer_w = 160;
1019 if (g_layer_h < 60) g_layer_h = 60;
1020 if (g_layer_x + g_layer_w > 800)
1021 g_layer_w = 800 - g_layer_x;
1022 if (g_layer_y + g_layer_h > 480)
1023 g_layer_h = 480 - g_layer_y;
1024 omap_enable_layer(1);
1028 omap_enable_layer(0);
1033 static menu_entry e_menu_gfx_options[] =
1035 mee_enum ("Scaler", 0, scaling, men_scaler),
1036 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1037 // mee_onoff ("Vsync", 0, vsync, 1),
1038 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1042 static int menu_loop_gfx_options(int id, int keys)
1046 me_loop(e_menu_gfx_options, &sel);
1051 // ------------ bios/plugins ------------
1053 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1054 static const char h_gpu_0[] = "Needed for Chrono Cross";
1055 static const char h_gpu_1[] = "Capcom fighting games";
1056 static const char h_gpu_2[] = "Black screens in Lunar";
1057 static const char h_gpu_3[] = "Compatibility mode";
1058 static const char h_gpu_6[] = "Pandemonium 2";
1059 static const char h_gpu_7[] = "Skip every second frame";
1060 static const char h_gpu_8[] = "Needed by Dark Forces";
1061 static const char h_gpu_9[] = "better g-colors, worse textures";
1062 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1064 static menu_entry e_menu_plugin_gpu[] =
1066 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1067 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1068 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1069 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1070 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1071 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1072 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1073 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1074 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1075 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1079 static int menu_loop_plugin_gpu(int id, int keys)
1082 me_loop(e_menu_plugin_gpu, &sel);
1086 static const char *men_spu_reverb[] = { "Off", "Fake", "On", NULL };
1087 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1088 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1089 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1091 static menu_entry e_menu_plugin_spu[] =
1093 mee_enum ("Reverb", 0, iUseReverb, men_spu_reverb),
1094 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1095 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1096 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1097 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1101 static int menu_loop_plugin_spu(int id, int keys)
1104 me_loop(e_menu_plugin_spu, &sel);
1108 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1109 "and can't be changed there. Must save config and reload\n"
1110 "the game for change to take effect";
1111 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1112 "for plugin change to take effect";
1113 static const char h_gpu[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1114 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1116 static menu_entry e_menu_plugin_options[] =
1118 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1119 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1120 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1121 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu, h_gpu),
1122 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1126 static menu_entry e_menu_main2[];
1128 static int menu_loop_plugin_options(int id, int keys)
1131 me_loop(e_menu_plugin_options, &sel);
1133 // sync BIOS/plugins
1134 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1135 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1136 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1137 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1142 // ------------ adv options menu ------------
1144 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1145 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1146 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1147 "(green: normal, red: fmod, blue: noise)";
1148 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1149 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1150 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1151 "(proper .cue/.bin dump is needed otherwise)";
1152 static const char h_cfg_sio[] = "You should not need this, breaks games";
1153 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1154 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1155 "(timing hack, breaks other games)";
1156 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1157 "(timing hack, breaks other games)";
1158 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1159 "(CD timing hack, breaks FMVs)";
1160 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1161 "Might be useful to overcome some dynarec bugs";
1163 static menu_entry e_menu_adv_options[] =
1165 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1166 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1167 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1168 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1169 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1170 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1171 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1172 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1173 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1174 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1175 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1179 static int menu_loop_adv_options(int id, int keys)
1182 me_loop(e_menu_adv_options, &sel);
1186 // ------------ options menu ------------
1188 static int mh_restore_defaults(int id, int keys)
1190 menu_set_defconfig();
1191 me_update_msg("defaults restored");
1195 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1197 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1198 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1199 "loading state or both";
1201 static const char h_restore_def[] = "Switches back to default / recommended\n"
1203 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1205 static menu_entry e_menu_options[] =
1207 // mee_range ("Save slot", 0, state_slot, 0, 9),
1208 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1209 mee_onoff_h ("Frameskip", 0, pl_rearmed_cbs.frameskip, 1, h_frameskip),
1210 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1211 mee_enum ("Region", 0, region, men_region),
1212 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1213 mee_handler ("[Display]", menu_loop_gfx_options),
1214 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1215 mee_handler ("[Advanced]", menu_loop_adv_options),
1216 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1217 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1218 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1222 static int menu_loop_options(int id, int keys)
1227 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1228 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1229 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1231 me_loop(e_menu_options, &sel);
1236 // ------------ debug menu ------------
1238 static void draw_frame_debug(GPUFreeze_t *gpuf)
1240 int w = min(g_menuscreen_w, 1024);
1241 int h = min(g_menuscreen_h, 512);
1242 u16 *d = g_menuscreen_ptr;
1243 u16 *s = (u16 *)gpuf->psxVRam;
1247 gpuf->ulFreezeVersion = 1;
1248 if (GPU_freeze != NULL)
1249 GPU_freeze(1, gpuf);
1251 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1252 bgr555_to_rgb565(d, s, w * 2);
1254 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1255 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1256 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1257 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1258 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1261 static void debug_menu_loop(void)
1266 gpuf = malloc(sizeof(*gpuf));
1273 draw_frame_debug(gpuf);
1276 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1277 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1278 if (inp & PBTN_MBACK)
1285 // --------- memcard manager ---------
1287 static void draw_mc_icon(int dx, int dy, const u16 *s)
1292 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1294 for (y = 0; y < 16; y++, s += 16) {
1295 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1296 for (x = 0; x < 16; x++) {
1298 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1299 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1305 static void draw_mc_bg(void)
1307 McdBlock *blocks1, *blocks2;
1311 blocks1 = malloc(15 * sizeof(blocks1[0]));
1312 blocks2 = malloc(15 * sizeof(blocks1[0]));
1313 if (blocks1 == NULL || blocks2 == NULL)
1316 for (i = 0; i < 15; i++) {
1317 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1318 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1323 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1325 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1329 maxicons = g_menuscreen_h / 32;
1332 row2 = g_menuscreen_w / 2;
1333 for (i = 0; i < maxicons; i++) {
1334 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1335 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1337 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1338 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1341 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1349 static void handle_memcard_sel(void)
1352 if (memcard1_sel != 0)
1353 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1355 if (memcard2_sel != 0)
1356 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1357 LoadMcds(Config.Mcd1, Config.Mcd2);
1361 static menu_entry e_memcard_options[] =
1363 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1364 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1368 static int menu_loop_memcards(int id, int keys)
1374 memcard1_sel = memcard2_sel = 0;
1375 p = strrchr(Config.Mcd1, '/');
1377 for (i = 0; memcards[i] != NULL; i++)
1378 if (strcmp(p + 1, memcards[i]) == 0)
1379 { memcard1_sel = i; break; }
1380 p = strrchr(Config.Mcd2, '/');
1382 for (i = 0; memcards[i] != NULL; i++)
1383 if (strcmp(p + 1, memcards[i]) == 0)
1384 { memcard2_sel = i; break; }
1386 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1388 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1393 // --------- main menu help ----------
1395 static void menu_bios_warn(void)
1398 static const char msg[] =
1399 "You don't seem to have copied any BIOS files to\n"
1400 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1401 "While many games work fine with fake (HLE) BIOS,\n"
1402 "others (like MGS and FF8) require BIOS to work.\n"
1403 "After copying the file, you'll also need to\n"
1404 "select it in the emu's options->[BIOS/Plugins]\n\n"
1405 "The file is usually named SCPH1001.BIN, but\n"
1406 "other not compressed files can be used too.\n\n"
1407 "Press (B) or (X) to continue";
1411 draw_menu_message(msg, NULL);
1413 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1414 if (inp & (PBTN_MBACK|PBTN_MOK))
1419 // ------------ main menu ------------
1423 static void draw_frame_main(void)
1425 if (CdromId[0] != 0) {
1427 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1428 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1429 Config.HLE ? "HLE" : "BIOS");
1430 smalltext_out16(4, 1, buff, 0x105f);
1434 static void draw_frame_credits(void)
1436 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1439 static const char credits_text[] =
1441 "(C) 1999-2003 PCSX Team\n"
1442 "(C) 2005-2009 PCSX-df Team\n"
1443 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1444 "GPU and SPU code by Pete Bernert\n"
1445 " and the P.E.Op.S. team\n"
1446 "ARM recompiler (C) 2009-2011 Ari64\n"
1447 "PCSX4ALL plugins by PCSX4ALL team\n"
1448 " Chui, Franxis, Unai\n\n"
1449 "integration, optimization and\n"
1450 " frontend (C) 2010-2011 notaz\n";
1452 static int reset_game(void)
1455 if (bios_sel == 0 && !Config.HLE)
1461 if (CheckCdrom() != -1) {
1467 static int reload_plugins(const char *cdimg)
1469 pl_fbdev_buf = NULL;
1473 set_cd_image(cdimg);
1475 pcnt_hook_plugins();
1477 if (OpenPlugins() == -1) {
1478 me_update_msg("failed to open plugins");
1481 plugin_call_rearmed_cbs();
1484 CdromLabel[0] = '\0';
1489 static int run_bios(void)
1495 if (reload_plugins(NULL) != 0)
1503 static int run_exe(void)
1507 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1512 if (reload_plugins(NULL) != 0)
1516 if (Load(fname) != 0) {
1517 me_update_msg("exe load failed, bad file?");
1526 static int run_cd_image(const char *fname)
1529 reload_plugins(fname);
1531 if (CheckCdrom() == -1) {
1532 // Only check the CD if we are starting the console with a CD
1534 me_update_msg("unsupported/invalid CD image");
1540 // Read main executable directly from CDRom and start it
1541 if (LoadCdrom() == -1) {
1543 me_update_msg("failed to load CD image");
1551 static int romsel_run(void)
1553 int prev_gpu, prev_spu;
1556 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1560 printf("selected file: %s\n", fname);
1562 new_dynarec_clear_full();
1564 if (run_cd_image(fname) != 0)
1567 prev_gpu = gpu_plugsel;
1568 prev_spu = spu_plugsel;
1569 if (menu_load_config(1) != 0)
1570 menu_load_config(0);
1572 // check for plugin changes, have to repeat
1573 // loading if game config changed plugins to reload them
1574 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1575 printf("plugin change detected, reloading plugins..\n");
1576 if (run_cd_image(fname) != 0)
1580 strcpy(last_selected_fname, rom_fname_reload);
1584 static int swap_cd_image(void)
1588 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1592 printf("selected file: %s\n", fname);
1595 CdromLabel[0] = '\0';
1597 set_cd_image(fname);
1598 if (ReloadCdromPlugin() < 0) {
1599 me_update_msg("failed to load cdr plugin");
1602 if (CDR_open() < 0) {
1603 me_update_msg("failed to open cdr plugin");
1607 SetCdOpenCaseTime(time(NULL) + 2);
1610 strcpy(last_selected_fname, rom_fname_reload);
1614 static int main_menu_handler(int id, int keys)
1618 case MA_MAIN_RESUME_GAME:
1622 case MA_MAIN_SAVE_STATE:
1624 return menu_loop_savestate(0);
1626 case MA_MAIN_LOAD_STATE:
1628 return menu_loop_savestate(1);
1630 case MA_MAIN_RESET_GAME:
1631 if (ready_to_go && reset_game() == 0)
1634 case MA_MAIN_LOAD_ROM:
1635 if (romsel_run() == 0)
1638 case MA_MAIN_SWAP_CD:
1639 if (swap_cd_image() == 0)
1642 case MA_MAIN_RUN_BIOS:
1643 if (run_bios() == 0)
1646 case MA_MAIN_RUN_EXE:
1650 case MA_MAIN_CREDITS:
1651 draw_menu_message(credits_text, draw_frame_credits);
1652 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1658 lprintf("%s: something unknown selected\n", __FUNCTION__);
1665 static menu_entry e_menu_main2[] =
1667 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1668 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1669 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1670 mee_handler ("Memcard manager", menu_loop_memcards),
1674 static int main_menu2_handler(int id, int keys)
1678 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1679 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1681 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1684 static const char h_extra[] = "Change CD, manage memcards..\n";
1686 static menu_entry e_menu_main[] =
1690 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1691 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1692 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1693 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1694 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1695 mee_handler ("Options", menu_loop_options),
1696 mee_handler ("Controls", menu_loop_keyconfig),
1697 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1698 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1699 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1703 // ----------------------------
1705 static void menu_leave_emu(void);
1707 void menu_loop(void)
1713 if (bioses[1] == NULL && !warned_about_bios) {
1715 warned_about_bios = 1;
1718 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1719 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1720 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1721 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1723 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1726 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1727 } while (!ready_to_go);
1729 /* wait until menu, ok, back is released */
1730 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1733 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1738 static int qsort_strcmp(const void *p1, const void *p2)
1740 char * const *s1 = (char * const *)p1;
1741 char * const *s2 = (char * const *)p2;
1742 return strcasecmp(*s1, *s2);
1745 static void scan_bios_plugins(void)
1747 char fname[MAXPATHLEN];
1749 int bios_i, gpu_i, spu_i, mc_i;
1754 gpu_plugins[0] = "builtin_gpu";
1755 spu_plugins[0] = "builtin_spu";
1756 memcards[0] = "(none)";
1757 bios_i = gpu_i = spu_i = mc_i = 1;
1759 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1760 dir = opendir(fname);
1762 perror("scan_bios_plugins bios opendir");
1777 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1780 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1781 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1782 printf("bad BIOS file: %s\n", ent->d_name);
1786 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1787 bioses[bios_i++] = strdup(ent->d_name);
1791 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1797 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1798 dir = opendir(fname);
1800 perror("scan_bios_plugins plugins opendir");
1814 p = strstr(ent->d_name, ".so");
1818 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1819 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1821 fprintf(stderr, "%s\n", dlerror());
1825 // now what do we have here?
1826 tmp = dlsym(h, "GPUinit");
1829 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1830 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1834 tmp = dlsym(h, "SPUinit");
1837 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1838 spu_plugins[spu_i++] = strdup(ent->d_name);
1842 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1849 dir = opendir("." MEMCARD_DIR);
1851 perror("scan_bios_plugins memcards opendir");
1866 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1869 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1870 if (stat(fname, &st) != 0) {
1871 printf("bad memcard file: %s\n", ent->d_name);
1875 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1876 memcards[mc_i++] = strdup(ent->d_name);
1880 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1884 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1889 void menu_init(void)
1891 char buff[MAXPATHLEN];
1893 strcpy(last_selected_fname, "/media");
1895 scan_bios_plugins();
1899 menu_set_defconfig();
1900 menu_load_config(0);
1905 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1906 if (g_menubg_src_ptr == NULL)
1908 emu_make_path(buff, "skin/background.png", sizeof(buff));
1909 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1912 void menu_notify_mode_change(int w, int h, int bpp)
1918 if (scaling == SCALE_1_1) {
1919 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1920 g_layer_w = w; g_layer_h = h;
1924 static void menu_leave_emu(void)
1926 if (GPU_close != NULL) {
1927 int ret = GPU_close();
1929 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1932 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1933 if (pl_fbdev_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1934 int x = max(0, g_menuscreen_w - last_psx_w);
1935 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1936 int w = min(g_menuscreen_w, last_psx_w);
1937 int h = min(g_menuscreen_h, last_psx_h);
1938 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1939 u16 *s = pl_fbdev_buf;
1941 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1942 menu_darken_bg(d, s, w, 0);
1946 cpu_clock = get_cpu_clock();
1948 plat_video_menu_enter(ready_to_go);
1951 void menu_prepare_emu(void)
1953 R3000Acpu *prev_cpu = psxCpu;
1955 plat_video_menu_leave();
1959 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
1962 g_layer_x = 80; g_layer_y = 0;
1963 g_layer_w = 640; g_layer_h = 480;
1965 case SCALE_FULLSCREEN:
1966 g_layer_x = 0; g_layer_y = 0;
1967 g_layer_w = 800; g_layer_h = 480;
1973 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
1974 if (psxCpu != prev_cpu)
1975 // note that this does not really reset, just clears drc caches
1978 // core doesn't care about Config.Cdda changes,
1979 // so handle them manually here
1984 apply_lcdrate(Config.PsxType);
1985 apply_filter(filter);
1988 // push config to GPU plugin
1989 plugin_call_rearmed_cbs();
1991 if (GPU_open != NULL) {
1992 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
1994 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
1997 dfinput_activate(in_type == PSE_PAD_TYPE_ANALOGPAD);
2000 void me_update_msg(const char *msg)
2002 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2003 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2005 menu_error_time = plat_get_ticks_ms();
2006 lprintf("msg: %s\n", menu_error_msg);