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, 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_sel;
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 in_type = in_type_sel ? PSE_PAD_TYPE_ANALOGPAD : PSE_PAD_TYPE_STANDARD;
147 if (in_evdev_allow_abs_only != allow_abs_only_old) {
148 pandora_rescan_inputs();
149 allow_abs_only_old = in_evdev_allow_abs_only;
152 pl_frame_interval = Config.PsxType ? 20000 : 16667;
153 // used by P.E.Op.S. frameskip code
154 pl_rearmed_cbs.gpu_peops.fFrameRateHz = Config.PsxType ? 50.0f : 59.94f;
155 pl_rearmed_cbs.gpu_peops.dwFrameRateTicks =
156 (100000*100 / (unsigned long)(pl_rearmed_cbs.gpu_peops.fFrameRateHz*100));
158 iVolume = 768 + 128 * volume_boost;
161 static void menu_set_defconfig(void)
169 in_evdev_allow_abs_only = 0;
170 Config.Xa = Config.Cdda = Config.Sio =
171 Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
172 Config.CdrReschedule = 0;
174 pl_rearmed_cbs.frameskip = 0;
175 pl_rearmed_cbs.gpu_peops.iUseDither = 0;
176 pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
179 iUseInterpolation = 1;
187 #define CE_CONFIG_STR(val) \
188 { #val, 0, Config.val }
190 #define CE_CONFIG_VAL(val) \
191 { #val, sizeof(Config.val), &Config.val }
193 #define CE_STR(val) \
196 #define CE_INTVAL(val) \
197 { #val, sizeof(val), &val }
199 #define CE_INTVAL_P(val) \
200 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
202 // 'versioned' var, used when defaults change
203 #define CE_INTVAL_V(val, ver) \
204 { #val #ver, sizeof(val), &val }
206 static const struct {
214 // CE_CONFIG_STR(Cdr),
219 CE_CONFIG_VAL(Debug),
220 CE_CONFIG_VAL(PsxOut),
221 CE_CONFIG_VAL(SpuIrq),
222 CE_CONFIG_VAL(RCntFix),
223 CE_CONFIG_VAL(VSyncWA),
225 CE_CONFIG_VAL(CdrReschedule),
228 CE_INTVAL(g_layer_x),
229 CE_INTVAL(g_layer_y),
230 CE_INTVAL(g_layer_w),
231 CE_INTVAL(g_layer_h),
233 CE_INTVAL(state_slot),
234 CE_INTVAL(cpu_clock),
236 CE_INTVAL(in_type_sel),
237 CE_INTVAL_P(frameskip),
238 CE_INTVAL_P(gpu_peops.iUseDither),
239 CE_INTVAL_P(gpu_peops.dwActFixes),
240 CE_INTVAL(iUseReverb),
242 CE_INTVAL_V(iUseInterpolation, 2),
243 CE_INTVAL_V(iSPUIRQWait, 2),
244 CE_INTVAL(iUseTimer),
245 CE_INTVAL(warned_about_bios),
246 CE_INTVAL(in_evdev_allow_abs_only),
247 CE_INTVAL(volume_boost),
250 static char *get_cd_label(void)
252 static char trimlabel[33];
255 strncpy(trimlabel, CdromLabel, 32);
257 for (j = 31; j >= 0; j--)
258 if (trimlabel[j] == ' ')
264 static void make_cfg_fname(char *buf, size_t size, int is_game)
267 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
269 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
272 static void keys_write_all(FILE *f);
274 static int menu_write_config(int is_game)
276 char cfgfile[MAXPATHLEN];
280 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
281 f = fopen(cfgfile, "w");
283 printf("menu_write_config: failed to open: %s\n", cfgfile);
287 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
288 fprintf(f, "%s = ", config_data[i].name);
289 switch (config_data[i].len) {
291 fprintf(f, "%s\n", (char *)config_data[i].val);
294 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
297 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
300 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
303 printf("menu_write_config: unhandled len %d for %s\n",
304 config_data[i].len, config_data[i].name);
310 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
318 static void parse_str_val(char *cval, const char *src)
321 strncpy(cval, src, MAXPATHLEN);
322 cval[MAXPATHLEN - 1] = 0;
323 tmp = strchr(cval, '\n');
325 tmp = strchr(cval, '\r');
330 static void keys_load_all(const char *cfg);
332 static int menu_load_config(int is_game)
334 char cfgfile[MAXPATHLEN];
340 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
341 f = fopen(cfgfile, "r");
343 printf("menu_load_config: failed to open: %s\n", cfgfile);
347 fseek(f, 0, SEEK_END);
350 printf("bad size %ld: %s\n", size, cfgfile);
354 cfg = malloc(size + 1);
358 fseek(f, 0, SEEK_SET);
359 if (fread(cfg, 1, size, f) != size) {
360 printf("failed to read: %s\n", cfgfile);
365 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
369 tmp = strstr(cfg, config_data[i].name);
372 tmp += strlen(config_data[i].name);
373 if (strncmp(tmp, " = ", 3) != 0)
377 if (config_data[i].len == 0) {
378 parse_str_val(config_data[i].val, tmp);
383 val = strtoul(tmp, &tmp2, 16);
384 if (tmp2 == NULL || tmp == tmp2)
385 continue; // parse failed
387 switch (config_data[i].len) {
389 *(u8 *)config_data[i].val = val;
392 *(u16 *)config_data[i].val = val;
395 *(u32 *)config_data[i].val = val;
398 printf("menu_load_config: unhandled len %d for %s\n",
399 config_data[i].len, config_data[i].name);
405 char *tmp = strstr(cfg, "lastcdimg = ");
408 parse_str_val(last_selected_fname, tmp);
415 for (i = bios_sel = 0; bioses[i] != NULL; i++)
416 if (strcmp(Config.Bios, bioses[i]) == 0)
417 { bios_sel = i; break; }
419 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
420 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
421 { gpu_plugsel = i; break; }
423 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
424 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
425 { spu_plugsel = i; break; }
436 // rrrr rggg gggb bbbb
437 static unsigned short fname2color(const char *fname)
439 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z", ".bz", ".znx", ".pbp" };
440 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub", ".table", ".index", ".sbi" };
441 const char *ext = strrchr(fname, '.');
446 for (i = 0; i < array_size(cdimg_exts); i++)
447 if (strcasecmp(ext, cdimg_exts[i]) == 0)
449 for (i = 0; i < array_size(other_exts); i++)
450 if (strcasecmp(ext, other_exts[i]) == 0)
455 static void draw_savestate_bg(int slot);
457 static const char *filter_exts[] = {
458 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
461 #define MENU_ALIGN_LEFT
462 #define menu_init menu_init_common
463 #include "common/menu.c"
466 // a bit of black magic here
467 static void draw_savestate_bg(int slot)
469 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
471 char fname[MAXPATHLEN];
478 ret = get_state_filename(fname, sizeof(fname), slot);
482 f = gzopen(fname, "rb");
486 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
487 fprintf(stderr, "gzseek failed\n");
492 gpu = malloc(sizeof(*gpu));
498 ret = gzread(f, gpu, sizeof(*gpu));
500 if (ret != sizeof(*gpu)) {
501 fprintf(stderr, "gzread failed\n");
505 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
507 if (gpu->ulStatus & 0x800000)
508 goto out; // disabled
510 x = gpu->ulControl[5] & 0x3ff;
511 y = (gpu->ulControl[5] >> 10) & 0x1ff;
512 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
513 w = psx_widths[(gpu->ulStatus >> 16) & 7];
514 tmp = gpu->ulControl[7];
515 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
516 if (gpu->ulStatus & 0x80000) // doubleheight
519 x = max(0, g_menuscreen_w - w) & ~3;
520 y = max(0, g_menuscreen_h / 2 - h / 2);
521 w = min(g_menuscreen_w, w);
522 h = min(g_menuscreen_h, h);
523 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
525 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
526 if (gpu->ulStatus & 0x200000)
527 bgr888_to_rgb565(d, s, w * 3);
529 bgr555_to_rgb565(d, s, w * 2);
535 // ---------- pandora specific -----------
537 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
538 static char **pnd_filter_list;
540 static int get_cpu_clock(void)
544 f = fopen("/proc/pandora/cpu_mhz_max", "r");
546 fscanf(f, "%d", &ret);
552 static void apply_cpu_clock(void)
556 if (cpu_clock != 0 && cpu_clock != get_cpu_clock()) {
557 snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
558 pnd_script_base, cpu_clock);
563 static void apply_filter(int which)
569 if (pnd_filter_list == NULL || which == old)
572 for (i = 0; i < which; i++)
573 if (pnd_filter_list[i] == NULL)
576 if (pnd_filter_list[i] == NULL)
579 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
584 static void apply_lcdrate(int pal)
592 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
593 pnd_script_base, pal ? 50 : 60);
598 static menu_entry e_menu_gfx_options[];
600 static void pnd_menu_init(void)
608 cpu_clock_st = cpu_clock = get_cpu_clock();
610 dir = opendir("/etc/pandora/conf/dss_fir");
612 perror("filter opendir");
625 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
634 mfilters = calloc(count + 1, sizeof(mfilters[0]));
635 if (mfilters == NULL)
639 for (i = 0; (ent = readdir(dir)); ) {
642 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
645 len = strlen(ent->d_name);
647 // skip pre-HF5 extra files
648 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
650 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
653 // have to cut "_up_h" for pre-HF5
654 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
657 if (len > sizeof(buff) - 1)
660 strncpy(buff, ent->d_name, len);
662 mfilters[i] = strdup(buff);
663 if (mfilters[i] != NULL)
668 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
669 e_menu_gfx_options[i].data = (void *)mfilters;
670 pnd_filter_list = mfilters;
673 void menu_finish(void)
675 cpu_clock = cpu_clock_st;
679 // -------------- key config --------------
681 me_bind_action me_ctrl_actions[] =
683 { "UP ", 1 << DKEY_UP},
684 { "DOWN ", 1 << DKEY_DOWN },
685 { "LEFT ", 1 << DKEY_LEFT },
686 { "RIGHT ", 1 << DKEY_RIGHT },
687 { "TRIANGLE", 1 << DKEY_TRIANGLE },
688 { "CIRCLE ", 1 << DKEY_CIRCLE },
689 { "CROSS ", 1 << DKEY_CROSS },
690 { "SQUARE ", 1 << DKEY_SQUARE },
691 { "L1 ", 1 << DKEY_L1 },
692 { "R1 ", 1 << DKEY_R1 },
693 { "L2 ", 1 << DKEY_L2 },
694 { "R2 ", 1 << DKEY_R2 },
695 { "L3 ", 1 << DKEY_L3 },
696 { "R3 ", 1 << DKEY_R3 },
697 { "START ", 1 << DKEY_START },
698 { "SELECT ", 1 << DKEY_SELECT },
702 me_bind_action emuctrl_actions[] =
704 { "Save State ", 1 << SACTION_SAVE_STATE },
705 { "Load State ", 1 << SACTION_LOAD_STATE },
706 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
707 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
708 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
709 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
710 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
714 static char *mystrip(char *str)
719 for (i = 0; i < len; i++)
720 if (str[i] != ' ') break;
721 if (i > 0) memmove(str, str + i, len - i + 1);
724 for (i = len - 1; i >= 0; i--)
725 if (str[i] != ' ') break;
731 static void get_line(char *d, size_t size, const char *s)
736 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
747 static void keys_write_all(FILE *f)
751 for (d = 0; d < IN_MAX_DEVS; d++)
753 const int *binds = in_get_dev_binds(d);
754 const char *name = in_get_dev_name(d, 0, 0);
757 if (binds == NULL || name == NULL)
760 fprintf(f, "binddev = %s\n", name);
761 in_get_config(d, IN_CFG_BIND_COUNT, &count);
763 for (k = 0; k < count; k++)
768 act[0] = act[31] = 0;
769 name = in_get_key_name(d, k);
771 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
772 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
773 mask = me_ctrl_actions[i].mask;
775 strncpy(act, me_ctrl_actions[i].name, 31);
776 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
779 mask = me_ctrl_actions[i].mask << 16;
781 strncpy(act, me_ctrl_actions[i].name, 31);
782 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
787 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
788 for (i = 0; kbinds && i < ARRAY_SIZE(emuctrl_actions) - 1; i++) {
789 mask = emuctrl_actions[i].mask;
791 strncpy(act, emuctrl_actions[i].name, 31);
792 fprintf(f, "bind %s = %s\n", name, mystrip(act));
800 static int parse_bind_val(const char *val, int *type)
804 *type = IN_BINDTYPE_NONE;
808 if (strncasecmp(val, "player", 6) == 0)
810 int player, shift = 0;
811 player = atoi(val + 6) - 1;
813 if ((unsigned int)player > 1)
818 *type = IN_BINDTYPE_PLAYER12;
819 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
820 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
821 return me_ctrl_actions[i].mask << shift;
824 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
825 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
826 *type = IN_BINDTYPE_EMU;
827 return emuctrl_actions[i].mask;
834 static void keys_load_all(const char *cfg)
836 char dev[256], key[128], *act;
842 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
845 get_line(dev, sizeof(dev), p);
846 dev_id = in_config_parse_dev(dev);
848 printf("input: can't handle dev: %s\n", dev);
852 in_unbind_all(dev_id, -1, -1);
853 while ((p = strstr(p, "bind"))) {
854 if (strncmp(p, "binddev = ", 10) == 0)
859 printf("input: parse error: %16s..\n", p);
863 get_line(key, sizeof(key), p);
864 act = strchr(key, '=');
866 printf("parse failed: %16s..\n", p);
874 bind = parse_bind_val(act, &bindtype);
875 if (bind != -1 && bind != 0) {
876 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
877 in_config_bind_key(dev_id, key, bind, bindtype);
880 lprintf("config: unhandled action \"%s\"\n", act);
886 static int key_config_loop_wrap(int id, int keys)
889 case MA_CTRL_PLAYER1:
890 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
892 case MA_CTRL_PLAYER2:
893 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
896 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
904 static const char *mgn_dev_name(int id, int *offs)
906 const char *name = NULL;
909 if (id == MA_CTRL_DEV_FIRST)
912 for (; it < IN_MAX_DEVS; it++) {
913 name = in_get_dev_name(it, 1, 1);
922 static const char *mgn_saveloadcfg(int id, int *offs)
927 static int mh_savecfg(int id, int keys)
929 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
930 me_update_msg("config saved");
932 me_update_msg("failed to write config");
937 static int mh_input_rescan(int id, int keys)
939 //menu_sync_config();
940 pandora_rescan_inputs();
941 me_update_msg("rescan complete.");
946 static const char *men_in_type_sel[] = { "Standard (SCPH-1080)", "Analog (SCPH-1150)", NULL };
947 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
949 static menu_entry e_menu_keyconfig[] =
951 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
952 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
953 mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
955 mee_enum ("Controller", 0, in_type_sel, men_in_type_sel),
956 mee_onoff_h ("Nubs as buttons", 0, in_evdev_allow_abs_only, 1, h_nub_btns),
957 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
958 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
959 mee_handler ("Rescan devices", mh_input_rescan),
961 mee_label ("Input devices:"),
962 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
963 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
964 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
965 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
966 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
967 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
968 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
972 static int menu_loop_keyconfig(int id, int keys)
976 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
977 me_loop(e_menu_keyconfig, &sel);
981 // ------------ gfx options menu ------------
983 static const char *men_scaler[] = { "1x1", "scaled 4:3", "fullscreen", "custom", NULL };
984 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
985 "using d-pad or move it using R+d-pad";
986 static const char *men_dummy[] = { NULL };
988 static int menu_loop_cscaler(int id, int keys)
992 scaling = SCALE_CUSTOM;
994 omap_enable_layer(1);
999 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1000 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1001 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1004 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1005 if (inp & PBTN_UP) g_layer_y--;
1006 if (inp & PBTN_DOWN) g_layer_y++;
1007 if (inp & PBTN_LEFT) g_layer_x--;
1008 if (inp & PBTN_RIGHT) g_layer_x++;
1009 if (!(inp & PBTN_R)) {
1010 if (inp & PBTN_UP) g_layer_h += 2;
1011 if (inp & PBTN_DOWN) g_layer_h -= 2;
1012 if (inp & PBTN_LEFT) g_layer_w += 2;
1013 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1015 if (inp & (PBTN_MOK|PBTN_MBACK))
1018 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1019 if (g_layer_x < 0) g_layer_x = 0;
1020 if (g_layer_x > 640) g_layer_x = 640;
1021 if (g_layer_y < 0) g_layer_y = 0;
1022 if (g_layer_y > 420) g_layer_y = 420;
1023 if (g_layer_w < 160) g_layer_w = 160;
1024 if (g_layer_h < 60) g_layer_h = 60;
1025 if (g_layer_x + g_layer_w > 800)
1026 g_layer_w = 800 - g_layer_x;
1027 if (g_layer_y + g_layer_h > 480)
1028 g_layer_h = 480 - g_layer_y;
1029 omap_enable_layer(1);
1033 omap_enable_layer(0);
1038 static menu_entry e_menu_gfx_options[] =
1040 mee_enum ("Scaler", 0, scaling, men_scaler),
1041 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1042 // mee_onoff ("Vsync", 0, vsync, 1),
1043 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1047 static int menu_loop_gfx_options(int id, int keys)
1051 me_loop(e_menu_gfx_options, &sel);
1056 // ------------ bios/plugins ------------
1058 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1059 static const char h_gpu_0[] = "Needed for Chrono Cross";
1060 static const char h_gpu_1[] = "Capcom fighting games";
1061 static const char h_gpu_2[] = "Black screens in Lunar";
1062 static const char h_gpu_3[] = "Compatibility mode";
1063 static const char h_gpu_6[] = "Pandemonium 2";
1064 static const char h_gpu_7[] = "Skip every second frame";
1065 static const char h_gpu_8[] = "Needed by Dark Forces";
1066 static const char h_gpu_9[] = "better g-colors, worse textures";
1067 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1069 static menu_entry e_menu_plugin_gpu[] =
1071 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1072 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1073 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1074 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1075 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1076 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1077 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1078 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1079 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1080 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1084 static int menu_loop_plugin_gpu(int id, int keys)
1087 me_loop(e_menu_plugin_gpu, &sel);
1091 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1092 static const char h_spu_volboost[] = "Large values cause distortion";
1093 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1094 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1096 static menu_entry e_menu_plugin_spu[] =
1098 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1099 mee_onoff ("Reverb", 0, iUseReverb, 2),
1100 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1101 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1102 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1103 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1107 static int menu_loop_plugin_spu(int id, int keys)
1110 me_loop(e_menu_plugin_spu, &sel);
1114 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in savestates\n"
1115 "and can't be changed there. Must save config and reload\n"
1116 "the game for change to take effect";
1117 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1118 "for plugin change to take effect";
1119 static const char h_gpu[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1120 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1122 static menu_entry e_menu_plugin_options[] =
1124 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1125 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1126 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1127 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu, h_gpu),
1128 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1132 static menu_entry e_menu_main2[];
1134 static int menu_loop_plugin_options(int id, int keys)
1137 me_loop(e_menu_plugin_options, &sel);
1139 // sync BIOS/plugins
1140 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1141 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1142 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1143 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1148 // ------------ adv options menu ------------
1150 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1151 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1152 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1153 "(green: normal, red: fmod, blue: noise)";
1154 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1155 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1156 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1157 "(proper .cue/.bin dump is needed otherwise)";
1158 static const char h_cfg_sio[] = "You should not need this, breaks games";
1159 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1160 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1161 "(timing hack, breaks other games)";
1162 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1163 "(timing hack, breaks other games)";
1164 static const char h_cfg_cdrr[] = "Compatibility tweak (fixes Team Buddies, maybe more)\n"
1165 "(CD timing hack, breaks FMVs)";
1166 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1167 "Might be useful to overcome some dynarec bugs";
1169 static menu_entry e_menu_adv_options[] =
1171 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1172 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1173 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1174 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1175 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1176 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1177 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1178 mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1179 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1180 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1181 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1185 static int menu_loop_adv_options(int id, int keys)
1188 me_loop(e_menu_adv_options, &sel);
1192 // ------------ options menu ------------
1194 static int mh_restore_defaults(int id, int keys)
1196 menu_set_defconfig();
1197 me_update_msg("defaults restored");
1201 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1203 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1204 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1205 "loading state or both";
1207 static const char h_restore_def[] = "Switches back to default / recommended\n"
1209 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1211 static menu_entry e_menu_options[] =
1213 // mee_range ("Save slot", 0, state_slot, 0, 9),
1214 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1215 mee_onoff_h ("Frameskip", 0, pl_rearmed_cbs.frameskip, 1, h_frameskip),
1216 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1217 mee_enum ("Region", 0, region, men_region),
1218 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1219 mee_handler ("[Display]", menu_loop_gfx_options),
1220 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1221 mee_handler ("[Advanced]", menu_loop_adv_options),
1222 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1223 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1224 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1228 static int menu_loop_options(int id, int keys)
1233 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1234 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1235 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1237 me_loop(e_menu_options, &sel);
1242 // ------------ debug menu ------------
1244 static void draw_frame_debug(GPUFreeze_t *gpuf)
1246 int w = min(g_menuscreen_w, 1024);
1247 int h = min(g_menuscreen_h, 512);
1248 u16 *d = g_menuscreen_ptr;
1249 u16 *s = (u16 *)gpuf->psxVRam;
1253 gpuf->ulFreezeVersion = 1;
1254 if (GPU_freeze != NULL)
1255 GPU_freeze(1, gpuf);
1257 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1258 bgr555_to_rgb565(d, s, w * 2);
1260 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1261 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1262 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1263 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1264 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1267 static void debug_menu_loop(void)
1272 gpuf = malloc(sizeof(*gpuf));
1279 draw_frame_debug(gpuf);
1282 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1283 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1284 if (inp & PBTN_MBACK)
1291 // --------- memcard manager ---------
1293 static void draw_mc_icon(int dx, int dy, const u16 *s)
1298 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1300 for (y = 0; y < 16; y++, s += 16) {
1301 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1302 for (x = 0; x < 16; x++) {
1304 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1305 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1311 static void draw_mc_bg(void)
1313 McdBlock *blocks1, *blocks2;
1317 blocks1 = malloc(15 * sizeof(blocks1[0]));
1318 blocks2 = malloc(15 * sizeof(blocks1[0]));
1319 if (blocks1 == NULL || blocks2 == NULL)
1322 for (i = 0; i < 15; i++) {
1323 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1324 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1329 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1331 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1335 maxicons = g_menuscreen_h / 32;
1338 row2 = g_menuscreen_w / 2;
1339 for (i = 0; i < maxicons; i++) {
1340 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1341 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1343 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1344 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1347 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1355 static void handle_memcard_sel(void)
1358 if (memcard1_sel != 0)
1359 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1361 if (memcard2_sel != 0)
1362 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1363 LoadMcds(Config.Mcd1, Config.Mcd2);
1367 static menu_entry e_memcard_options[] =
1369 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1370 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1374 static int menu_loop_memcards(int id, int keys)
1380 memcard1_sel = memcard2_sel = 0;
1381 p = strrchr(Config.Mcd1, '/');
1383 for (i = 0; memcards[i] != NULL; i++)
1384 if (strcmp(p + 1, memcards[i]) == 0)
1385 { memcard1_sel = i; break; }
1386 p = strrchr(Config.Mcd2, '/');
1388 for (i = 0; memcards[i] != NULL; i++)
1389 if (strcmp(p + 1, memcards[i]) == 0)
1390 { memcard2_sel = i; break; }
1392 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1394 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1399 // --------- main menu help ----------
1401 static void menu_bios_warn(void)
1404 static const char msg[] =
1405 "You don't seem to have copied any BIOS files to\n"
1406 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1407 "While many games work fine with fake (HLE) BIOS,\n"
1408 "others (like MGS and FF8) require BIOS to work.\n"
1409 "After copying the file, you'll also need to\n"
1410 "select it in the emu's options->[BIOS/Plugins]\n\n"
1411 "The file is usually named SCPH1001.BIN, but\n"
1412 "other not compressed files can be used too.\n\n"
1413 "Press (B) or (X) to continue";
1417 draw_menu_message(msg, NULL);
1419 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1420 if (inp & (PBTN_MBACK|PBTN_MOK))
1425 // ------------ main menu ------------
1429 static void draw_frame_main(void)
1431 if (CdromId[0] != 0) {
1433 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1434 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1435 Config.HLE ? "HLE" : "BIOS");
1436 smalltext_out16(4, 1, buff, 0x105f);
1440 static void draw_frame_credits(void)
1442 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1445 static const char credits_text[] =
1447 "(C) 1999-2003 PCSX Team\n"
1448 "(C) 2005-2009 PCSX-df Team\n"
1449 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1450 "GPU and SPU code by Pete Bernert\n"
1451 " and the P.E.Op.S. team\n"
1452 "ARM recompiler (C) 2009-2011 Ari64\n"
1453 "PCSX4ALL plugins by PCSX4ALL team\n"
1454 " Chui, Franxis, Unai\n\n"
1455 "integration, optimization and\n"
1456 " frontend (C) 2010-2011 notaz\n";
1458 static int reset_game(void)
1461 if (bios_sel == 0 && !Config.HLE)
1467 if (CheckCdrom() != -1) {
1473 static int reload_plugins(const char *cdimg)
1475 pl_fbdev_buf = NULL;
1479 set_cd_image(cdimg);
1481 pcnt_hook_plugins();
1483 if (OpenPlugins() == -1) {
1484 me_update_msg("failed to open plugins");
1487 plugin_call_rearmed_cbs();
1490 CdromLabel[0] = '\0';
1495 static int run_bios(void)
1501 if (reload_plugins(NULL) != 0)
1509 static int run_exe(void)
1513 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1518 if (reload_plugins(NULL) != 0)
1522 if (Load(fname) != 0) {
1523 me_update_msg("exe load failed, bad file?");
1532 static int run_cd_image(const char *fname)
1535 reload_plugins(fname);
1537 if (CheckCdrom() == -1) {
1538 // Only check the CD if we are starting the console with a CD
1540 me_update_msg("unsupported/invalid CD image");
1546 // Read main executable directly from CDRom and start it
1547 if (LoadCdrom() == -1) {
1549 me_update_msg("failed to load CD image");
1557 static int romsel_run(void)
1559 int prev_gpu, prev_spu;
1562 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1566 printf("selected file: %s\n", fname);
1568 new_dynarec_clear_full();
1570 if (run_cd_image(fname) != 0)
1573 prev_gpu = gpu_plugsel;
1574 prev_spu = spu_plugsel;
1575 if (menu_load_config(1) != 0)
1576 menu_load_config(0);
1578 // check for plugin changes, have to repeat
1579 // loading if game config changed plugins to reload them
1580 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1581 printf("plugin change detected, reloading plugins..\n");
1582 if (run_cd_image(fname) != 0)
1586 strcpy(last_selected_fname, rom_fname_reload);
1590 static int swap_cd_image(void)
1594 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1598 printf("selected file: %s\n", fname);
1601 CdromLabel[0] = '\0';
1603 set_cd_image(fname);
1604 if (ReloadCdromPlugin() < 0) {
1605 me_update_msg("failed to load cdr plugin");
1608 if (CDR_open() < 0) {
1609 me_update_msg("failed to open cdr plugin");
1613 SetCdOpenCaseTime(time(NULL) + 2);
1616 strcpy(last_selected_fname, rom_fname_reload);
1620 static int main_menu_handler(int id, int keys)
1624 case MA_MAIN_RESUME_GAME:
1628 case MA_MAIN_SAVE_STATE:
1630 return menu_loop_savestate(0);
1632 case MA_MAIN_LOAD_STATE:
1634 return menu_loop_savestate(1);
1636 case MA_MAIN_RESET_GAME:
1637 if (ready_to_go && reset_game() == 0)
1640 case MA_MAIN_LOAD_ROM:
1641 if (romsel_run() == 0)
1644 case MA_MAIN_SWAP_CD:
1645 if (swap_cd_image() == 0)
1648 case MA_MAIN_RUN_BIOS:
1649 if (run_bios() == 0)
1652 case MA_MAIN_RUN_EXE:
1656 case MA_MAIN_CREDITS:
1657 draw_menu_message(credits_text, draw_frame_credits);
1658 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1664 lprintf("%s: something unknown selected\n", __FUNCTION__);
1671 static menu_entry e_menu_main2[] =
1673 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1674 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1675 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1676 mee_handler ("Memcard manager", menu_loop_memcards),
1680 static int main_menu2_handler(int id, int keys)
1684 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1685 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1687 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1690 static const char h_extra[] = "Change CD, manage memcards..\n";
1692 static menu_entry e_menu_main[] =
1696 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1697 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1698 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1699 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1700 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1701 mee_handler ("Options", menu_loop_options),
1702 mee_handler ("Controls", menu_loop_keyconfig),
1703 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1704 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1705 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1709 // ----------------------------
1711 static void menu_leave_emu(void);
1713 void menu_loop(void)
1719 if (bioses[1] == NULL && !warned_about_bios) {
1721 warned_about_bios = 1;
1724 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1725 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1726 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1727 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1729 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1732 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1733 } while (!ready_to_go);
1735 /* wait until menu, ok, back is released */
1736 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1739 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1744 static int qsort_strcmp(const void *p1, const void *p2)
1746 char * const *s1 = (char * const *)p1;
1747 char * const *s2 = (char * const *)p2;
1748 return strcasecmp(*s1, *s2);
1751 static void scan_bios_plugins(void)
1753 char fname[MAXPATHLEN];
1755 int bios_i, gpu_i, spu_i, mc_i;
1760 gpu_plugins[0] = "builtin_gpu";
1761 spu_plugins[0] = "builtin_spu";
1762 memcards[0] = "(none)";
1763 bios_i = gpu_i = spu_i = mc_i = 1;
1765 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1766 dir = opendir(fname);
1768 perror("scan_bios_plugins bios opendir");
1783 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1786 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1787 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1788 printf("bad BIOS file: %s\n", ent->d_name);
1792 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1793 bioses[bios_i++] = strdup(ent->d_name);
1797 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1803 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1804 dir = opendir(fname);
1806 perror("scan_bios_plugins plugins opendir");
1820 p = strstr(ent->d_name, ".so");
1824 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1825 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1827 fprintf(stderr, "%s\n", dlerror());
1831 // now what do we have here?
1832 tmp = dlsym(h, "GPUinit");
1835 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1836 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1840 tmp = dlsym(h, "SPUinit");
1843 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1844 spu_plugins[spu_i++] = strdup(ent->d_name);
1848 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1855 dir = opendir("." MEMCARD_DIR);
1857 perror("scan_bios_plugins memcards opendir");
1872 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1875 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1876 if (stat(fname, &st) != 0) {
1877 printf("bad memcard file: %s\n", ent->d_name);
1881 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1882 memcards[mc_i++] = strdup(ent->d_name);
1886 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1890 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1895 void menu_init(void)
1897 char buff[MAXPATHLEN];
1899 strcpy(last_selected_fname, "/media");
1901 scan_bios_plugins();
1905 menu_set_defconfig();
1906 menu_load_config(0);
1911 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
1912 if (g_menubg_src_ptr == NULL)
1914 emu_make_path(buff, "skin/background.png", sizeof(buff));
1915 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
1918 void menu_notify_mode_change(int w, int h, int bpp)
1924 if (scaling == SCALE_1_1) {
1925 g_layer_x = 800/2 - w/2; g_layer_y = 480/2 - h/2;
1926 g_layer_w = w; g_layer_h = h;
1930 static void menu_leave_emu(void)
1932 if (GPU_close != NULL) {
1933 int ret = GPU_close();
1935 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
1938 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1939 if (pl_fbdev_buf != NULL && ready_to_go && last_psx_bpp == 16) {
1940 int x = max(0, g_menuscreen_w - last_psx_w);
1941 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
1942 int w = min(g_menuscreen_w, last_psx_w);
1943 int h = min(g_menuscreen_h, last_psx_h);
1944 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
1945 u16 *s = pl_fbdev_buf;
1947 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
1948 menu_darken_bg(d, s, w, 0);
1952 cpu_clock = get_cpu_clock();
1954 plat_video_menu_enter(ready_to_go);
1957 void menu_prepare_emu(void)
1959 R3000Acpu *prev_cpu = psxCpu;
1961 plat_video_menu_leave();
1965 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
1968 g_layer_x = 80; g_layer_y = 0;
1969 g_layer_w = 640; g_layer_h = 480;
1971 case SCALE_FULLSCREEN:
1972 g_layer_x = 0; g_layer_y = 0;
1973 g_layer_w = 800; g_layer_h = 480;
1979 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
1980 if (psxCpu != prev_cpu)
1981 // note that this does not really reset, just clears drc caches
1984 // core doesn't care about Config.Cdda changes,
1985 // so handle them manually here
1990 apply_lcdrate(Config.PsxType);
1991 apply_filter(filter);
1994 // push config to GPU plugin
1995 plugin_call_rearmed_cbs();
1997 if (GPU_open != NULL) {
1998 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2000 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2003 dfinput_activate(in_type == PSE_PAD_TYPE_ANALOGPAD);
2006 void me_update_msg(const char *msg)
2008 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2009 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2011 menu_error_time = plat_get_ticks_ms();
2012 lprintf("msg: %s\n", menu_error_msg);