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.
16 #include <sys/types.h>
24 #include "plugin_lib.h"
29 #include "common/plat.h"
30 #include "common/input.h"
31 #include "linux/in_evdev.h"
32 #include "../libpcsxcore/misc.h"
33 #include "../libpcsxcore/cdrom.h"
34 #include "../libpcsxcore/cdriso.h"
35 #include "../libpcsxcore/psemu_plugin_defs.h"
36 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
37 #include "../plugins/dfinput/main.h"
40 #define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
42 #define array_size(x) (sizeof(x) / sizeof(x[0]))
53 MA_MAIN_SWAP_CD_MULTI,
84 static int last_psx_w, last_psx_h, last_psx_bpp;
85 static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
86 static char rom_fname_reload[MAXPATHLEN];
87 static char last_selected_fname[MAXPATHLEN];
88 static int warned_about_bios, region, in_type_sel1, in_type_sel2;
90 static int memcard1_sel, memcard2_sel;
92 int analog_deadzone; // for Caanoo
94 #ifdef __ARM_ARCH_7A__
95 #define DEFAULT_PSX_CLOCK 57
96 #define DEFAULT_PSX_CLOCK_S "57"
98 #define DEFAULT_PSX_CLOCK 50
99 #define DEFAULT_PSX_CLOCK_S "50"
103 extern int iUseReverb;
104 extern int iUseInterpolation;
106 extern int iSPUIRQWait;
107 extern int iUseTimer;
110 static const char *bioses[24];
111 static const char *gpu_plugins[16];
112 static const char *spu_plugins[16];
113 static const char *memcards[32];
114 static int bios_sel, gpu_plugsel, spu_plugsel;
117 static int min(int x, int y) { return x < y ? x : y; }
118 static int max(int x, int y) { return x > y ? x : y; }
120 void emu_make_path(char *buff, const char *end, int size)
124 end_len = strlen(end);
125 pos = plat_get_root_dir(buff, size);
126 strncpy(buff + pos, end, size - pos);
128 if (pos + end_len > size - 1)
129 printf("Warning: path truncated: %s\n", buff);
132 static int emu_check_save_file(int slot, int *time)
134 char fname[MAXPATHLEN];
138 ret = emu_check_state(slot);
139 if (ret != 0 || time == NULL)
140 return ret == 0 ? 1 : 0;
142 ret = get_state_filename(fname, sizeof(fname), slot);
146 ret = stat(fname, &status);
150 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
151 return 1; // probably bad rtc like on some Caanoos
153 *time = status.st_mtime;
158 static int emu_save_load_game(int load, int unused)
163 ret = emu_load_state(state_slot);
165 // reflect hle/bios mode from savestate
168 else if (bios_sel == 0 && bioses[1] != NULL)
169 // XXX: maybe find the right bios instead
173 ret = emu_save_state(state_slot);
178 // propagate menu settings to the emu vars
179 static void menu_sync_config(void)
181 static int allow_abs_only_old;
186 Config.PsxType = region - 1;
188 cycle_multiplier = 10000 / psx_clock;
190 switch (in_type_sel1) {
191 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
192 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
193 default: in_type1 = PSE_PAD_TYPE_STANDARD;
195 switch (in_type_sel2) {
196 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
197 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
198 default: in_type2 = PSE_PAD_TYPE_STANDARD;
200 if (in_evdev_allow_abs_only != allow_abs_only_old) {
202 allow_abs_only_old = in_evdev_allow_abs_only;
205 iVolume = 768 + 128 * volume_boost;
206 pl_rearmed_cbs.frameskip = frameskip - 1;
207 pl_timing_prepare(Config.PsxType);
210 static void menu_set_defconfig(void)
212 emu_set_default_config();
218 analog_deadzone = 50;
219 psx_clock = DEFAULT_PSX_CLOCK;
222 in_type_sel1 = in_type_sel2 = 0;
223 in_evdev_allow_abs_only = 0;
228 #define CE_CONFIG_STR(val) \
229 { #val, 0, Config.val }
231 #define CE_CONFIG_VAL(val) \
232 { #val, sizeof(Config.val), &Config.val }
234 #define CE_STR(val) \
237 #define CE_INTVAL(val) \
238 { #val, sizeof(val), &val }
240 #define CE_INTVAL_P(val) \
241 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
243 // 'versioned' var, used when defaults change
244 #define CE_INTVAL_V(val, ver) \
245 { #val #ver, sizeof(val), &val }
247 #define CE_INTVAL_PV(val, ver) \
248 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
250 static const struct {
258 // CE_CONFIG_STR(Cdr),
263 CE_CONFIG_VAL(Debug),
264 CE_CONFIG_VAL(PsxOut),
265 CE_CONFIG_VAL(SpuIrq),
266 CE_CONFIG_VAL(RCntFix),
267 CE_CONFIG_VAL(VSyncWA),
269 CE_CONFIG_VAL(CdrReschedule),
271 CE_INTVAL_V(scaling, 2),
272 CE_INTVAL(g_layer_x),
273 CE_INTVAL(g_layer_y),
274 CE_INTVAL(g_layer_w),
275 CE_INTVAL(g_layer_h),
277 CE_INTVAL(state_slot),
278 CE_INTVAL(cpu_clock),
280 CE_INTVAL(in_type_sel1),
281 CE_INTVAL(in_type_sel2),
282 CE_INTVAL(analog_deadzone),
283 CE_INTVAL_V(frameskip, 3),
284 CE_INTVAL_P(gpu_peops.iUseDither),
285 CE_INTVAL_P(gpu_peops.dwActFixes),
286 CE_INTVAL_P(gpu_unai.lineskip),
287 CE_INTVAL_P(gpu_unai.abe_hack),
288 CE_INTVAL_P(gpu_unai.no_light),
289 CE_INTVAL_P(gpu_unai.no_blend),
290 CE_INTVAL_V(iUseReverb, 3),
291 CE_INTVAL_V(iXAPitch, 3),
292 CE_INTVAL_V(iUseInterpolation, 3),
293 CE_INTVAL_V(iSPUIRQWait, 3),
294 CE_INTVAL_V(iUseTimer, 3),
295 CE_INTVAL(warned_about_bios),
296 CE_INTVAL(in_evdev_allow_abs_only),
297 CE_INTVAL(volume_boost),
298 CE_INTVAL(psx_clock),
299 CE_INTVAL(new_dynarec_hacks),
300 CE_INTVAL(in_enable_vibration),
303 static char *get_cd_label(void)
305 static char trimlabel[33];
308 strncpy(trimlabel, CdromLabel, 32);
310 for (j = 31; j >= 0; j--)
311 if (trimlabel[j] == ' ')
317 static void make_cfg_fname(char *buf, size_t size, int is_game)
320 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
322 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
325 static void keys_write_all(FILE *f);
327 static int menu_write_config(int is_game)
329 char cfgfile[MAXPATHLEN];
333 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
334 f = fopen(cfgfile, "w");
336 printf("menu_write_config: failed to open: %s\n", cfgfile);
340 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
341 fprintf(f, "%s = ", config_data[i].name);
342 switch (config_data[i].len) {
344 fprintf(f, "%s\n", (char *)config_data[i].val);
347 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
350 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
353 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
356 printf("menu_write_config: unhandled len %d for %s\n",
357 config_data[i].len, config_data[i].name);
363 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
371 static void parse_str_val(char *cval, const char *src)
374 strncpy(cval, src, MAXPATHLEN);
375 cval[MAXPATHLEN - 1] = 0;
376 tmp = strchr(cval, '\n');
378 tmp = strchr(cval, '\r');
383 static void keys_load_all(const char *cfg);
385 static int menu_load_config(int is_game)
387 char cfgfile[MAXPATHLEN];
393 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
394 f = fopen(cfgfile, "r");
396 printf("menu_load_config: failed to open: %s\n", cfgfile);
400 fseek(f, 0, SEEK_END);
403 printf("bad size %ld: %s\n", size, cfgfile);
407 cfg = malloc(size + 1);
411 fseek(f, 0, SEEK_SET);
412 if (fread(cfg, 1, size, f) != size) {
413 printf("failed to read: %s\n", cfgfile);
418 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
422 tmp = strstr(cfg, config_data[i].name);
425 tmp += strlen(config_data[i].name);
426 if (strncmp(tmp, " = ", 3) != 0)
430 if (config_data[i].len == 0) {
431 parse_str_val(config_data[i].val, tmp);
436 val = strtoul(tmp, &tmp2, 16);
437 if (tmp2 == NULL || tmp == tmp2)
438 continue; // parse failed
440 switch (config_data[i].len) {
442 *(u8 *)config_data[i].val = val;
445 *(u16 *)config_data[i].val = val;
448 *(u32 *)config_data[i].val = val;
451 printf("menu_load_config: unhandled len %d for %s\n",
452 config_data[i].len, config_data[i].name);
458 char *tmp = strstr(cfg, "lastcdimg = ");
461 parse_str_val(last_selected_fname, tmp);
476 for (i = bios_sel = 0; bioses[i] != NULL; i++)
477 if (strcmp(Config.Bios, bioses[i]) == 0)
478 { bios_sel = i; break; }
480 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
481 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
482 { gpu_plugsel = i; break; }
484 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
485 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
486 { spu_plugsel = i; break; }
491 // rrrr rggg gggb bbbb
492 static unsigned short fname2color(const char *fname)
494 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
495 ".bz", ".znx", ".pbp", ".cbn" };
496 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
497 ".table", ".index", ".sbi" };
498 const char *ext = strrchr(fname, '.');
503 for (i = 0; i < array_size(cdimg_exts); i++)
504 if (strcasecmp(ext, cdimg_exts[i]) == 0)
506 for (i = 0; i < array_size(other_exts); i++)
507 if (strcasecmp(ext, other_exts[i]) == 0)
512 static void draw_savestate_bg(int slot);
514 static const char *filter_exts[] = {
515 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
518 #define MENU_ALIGN_LEFT
519 #ifdef __ARM_ARCH_7A__ // assume hires device
525 #define menu_init menu_init_common
526 #include "common/menu.c"
529 // a bit of black magic here
530 static void draw_savestate_bg(int slot)
532 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
534 char fname[MAXPATHLEN];
541 ret = get_state_filename(fname, sizeof(fname), slot);
545 f = gzopen(fname, "rb");
549 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
550 fprintf(stderr, "gzseek failed\n");
555 gpu = malloc(sizeof(*gpu));
561 ret = gzread(f, gpu, sizeof(*gpu));
563 if (ret != sizeof(*gpu)) {
564 fprintf(stderr, "gzread failed\n");
568 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
570 if (gpu->ulStatus & 0x800000)
571 goto out; // disabled
573 x = gpu->ulControl[5] & 0x3ff;
574 y = (gpu->ulControl[5] >> 10) & 0x1ff;
575 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
576 w = psx_widths[(gpu->ulStatus >> 16) & 7];
577 tmp = gpu->ulControl[7];
578 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
579 if (gpu->ulStatus & 0x80000) // doubleheight
582 x = max(0, g_menuscreen_w - w) & ~3;
583 y = max(0, g_menuscreen_h / 2 - h / 2);
584 w = min(g_menuscreen_w, w);
585 h = min(g_menuscreen_h, h);
586 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
588 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
589 if (gpu->ulStatus & 0x200000)
590 bgr888_to_rgb565(d, s, w * 3);
592 bgr555_to_rgb565(d, s, w * 2);
593 #ifndef __ARM_ARCH_7A__
594 // better darken this on small screens
595 menu_darken_bg(d, d, w * 2, 0);
603 // ---------- XXX: pandora specific -----------
605 static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
606 static char **pnd_filter_list;
608 static void apply_filter(int which)
614 if (pnd_filter_list == NULL || which == old)
617 for (i = 0; i < which; i++)
618 if (pnd_filter_list[i] == NULL)
621 if (pnd_filter_list[i] == NULL)
624 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
629 static void apply_lcdrate(int pal)
637 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
638 pnd_script_base, pal ? 50 : 60);
643 static menu_entry e_menu_gfx_options[];
645 static void pnd_menu_init(void)
653 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
655 dir = opendir("/etc/pandora/conf/dss_fir");
657 perror("filter opendir");
670 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
679 mfilters = calloc(count + 1, sizeof(mfilters[0]));
680 if (mfilters == NULL)
684 for (i = 0; (ent = readdir(dir)); ) {
687 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
690 len = strlen(ent->d_name);
692 // skip pre-HF5 extra files
693 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
695 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
698 // have to cut "_up_h" for pre-HF5
699 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
702 if (len > sizeof(buff) - 1)
705 strncpy(buff, ent->d_name, len);
707 mfilters[i] = strdup(buff);
708 if (mfilters[i] != NULL)
713 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
714 e_menu_gfx_options[i].data = (void *)mfilters;
715 pnd_filter_list = mfilters;
718 void menu_finish(void)
720 plat_cpu_clock_apply(cpu_clock_st);
723 // -------------- key config --------------
725 me_bind_action me_ctrl_actions[] =
727 { "UP ", 1 << DKEY_UP},
728 { "DOWN ", 1 << DKEY_DOWN },
729 { "LEFT ", 1 << DKEY_LEFT },
730 { "RIGHT ", 1 << DKEY_RIGHT },
731 { "TRIANGLE", 1 << DKEY_TRIANGLE },
732 { "CIRCLE ", 1 << DKEY_CIRCLE },
733 { "CROSS ", 1 << DKEY_CROSS },
734 { "SQUARE ", 1 << DKEY_SQUARE },
735 { "L1 ", 1 << DKEY_L1 },
736 { "R1 ", 1 << DKEY_R1 },
737 { "L2 ", 1 << DKEY_L2 },
738 { "R2 ", 1 << DKEY_R2 },
739 { "L3 ", 1 << DKEY_L3 },
740 { "R3 ", 1 << DKEY_R3 },
741 { "START ", 1 << DKEY_START },
742 { "SELECT ", 1 << DKEY_SELECT },
746 me_bind_action emuctrl_actions[] =
748 { "Save State ", 1 << SACTION_SAVE_STATE },
749 { "Load State ", 1 << SACTION_LOAD_STATE },
750 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
751 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
752 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
753 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
754 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
755 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
756 { "Gun A button ", 1 << SACTION_GUN_A },
757 { "Gun B button ", 1 << SACTION_GUN_B },
758 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
759 #ifndef __ARM_ARCH_7A__ /* XXX */
760 { "Volume Up ", 1 << SACTION_VOLUME_UP },
761 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
766 static char *mystrip(char *str)
771 for (i = 0; i < len; i++)
772 if (str[i] != ' ') break;
773 if (i > 0) memmove(str, str + i, len - i + 1);
776 for (i = len - 1; i >= 0; i--)
777 if (str[i] != ' ') break;
783 static void get_line(char *d, size_t size, const char *s)
788 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
799 static void keys_write_all(FILE *f)
803 for (d = 0; d < IN_MAX_DEVS; d++)
805 const int *binds = in_get_dev_binds(d);
806 const char *name = in_get_dev_name(d, 0, 0);
809 if (binds == NULL || name == NULL)
812 fprintf(f, "binddev = %s\n", name);
813 in_get_config(d, IN_CFG_BIND_COUNT, &count);
815 for (k = 0; k < count; k++)
820 act[0] = act[31] = 0;
821 name = in_get_key_name(d, k);
823 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
824 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
825 mask = me_ctrl_actions[i].mask;
827 strncpy(act, me_ctrl_actions[i].name, 31);
828 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
831 mask = me_ctrl_actions[i].mask << 16;
833 strncpy(act, me_ctrl_actions[i].name, 31);
834 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
839 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
840 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
841 mask = emuctrl_actions[i].mask;
843 strncpy(act, emuctrl_actions[i].name, 31);
844 fprintf(f, "bind %s = %s\n", name, mystrip(act));
850 for (k = 0; k < array_size(in_adev); k++)
853 fprintf(f, "bind_analog = %d\n", k);
858 static int parse_bind_val(const char *val, int *type)
862 *type = IN_BINDTYPE_NONE;
866 if (strncasecmp(val, "player", 6) == 0)
868 int player, shift = 0;
869 player = atoi(val + 6) - 1;
871 if ((unsigned int)player > 1)
876 *type = IN_BINDTYPE_PLAYER12;
877 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
878 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
879 return me_ctrl_actions[i].mask << shift;
882 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
883 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
884 *type = IN_BINDTYPE_EMU;
885 return emuctrl_actions[i].mask;
892 static void keys_load_all(const char *cfg)
894 char dev[256], key[128], *act;
900 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
903 get_line(dev, sizeof(dev), p);
904 dev_id = in_config_parse_dev(dev);
906 printf("input: can't handle dev: %s\n", dev);
910 in_unbind_all(dev_id, -1, -1);
911 while ((p = strstr(p, "bind"))) {
912 if (strncmp(p, "binddev = ", 10) == 0)
915 if (strncmp(p, "bind_analog", 11) == 0) {
916 ret = sscanf(p, "bind_analog = %d", &bind);
919 printf("input: parse error: %16s..\n", p);
922 if ((unsigned int)bind >= array_size(in_adev)) {
923 printf("input: analog id %d out of range\n", bind);
926 in_adev[bind] = dev_id;
932 printf("input: parse error: %16s..\n", p);
936 get_line(key, sizeof(key), p);
937 act = strchr(key, '=');
939 printf("parse failed: %16s..\n", p);
947 bind = parse_bind_val(act, &bindtype);
948 if (bind != -1 && bind != 0) {
949 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
950 in_config_bind_key(dev_id, key, bind, bindtype);
953 lprintf("config: unhandled action \"%s\"\n", act);
959 static int key_config_loop_wrap(int id, int keys)
962 case MA_CTRL_PLAYER1:
963 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
965 case MA_CTRL_PLAYER2:
966 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
969 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
977 static const char *adevnames[IN_MAX_DEVS + 2];
978 static int stick_sel[2];
980 static menu_entry e_menu_keyconfig_analog[] =
982 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
983 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
984 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
985 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
986 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
987 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
991 static int key_config_analog(int id, int keys)
993 int i, d, count, sel = 0;
994 int sel2dev_map[IN_MAX_DEVS];
996 memset(adevnames, 0, sizeof(adevnames));
997 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
998 memset(stick_sel, 0, sizeof(stick_sel));
1000 adevnames[0] = "None";
1002 for (d = 0; d < IN_MAX_DEVS; d++)
1004 const char *name = in_get_dev_name(d, 0, 1);
1009 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1013 if (in_adev[0] == d) stick_sel[0] = i;
1014 if (in_adev[1] == d) stick_sel[1] = i;
1016 adevnames[i++] = name;
1018 adevnames[i] = NULL;
1020 me_loop(e_menu_keyconfig_analog, &sel);
1022 in_adev[0] = sel2dev_map[stick_sel[0]];
1023 in_adev[1] = sel2dev_map[stick_sel[1]];
1028 static const char *mgn_dev_name(int id, int *offs)
1030 const char *name = NULL;
1033 if (id == MA_CTRL_DEV_FIRST)
1036 for (; it < IN_MAX_DEVS; it++) {
1037 name = in_get_dev_name(it, 1, 1);
1046 static const char *mgn_saveloadcfg(int id, int *offs)
1051 static int mh_savecfg(int id, int keys)
1053 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1054 me_update_msg("config saved");
1056 me_update_msg("failed to write config");
1061 static int mh_input_rescan(int id, int keys)
1063 //menu_sync_config();
1065 me_update_msg("rescan complete.");
1070 static const char *men_in_type_sel[] = {
1071 "Standard (SCPH-1080)",
1072 "Analog (SCPH-1150)",
1076 static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
1077 static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1078 static const char h_vibration[]= "Must select analog above and enable this ingame too.";
1080 static menu_entry e_menu_keyconfig[] =
1082 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1083 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1084 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
1085 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
1087 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1088 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
1089 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
1090 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
1091 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
1092 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
1093 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1094 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1095 mee_handler ("Rescan devices:", mh_input_rescan),
1097 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1098 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1099 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1100 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1101 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1102 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1103 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
1107 static int menu_loop_keyconfig(int id, int keys)
1111 // me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1112 me_loop(e_menu_keyconfig, &sel);
1116 // ------------ gfx options menu ------------
1118 static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
1119 static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1120 "using d-pad or move it using R+d-pad";
1121 static const char *men_dummy[] = { NULL };
1123 static int menu_loop_cscaler(int id, int keys)
1127 scaling = SCALE_CUSTOM;
1129 omap_enable_layer(1);
1134 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1135 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1136 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
1139 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1140 if (inp & PBTN_UP) g_layer_y--;
1141 if (inp & PBTN_DOWN) g_layer_y++;
1142 if (inp & PBTN_LEFT) g_layer_x--;
1143 if (inp & PBTN_RIGHT) g_layer_x++;
1144 if (!(inp & PBTN_R)) {
1145 if (inp & PBTN_UP) g_layer_h += 2;
1146 if (inp & PBTN_DOWN) g_layer_h -= 2;
1147 if (inp & PBTN_LEFT) g_layer_w += 2;
1148 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1150 if (inp & (PBTN_MOK|PBTN_MBACK))
1153 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1154 if (g_layer_x < 0) g_layer_x = 0;
1155 if (g_layer_x > 640) g_layer_x = 640;
1156 if (g_layer_y < 0) g_layer_y = 0;
1157 if (g_layer_y > 420) g_layer_y = 420;
1158 if (g_layer_w < 160) g_layer_w = 160;
1159 if (g_layer_h < 60) g_layer_h = 60;
1160 if (g_layer_x + g_layer_w > 800)
1161 g_layer_w = 800 - g_layer_x;
1162 if (g_layer_y + g_layer_h > 480)
1163 g_layer_h = 480 - g_layer_y;
1164 omap_enable_layer(1);
1168 omap_enable_layer(0);
1173 static menu_entry e_menu_gfx_options[] =
1175 mee_enum ("Scaler", 0, scaling, men_scaler),
1176 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1177 // mee_onoff ("Vsync", 0, vsync, 1),
1178 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
1182 static int menu_loop_gfx_options(int id, int keys)
1186 me_loop(e_menu_gfx_options, &sel);
1191 // ------------ bios/plugins ------------
1193 static menu_entry e_menu_plugin_gpu_unai[] =
1195 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
1196 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1197 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1198 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1202 static int menu_loop_plugin_gpu_unai(int id, int keys)
1205 me_loop(e_menu_plugin_gpu_unai, &sel);
1209 static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
1210 static const char h_gpu_0[] = "Needed for Chrono Cross";
1211 static const char h_gpu_1[] = "Capcom fighting games";
1212 static const char h_gpu_2[] = "Black screens in Lunar";
1213 static const char h_gpu_3[] = "Compatibility mode";
1214 static const char h_gpu_6[] = "Pandemonium 2";
1215 static const char h_gpu_7[] = "Skip every second frame";
1216 static const char h_gpu_8[] = "Needed by Dark Forces";
1217 static const char h_gpu_9[] = "better g-colors, worse textures";
1218 static const char h_gpu_10[] = "Toggle busy flags after drawing";
1220 static menu_entry e_menu_plugin_gpu_peops[] =
1222 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1223 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1224 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1225 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1226 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1227 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1228 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1229 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1230 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1231 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
1235 static int menu_loop_plugin_gpu_peops(int id, int keys)
1238 me_loop(e_menu_plugin_gpu_peops, &sel);
1242 static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
1243 static const char h_spu_volboost[] = "Large values cause distortion";
1244 static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1245 static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
1247 static menu_entry e_menu_plugin_spu[] =
1249 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
1250 mee_onoff ("Reverb", 0, iUseReverb, 2),
1251 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1252 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1253 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1254 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
1258 static int menu_loop_plugin_spu(int id, int keys)
1261 me_loop(e_menu_plugin_spu, &sel);
1265 static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1266 "savestates and can't be changed there. Must save\n"
1267 "config and reload the game for change to take effect";
1268 static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1269 "for plugin change to take effect";
1270 static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1271 static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
1272 static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
1274 static menu_entry e_menu_plugin_options[] =
1276 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
1277 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1278 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
1279 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1280 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1281 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1285 static menu_entry e_menu_main2[];
1287 static int menu_loop_plugin_options(int id, int keys)
1290 me_loop(e_menu_plugin_options, &sel);
1292 // sync BIOS/plugins
1293 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
1294 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1295 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
1296 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1301 // ------------ adv options menu ------------
1303 static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
1304 static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
1305 static const char h_cfg_gteunn[] = "May cause graphical glitches";
1306 static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1308 static menu_entry e_menu_speed_hacks[] =
1310 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1311 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1312 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1313 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1317 static int menu_loop_speed_hacks(int id, int keys)
1320 me_loop(e_menu_speed_hacks, &sel);
1324 static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
1325 static const char h_cfg_cpul[] = "Shows CPU usage in %";
1326 static const char h_cfg_spu[] = "Shows active SPU channels\n"
1327 "(green: normal, red: fmod, blue: noise)";
1328 static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
1329 static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1330 static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1331 "(proper .cue/.bin dump is needed otherwise)";
1332 static const char h_cfg_sio[] = "You should not need this, breaks games";
1333 static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1334 static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1335 "(timing hack, breaks other games)";
1336 static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1337 "(timing hack, breaks other games)";
1338 static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
1339 static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1340 "Might be useful to overcome some dynarec bugs";
1341 static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1342 "must reload game for any change to take effect";
1344 static menu_entry e_menu_adv_options[] =
1346 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
1347 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
1348 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
1349 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1350 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1351 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1352 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
1353 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
1354 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
1355 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
1356 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
1357 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
1361 static int menu_loop_adv_options(int id, int keys)
1364 me_loop(e_menu_adv_options, &sel);
1368 // ------------ options menu ------------
1370 static int mh_restore_defaults(int id, int keys)
1372 menu_set_defconfig();
1373 me_update_msg("defaults restored");
1377 static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
1378 static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
1380 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1381 static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1382 "loading state or both";
1384 static const char h_restore_def[] = "Switches back to default / recommended\n"
1386 static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
1388 static menu_entry e_menu_options[] =
1390 // mee_range ("Save slot", 0, state_slot, 0, 9),
1391 // mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
1392 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
1393 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
1394 mee_enum ("Region", 0, region, men_region),
1395 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
1396 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
1397 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
1398 mee_handler ("[Advanced]", menu_loop_adv_options),
1399 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1400 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1401 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
1405 static int menu_loop_options(int id, int keys)
1410 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
1411 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
1412 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
1414 me_loop(e_menu_options, &sel);
1419 // ------------ debug menu ------------
1421 static void draw_frame_debug(GPUFreeze_t *gpuf)
1423 int w = min(g_menuscreen_w, 1024);
1424 int h = min(g_menuscreen_h, 512);
1425 u16 *d = g_menuscreen_ptr;
1426 u16 *s = (u16 *)gpuf->psxVRam;
1430 gpuf->ulFreezeVersion = 1;
1431 if (GPU_freeze != NULL)
1432 GPU_freeze(1, gpuf);
1434 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1435 bgr555_to_rgb565(d, s, w * 2);
1437 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1438 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1439 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1440 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1441 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1444 static void debug_menu_loop(void)
1449 gpuf = malloc(sizeof(*gpuf));
1456 draw_frame_debug(gpuf);
1459 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1460 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1461 if (inp & PBTN_MBACK)
1468 // --------- memcard manager ---------
1470 static void draw_mc_icon(int dx, int dy, const u16 *s)
1475 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1477 for (y = 0; y < 16; y++, s += 16) {
1478 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1479 for (x = 0; x < 16; x++) {
1481 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1482 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1488 static void draw_mc_bg(void)
1490 McdBlock *blocks1, *blocks2;
1494 blocks1 = malloc(15 * sizeof(blocks1[0]));
1495 blocks2 = malloc(15 * sizeof(blocks1[0]));
1496 if (blocks1 == NULL || blocks2 == NULL)
1499 for (i = 0; i < 15; i++) {
1500 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1501 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1506 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1508 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1512 maxicons = g_menuscreen_h / 32;
1515 row2 = g_menuscreen_w / 2;
1516 for (i = 0; i < maxicons; i++) {
1517 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1518 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1520 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1521 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1524 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1532 static void handle_memcard_sel(void)
1535 if (memcard1_sel != 0)
1536 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1538 if (memcard2_sel != 0)
1539 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1540 LoadMcds(Config.Mcd1, Config.Mcd2);
1544 static menu_entry e_memcard_options[] =
1546 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1547 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1551 static int menu_loop_memcards(int id, int keys)
1557 memcard1_sel = memcard2_sel = 0;
1558 p = strrchr(Config.Mcd1, '/');
1560 for (i = 0; memcards[i] != NULL; i++)
1561 if (strcmp(p + 1, memcards[i]) == 0)
1562 { memcard1_sel = i; break; }
1563 p = strrchr(Config.Mcd2, '/');
1565 for (i = 0; memcards[i] != NULL; i++)
1566 if (strcmp(p + 1, memcards[i]) == 0)
1567 { memcard2_sel = i; break; }
1569 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1571 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1576 // --------- main menu help ----------
1578 static void menu_bios_warn(void)
1581 static const char msg[] =
1582 "You don't seem to have copied any BIOS\n"
1584 #ifdef __ARM_ARCH_7A__ // XXX
1585 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
1587 "pcsx_rearmed/bios/\n\n"
1589 "While many games work fine with fake\n"
1590 "(HLE) BIOS, others (like MGS and FF8)\n"
1591 "require BIOS to work.\n"
1592 "After copying the file, you'll also need\n"
1593 "to select it in the emu's menu:\n"
1594 "options->[BIOS/Plugins]\n\n"
1595 "The file is usually named SCPH1001.BIN,\n"
1596 "but other not compressed files can be\n"
1598 "Press (B) or (X) to continue";
1602 draw_menu_message(msg, NULL);
1604 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1605 if (inp & (PBTN_MBACK|PBTN_MOK))
1610 // ------------ main menu ------------
1614 static void draw_frame_main(void)
1621 if (CdromId[0] != 0) {
1622 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1623 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1624 Config.HLE ? "HLE" : "BIOS");
1625 smalltext_out16(4, 1, buff, 0x105f);
1630 tmp = localtime(<ime);
1631 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
1632 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
1633 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1637 static void draw_frame_credits(void)
1639 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1642 static const char credits_text[] =
1644 "(C) 1999-2003 PCSX Team\n"
1645 "(C) 2005-2009 PCSX-df Team\n"
1646 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1647 "GPU and SPU code by Pete Bernert\n"
1648 " and the P.E.Op.S. team\n"
1649 "ARM recompiler (C) 2009-2011 Ari64\n"
1650 "PCSX4ALL plugins by PCSX4ALL team\n"
1651 " Chui, Franxis, Unai\n\n"
1652 "integration, optimization and\n"
1653 " frontend (C) 2010-2011 notaz\n";
1655 static int reset_game(void)
1658 if (bios_sel == 0 && !Config.HLE)
1664 if (CheckCdrom() != -1) {
1670 static int reload_plugins(const char *cdimg)
1676 set_cd_image(cdimg);
1678 pcnt_hook_plugins();
1680 if (OpenPlugins() == -1) {
1681 me_update_msg("failed to open plugins");
1684 plugin_call_rearmed_cbs();
1686 cdrIsoMultidiskCount = 1;
1688 CdromLabel[0] = '\0';
1693 static int run_bios(void)
1699 if (reload_plugins(NULL) != 0)
1707 static int run_exe(void)
1711 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1716 if (reload_plugins(NULL) != 0)
1720 if (Load(fname) != 0) {
1721 me_update_msg("exe load failed, bad file?");
1730 static int run_cd_image(const char *fname)
1733 reload_plugins(fname);
1735 // always autodetect, menu_sync_config will override as needed
1738 if (CheckCdrom() == -1) {
1739 // Only check the CD if we are starting the console with a CD
1741 me_update_msg("unsupported/invalid CD image");
1747 // Read main executable directly from CDRom and start it
1748 if (LoadCdrom() == -1) {
1750 me_update_msg("failed to load CD image");
1755 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1760 static int romsel_run(void)
1762 int prev_gpu, prev_spu;
1765 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1769 printf("selected file: %s\n", fname);
1771 new_dynarec_clear_full();
1773 if (run_cd_image(fname) != 0)
1776 prev_gpu = gpu_plugsel;
1777 prev_spu = spu_plugsel;
1778 if (menu_load_config(1) != 0)
1779 menu_load_config(0);
1781 // check for plugin changes, have to repeat
1782 // loading if game config changed plugins to reload them
1783 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1784 printf("plugin change detected, reloading plugins..\n");
1785 if (run_cd_image(fname) != 0)
1790 printf("note: running without BIOS, expect compatibility problems\n");
1792 strcpy(last_selected_fname, rom_fname_reload);
1796 static int swap_cd_image(void)
1800 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1804 printf("selected file: %s\n", fname);
1807 CdromLabel[0] = '\0';
1809 set_cd_image(fname);
1810 if (ReloadCdromPlugin() < 0) {
1811 me_update_msg("failed to load cdr plugin");
1814 if (CDR_open() < 0) {
1815 me_update_msg("failed to open cdr plugin");
1819 SetCdOpenCaseTime(time(NULL) + 2);
1822 strcpy(last_selected_fname, rom_fname_reload);
1826 static int swap_cd_multidisk(void)
1828 cdrIsoMultidiskSelect++;
1830 CdromLabel[0] = '\0';
1833 if (CDR_open() < 0) {
1834 me_update_msg("failed to open cdr plugin");
1838 SetCdOpenCaseTime(time(NULL) + 2);
1844 static int main_menu_handler(int id, int keys)
1848 case MA_MAIN_RESUME_GAME:
1852 case MA_MAIN_SAVE_STATE:
1854 return menu_loop_savestate(0);
1856 case MA_MAIN_LOAD_STATE:
1858 return menu_loop_savestate(1);
1860 case MA_MAIN_RESET_GAME:
1861 if (ready_to_go && reset_game() == 0)
1864 case MA_MAIN_LOAD_ROM:
1865 if (romsel_run() == 0)
1868 case MA_MAIN_SWAP_CD:
1869 if (swap_cd_image() == 0)
1872 case MA_MAIN_SWAP_CD_MULTI:
1873 if (swap_cd_multidisk() == 0)
1876 case MA_MAIN_RUN_BIOS:
1877 if (run_bios() == 0)
1880 case MA_MAIN_RUN_EXE:
1884 case MA_MAIN_CREDITS:
1885 draw_menu_message(credits_text, draw_frame_credits);
1886 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1892 lprintf("%s: something unknown selected\n", __FUNCTION__);
1899 static menu_entry e_menu_main2[] =
1901 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1902 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1903 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1904 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1905 mee_handler ("Memcard manager", menu_loop_memcards),
1909 static int main_menu2_handler(int id, int keys)
1913 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1914 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
1915 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1917 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1920 static const char h_extra[] = "Change CD, manage memcards..\n";
1922 static menu_entry e_menu_main[] =
1926 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1927 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1928 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1929 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1930 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1931 mee_handler ("Options", menu_loop_options),
1932 mee_handler ("Controls", menu_loop_keyconfig),
1933 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
1934 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1935 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1939 // ----------------------------
1941 static void menu_leave_emu(void);
1943 void menu_loop(void)
1949 if (bioses[1] == NULL && !warned_about_bios) {
1951 warned_about_bios = 1;
1954 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
1955 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1956 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
1957 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1959 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1962 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
1963 } while (!ready_to_go);
1965 /* wait until menu, ok, back is released */
1966 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1969 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1974 static int qsort_strcmp(const void *p1, const void *p2)
1976 char * const *s1 = (char * const *)p1;
1977 char * const *s2 = (char * const *)p2;
1978 return strcasecmp(*s1, *s2);
1981 static void scan_bios_plugins(void)
1983 char fname[MAXPATHLEN];
1985 int bios_i, gpu_i, spu_i, mc_i;
1990 gpu_plugins[0] = "builtin_gpu";
1991 spu_plugins[0] = "builtin_spu";
1992 memcards[0] = "(none)";
1993 bios_i = gpu_i = spu_i = mc_i = 1;
1995 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1996 dir = opendir(fname);
1998 perror("scan_bios_plugins bios opendir");
2013 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2016 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2017 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2018 printf("bad BIOS file: %s\n", ent->d_name);
2022 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2023 bioses[bios_i++] = strdup(ent->d_name);
2027 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2033 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2034 dir = opendir(fname);
2036 perror("scan_bios_plugins plugins opendir");
2050 p = strstr(ent->d_name, ".so");
2054 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2055 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2057 fprintf(stderr, "%s\n", dlerror());
2061 // now what do we have here?
2062 tmp = dlsym(h, "GPUinit");
2065 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2066 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2070 tmp = dlsym(h, "SPUinit");
2073 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2074 spu_plugins[spu_i++] = strdup(ent->d_name);
2078 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2085 dir = opendir("." MEMCARD_DIR);
2087 perror("scan_bios_plugins memcards opendir");
2102 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2105 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2106 if (stat(fname, &st) != 0) {
2107 printf("bad memcard file: %s\n", ent->d_name);
2111 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2112 memcards[mc_i++] = strdup(ent->d_name);
2116 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2120 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2125 void menu_init(void)
2127 char buff[MAXPATHLEN];
2129 strcpy(last_selected_fname, "/media");
2131 scan_bios_plugins();
2135 menu_set_defconfig();
2136 menu_load_config(0);
2141 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2142 if (g_menubg_src_ptr == NULL)
2144 emu_make_path(buff, "skin/background.png", sizeof(buff));
2145 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
2147 #ifndef __ARM_ARCH_7A__ /* XXX */
2148 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2149 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2151 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
2152 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2156 void menu_notify_mode_change(int w, int h, int bpp)
2167 g_layer_w = w; g_layer_h = h;
2171 if (h > g_menuscreen_h || (240 < h && h <= 360))
2172 goto fractional_4_3;
2174 // 4:3 that prefers integer scaling
2175 imult = g_menuscreen_h / h;
2176 g_layer_w = w * imult;
2177 g_layer_h = h * imult;
2178 mult = (float)g_layer_w / (float)g_layer_h;
2179 if (mult < 1.25f || mult > 1.666f)
2180 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2181 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2186 mult = 240.0f / (float)h * 4.0f / 3.0f;
2189 g_layer_w = mult * (float)g_menuscreen_h;
2190 g_layer_h = g_menuscreen_h;
2191 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2194 case SCALE_FULLSCREEN:
2195 g_layer_w = g_menuscreen_w;
2196 g_layer_h = g_menuscreen_h;
2203 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2204 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2205 if (g_layer_x < 0) g_layer_x = 0;
2206 if (g_layer_y < 0) g_layer_y = 0;
2207 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2208 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
2211 static void menu_leave_emu(void)
2213 if (GPU_close != NULL) {
2214 int ret = GPU_close();
2216 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2219 plat_video_menu_enter(ready_to_go);
2221 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
2222 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
2223 int x = max(0, g_menuscreen_w - last_psx_w);
2224 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2225 int w = min(g_menuscreen_w, last_psx_w);
2226 int h = min(g_menuscreen_h, last_psx_h);
2227 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
2228 u16 *s = pl_vout_buf;
2230 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
2231 menu_darken_bg(d, s, w, 0);
2235 cpu_clock = plat_cpu_clock_get();
2238 void menu_prepare_emu(void)
2240 R3000Acpu *prev_cpu = psxCpu;
2242 plat_video_menu_leave();
2244 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
2246 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2247 if (psxCpu != prev_cpu)
2248 // note that this does not really reset, just clears drc caches
2251 // core doesn't care about Config.Cdda changes,
2252 // so handle them manually here
2257 apply_lcdrate(Config.PsxType);
2258 apply_filter(filter);
2259 plat_cpu_clock_apply(cpu_clock);
2261 // push config to GPU plugin
2262 plugin_call_rearmed_cbs();
2264 if (GPU_open != NULL) {
2265 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2267 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2273 void me_update_msg(const char *msg)
2275 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2276 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2278 menu_error_time = plat_get_ticks_ms();
2279 lprintf("msg: %s\n", menu_error_msg);