gpu_neon: fix test mode of unai renderer
[pcsx_rearmed.git] / frontend / menu.c
CommitLineData
69af03a2 1/*
201c21e2 2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
69af03a2 3 *
4 * This work is licensed under the terms of any of these licenses
5 * (at your option):
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.
9 */
10
11#include <stdio.h>
12#include <string.h>
3c70c47b 13#include <errno.h>
bbd837c6 14#include <dlfcn.h>
61363062 15#include <zlib.h>
4b98cfee 16#include <sys/types.h>
17#include <sys/stat.h>
18#include <unistd.h>
69af03a2 19
c5061935 20#include "main.h"
3c70c47b 21#include "menu.h"
69af03a2 22#include "config.h"
201c21e2 23#include "plugin.h"
69af03a2 24#include "plugin_lib.h"
25#include "omap.h"
55b0eeea 26#include "plat.h"
c22b95ab 27#include "pcnt.h"
a80ae4a0 28#include "cspace.h"
69af03a2 29#include "common/plat.h"
ef94866c 30#include "common/input.h"
31#include "linux/in_evdev.h"
69af03a2 32#include "../libpcsxcore/misc.h"
1df403c5 33#include "../libpcsxcore/cdrom.h"
0c2871a7 34#include "../libpcsxcore/cdriso.h"
799b0b87 35#include "../libpcsxcore/psemu_plugin_defs.h"
dc990066 36#include "../libpcsxcore/new_dynarec/new_dynarec.h"
4c08b9e7 37#include "../plugins/dfinput/main.h"
3c70c47b 38#include "revision.h"
69af03a2 39
4b98cfee 40#define REARMED_BIRTHDAY_TIME 1293306830 /* 25 Dec 2010 */
41
69af03a2 42#define array_size(x) (sizeof(x) / sizeof(x[0]))
43
44typedef enum
45{
46 MA_NONE = 1,
47 MA_MAIN_RESUME_GAME,
48 MA_MAIN_SAVE_STATE,
49 MA_MAIN_LOAD_STATE,
50 MA_MAIN_RESET_GAME,
51 MA_MAIN_LOAD_ROM,
1df403c5 52 MA_MAIN_SWAP_CD,
0c2871a7 53 MA_MAIN_SWAP_CD_MULTI,
e16a7e51 54 MA_MAIN_RUN_BIOS,
51f77282 55 MA_MAIN_RUN_EXE,
69af03a2 56 MA_MAIN_CONTROLS,
57 MA_MAIN_CREDITS,
58 MA_MAIN_EXIT,
59 MA_CTRL_PLAYER1,
60 MA_CTRL_PLAYER2,
1b0c5139 61 MA_CTRL_ANALOG,
69af03a2 62 MA_CTRL_EMU,
63 MA_CTRL_DEV_FIRST,
64 MA_CTRL_DEV_NEXT,
55b0eeea 65 MA_CTRL_NUBS_BTNS,
66 MA_CTRL_DEADZONE,
b944a30e 67 MA_CTRL_VIBRATION,
69af03a2 68 MA_CTRL_DONE,
69 MA_OPT_SAVECFG,
70 MA_OPT_SAVECFG_GAME,
71 MA_OPT_CPU_CLOCKS,
3c70c47b 72 MA_OPT_FILTERING,
55b0eeea 73 MA_OPT_DISP_OPTS,
69af03a2 74} menu_id;
75
3c70c47b 76enum {
77 SCALE_1_1,
78 SCALE_4_3,
a185be70 79 SCALE_4_3v2,
3c70c47b 80 SCALE_FULLSCREEN,
81 SCALE_CUSTOM,
82};
69af03a2 83
bd6267e6 84static int last_psx_w, last_psx_h, last_psx_bpp;
ea4a16e7 85static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
69af03a2 86static char rom_fname_reload[MAXPATHLEN];
87static char last_selected_fname[MAXPATHLEN];
4c08b9e7 88static int warned_about_bios, region, in_type_sel1, in_type_sel2;
2573466a 89static int psx_clock;
51f77282 90static int memcard1_sel, memcard2_sel;
221be40d 91int g_opts;
92int analog_deadzone; // for Caanoo
bd6267e6 93
67d399b0 94#ifdef __ARM_ARCH_7A__
95#define DEFAULT_PSX_CLOCK 57
96#define DEFAULT_PSX_CLOCK_S "57"
97#else
2573466a 98#define DEFAULT_PSX_CLOCK 50
99#define DEFAULT_PSX_CLOCK_S "50"
67d399b0 100#endif
2573466a 101
bd6267e6 102// sound plugin
103extern int iUseReverb;
104extern int iUseInterpolation;
105extern int iXAPitch;
106extern int iSPUIRQWait;
107extern int iUseTimer;
9e7a7352 108extern int iVolume;
bd6267e6 109
e6eb2066 110static const char *bioses[24];
bbd837c6 111static const char *gpu_plugins[16];
112static const char *spu_plugins[16];
51f77282 113static const char *memcards[32];
e6eb2066 114static int bios_sel, gpu_plugsel, spu_plugsel;
bbd837c6 115
bd6267e6 116
117static int min(int x, int y) { return x < y ? x : y; }
118static int max(int x, int y) { return x > y ? x : y; }
69af03a2 119
120void emu_make_path(char *buff, const char *end, int size)
121{
122 int pos, end_len;
123
124 end_len = strlen(end);
125 pos = plat_get_root_dir(buff, size);
126 strncpy(buff + pos, end, size - pos);
127 buff[size - 1] = 0;
128 if (pos + end_len > size - 1)
129 printf("Warning: path truncated: %s\n", buff);
130}
131
4b98cfee 132static int emu_check_save_file(int slot, int *time)
69af03a2 133{
4b98cfee 134 char fname[MAXPATHLEN];
135 struct stat status;
136 int ret;
137
138 ret = emu_check_state(slot);
139 if (ret != 0 || time == NULL)
140 return ret == 0 ? 1 : 0;
141
142 ret = get_state_filename(fname, sizeof(fname), slot);
143 if (ret != 0)
144 return 1;
145
146 ret = stat(fname, &status);
147 if (ret != 0)
148 return 1;
149
150 if (status.st_mtime < REARMED_BIRTHDAY_TIME)
151 return 1; // probably bad rtc like on some Caanoos
152
153 *time = status.st_mtime;
154
155 return 1;
69af03a2 156}
157
8f892648 158static int emu_save_load_game(int load, int unused)
69af03a2 159{
3c70c47b 160 int ret;
161
33f56da1 162 if (load) {
8f892648 163 ret = emu_load_state(state_slot);
33f56da1 164
165 // reflect hle/bios mode from savestate
166 if (Config.HLE)
167 bios_sel = 0;
168 else if (bios_sel == 0 && bioses[1] != NULL)
169 // XXX: maybe find the right bios instead
170 bios_sel = 1;
171 }
3c70c47b 172 else
8f892648 173 ret = emu_save_state(state_slot);
3c70c47b 174
175 return ret;
69af03a2 176}
177
907b1e90 178// propagate menu settings to the emu vars
179static void menu_sync_config(void)
180{
ef94866c 181 static int allow_abs_only_old;
182
907b1e90 183 Config.PsxAuto = 1;
184 if (region > 0) {
185 Config.PsxAuto = 0;
186 Config.PsxType = region - 1;
187 }
2573466a 188 cycle_multiplier = 10000 / psx_clock;
189
4c08b9e7 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;
194 }
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;
199 }
ef94866c 200 if (in_evdev_allow_abs_only != allow_abs_only_old) {
9b4bd105 201 in_probe();
ef94866c 202 allow_abs_only_old = in_evdev_allow_abs_only;
203 }
907b1e90 204
9e7a7352 205 iVolume = 768 + 128 * volume_boost;
ea4a16e7 206 pl_rearmed_cbs.frameskip = frameskip - 1;
76f7048e 207 pl_timing_prepare(Config.PsxType);
907b1e90 208}
209
3c70c47b 210static void menu_set_defconfig(void)
211{
33400707 212 emu_set_default_config();
213
bce6b056 214 g_opts = 0;
3c70c47b 215 scaling = SCALE_4_3;
9e7a7352 216 volume_boost = 0;
ea4a16e7 217 frameskip = 0;
bab59f00 218 analog_deadzone = 50;
2573466a 219 psx_clock = DEFAULT_PSX_CLOCK;
bd6267e6 220
907b1e90 221 region = 0;
4c08b9e7 222 in_type_sel1 = in_type_sel2 = 0;
ef94866c 223 in_evdev_allow_abs_only = 0;
907b1e90 224
225 menu_sync_config();
3c70c47b 226}
227
4f3639fa 228#define CE_CONFIG_STR(val) \
229 { #val, 0, Config.val }
230
231#define CE_CONFIG_VAL(val) \
232 { #val, sizeof(Config.val), &Config.val }
233
234#define CE_STR(val) \
235 { #val, 0, val }
236
237#define CE_INTVAL(val) \
238 { #val, sizeof(val), &val }
239
e64dc4c5 240#define CE_INTVAL_P(val) \
241 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
242
cdb31c95 243// 'versioned' var, used when defaults change
244#define CE_INTVAL_V(val, ver) \
245 { #val #ver, sizeof(val), &val }
246
ea4a16e7 247#define CE_INTVAL_PV(val, ver) \
248 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
249
4f3639fa 250static const struct {
251 const char *name;
252 size_t len;
253 void *val;
254} config_data[] = {
255 CE_CONFIG_STR(Bios),
256 CE_CONFIG_STR(Gpu),
257 CE_CONFIG_STR(Spu),
33716956 258// CE_CONFIG_STR(Cdr),
4f3639fa 259 CE_CONFIG_VAL(Xa),
260 CE_CONFIG_VAL(Sio),
261 CE_CONFIG_VAL(Mdec),
4f3639fa 262 CE_CONFIG_VAL(Cdda),
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),
268 CE_CONFIG_VAL(Cpu),
4feed8d3 269 CE_CONFIG_VAL(CdrReschedule),
907b1e90 270 CE_INTVAL(region),
a185be70 271 CE_INTVAL_V(scaling, 2),
cd6e8d0f 272 CE_INTVAL(g_layer_x),
273 CE_INTVAL(g_layer_y),
274 CE_INTVAL(g_layer_w),
275 CE_INTVAL(g_layer_h),
4f3639fa 276 CE_INTVAL(filter),
277 CE_INTVAL(state_slot),
278 CE_INTVAL(cpu_clock),
279 CE_INTVAL(g_opts),
4c08b9e7 280 CE_INTVAL(in_type_sel1),
281 CE_INTVAL(in_type_sel2),
55b0eeea 282 CE_INTVAL(analog_deadzone),
9fe27e25 283 CE_INTVAL_V(frameskip, 3),
e64dc4c5 284 CE_INTVAL_P(gpu_peops.iUseDither),
285 CE_INTVAL_P(gpu_peops.dwActFixes),
17a54a4a 286 CE_INTVAL_P(gpu_unai.abe_hack),
287 CE_INTVAL_P(gpu_unai.no_light),
288 CE_INTVAL_P(gpu_unai.no_blend),
ffdbda29 289 CE_INTVAL_V(iUseReverb, 3),
290 CE_INTVAL_V(iXAPitch, 3),
291 CE_INTVAL_V(iUseInterpolation, 3),
292 CE_INTVAL_V(iSPUIRQWait, 3),
293 CE_INTVAL_V(iUseTimer, 3),
4f5a1b2a 294 CE_INTVAL(warned_about_bios),
ef94866c 295 CE_INTVAL(in_evdev_allow_abs_only),
9e7a7352 296 CE_INTVAL(volume_boost),
2573466a 297 CE_INTVAL(psx_clock),
0ff8c62c 298 CE_INTVAL(new_dynarec_hacks),
b944a30e 299 CE_INTVAL(in_enable_vibration),
4f3639fa 300};
301
1bd9ee68 302static char *get_cd_label(void)
cd6e8d0f 303{
1bd9ee68 304 static char trimlabel[33];
cd6e8d0f 305 int j;
306
307 strncpy(trimlabel, CdromLabel, 32);
308 trimlabel[32] = 0;
309 for (j = 31; j >= 0; j--)
310 if (trimlabel[j] == ' ')
311 trimlabel[j] = 0;
312
1bd9ee68 313 return trimlabel;
314}
315
316static void make_cfg_fname(char *buf, size_t size, int is_game)
317{
cd6e8d0f 318 if (is_game)
1bd9ee68 319 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
cd6e8d0f 320 else
bbd837c6 321 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
cd6e8d0f 322}
323
43bca6fb 324static void keys_write_all(FILE *f);
325
3c70c47b 326static int menu_write_config(int is_game)
327{
4f3639fa 328 char cfgfile[MAXPATHLEN];
329 FILE *f;
330 int i;
331
cd6e8d0f 332 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
4f3639fa 333 f = fopen(cfgfile, "w");
334 if (f == NULL) {
bbd837c6 335 printf("menu_write_config: failed to open: %s\n", cfgfile);
4f3639fa 336 return -1;
337 }
338
339 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
340 fprintf(f, "%s = ", config_data[i].name);
341 switch (config_data[i].len) {
342 case 0:
343 fprintf(f, "%s\n", (char *)config_data[i].val);
344 break;
345 case 1:
346 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
347 break;
348 case 2:
349 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
350 break;
351 case 4:
352 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
353 break;
354 default:
355 printf("menu_write_config: unhandled len %d for %s\n",
356 config_data[i].len, config_data[i].name);
357 break;
358 }
359 }
360
361 if (!is_game)
362 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
363
43bca6fb 364 keys_write_all(f);
4f3639fa 365 fclose(f);
43bca6fb 366
4f3639fa 367 return 0;
368}
369
370static void parse_str_val(char *cval, const char *src)
371{
372 char *tmp;
373 strncpy(cval, src, MAXPATHLEN);
374 cval[MAXPATHLEN - 1] = 0;
375 tmp = strchr(cval, '\n');
376 if (tmp == NULL)
377 tmp = strchr(cval, '\r');
378 if (tmp != NULL)
379 *tmp = 0;
3c70c47b 380}
381
43bca6fb 382static void keys_load_all(const char *cfg);
383
3c70c47b 384static int menu_load_config(int is_game)
69af03a2 385{
4f3639fa 386 char cfgfile[MAXPATHLEN];
387 int i, ret = -1;
388 long size;
389 char *cfg;
390 FILE *f;
391
cd6e8d0f 392 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
4f3639fa 393 f = fopen(cfgfile, "r");
394 if (f == NULL) {
bbd837c6 395 printf("menu_load_config: failed to open: %s\n", cfgfile);
cbd45cda 396 goto fail;
4f3639fa 397 }
398
399 fseek(f, 0, SEEK_END);
400 size = ftell(f);
401 if (size <= 0) {
402 printf("bad size %ld: %s\n", size, cfgfile);
403 goto fail;
404 }
405
406 cfg = malloc(size + 1);
407 if (cfg == NULL)
408 goto fail;
409
410 fseek(f, 0, SEEK_SET);
411 if (fread(cfg, 1, size, f) != size) {
412 printf("failed to read: %s\n", cfgfile);
413 goto fail_read;
414 }
415 cfg[size] = 0;
416
417 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
418 char *tmp, *tmp2;
419 u32 val;
420
421 tmp = strstr(cfg, config_data[i].name);
422 if (tmp == NULL)
423 continue;
424 tmp += strlen(config_data[i].name);
425 if (strncmp(tmp, " = ", 3) != 0)
426 continue;
427 tmp += 3;
428
429 if (config_data[i].len == 0) {
430 parse_str_val(config_data[i].val, tmp);
431 continue;
432 }
433
434 tmp2 = NULL;
435 val = strtoul(tmp, &tmp2, 16);
436 if (tmp2 == NULL || tmp == tmp2)
437 continue; // parse failed
438
439 switch (config_data[i].len) {
440 case 1:
441 *(u8 *)config_data[i].val = val;
442 break;
443 case 2:
444 *(u16 *)config_data[i].val = val;
445 break;
446 case 4:
447 *(u32 *)config_data[i].val = val;
448 break;
449 default:
450 printf("menu_load_config: unhandled len %d for %s\n",
451 config_data[i].len, config_data[i].name);
452 break;
453 }
454 }
455
456 if (!is_game) {
457 char *tmp = strstr(cfg, "lastcdimg = ");
458 if (tmp != NULL) {
459 tmp += 12;
460 parse_str_val(last_selected_fname, tmp);
461 }
462 }
463
cbd45cda 464 keys_load_all(cfg);
465 ret = 0;
466fail_read:
467 free(cfg);
468fail:
469 if (f != NULL)
470 fclose(f);
471
907b1e90 472 menu_sync_config();
473
bbd837c6 474 // sync plugins
e6eb2066 475 for (i = bios_sel = 0; bioses[i] != NULL; i++)
476 if (strcmp(Config.Bios, bioses[i]) == 0)
477 { bios_sel = i; break; }
478
bbd837c6 479 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
480 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
481 { gpu_plugsel = i; break; }
482
483 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
484 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
485 { spu_plugsel = i; break; }
486
4f3639fa 487 return ret;
69af03a2 488}
489
9564e73d 490// rrrr rggg gggb bbbb
491static unsigned short fname2color(const char *fname)
492{
bab59f00 493 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
494 ".bz", ".znx", ".pbp", ".cbn" };
495 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
496 ".table", ".index", ".sbi" };
9564e73d 497 const char *ext = strrchr(fname, '.');
498 int i;
499
500 if (ext == NULL)
501 return 0xffff;
502 for (i = 0; i < array_size(cdimg_exts); i++)
503 if (strcasecmp(ext, cdimg_exts[i]) == 0)
504 return 0x7bff;
505 for (i = 0; i < array_size(other_exts); i++)
506 if (strcasecmp(ext, other_exts[i]) == 0)
507 return 0xa514;
508 return 0xffff;
509}
510
61363062 511static void draw_savestate_bg(int slot);
512
f246f461 513static const char *filter_exts[] = {
514 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
515};
516
bd6267e6 517#define MENU_ALIGN_LEFT
55b0eeea 518#ifdef __ARM_ARCH_7A__ // assume hires device
519#define MENU_X2 1
520#else
521#define MENU_X2 0
522#endif
523
3c70c47b 524#define menu_init menu_init_common
69af03a2 525#include "common/menu.c"
3c70c47b 526#undef menu_init
69af03a2 527
61363062 528// a bit of black magic here
529static void draw_savestate_bg(int slot)
530{
61363062 531 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
532 int x, y, w, h;
533 char fname[MAXPATHLEN];
534 GPUFreeze_t *gpu;
535 u16 *s, *d;
536 gzFile f;
537 int ret;
538 u32 tmp;
539
540 ret = get_state_filename(fname, sizeof(fname), slot);
541 if (ret != 0)
542 return;
543
544 f = gzopen(fname, "rb");
545 if (f == NULL)
546 return;
547
548 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
549 fprintf(stderr, "gzseek failed\n");
550 gzclose(f);
551 return;
552 }
553
554 gpu = malloc(sizeof(*gpu));
555 if (gpu == NULL) {
556 gzclose(f);
557 return;
558 }
559
560 ret = gzread(f, gpu, sizeof(*gpu));
561 gzclose(f);
562 if (ret != sizeof(*gpu)) {
563 fprintf(stderr, "gzread failed\n");
564 goto out;
565 }
566
567 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
568
ff847a2e 569 if (gpu->ulStatus & 0x800000)
570 goto out; // disabled
61363062 571
572 x = gpu->ulControl[5] & 0x3ff;
573 y = (gpu->ulControl[5] >> 10) & 0x1ff;
ff847a2e 574 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
61363062 575 w = psx_widths[(gpu->ulStatus >> 16) & 7];
576 tmp = gpu->ulControl[7];
577 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
578 if (gpu->ulStatus & 0x80000) // doubleheight
579 h *= 2;
580
581 x = max(0, g_menuscreen_w - w) & ~3;
582 y = max(0, g_menuscreen_h / 2 - h / 2);
583 w = min(g_menuscreen_w, w);
584 h = min(g_menuscreen_h, h);
585 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
586
55b0eeea 587 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
ff847a2e 588 if (gpu->ulStatus & 0x200000)
589 bgr888_to_rgb565(d, s, w * 3);
590 else
591 bgr555_to_rgb565(d, s, w * 2);
55b0eeea 592#ifndef __ARM_ARCH_7A__
593 // better darken this on small screens
594 menu_darken_bg(d, d, w * 2, 0);
595#endif
596 }
61363062 597
598out:
599 free(gpu);
600}
601
55b0eeea 602// ---------- XXX: pandora specific -----------
3c70c47b 603
604static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
605static char **pnd_filter_list;
606
3c70c47b 607static void apply_filter(int which)
608{
4f3639fa 609 static int old = -1;
3c70c47b 610 char buf[128];
611 int i;
612
4f3639fa 613 if (pnd_filter_list == NULL || which == old)
3c70c47b 614 return;
615
616 for (i = 0; i < which; i++)
617 if (pnd_filter_list[i] == NULL)
618 return;
619
620 if (pnd_filter_list[i] == NULL)
621 return;
622
623 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
624 system(buf);
4f3639fa 625 old = which;
3c70c47b 626}
627
cefe86b7 628static void apply_lcdrate(int pal)
629{
630 static int old = -1;
631 char buf[128];
632
633 if (pal == old)
634 return;
635
636 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
637 pnd_script_base, pal ? 50 : 60);
638 system(buf);
639 old = pal;
640}
641
3c70c47b 642static menu_entry e_menu_gfx_options[];
643
644static void pnd_menu_init(void)
645{
646 struct dirent *ent;
647 int i, count = 0;
648 char **mfilters;
1bd9ee68 649 char buff[64];
3c70c47b 650 DIR *dir;
651
55b0eeea 652 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
3c70c47b 653
654 dir = opendir("/etc/pandora/conf/dss_fir");
655 if (dir == NULL) {
656 perror("filter opendir");
657 return;
658 }
659
660 while (1) {
661 errno = 0;
662 ent = readdir(dir);
663 if (ent == NULL) {
664 if (errno != 0)
665 perror("readdir");
666 break;
667 }
1bd9ee68 668
669 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
670 continue;
671
672 count++;
3c70c47b 673 }
674
675 if (count == 0)
676 return;
677
678 mfilters = calloc(count + 1, sizeof(mfilters[0]));
679 if (mfilters == NULL)
680 return;
681
682 rewinddir(dir);
683 for (i = 0; (ent = readdir(dir)); ) {
684 size_t len;
685
1bd9ee68 686 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
687 continue;
688
689 len = strlen(ent->d_name);
690
691 // skip pre-HF5 extra files
692 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
693 continue;
694 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
3c70c47b 695 continue;
696
1bd9ee68 697 // have to cut "_up_h" for pre-HF5
698 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
699 len -= 5;
700
3c70c47b 701 if (len > sizeof(buff) - 1)
702 continue;
703
704 strncpy(buff, ent->d_name, len);
705 buff[len] = 0;
706 mfilters[i] = strdup(buff);
707 if (mfilters[i] != NULL)
708 i++;
709 }
710 closedir(dir);
711
712 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
713 e_menu_gfx_options[i].data = (void *)mfilters;
714 pnd_filter_list = mfilters;
69af03a2 715}
716
201c21e2 717void menu_finish(void)
718{
55b0eeea 719 plat_cpu_clock_apply(cpu_clock_st);
201c21e2 720}
721
69af03a2 722// -------------- key config --------------
723
724me_bind_action me_ctrl_actions[] =
725{
726 { "UP ", 1 << DKEY_UP},
727 { "DOWN ", 1 << DKEY_DOWN },
728 { "LEFT ", 1 << DKEY_LEFT },
729 { "RIGHT ", 1 << DKEY_RIGHT },
730 { "TRIANGLE", 1 << DKEY_TRIANGLE },
22a8a805 731 { "CIRCLE ", 1 << DKEY_CIRCLE },
69af03a2 732 { "CROSS ", 1 << DKEY_CROSS },
733 { "SQUARE ", 1 << DKEY_SQUARE },
734 { "L1 ", 1 << DKEY_L1 },
735 { "R1 ", 1 << DKEY_R1 },
736 { "L2 ", 1 << DKEY_L2 },
737 { "R2 ", 1 << DKEY_R2 },
43bca6fb 738 { "L3 ", 1 << DKEY_L3 },
739 { "R3 ", 1 << DKEY_R3 },
69af03a2 740 { "START ", 1 << DKEY_START },
741 { "SELECT ", 1 << DKEY_SELECT },
742 { NULL, 0 }
743};
744
745me_bind_action emuctrl_actions[] =
746{
8f892648 747 { "Save State ", 1 << SACTION_SAVE_STATE },
748 { "Load State ", 1 << SACTION_LOAD_STATE },
749 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
750 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
751 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
29a8c4f3 752 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
8f892648 753 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
4c08b9e7 754 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
755 { "Gun A button ", 1 << SACTION_GUN_A },
756 { "Gun B button ", 1 << SACTION_GUN_B },
757 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
221be40d 758#ifndef __ARM_ARCH_7A__ /* XXX */
759 { "Volume Up ", 1 << SACTION_VOLUME_UP },
760 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
761#endif
69af03a2 762 { NULL, 0 }
763};
764
43bca6fb 765static char *mystrip(char *str)
766{
767 int i, len;
768
769 len = strlen(str);
770 for (i = 0; i < len; i++)
771 if (str[i] != ' ') break;
772 if (i > 0) memmove(str, str + i, len - i + 1);
773
774 len = strlen(str);
775 for (i = len - 1; i >= 0; i--)
776 if (str[i] != ' ') break;
777 str[i+1] = 0;
778
779 return str;
780}
781
782static void get_line(char *d, size_t size, const char *s)
783{
784 const char *pe;
785 size_t len;
786
787 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
788 ;
789 len = pe - s;
790 if (len > size - 1)
791 len = size - 1;
792 strncpy(d, s, len);
793 d[len] = 0;
794
795 mystrip(d);
796}
797
798static void keys_write_all(FILE *f)
799{
800 int d;
801
802 for (d = 0; d < IN_MAX_DEVS; d++)
803 {
804 const int *binds = in_get_dev_binds(d);
805 const char *name = in_get_dev_name(d, 0, 0);
806 int k, count = 0;
807
808 if (binds == NULL || name == NULL)
809 continue;
810
811 fprintf(f, "binddev = %s\n", name);
812 in_get_config(d, IN_CFG_BIND_COUNT, &count);
813
814 for (k = 0; k < count; k++)
815 {
816 int i, kbinds, mask;
817 char act[32];
818
819 act[0] = act[31] = 0;
820 name = in_get_key_name(d, k);
821
822 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
823 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
824 mask = me_ctrl_actions[i].mask;
825 if (mask & kbinds) {
826 strncpy(act, me_ctrl_actions[i].name, 31);
827 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
828 kbinds &= ~mask;
829 }
830 mask = me_ctrl_actions[i].mask << 16;
831 if (mask & kbinds) {
832 strncpy(act, me_ctrl_actions[i].name, 31);
833 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
834 kbinds &= ~mask;
835 }
836 }
837
838 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
221be40d 839 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
43bca6fb 840 mask = emuctrl_actions[i].mask;
841 if (mask & kbinds) {
842 strncpy(act, emuctrl_actions[i].name, 31);
843 fprintf(f, "bind %s = %s\n", name, mystrip(act));
844 kbinds &= ~mask;
845 }
846 }
847 }
1b0c5139 848
849 for (k = 0; k < array_size(in_adev); k++)
850 {
851 if (in_adev[k] == d)
852 fprintf(f, "bind_analog = %d\n", k);
853 }
43bca6fb 854 }
855}
856
857static int parse_bind_val(const char *val, int *type)
858{
859 int i;
860
861 *type = IN_BINDTYPE_NONE;
862 if (val[0] == 0)
863 return 0;
864
865 if (strncasecmp(val, "player", 6) == 0)
866 {
867 int player, shift = 0;
868 player = atoi(val + 6) - 1;
869
870 if ((unsigned int)player > 1)
871 return -1;
872 if (player == 1)
873 shift = 16;
874
875 *type = IN_BINDTYPE_PLAYER12;
876 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
877 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
878 return me_ctrl_actions[i].mask << shift;
879 }
880 }
881 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
882 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
883 *type = IN_BINDTYPE_EMU;
884 return emuctrl_actions[i].mask;
885 }
886 }
887
888 return -1;
889}
890
891static void keys_load_all(const char *cfg)
892{
893 char dev[256], key[128], *act;
894 const char *p;
895 int bind, bindtype;
1b0c5139 896 int ret, dev_id;
43bca6fb 897
898 p = cfg;
899 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
900 p += 10;
901
902 get_line(dev, sizeof(dev), p);
903 dev_id = in_config_parse_dev(dev);
904 if (dev_id < 0) {
905 printf("input: can't handle dev: %s\n", dev);
906 continue;
907 }
908
909 in_unbind_all(dev_id, -1, -1);
910 while ((p = strstr(p, "bind"))) {
911 if (strncmp(p, "binddev = ", 10) == 0)
912 break;
913
1b0c5139 914 if (strncmp(p, "bind_analog", 11) == 0) {
915 ret = sscanf(p, "bind_analog = %d", &bind);
916 p += 11;
917 if (ret != 1) {
918 printf("input: parse error: %16s..\n", p);
919 continue;
920 }
921 if ((unsigned int)bind >= array_size(in_adev)) {
922 printf("input: analog id %d out of range\n", bind);
923 continue;
924 }
925 in_adev[bind] = dev_id;
926 continue;
927 }
928
43bca6fb 929 p += 4;
930 if (*p != ' ') {
931 printf("input: parse error: %16s..\n", p);
932 continue;
933 }
934
935 get_line(key, sizeof(key), p);
936 act = strchr(key, '=');
937 if (act == NULL) {
938 printf("parse failed: %16s..\n", p);
939 continue;
940 }
941 *act = 0;
942 act++;
943 mystrip(key);
944 mystrip(act);
945
946 bind = parse_bind_val(act, &bindtype);
947 if (bind != -1 && bind != 0) {
8f892648 948 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
43bca6fb 949 in_config_bind_key(dev_id, key, bind, bindtype);
950 }
951 else
952 lprintf("config: unhandled action \"%s\"\n", act);
953 }
954 }
ef94866c 955 in_clean_binds();
43bca6fb 956}
957
69af03a2 958static int key_config_loop_wrap(int id, int keys)
959{
960 switch (id) {
961 case MA_CTRL_PLAYER1:
962 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
963 break;
964 case MA_CTRL_PLAYER2:
965 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
966 break;
967 case MA_CTRL_EMU:
968 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
969 break;
970 default:
971 break;
972 }
973 return 0;
974}
975
1b0c5139 976static const char *adevnames[IN_MAX_DEVS + 2];
977static int stick_sel[2];
978
979static menu_entry e_menu_keyconfig_analog[] =
980{
981 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
982 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
983 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
984 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
985 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
986 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
987 mee_end,
988};
989
990static int key_config_analog(int id, int keys)
991{
992 int i, d, count, sel = 0;
993 int sel2dev_map[IN_MAX_DEVS];
994
995 memset(adevnames, 0, sizeof(adevnames));
996 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
997 memset(stick_sel, 0, sizeof(stick_sel));
998
999 adevnames[0] = "None";
1000 i = 1;
1001 for (d = 0; d < IN_MAX_DEVS; d++)
1002 {
1003 const char *name = in_get_dev_name(d, 0, 1);
1004 if (name == NULL)
1005 continue;
1006
1007 count = 0;
1008 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1009 if (count == 0)
1010 continue;
1011
1012 if (in_adev[0] == d) stick_sel[0] = i;
1013 if (in_adev[1] == d) stick_sel[1] = i;
1014 sel2dev_map[i] = d;
1015 adevnames[i++] = name;
1016 }
1017 adevnames[i] = NULL;
1018
1019 me_loop(e_menu_keyconfig_analog, &sel);
1020
1021 in_adev[0] = sel2dev_map[stick_sel[0]];
1022 in_adev[1] = sel2dev_map[stick_sel[1]];
1023
1024 return 0;
1025}
1026
69af03a2 1027static const char *mgn_dev_name(int id, int *offs)
1028{
1029 const char *name = NULL;
1030 static int it = 0;
1031
1032 if (id == MA_CTRL_DEV_FIRST)
1033 it = 0;
1034
1035 for (; it < IN_MAX_DEVS; it++) {
1036 name = in_get_dev_name(it, 1, 1);
1037 if (name != NULL)
1038 break;
1039 }
1040
1041 it++;
1042 return name;
1043}
1044
1045static const char *mgn_saveloadcfg(int id, int *offs)
1046{
1047 return "";
1048}
1049
cd6e8d0f 1050static int mh_savecfg(int id, int keys)
69af03a2 1051{
cd6e8d0f 1052 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1053 me_update_msg("config saved");
1054 else
1055 me_update_msg("failed to write config");
69af03a2 1056
1057 return 1;
1058}
1059
ef94866c 1060static int mh_input_rescan(int id, int keys)
1061{
1062 //menu_sync_config();
9b4bd105 1063 in_probe();
ef94866c 1064 me_update_msg("rescan complete.");
1065
1066 return 0;
1067}
1068
4c08b9e7 1069static const char *men_in_type_sel[] = {
1070 "Standard (SCPH-1080)",
1071 "Analog (SCPH-1150)",
1072 "GunCon",
1073 NULL
1074};
ef94866c 1075static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
b944a30e 1076static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1077static const char h_vibration[]= "Must select analog above and enable this ingame too.";
799b0b87 1078
69af03a2 1079static menu_entry e_menu_keyconfig[] =
1080{
4c08b9e7 1081 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
1082 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1b0c5139 1083 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
4c08b9e7 1084 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
799b0b87 1085 mee_label (""),
4c08b9e7 1086 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1087 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
55b0eeea 1088 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
b944a30e 1089 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
55b0eeea 1090 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
4c08b9e7 1091 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
799b0b87 1092 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1093 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1b0c5139 1094 mee_handler ("Rescan devices:", mh_input_rescan),
69af03a2 1095 mee_label (""),
69af03a2 1096 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1097 mee_label_mk (MA_CTRL_DEV_NEXT, 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_end,
1104};
1105
1106static int menu_loop_keyconfig(int id, int keys)
1107{
1108 static int sel = 0;
1109
e16a7e51 1110// me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
51f77282 1111 me_loop(e_menu_keyconfig, &sel);
69af03a2 1112 return 0;
1113}
1114
69af03a2 1115// ------------ gfx options menu ------------
1116
a185be70 1117static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
3c70c47b 1118static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1119 "using d-pad or move it using R+d-pad";
1120static const char *men_dummy[] = { NULL };
1121
1122static int menu_loop_cscaler(int id, int keys)
1123{
1124 unsigned int inp;
1125
1126 scaling = SCALE_CUSTOM;
1127
1128 omap_enable_layer(1);
3c70c47b 1129
1130 for (;;)
1131 {
1132 menu_draw_begin(0);
201c21e2 1133 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1134 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1135 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
3c70c47b 1136 menu_draw_end();
1137
1138 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1139 if (inp & PBTN_UP) g_layer_y--;
1140 if (inp & PBTN_DOWN) g_layer_y++;
1141 if (inp & PBTN_LEFT) g_layer_x--;
1142 if (inp & PBTN_RIGHT) g_layer_x++;
1143 if (!(inp & PBTN_R)) {
1144 if (inp & PBTN_UP) g_layer_h += 2;
1145 if (inp & PBTN_DOWN) g_layer_h -= 2;
1146 if (inp & PBTN_LEFT) g_layer_w += 2;
1147 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1148 }
1149 if (inp & (PBTN_MOK|PBTN_MBACK))
1150 break;
1151
1152 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1153 if (g_layer_x < 0) g_layer_x = 0;
1154 if (g_layer_x > 640) g_layer_x = 640;
1155 if (g_layer_y < 0) g_layer_y = 0;
1156 if (g_layer_y > 420) g_layer_y = 420;
1157 if (g_layer_w < 160) g_layer_w = 160;
1158 if (g_layer_h < 60) g_layer_h = 60;
1159 if (g_layer_x + g_layer_w > 800)
1160 g_layer_w = 800 - g_layer_x;
1161 if (g_layer_y + g_layer_h > 480)
1162 g_layer_h = 480 - g_layer_y;
1163 omap_enable_layer(1);
1164 }
1165 }
1166
1167 omap_enable_layer(0);
1168
1169 return 0;
1170}
1171
69af03a2 1172static menu_entry e_menu_gfx_options[] =
1173{
3c70c47b 1174 mee_enum ("Scaler", 0, scaling, men_scaler),
1175 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1176// mee_onoff ("Vsync", 0, vsync, 1),
1177 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
69af03a2 1178 mee_end,
1179};
1180
1181static int menu_loop_gfx_options(int id, int keys)
1182{
1183 static int sel = 0;
1184
51f77282 1185 me_loop(e_menu_gfx_options, &sel);
69af03a2 1186
1187 return 0;
1188}
1189
bd6267e6 1190// ------------ bios/plugins ------------
1191
17a54a4a 1192static menu_entry e_menu_plugin_gpu_unai[] =
1193{
1194 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1195 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1196 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1197 mee_end,
1198};
1199
1200static int menu_loop_plugin_gpu_unai(int id, int keys)
1201{
1202 int sel = 0;
1203 me_loop(e_menu_plugin_gpu_unai, &sel);
1204 return 0;
1205}
1206
bd6267e6 1207static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
bd6267e6 1208static const char h_gpu_0[] = "Needed for Chrono Cross";
1209static const char h_gpu_1[] = "Capcom fighting games";
1210static const char h_gpu_2[] = "Black screens in Lunar";
1211static const char h_gpu_3[] = "Compatibility mode";
1212static const char h_gpu_6[] = "Pandemonium 2";
1213static const char h_gpu_7[] = "Skip every second frame";
1214static const char h_gpu_8[] = "Needed by Dark Forces";
1215static const char h_gpu_9[] = "better g-colors, worse textures";
1216static const char h_gpu_10[] = "Toggle busy flags after drawing";
1217
17a54a4a 1218static menu_entry e_menu_plugin_gpu_peops[] =
bd6267e6 1219{
e64dc4c5 1220 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1221 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1222 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1223 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1224 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1225 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1226 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1227 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1228 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1229 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
bd6267e6 1230 mee_end,
1231};
1232
17a54a4a 1233static int menu_loop_plugin_gpu_peops(int id, int keys)
bd6267e6 1234{
1235 static int sel = 0;
17a54a4a 1236 me_loop(e_menu_plugin_gpu_peops, &sel);
bd6267e6 1237 return 0;
1238}
1239
bd6267e6 1240static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
9e7a7352 1241static const char h_spu_volboost[] = "Large values cause distortion";
cdb31c95 1242static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1bd9ee68 1243static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
bd6267e6 1244
1245static menu_entry e_menu_plugin_spu[] =
1246{
9e7a7352 1247 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
381ea103 1248 mee_onoff ("Reverb", 0, iUseReverb, 2),
bd6267e6 1249 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1250 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1251 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1bd9ee68 1252 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
bd6267e6 1253 mee_end,
1254};
1255
1256static int menu_loop_plugin_spu(int id, int keys)
1257{
1258 static int sel = 0;
51f77282 1259 me_loop(e_menu_plugin_spu, &sel);
bd6267e6 1260 return 0;
1261}
1262
55b0eeea 1263static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1264 "savestates and can't be changed there. Must save\n"
1265 "config and reload the game for change to take effect";
bbd837c6 1266static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1267 "for plugin change to take effect";
17a54a4a 1268static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1269static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
e6eb2066 1270static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
bbd837c6 1271
bd6267e6 1272static menu_entry e_menu_plugin_options[] =
1273{
e6eb2066 1274 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
bbd837c6 1275 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1276 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
17a54a4a 1277 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1278 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
bd6267e6 1279 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1280 mee_end,
1281};
1282
51f77282 1283static menu_entry e_menu_main2[];
e16a7e51 1284
bd6267e6 1285static int menu_loop_plugin_options(int id, int keys)
1286{
1287 static int sel = 0;
51f77282 1288 me_loop(e_menu_plugin_options, &sel);
bbd837c6 1289
e6eb2066 1290 // sync BIOS/plugins
1291 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
bbd837c6 1292 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1293 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
51f77282 1294 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
bbd837c6 1295
bd6267e6 1296 return 0;
1297}
1298
1299// ------------ adv options menu ------------
1300
0ff8c62c 1301static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
bab59f00 1302static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
0ff8c62c 1303static const char h_cfg_gteunn[] = "May cause graphical glitches";
1304static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1305
1306static menu_entry e_menu_speed_hacks[] =
1307{
1308 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1309 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1310 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1311 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1312 mee_end,
1313};
1314
1315static int menu_loop_speed_hacks(int id, int keys)
1316{
1317 static int sel = 0;
1318 me_loop(e_menu_speed_hacks, &sel);
1319 return 0;
1320}
1321
4feed8d3 1322static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
8f892648 1323static const char h_cfg_cpul[] = "Shows CPU usage in %";
90f1d26c 1324static const char h_cfg_spu[] = "Shows active SPU channels\n"
1325 "(green: normal, red: fmod, blue: noise)";
1bd9ee68 1326static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
bd6267e6 1327static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1328static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1329 "(proper .cue/.bin dump is needed otherwise)";
4feed8d3 1330static const char h_cfg_sio[] = "You should not need this, breaks games";
1331static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1332static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1333 "(timing hack, breaks other games)";
1334static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1335 "(timing hack, breaks other games)";
0ff8c62c 1336static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
b5e7e49a 1337static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1338 "Might be useful to overcome some dynarec bugs";
0ff8c62c 1339static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1340 "must reload game for any change to take effect";
bd6267e6 1341
1342static menu_entry e_menu_adv_options[] =
1343{
fba06457 1344 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
90f1d26c 1345 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
bce6b056 1346 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
bd6267e6 1347 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1348 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1349 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1350 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
b1be1eee 1351 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
bd6267e6 1352 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
4feed8d3 1353 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
b5e7e49a 1354 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
0ff8c62c 1355 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
bd6267e6 1356 mee_end,
1357};
1358
1359static int menu_loop_adv_options(int id, int keys)
1360{
1361 static int sel = 0;
51f77282 1362 me_loop(e_menu_adv_options, &sel);
bd6267e6 1363 return 0;
1364}
1365
69af03a2 1366// ------------ options menu ------------
1367
69af03a2 1368static int mh_restore_defaults(int id, int keys)
1369{
3c70c47b 1370 menu_set_defconfig();
69af03a2 1371 me_update_msg("defaults restored");
1372 return 1;
1373}
1374
907b1e90 1375static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
9fe27e25 1376static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
bd6267e6 1377/*
69af03a2 1378static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1379static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1380 "loading state or both";
bd6267e6 1381*/
1382static const char h_restore_def[] = "Switches back to default / recommended\n"
1383 "configuration";
9f4a4237 1384static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
69af03a2 1385
1386static menu_entry e_menu_options[] =
1387{
bd6267e6 1388// mee_range ("Save slot", 0, state_slot, 0, 9),
1389// mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
ea4a16e7 1390 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
bd6267e6 1391 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
907b1e90 1392 mee_enum ("Region", 0, region, men_region),
3c70c47b 1393 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
55b0eeea 1394 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
bd6267e6 1395 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
69af03a2 1396 mee_handler ("[Advanced]", menu_loop_adv_options),
cd6e8d0f 1397 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1398 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
bd6267e6 1399 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
69af03a2 1400 mee_end,
1401};
1402
1403static int menu_loop_options(int id, int keys)
1404{
1405 static int sel = 0;
1406 int i;
1407
1408 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
3c70c47b 1409 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
e16a7e51 1410 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
69af03a2 1411
51f77282 1412 me_loop(e_menu_options, &sel);
69af03a2 1413
1414 return 0;
1415}
1416
1417// ------------ debug menu ------------
1418
72bb6fdd 1419static void draw_frame_debug(GPUFreeze_t *gpuf)
69af03a2 1420{
72bb6fdd 1421 int w = min(g_menuscreen_w, 1024);
1422 int h = min(g_menuscreen_h, 512);
1423 u16 *d = g_menuscreen_ptr;
1424 u16 *s = (u16 *)gpuf->psxVRam;
1425 char buff[64];
1426 int ty = 1;
1427
1428 gpuf->ulFreezeVersion = 1;
1429 if (GPU_freeze != NULL)
1430 GPU_freeze(1, gpuf);
1431
1432 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1433 bgr555_to_rgb565(d, s, w * 2);
1434
3c70c47b 1435 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
72bb6fdd 1436 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1437 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1438 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1439 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
69af03a2 1440}
1441
1442static void debug_menu_loop(void)
1443{
72bb6fdd 1444 GPUFreeze_t *gpuf;
69af03a2 1445 int inp;
1446
72bb6fdd 1447 gpuf = malloc(sizeof(*gpuf));
1448 if (gpuf == NULL)
1449 return;
1450
69af03a2 1451 while (1)
1452 {
72bb6fdd 1453 menu_draw_begin(0);
1454 draw_frame_debug(gpuf);
69af03a2 1455 menu_draw_end();
1456
1457 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1458 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1459 if (inp & PBTN_MBACK)
72bb6fdd 1460 break;
69af03a2 1461 }
72bb6fdd 1462
1463 free(gpuf);
69af03a2 1464}
1465
51f77282 1466// --------- memcard manager ---------
1467
1468static void draw_mc_icon(int dx, int dy, const u16 *s)
1469{
1470 u16 *d;
1471 int x, y, l, p;
1472
1473 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1474
1475 for (y = 0; y < 16; y++, s += 16) {
1476 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1477 for (x = 0; x < 16; x++) {
1478 p = s[x];
1479 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1480 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1481 }
1482 }
1483 }
1484}
1485
1486static void draw_mc_bg(void)
1487{
1488 McdBlock *blocks1, *blocks2;
1489 int maxicons = 15;
1490 int i, y, row2;
1491
1492 blocks1 = malloc(15 * sizeof(blocks1[0]));
1493 blocks2 = malloc(15 * sizeof(blocks1[0]));
1494 if (blocks1 == NULL || blocks2 == NULL)
1495 goto out;
1496
1497 for (i = 0; i < 15; i++) {
1498 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1499 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1500 }
1501
1502 menu_draw_begin(1);
1503
1504 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1505
1506 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1507 if (y < 0) {
1508 // doesn't fit..
1509 y = 0;
1510 maxicons = g_menuscreen_h / 32;
1511 }
1512
1513 row2 = g_menuscreen_w / 2;
1514 for (i = 0; i < maxicons; i++) {
1515 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1516 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1517
1518 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1519 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1520 }
1521
1522 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1523
1524 menu_draw_end();
1525out:
1526 free(blocks1);
1527 free(blocks2);
1528}
1529
1530static void handle_memcard_sel(void)
1531{
1532 Config.Mcd1[0] = 0;
1533 if (memcard1_sel != 0)
1534 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1535 Config.Mcd2[0] = 0;
1536 if (memcard2_sel != 0)
1537 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1538 LoadMcds(Config.Mcd1, Config.Mcd2);
1539 draw_mc_bg();
1540}
1541
1542static menu_entry e_memcard_options[] =
1543{
1544 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1545 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1546 mee_end,
1547};
1548
1549static int menu_loop_memcards(int id, int keys)
1550{
1551 static int sel = 0;
1552 char *p;
1553 int i;
1554
1555 memcard1_sel = memcard2_sel = 0;
1556 p = strrchr(Config.Mcd1, '/');
1557 if (p != NULL)
1558 for (i = 0; memcards[i] != NULL; i++)
1559 if (strcmp(p + 1, memcards[i]) == 0)
1560 { memcard1_sel = i; break; }
1561 p = strrchr(Config.Mcd2, '/');
1562 if (p != NULL)
1563 for (i = 0; memcards[i] != NULL; i++)
1564 if (strcmp(p + 1, memcards[i]) == 0)
1565 { memcard2_sel = i; break; }
1566
1567 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1568
1569 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1570
1571 return 0;
1572}
1573
1574// --------- main menu help ----------
69af03a2 1575
4f5a1b2a 1576static void menu_bios_warn(void)
1577{
1578 int inp;
1579 static const char msg[] =
cbd45cda 1580 "You don't seem to have copied any BIOS\n"
1581 "files to\n"
1582#ifdef __ARM_ARCH_7A__ // XXX
4f5a1b2a 1583 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
cbd45cda 1584#else
1585 "pcsx_rearmed/bios/\n\n"
1586#endif
1587 "While many games work fine with fake\n"
1588 "(HLE) BIOS, others (like MGS and FF8)\n"
1589 "require BIOS to work.\n"
1590 "After copying the file, you'll also need\n"
1591 "to select it in the emu's menu:\n"
1592 "options->[BIOS/Plugins]\n\n"
1593 "The file is usually named SCPH1001.BIN,\n"
1594 "but other not compressed files can be\n"
1595 "used too.\n\n"
4f5a1b2a 1596 "Press (B) or (X) to continue";
1597
1598 while (1)
1599 {
4f5a1b2a 1600 draw_menu_message(msg, NULL);
4f5a1b2a 1601
1602 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1603 if (inp & (PBTN_MBACK|PBTN_MOK))
1604 return;
1605 }
1606}
1607
1608// ------------ main menu ------------
1609
bd6267e6 1610void OnFile_Exit();
1611
1bd9ee68 1612static void draw_frame_main(void)
1613{
65092fd8 1614 struct tm *tmp;
1615 time_t ltime;
1616 char ltime_s[16];
1617 char buff[64];
1618
1bd9ee68 1619 if (CdromId[0] != 0) {
c22b95ab 1620 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1621 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1622 Config.HLE ? "HLE" : "BIOS");
1bd9ee68 1623 smalltext_out16(4, 1, buff, 0x105f);
1624 }
65092fd8 1625
1626 if (ready_to_go) {
1627 ltime = time(NULL);
1628 tmp = localtime(&ltime);
1629 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
55b0eeea 1630 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
65092fd8 1631 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1632 }
1bd9ee68 1633}
1634
1635static void draw_frame_credits(void)
1636{
1637 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1638}
1639
4f5a1b2a 1640static const char credits_text[] =
1641 "PCSX-ReARMed\n\n"
1642 "(C) 1999-2003 PCSX Team\n"
1643 "(C) 2005-2009 PCSX-df Team\n"
1644 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1645 "GPU and SPU code by Pete Bernert\n"
1646 " and the P.E.Op.S. team\n"
1647 "ARM recompiler (C) 2009-2011 Ari64\n"
1648 "PCSX4ALL plugins by PCSX4ALL team\n"
1649 " Chui, Franxis, Unai\n\n"
1650 "integration, optimization and\n"
1651 " frontend (C) 2010-2011 notaz\n";
69af03a2 1652
e16a7e51 1653static int reset_game(void)
1654{
1655 // sanity check
1656 if (bios_sel == 0 && !Config.HLE)
1657 return -1;
1658
1659 ClosePlugins();
1660 OpenPlugins();
1661 SysReset();
1662 if (CheckCdrom() != -1) {
1663 LoadCdrom();
1664 }
1665 return 0;
1666}
1667
51f77282 1668static int reload_plugins(const char *cdimg)
e16a7e51 1669{
76f7048e 1670 pl_vout_buf = NULL;
e16a7e51 1671
1672 ClosePlugins();
51f77282 1673
1674 set_cd_image(cdimg);
e16a7e51 1675 LoadPlugins();
c22b95ab 1676 pcnt_hook_plugins();
e16a7e51 1677 NetOpened = 0;
1678 if (OpenPlugins() == -1) {
1679 me_update_msg("failed to open plugins");
1680 return -1;
1681 }
1682 plugin_call_rearmed_cbs();
1683
0c2871a7 1684 cdrIsoMultidiskCount = 1;
e16a7e51 1685 CdromId[0] = '\0';
1686 CdromLabel[0] = '\0';
1687
51f77282 1688 return 0;
1689}
1690
1691static int run_bios(void)
1692{
1693 if (bios_sel == 0)
1694 return -1;
1695
1696 ready_to_go = 0;
1697 if (reload_plugins(NULL) != 0)
1698 return -1;
e16a7e51 1699 SysReset();
1700
1701 ready_to_go = 1;
1702 return 0;
1703}
1704
51f77282 1705static int run_exe(void)
69af03a2 1706{
51f77282 1707 const char *fname;
1708
1709 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1710 if (fname == NULL)
1711 return -1;
1712
69af03a2 1713 ready_to_go = 0;
51f77282 1714 if (reload_plugins(NULL) != 0)
1715 return -1;
69af03a2 1716
51f77282 1717 SysReset();
1718 if (Load(fname) != 0) {
1719 me_update_msg("exe load failed, bad file?");
1720 printf("meh\n");
bbd837c6 1721 return -1;
69af03a2 1722 }
51f77282 1723
1724 ready_to_go = 1;
1725 return 0;
1726}
1727
1728static int run_cd_image(const char *fname)
1729{
1730 ready_to_go = 0;
1731 reload_plugins(fname);
69af03a2 1732
76d63edf 1733 // always autodetect, menu_sync_config will override as needed
1734 Config.PsxAuto = 1;
1735
69af03a2 1736 if (CheckCdrom() == -1) {
1737 // Only check the CD if we are starting the console with a CD
1738 ClosePlugins();
1739 me_update_msg("unsupported/invalid CD image");
bbd837c6 1740 return -1;
69af03a2 1741 }
1742
bbd837c6 1743 SysReset();
1744
69af03a2 1745 // Read main executable directly from CDRom and start it
1746 if (LoadCdrom() == -1) {
1747 ClosePlugins();
1748 me_update_msg("failed to load CD image");
bbd837c6 1749 return -1;
69af03a2 1750 }
1751
1752 ready_to_go = 1;
47232ea4 1753 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1754 hud_new_msg = 2;
bbd837c6 1755 return 0;
69af03a2 1756}
1757
bbd837c6 1758static int romsel_run(void)
69af03a2 1759{
bbd837c6 1760 int prev_gpu, prev_spu;
51f77282 1761 const char *fname;
bbd837c6 1762
1763 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1764 if (fname == NULL)
1765 return -1;
69af03a2 1766
bbd837c6 1767 printf("selected file: %s\n", fname);
1768
dc990066 1769 new_dynarec_clear_full();
1770
bbd837c6 1771 if (run_cd_image(fname) != 0)
1772 return -1;
1773
1774 prev_gpu = gpu_plugsel;
1775 prev_spu = spu_plugsel;
1776 if (menu_load_config(1) != 0)
1777 menu_load_config(0);
1778
1779 // check for plugin changes, have to repeat
1780 // loading if game config changed plugins to reload them
1781 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1782 printf("plugin change detected, reloading plugins..\n");
1783 if (run_cd_image(fname) != 0)
1784 return -1;
1785 }
1786
bab59f00 1787 if (Config.HLE)
1788 printf("note: running without BIOS, expect compatibility problems\n");
1789
bbd837c6 1790 strcpy(last_selected_fname, rom_fname_reload);
1791 return 0;
1792}
1793
1df403c5 1794static int swap_cd_image(void)
1795{
1796 char *fname;
1797
1798 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1799 if (fname == NULL)
1800 return -1;
1801
1802 printf("selected file: %s\n", fname);
1803
1804 CdromId[0] = '\0';
1805 CdromLabel[0] = '\0';
1806
1807 set_cd_image(fname);
1808 if (ReloadCdromPlugin() < 0) {
1809 me_update_msg("failed to load cdr plugin");
1810 return -1;
1811 }
1812 if (CDR_open() < 0) {
1813 me_update_msg("failed to open cdr plugin");
1814 return -1;
1815 }
1816
1817 SetCdOpenCaseTime(time(NULL) + 2);
1818 LidInterrupt();
1819
1820 strcpy(last_selected_fname, rom_fname_reload);
1821 return 0;
1822}
1823
0c2871a7 1824static int swap_cd_multidisk(void)
1825{
1826 cdrIsoMultidiskSelect++;
1827 CdromId[0] = '\0';
1828 CdromLabel[0] = '\0';
1829
1830 CDR_close();
1831 if (CDR_open() < 0) {
1832 me_update_msg("failed to open cdr plugin");
1833 return -1;
1834 }
1835
1836 SetCdOpenCaseTime(time(NULL) + 2);
1837 LidInterrupt();
1838
1839 return 0;
1840}
1841
bbd837c6 1842static int main_menu_handler(int id, int keys)
1843{
69af03a2 1844 switch (id)
1845 {
1846 case MA_MAIN_RESUME_GAME:
3c70c47b 1847 if (ready_to_go)
1848 return 1;
69af03a2 1849 break;
1850 case MA_MAIN_SAVE_STATE:
1851 if (ready_to_go)
1852 return menu_loop_savestate(0);
1853 break;
1854 case MA_MAIN_LOAD_STATE:
1855 if (ready_to_go)
1856 return menu_loop_savestate(1);
1857 break;
1858 case MA_MAIN_RESET_GAME:
e16a7e51 1859 if (ready_to_go && reset_game() == 0)
3c70c47b 1860 return 1;
69af03a2 1861 break;
1862 case MA_MAIN_LOAD_ROM:
bbd837c6 1863 if (romsel_run() == 0)
69af03a2 1864 return 1;
1865 break;
1df403c5 1866 case MA_MAIN_SWAP_CD:
1867 if (swap_cd_image() == 0)
1868 return 1;
1869 break;
0c2871a7 1870 case MA_MAIN_SWAP_CD_MULTI:
1871 if (swap_cd_multidisk() == 0)
1872 return 1;
1873 break;
e16a7e51 1874 case MA_MAIN_RUN_BIOS:
1875 if (run_bios() == 0)
1876 return 1;
1877 break;
51f77282 1878 case MA_MAIN_RUN_EXE:
1879 if (run_exe() == 0)
1880 return 1;
1881 break;
69af03a2 1882 case MA_MAIN_CREDITS:
4f5a1b2a 1883 draw_menu_message(credits_text, draw_frame_credits);
69af03a2 1884 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1885 break;
1886 case MA_MAIN_EXIT:
bd6267e6 1887 OnFile_Exit();
1888 break;
69af03a2 1889 default:
1890 lprintf("%s: something unknown selected\n", __FUNCTION__);
1891 break;
1892 }
1893
1894 return 0;
1895}
1896
51f77282 1897static menu_entry e_menu_main2[] =
1898{
0c2871a7 1899 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1900 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1901 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1902 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
51f77282 1903 mee_handler ("Memcard manager", menu_loop_memcards),
1904 mee_end,
1905};
1906
1907static int main_menu2_handler(int id, int keys)
1908{
1909 static int sel = 0;
1910
1911 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
0c2871a7 1912 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
51f77282 1913 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1914
1915 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1916}
1917
1918static const char h_extra[] = "Change CD, manage memcards..\n";
1919
69af03a2 1920static menu_entry e_menu_main[] =
1921{
1922 mee_label (""),
1923 mee_label (""),
1924 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1925 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1926 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1927 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1928 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1929 mee_handler ("Options", menu_loop_options),
1930 mee_handler ("Controls", menu_loop_keyconfig),
51f77282 1931 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
69af03a2 1932 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1933 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1934 mee_end,
1935};
1936
3c70c47b 1937// ----------------------------
1938
bd6267e6 1939static void menu_leave_emu(void);
1940
69af03a2 1941void menu_loop(void)
1942{
1943 static int sel = 0;
1944
bd6267e6 1945 menu_leave_emu();
69af03a2 1946
4f5a1b2a 1947 if (bioses[1] == NULL && !warned_about_bios) {
1948 menu_bios_warn();
1949 warned_about_bios = 1;
1950 }
1951
69af03a2 1952 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
e16a7e51 1953 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1954 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
69af03a2 1955 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1956
69af03a2 1957 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1958
1959 do {
51f77282 1960 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
69af03a2 1961 } while (!ready_to_go);
1962
1963 /* wait until menu, ok, back is released */
1964 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1965 ;
1966
1967 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1968
3c70c47b 1969 menu_prepare_emu();
1970}
1971
51f77282 1972static int qsort_strcmp(const void *p1, const void *p2)
1973{
1974 char * const *s1 = (char * const *)p1;
1975 char * const *s2 = (char * const *)p2;
1976 return strcasecmp(*s1, *s2);
1977}
1978
e6eb2066 1979static void scan_bios_plugins(void)
bbd837c6 1980{
1981 char fname[MAXPATHLEN];
1982 struct dirent *ent;
51f77282 1983 int bios_i, gpu_i, spu_i, mc_i;
bbd837c6 1984 char *p;
1985 DIR *dir;
1986
e6eb2066 1987 bioses[0] = "HLE";
bbd837c6 1988 gpu_plugins[0] = "builtin_gpu";
1989 spu_plugins[0] = "builtin_spu";
51f77282 1990 memcards[0] = "(none)";
1991 bios_i = gpu_i = spu_i = mc_i = 1;
e6eb2066 1992
1993 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1994 dir = opendir(fname);
1995 if (dir == NULL) {
1996 perror("scan_bios_plugins bios opendir");
1997 goto do_plugins;
1998 }
1999
2000 while (1) {
2001 struct stat st;
2002
2003 errno = 0;
2004 ent = readdir(dir);
2005 if (ent == NULL) {
2006 if (errno != 0)
2007 perror("readdir");
2008 break;
2009 }
2010
2011 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2012 continue;
2013
2014 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2015 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2016 printf("bad BIOS file: %s\n", ent->d_name);
2017 continue;
2018 }
2019
2020 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2021 bioses[bios_i++] = strdup(ent->d_name);
2022 continue;
2023 }
2024
2025 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2026 }
2027
2028 closedir(dir);
bbd837c6 2029
e6eb2066 2030do_plugins:
bbd837c6 2031 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2032 dir = opendir(fname);
2033 if (dir == NULL) {
51f77282 2034 perror("scan_bios_plugins plugins opendir");
2035 goto do_memcards;
bbd837c6 2036 }
2037
2038 while (1) {
2039 void *h, *tmp;
2040
2041 errno = 0;
2042 ent = readdir(dir);
2043 if (ent == NULL) {
2044 if (errno != 0)
2045 perror("readdir");
2046 break;
2047 }
2048 p = strstr(ent->d_name, ".so");
2049 if (p == NULL)
2050 continue;
2051
2052 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2053 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2054 if (h == NULL) {
2055 fprintf(stderr, "%s\n", dlerror());
2056 continue;
2057 }
2058
2059 // now what do we have here?
2060 tmp = dlsym(h, "GPUinit");
2061 if (tmp) {
2062 dlclose(h);
2063 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2064 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2065 continue;
2066 }
2067
2068 tmp = dlsym(h, "SPUinit");
2069 if (tmp) {
2070 dlclose(h);
2071 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2072 spu_plugins[spu_i++] = strdup(ent->d_name);
2073 continue;
2074 }
2075
2076 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2077 dlclose(h);
2078 }
2079
2080 closedir(dir);
51f77282 2081
2082do_memcards:
2083 dir = opendir("." MEMCARD_DIR);
2084 if (dir == NULL) {
2085 perror("scan_bios_plugins memcards opendir");
2086 return;
2087 }
2088
2089 while (1) {
2090 struct stat st;
2091
2092 errno = 0;
2093 ent = readdir(dir);
2094 if (ent == NULL) {
2095 if (errno != 0)
2096 perror("readdir");
2097 break;
2098 }
2099
2100 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2101 continue;
2102
2103 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2104 if (stat(fname, &st) != 0) {
2105 printf("bad memcard file: %s\n", ent->d_name);
2106 continue;
2107 }
2108
2109 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2110 memcards[mc_i++] = strdup(ent->d_name);
2111 continue;
2112 }
2113
2114 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2115 }
2116
2117 if (mc_i > 2)
2118 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2119
2120 closedir(dir);
bbd837c6 2121}
2122
3c70c47b 2123void menu_init(void)
2124{
4f3639fa 2125 char buff[MAXPATHLEN];
2126
2127 strcpy(last_selected_fname, "/media");
2128
e6eb2066 2129 scan_bios_plugins();
4f3639fa 2130 pnd_menu_init();
2131 menu_init_common();
2132
3c70c47b 2133 menu_set_defconfig();
2134 menu_load_config(0);
3c70c47b 2135 last_psx_w = 320;
2136 last_psx_h = 240;
bd6267e6 2137 last_psx_bpp = 16;
2138
4f3639fa 2139 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2140 if (g_menubg_src_ptr == NULL)
2141 exit(1);
2142 emu_make_path(buff, "skin/background.png", sizeof(buff));
2143 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
55b0eeea 2144
2145#ifndef __ARM_ARCH_7A__ /* XXX */
2146 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2147 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2148#else
b944a30e 2149 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
55b0eeea 2150 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2151#endif
3c70c47b 2152}
2153
bd6267e6 2154void menu_notify_mode_change(int w, int h, int bpp)
3c70c47b 2155{
a185be70 2156 float mult;
2157 int imult;
2158
3c70c47b 2159 last_psx_w = w;
2160 last_psx_h = h;
bd6267e6 2161 last_psx_bpp = bpp;
3c70c47b 2162
a185be70 2163 switch (scaling) {
2164 case SCALE_1_1:
3c70c47b 2165 g_layer_w = w; g_layer_h = h;
a185be70 2166 break;
2167
a185be70 2168 case SCALE_4_3v2:
fb005d87 2169 if (h > g_menuscreen_h || (240 < h && h <= 360))
2170 goto fractional_4_3;
2171
a185be70 2172 // 4:3 that prefers integer scaling
2173 imult = g_menuscreen_h / h;
2174 g_layer_w = w * imult;
2175 g_layer_h = h * imult;
2176 mult = (float)g_layer_w / (float)g_layer_h;
2177 if (mult < 1.25f || mult > 1.666f)
2178 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2179 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2180 break;
2181
fb005d87 2182 fractional_4_3:
2183 case SCALE_4_3:
2184 mult = 240.0f / (float)h * 4.0f / 3.0f;
2185 if (h > 256)
2186 mult *= 2.0f;
2187 g_layer_w = mult * (float)g_menuscreen_h;
2188 g_layer_h = g_menuscreen_h;
2189 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2190 break;
2191
a185be70 2192 case SCALE_FULLSCREEN:
2193 g_layer_w = g_menuscreen_w;
2194 g_layer_h = g_menuscreen_h;
2195 break;
2196
2197 default:
2198 break;
3c70c47b 2199 }
a185be70 2200
2201 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2202 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2203 if (g_layer_x < 0) g_layer_x = 0;
2204 if (g_layer_y < 0) g_layer_y = 0;
2205 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2206 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
3c70c47b 2207}
2208
bd6267e6 2209static void menu_leave_emu(void)
2210{
6d1a1ac2 2211 if (GPU_close != NULL) {
2212 int ret = GPU_close();
2213 if (ret)
2214 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2215 }
bd6267e6 2216
55b0eeea 2217 plat_video_menu_enter(ready_to_go);
2218
4f3639fa 2219 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
76f7048e 2220 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
bd6267e6 2221 int x = max(0, g_menuscreen_w - last_psx_w);
2222 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2223 int w = min(g_menuscreen_w, last_psx_w);
2224 int h = min(g_menuscreen_h, last_psx_h);
4f3639fa 2225 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
76f7048e 2226 u16 *s = pl_vout_buf;
bd6267e6 2227
2228 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
4f3639fa 2229 menu_darken_bg(d, s, w, 0);
bd6267e6 2230 }
fba06457 2231
1bd9ee68 2232 if (ready_to_go)
55b0eeea 2233 cpu_clock = plat_cpu_clock_get();
bd6267e6 2234}
2235
3c70c47b 2236void menu_prepare_emu(void)
2237{
b5e7e49a 2238 R3000Acpu *prev_cpu = psxCpu;
2239
fba06457 2240 plat_video_menu_leave();
2241
a185be70 2242 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
bd6267e6 2243
b5e7e49a 2244 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2245 if (psxCpu != prev_cpu)
2246 // note that this does not really reset, just clears drc caches
2247 psxCpu->Reset();
2248
bd6267e6 2249 // core doesn't care about Config.Cdda changes,
2250 // so handle them manually here
2251 if (Config.Cdda)
2252 CDR_stop();
6d1a1ac2 2253
907b1e90 2254 menu_sync_config();
cefe86b7 2255 apply_lcdrate(Config.PsxType);
2256 apply_filter(filter);
55b0eeea 2257 plat_cpu_clock_apply(cpu_clock);
fba06457 2258
e64dc4c5 2259 // push config to GPU plugin
2260 plugin_call_rearmed_cbs();
2261
6d1a1ac2 2262 if (GPU_open != NULL) {
6d1a1ac2 2263 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2264 if (ret)
2265 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2266 }
384f5f43 2267
4c08b9e7 2268 dfinput_activate();
69af03a2 2269}
2270
2271void me_update_msg(const char *msg)
2272{
2273 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2274 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2275
2276 menu_error_time = plat_get_ticks_ms();
2277 lprintf("msg: %s\n", menu_error_msg);
2278}
2279