gpu_neon/psx_gpu: remove unused psx_gpu_alt
[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),
89c0de42 286 CE_INTVAL_P(gpu_unai.lineskip),
17a54a4a 287 CE_INTVAL_P(gpu_unai.abe_hack),
288 CE_INTVAL_P(gpu_unai.no_light),
289 CE_INTVAL_P(gpu_unai.no_blend),
ffdbda29 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),
4f5a1b2a 295 CE_INTVAL(warned_about_bios),
ef94866c 296 CE_INTVAL(in_evdev_allow_abs_only),
9e7a7352 297 CE_INTVAL(volume_boost),
2573466a 298 CE_INTVAL(psx_clock),
0ff8c62c 299 CE_INTVAL(new_dynarec_hacks),
b944a30e 300 CE_INTVAL(in_enable_vibration),
4f3639fa 301};
302
1bd9ee68 303static char *get_cd_label(void)
cd6e8d0f 304{
1bd9ee68 305 static char trimlabel[33];
cd6e8d0f 306 int j;
307
308 strncpy(trimlabel, CdromLabel, 32);
309 trimlabel[32] = 0;
310 for (j = 31; j >= 0; j--)
311 if (trimlabel[j] == ' ')
312 trimlabel[j] = 0;
313
1bd9ee68 314 return trimlabel;
315}
316
317static void make_cfg_fname(char *buf, size_t size, int is_game)
318{
cd6e8d0f 319 if (is_game)
1bd9ee68 320 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
cd6e8d0f 321 else
bbd837c6 322 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
cd6e8d0f 323}
324
43bca6fb 325static void keys_write_all(FILE *f);
326
3c70c47b 327static int menu_write_config(int is_game)
328{
4f3639fa 329 char cfgfile[MAXPATHLEN];
330 FILE *f;
331 int i;
332
cd6e8d0f 333 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
4f3639fa 334 f = fopen(cfgfile, "w");
335 if (f == NULL) {
bbd837c6 336 printf("menu_write_config: failed to open: %s\n", cfgfile);
4f3639fa 337 return -1;
338 }
339
340 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
341 fprintf(f, "%s = ", config_data[i].name);
342 switch (config_data[i].len) {
343 case 0:
344 fprintf(f, "%s\n", (char *)config_data[i].val);
345 break;
346 case 1:
347 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
348 break;
349 case 2:
350 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
351 break;
352 case 4:
353 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
354 break;
355 default:
356 printf("menu_write_config: unhandled len %d for %s\n",
357 config_data[i].len, config_data[i].name);
358 break;
359 }
360 }
361
362 if (!is_game)
363 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
364
43bca6fb 365 keys_write_all(f);
4f3639fa 366 fclose(f);
43bca6fb 367
4f3639fa 368 return 0;
369}
370
371static void parse_str_val(char *cval, const char *src)
372{
373 char *tmp;
374 strncpy(cval, src, MAXPATHLEN);
375 cval[MAXPATHLEN - 1] = 0;
376 tmp = strchr(cval, '\n');
377 if (tmp == NULL)
378 tmp = strchr(cval, '\r');
379 if (tmp != NULL)
380 *tmp = 0;
3c70c47b 381}
382
43bca6fb 383static void keys_load_all(const char *cfg);
384
3c70c47b 385static int menu_load_config(int is_game)
69af03a2 386{
4f3639fa 387 char cfgfile[MAXPATHLEN];
388 int i, ret = -1;
389 long size;
390 char *cfg;
391 FILE *f;
392
cd6e8d0f 393 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
4f3639fa 394 f = fopen(cfgfile, "r");
395 if (f == NULL) {
bbd837c6 396 printf("menu_load_config: failed to open: %s\n", cfgfile);
cbd45cda 397 goto fail;
4f3639fa 398 }
399
400 fseek(f, 0, SEEK_END);
401 size = ftell(f);
402 if (size <= 0) {
403 printf("bad size %ld: %s\n", size, cfgfile);
404 goto fail;
405 }
406
407 cfg = malloc(size + 1);
408 if (cfg == NULL)
409 goto fail;
410
411 fseek(f, 0, SEEK_SET);
412 if (fread(cfg, 1, size, f) != size) {
413 printf("failed to read: %s\n", cfgfile);
414 goto fail_read;
415 }
416 cfg[size] = 0;
417
418 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
419 char *tmp, *tmp2;
420 u32 val;
421
422 tmp = strstr(cfg, config_data[i].name);
423 if (tmp == NULL)
424 continue;
425 tmp += strlen(config_data[i].name);
426 if (strncmp(tmp, " = ", 3) != 0)
427 continue;
428 tmp += 3;
429
430 if (config_data[i].len == 0) {
431 parse_str_val(config_data[i].val, tmp);
432 continue;
433 }
434
435 tmp2 = NULL;
436 val = strtoul(tmp, &tmp2, 16);
437 if (tmp2 == NULL || tmp == tmp2)
438 continue; // parse failed
439
440 switch (config_data[i].len) {
441 case 1:
442 *(u8 *)config_data[i].val = val;
443 break;
444 case 2:
445 *(u16 *)config_data[i].val = val;
446 break;
447 case 4:
448 *(u32 *)config_data[i].val = val;
449 break;
450 default:
451 printf("menu_load_config: unhandled len %d for %s\n",
452 config_data[i].len, config_data[i].name);
453 break;
454 }
455 }
456
457 if (!is_game) {
458 char *tmp = strstr(cfg, "lastcdimg = ");
459 if (tmp != NULL) {
460 tmp += 12;
461 parse_str_val(last_selected_fname, tmp);
462 }
463 }
464
cbd45cda 465 keys_load_all(cfg);
466 ret = 0;
467fail_read:
468 free(cfg);
469fail:
470 if (f != NULL)
471 fclose(f);
472
907b1e90 473 menu_sync_config();
474
bbd837c6 475 // sync plugins
e6eb2066 476 for (i = bios_sel = 0; bioses[i] != NULL; i++)
477 if (strcmp(Config.Bios, bioses[i]) == 0)
478 { bios_sel = i; break; }
479
bbd837c6 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; }
483
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; }
487
4f3639fa 488 return ret;
69af03a2 489}
490
9564e73d 491// rrrr rggg gggb bbbb
492static unsigned short fname2color(const char *fname)
493{
bab59f00 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" };
9564e73d 498 const char *ext = strrchr(fname, '.');
499 int i;
500
501 if (ext == NULL)
502 return 0xffff;
503 for (i = 0; i < array_size(cdimg_exts); i++)
504 if (strcasecmp(ext, cdimg_exts[i]) == 0)
505 return 0x7bff;
506 for (i = 0; i < array_size(other_exts); i++)
507 if (strcasecmp(ext, other_exts[i]) == 0)
508 return 0xa514;
509 return 0xffff;
510}
511
61363062 512static void draw_savestate_bg(int slot);
513
f246f461 514static const char *filter_exts[] = {
515 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
516};
517
bd6267e6 518#define MENU_ALIGN_LEFT
55b0eeea 519#ifdef __ARM_ARCH_7A__ // assume hires device
520#define MENU_X2 1
521#else
522#define MENU_X2 0
523#endif
524
3c70c47b 525#define menu_init menu_init_common
69af03a2 526#include "common/menu.c"
3c70c47b 527#undef menu_init
69af03a2 528
61363062 529// a bit of black magic here
530static void draw_savestate_bg(int slot)
531{
61363062 532 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
533 int x, y, w, h;
534 char fname[MAXPATHLEN];
535 GPUFreeze_t *gpu;
536 u16 *s, *d;
537 gzFile f;
538 int ret;
539 u32 tmp;
540
541 ret = get_state_filename(fname, sizeof(fname), slot);
542 if (ret != 0)
543 return;
544
545 f = gzopen(fname, "rb");
546 if (f == NULL)
547 return;
548
549 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
550 fprintf(stderr, "gzseek failed\n");
551 gzclose(f);
552 return;
553 }
554
555 gpu = malloc(sizeof(*gpu));
556 if (gpu == NULL) {
557 gzclose(f);
558 return;
559 }
560
561 ret = gzread(f, gpu, sizeof(*gpu));
562 gzclose(f);
563 if (ret != sizeof(*gpu)) {
564 fprintf(stderr, "gzread failed\n");
565 goto out;
566 }
567
568 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
569
ff847a2e 570 if (gpu->ulStatus & 0x800000)
571 goto out; // disabled
61363062 572
573 x = gpu->ulControl[5] & 0x3ff;
574 y = (gpu->ulControl[5] >> 10) & 0x1ff;
ff847a2e 575 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
61363062 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
580 h *= 2;
581
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;
587
55b0eeea 588 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
ff847a2e 589 if (gpu->ulStatus & 0x200000)
590 bgr888_to_rgb565(d, s, w * 3);
591 else
592 bgr555_to_rgb565(d, s, w * 2);
55b0eeea 593#ifndef __ARM_ARCH_7A__
594 // better darken this on small screens
595 menu_darken_bg(d, d, w * 2, 0);
596#endif
597 }
61363062 598
599out:
600 free(gpu);
601}
602
55b0eeea 603// ---------- XXX: pandora specific -----------
3c70c47b 604
605static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
606static char **pnd_filter_list;
607
3c70c47b 608static void apply_filter(int which)
609{
4f3639fa 610 static int old = -1;
3c70c47b 611 char buf[128];
612 int i;
613
4f3639fa 614 if (pnd_filter_list == NULL || which == old)
3c70c47b 615 return;
616
617 for (i = 0; i < which; i++)
618 if (pnd_filter_list[i] == NULL)
619 return;
620
621 if (pnd_filter_list[i] == NULL)
622 return;
623
624 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
625 system(buf);
4f3639fa 626 old = which;
3c70c47b 627}
628
cefe86b7 629static void apply_lcdrate(int pal)
630{
631 static int old = -1;
632 char buf[128];
633
634 if (pal == old)
635 return;
636
637 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
638 pnd_script_base, pal ? 50 : 60);
639 system(buf);
640 old = pal;
641}
642
3c70c47b 643static menu_entry e_menu_gfx_options[];
644
645static void pnd_menu_init(void)
646{
647 struct dirent *ent;
648 int i, count = 0;
649 char **mfilters;
1bd9ee68 650 char buff[64];
3c70c47b 651 DIR *dir;
652
55b0eeea 653 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
3c70c47b 654
655 dir = opendir("/etc/pandora/conf/dss_fir");
656 if (dir == NULL) {
657 perror("filter opendir");
658 return;
659 }
660
661 while (1) {
662 errno = 0;
663 ent = readdir(dir);
664 if (ent == NULL) {
665 if (errno != 0)
666 perror("readdir");
667 break;
668 }
1bd9ee68 669
670 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
671 continue;
672
673 count++;
3c70c47b 674 }
675
676 if (count == 0)
677 return;
678
679 mfilters = calloc(count + 1, sizeof(mfilters[0]));
680 if (mfilters == NULL)
681 return;
682
683 rewinddir(dir);
684 for (i = 0; (ent = readdir(dir)); ) {
685 size_t len;
686
1bd9ee68 687 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
688 continue;
689
690 len = strlen(ent->d_name);
691
692 // skip pre-HF5 extra files
693 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
694 continue;
695 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
3c70c47b 696 continue;
697
1bd9ee68 698 // have to cut "_up_h" for pre-HF5
699 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
700 len -= 5;
701
3c70c47b 702 if (len > sizeof(buff) - 1)
703 continue;
704
705 strncpy(buff, ent->d_name, len);
706 buff[len] = 0;
707 mfilters[i] = strdup(buff);
708 if (mfilters[i] != NULL)
709 i++;
710 }
711 closedir(dir);
712
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;
69af03a2 716}
717
201c21e2 718void menu_finish(void)
719{
55b0eeea 720 plat_cpu_clock_apply(cpu_clock_st);
201c21e2 721}
722
69af03a2 723// -------------- key config --------------
724
725me_bind_action me_ctrl_actions[] =
726{
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 },
22a8a805 732 { "CIRCLE ", 1 << DKEY_CIRCLE },
69af03a2 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 },
43bca6fb 739 { "L3 ", 1 << DKEY_L3 },
740 { "R3 ", 1 << DKEY_R3 },
69af03a2 741 { "START ", 1 << DKEY_START },
742 { "SELECT ", 1 << DKEY_SELECT },
743 { NULL, 0 }
744};
745
746me_bind_action emuctrl_actions[] =
747{
8f892648 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 },
29a8c4f3 753 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
8f892648 754 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
4c08b9e7 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 },
221be40d 759#ifndef __ARM_ARCH_7A__ /* XXX */
760 { "Volume Up ", 1 << SACTION_VOLUME_UP },
761 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
762#endif
69af03a2 763 { NULL, 0 }
764};
765
43bca6fb 766static char *mystrip(char *str)
767{
768 int i, len;
769
770 len = strlen(str);
771 for (i = 0; i < len; i++)
772 if (str[i] != ' ') break;
773 if (i > 0) memmove(str, str + i, len - i + 1);
774
775 len = strlen(str);
776 for (i = len - 1; i >= 0; i--)
777 if (str[i] != ' ') break;
778 str[i+1] = 0;
779
780 return str;
781}
782
783static void get_line(char *d, size_t size, const char *s)
784{
785 const char *pe;
786 size_t len;
787
788 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
789 ;
790 len = pe - s;
791 if (len > size - 1)
792 len = size - 1;
793 strncpy(d, s, len);
794 d[len] = 0;
795
796 mystrip(d);
797}
798
799static void keys_write_all(FILE *f)
800{
801 int d;
802
803 for (d = 0; d < IN_MAX_DEVS; d++)
804 {
805 const int *binds = in_get_dev_binds(d);
806 const char *name = in_get_dev_name(d, 0, 0);
807 int k, count = 0;
808
809 if (binds == NULL || name == NULL)
810 continue;
811
812 fprintf(f, "binddev = %s\n", name);
813 in_get_config(d, IN_CFG_BIND_COUNT, &count);
814
815 for (k = 0; k < count; k++)
816 {
817 int i, kbinds, mask;
818 char act[32];
819
820 act[0] = act[31] = 0;
821 name = in_get_key_name(d, k);
822
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;
826 if (mask & kbinds) {
827 strncpy(act, me_ctrl_actions[i].name, 31);
828 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
829 kbinds &= ~mask;
830 }
831 mask = me_ctrl_actions[i].mask << 16;
832 if (mask & kbinds) {
833 strncpy(act, me_ctrl_actions[i].name, 31);
834 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
835 kbinds &= ~mask;
836 }
837 }
838
839 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
221be40d 840 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
43bca6fb 841 mask = emuctrl_actions[i].mask;
842 if (mask & kbinds) {
843 strncpy(act, emuctrl_actions[i].name, 31);
844 fprintf(f, "bind %s = %s\n", name, mystrip(act));
845 kbinds &= ~mask;
846 }
847 }
848 }
1b0c5139 849
850 for (k = 0; k < array_size(in_adev); k++)
851 {
852 if (in_adev[k] == d)
853 fprintf(f, "bind_analog = %d\n", k);
854 }
43bca6fb 855 }
856}
857
858static int parse_bind_val(const char *val, int *type)
859{
860 int i;
861
862 *type = IN_BINDTYPE_NONE;
863 if (val[0] == 0)
864 return 0;
865
866 if (strncasecmp(val, "player", 6) == 0)
867 {
868 int player, shift = 0;
869 player = atoi(val + 6) - 1;
870
871 if ((unsigned int)player > 1)
872 return -1;
873 if (player == 1)
874 shift = 16;
875
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;
880 }
881 }
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;
886 }
887 }
888
889 return -1;
890}
891
892static void keys_load_all(const char *cfg)
893{
894 char dev[256], key[128], *act;
895 const char *p;
896 int bind, bindtype;
1b0c5139 897 int ret, dev_id;
43bca6fb 898
899 p = cfg;
900 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
901 p += 10;
902
903 get_line(dev, sizeof(dev), p);
904 dev_id = in_config_parse_dev(dev);
905 if (dev_id < 0) {
906 printf("input: can't handle dev: %s\n", dev);
907 continue;
908 }
909
910 in_unbind_all(dev_id, -1, -1);
911 while ((p = strstr(p, "bind"))) {
912 if (strncmp(p, "binddev = ", 10) == 0)
913 break;
914
1b0c5139 915 if (strncmp(p, "bind_analog", 11) == 0) {
916 ret = sscanf(p, "bind_analog = %d", &bind);
917 p += 11;
918 if (ret != 1) {
919 printf("input: parse error: %16s..\n", p);
920 continue;
921 }
922 if ((unsigned int)bind >= array_size(in_adev)) {
923 printf("input: analog id %d out of range\n", bind);
924 continue;
925 }
926 in_adev[bind] = dev_id;
927 continue;
928 }
929
43bca6fb 930 p += 4;
931 if (*p != ' ') {
932 printf("input: parse error: %16s..\n", p);
933 continue;
934 }
935
936 get_line(key, sizeof(key), p);
937 act = strchr(key, '=');
938 if (act == NULL) {
939 printf("parse failed: %16s..\n", p);
940 continue;
941 }
942 *act = 0;
943 act++;
944 mystrip(key);
945 mystrip(act);
946
947 bind = parse_bind_val(act, &bindtype);
948 if (bind != -1 && bind != 0) {
8f892648 949 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
43bca6fb 950 in_config_bind_key(dev_id, key, bind, bindtype);
951 }
952 else
953 lprintf("config: unhandled action \"%s\"\n", act);
954 }
955 }
ef94866c 956 in_clean_binds();
43bca6fb 957}
958
69af03a2 959static int key_config_loop_wrap(int id, int keys)
960{
961 switch (id) {
962 case MA_CTRL_PLAYER1:
963 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
964 break;
965 case MA_CTRL_PLAYER2:
966 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
967 break;
968 case MA_CTRL_EMU:
969 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
970 break;
971 default:
972 break;
973 }
974 return 0;
975}
976
1b0c5139 977static const char *adevnames[IN_MAX_DEVS + 2];
978static int stick_sel[2];
979
980static menu_entry e_menu_keyconfig_analog[] =
981{
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),
988 mee_end,
989};
990
991static int key_config_analog(int id, int keys)
992{
993 int i, d, count, sel = 0;
994 int sel2dev_map[IN_MAX_DEVS];
995
996 memset(adevnames, 0, sizeof(adevnames));
997 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
998 memset(stick_sel, 0, sizeof(stick_sel));
999
1000 adevnames[0] = "None";
1001 i = 1;
1002 for (d = 0; d < IN_MAX_DEVS; d++)
1003 {
1004 const char *name = in_get_dev_name(d, 0, 1);
1005 if (name == NULL)
1006 continue;
1007
1008 count = 0;
1009 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
1010 if (count == 0)
1011 continue;
1012
1013 if (in_adev[0] == d) stick_sel[0] = i;
1014 if (in_adev[1] == d) stick_sel[1] = i;
1015 sel2dev_map[i] = d;
1016 adevnames[i++] = name;
1017 }
1018 adevnames[i] = NULL;
1019
1020 me_loop(e_menu_keyconfig_analog, &sel);
1021
1022 in_adev[0] = sel2dev_map[stick_sel[0]];
1023 in_adev[1] = sel2dev_map[stick_sel[1]];
1024
1025 return 0;
1026}
1027
69af03a2 1028static const char *mgn_dev_name(int id, int *offs)
1029{
1030 const char *name = NULL;
1031 static int it = 0;
1032
1033 if (id == MA_CTRL_DEV_FIRST)
1034 it = 0;
1035
1036 for (; it < IN_MAX_DEVS; it++) {
1037 name = in_get_dev_name(it, 1, 1);
1038 if (name != NULL)
1039 break;
1040 }
1041
1042 it++;
1043 return name;
1044}
1045
1046static const char *mgn_saveloadcfg(int id, int *offs)
1047{
1048 return "";
1049}
1050
cd6e8d0f 1051static int mh_savecfg(int id, int keys)
69af03a2 1052{
cd6e8d0f 1053 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
1054 me_update_msg("config saved");
1055 else
1056 me_update_msg("failed to write config");
69af03a2 1057
1058 return 1;
1059}
1060
ef94866c 1061static int mh_input_rescan(int id, int keys)
1062{
1063 //menu_sync_config();
9b4bd105 1064 in_probe();
ef94866c 1065 me_update_msg("rescan complete.");
1066
1067 return 0;
1068}
1069
4c08b9e7 1070static const char *men_in_type_sel[] = {
1071 "Standard (SCPH-1080)",
1072 "Analog (SCPH-1150)",
1073 "GunCon",
1074 NULL
1075};
ef94866c 1076static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
b944a30e 1077static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
1078static const char h_vibration[]= "Must select analog above and enable this ingame too.";
799b0b87 1079
69af03a2 1080static menu_entry e_menu_keyconfig[] =
1081{
4c08b9e7 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),
1b0c5139 1084 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
4c08b9e7 1085 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
799b0b87 1086 mee_label (""),
4c08b9e7 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),
55b0eeea 1089 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
b944a30e 1090 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
55b0eeea 1091 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
4c08b9e7 1092 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
799b0b87 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),
1b0c5139 1095 mee_handler ("Rescan devices:", mh_input_rescan),
69af03a2 1096 mee_label (""),
69af03a2 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),
1104 mee_end,
1105};
1106
1107static int menu_loop_keyconfig(int id, int keys)
1108{
1109 static int sel = 0;
1110
e16a7e51 1111// me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
51f77282 1112 me_loop(e_menu_keyconfig, &sel);
69af03a2 1113 return 0;
1114}
1115
69af03a2 1116// ------------ gfx options menu ------------
1117
a185be70 1118static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
3c70c47b 1119static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1120 "using d-pad or move it using R+d-pad";
1121static const char *men_dummy[] = { NULL };
1122
1123static int menu_loop_cscaler(int id, int keys)
1124{
1125 unsigned int inp;
1126
1127 scaling = SCALE_CUSTOM;
1128
1129 omap_enable_layer(1);
3c70c47b 1130
1131 for (;;)
1132 {
1133 menu_draw_begin(0);
201c21e2 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);
3c70c47b 1137 menu_draw_end();
1138
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;
1149 }
1150 if (inp & (PBTN_MOK|PBTN_MBACK))
1151 break;
1152
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);
1165 }
1166 }
1167
1168 omap_enable_layer(0);
1169
1170 return 0;
1171}
1172
69af03a2 1173static menu_entry e_menu_gfx_options[] =
1174{
3c70c47b 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),
69af03a2 1179 mee_end,
1180};
1181
1182static int menu_loop_gfx_options(int id, int keys)
1183{
1184 static int sel = 0;
1185
51f77282 1186 me_loop(e_menu_gfx_options, &sel);
69af03a2 1187
1188 return 0;
1189}
1190
bd6267e6 1191// ------------ bios/plugins ------------
1192
17a54a4a 1193static menu_entry e_menu_plugin_gpu_unai[] =
1194{
89c0de42 1195 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
17a54a4a 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),
1199 mee_end,
1200};
1201
1202static int menu_loop_plugin_gpu_unai(int id, int keys)
1203{
1204 int sel = 0;
1205 me_loop(e_menu_plugin_gpu_unai, &sel);
1206 return 0;
1207}
1208
bd6267e6 1209static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
bd6267e6 1210static const char h_gpu_0[] = "Needed for Chrono Cross";
1211static const char h_gpu_1[] = "Capcom fighting games";
1212static const char h_gpu_2[] = "Black screens in Lunar";
1213static const char h_gpu_3[] = "Compatibility mode";
1214static const char h_gpu_6[] = "Pandemonium 2";
1215static const char h_gpu_7[] = "Skip every second frame";
1216static const char h_gpu_8[] = "Needed by Dark Forces";
1217static const char h_gpu_9[] = "better g-colors, worse textures";
1218static const char h_gpu_10[] = "Toggle busy flags after drawing";
1219
17a54a4a 1220static menu_entry e_menu_plugin_gpu_peops[] =
bd6267e6 1221{
e64dc4c5 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),
bd6267e6 1232 mee_end,
1233};
1234
17a54a4a 1235static int menu_loop_plugin_gpu_peops(int id, int keys)
bd6267e6 1236{
1237 static int sel = 0;
17a54a4a 1238 me_loop(e_menu_plugin_gpu_peops, &sel);
bd6267e6 1239 return 0;
1240}
1241
bd6267e6 1242static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
9e7a7352 1243static const char h_spu_volboost[] = "Large values cause distortion";
cdb31c95 1244static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1bd9ee68 1245static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
bd6267e6 1246
1247static menu_entry e_menu_plugin_spu[] =
1248{
9e7a7352 1249 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
381ea103 1250 mee_onoff ("Reverb", 0, iUseReverb, 2),
bd6267e6 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),
1bd9ee68 1254 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
bd6267e6 1255 mee_end,
1256};
1257
1258static int menu_loop_plugin_spu(int id, int keys)
1259{
1260 static int sel = 0;
51f77282 1261 me_loop(e_menu_plugin_spu, &sel);
bd6267e6 1262 return 0;
1263}
1264
55b0eeea 1265static 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";
bbd837c6 1268static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1269 "for plugin change to take effect";
17a54a4a 1270static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1271static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
e6eb2066 1272static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
bbd837c6 1273
bd6267e6 1274static menu_entry e_menu_plugin_options[] =
1275{
e6eb2066 1276 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
bbd837c6 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),
17a54a4a 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),
bd6267e6 1281 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1282 mee_end,
1283};
1284
51f77282 1285static menu_entry e_menu_main2[];
e16a7e51 1286
bd6267e6 1287static int menu_loop_plugin_options(int id, int keys)
1288{
1289 static int sel = 0;
51f77282 1290 me_loop(e_menu_plugin_options, &sel);
bbd837c6 1291
e6eb2066 1292 // sync BIOS/plugins
1293 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
bbd837c6 1294 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1295 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
51f77282 1296 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
bbd837c6 1297
bd6267e6 1298 return 0;
1299}
1300
1301// ------------ adv options menu ------------
1302
0ff8c62c 1303static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
bab59f00 1304static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
0ff8c62c 1305static const char h_cfg_gteunn[] = "May cause graphical glitches";
1306static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1307
1308static menu_entry e_menu_speed_hacks[] =
1309{
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),
1314 mee_end,
1315};
1316
1317static int menu_loop_speed_hacks(int id, int keys)
1318{
1319 static int sel = 0;
1320 me_loop(e_menu_speed_hacks, &sel);
1321 return 0;
1322}
1323
4feed8d3 1324static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
8f892648 1325static const char h_cfg_cpul[] = "Shows CPU usage in %";
90f1d26c 1326static const char h_cfg_spu[] = "Shows active SPU channels\n"
1327 "(green: normal, red: fmod, blue: noise)";
1bd9ee68 1328static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
bd6267e6 1329static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1330static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1331 "(proper .cue/.bin dump is needed otherwise)";
4feed8d3 1332static const char h_cfg_sio[] = "You should not need this, breaks games";
1333static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1334static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1335 "(timing hack, breaks other games)";
1336static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1337 "(timing hack, breaks other games)";
0ff8c62c 1338static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
b5e7e49a 1339static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1340 "Might be useful to overcome some dynarec bugs";
0ff8c62c 1341static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1342 "must reload game for any change to take effect";
bd6267e6 1343
1344static menu_entry e_menu_adv_options[] =
1345{
fba06457 1346 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
90f1d26c 1347 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
bce6b056 1348 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
bd6267e6 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),
b1be1eee 1353 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
bd6267e6 1354 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
4feed8d3 1355 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
b5e7e49a 1356 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
0ff8c62c 1357 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
bd6267e6 1358 mee_end,
1359};
1360
1361static int menu_loop_adv_options(int id, int keys)
1362{
1363 static int sel = 0;
51f77282 1364 me_loop(e_menu_adv_options, &sel);
bd6267e6 1365 return 0;
1366}
1367
69af03a2 1368// ------------ options menu ------------
1369
69af03a2 1370static int mh_restore_defaults(int id, int keys)
1371{
3c70c47b 1372 menu_set_defconfig();
69af03a2 1373 me_update_msg("defaults restored");
1374 return 1;
1375}
1376
907b1e90 1377static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
9fe27e25 1378static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
bd6267e6 1379/*
69af03a2 1380static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1381static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1382 "loading state or both";
bd6267e6 1383*/
1384static const char h_restore_def[] = "Switches back to default / recommended\n"
1385 "configuration";
9f4a4237 1386static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
69af03a2 1387
1388static menu_entry e_menu_options[] =
1389{
bd6267e6 1390// mee_range ("Save slot", 0, state_slot, 0, 9),
1391// mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
ea4a16e7 1392 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
bd6267e6 1393 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
907b1e90 1394 mee_enum ("Region", 0, region, men_region),
3c70c47b 1395 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
55b0eeea 1396 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
bd6267e6 1397 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
69af03a2 1398 mee_handler ("[Advanced]", menu_loop_adv_options),
cd6e8d0f 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),
bd6267e6 1401 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
69af03a2 1402 mee_end,
1403};
1404
1405static int menu_loop_options(int id, int keys)
1406{
1407 static int sel = 0;
1408 int i;
1409
1410 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
3c70c47b 1411 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
e16a7e51 1412 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
69af03a2 1413
51f77282 1414 me_loop(e_menu_options, &sel);
69af03a2 1415
1416 return 0;
1417}
1418
1419// ------------ debug menu ------------
1420
72bb6fdd 1421static void draw_frame_debug(GPUFreeze_t *gpuf)
69af03a2 1422{
72bb6fdd 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;
1427 char buff[64];
1428 int ty = 1;
1429
1430 gpuf->ulFreezeVersion = 1;
1431 if (GPU_freeze != NULL)
1432 GPU_freeze(1, gpuf);
1433
1434 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1435 bgr555_to_rgb565(d, s, w * 2);
1436
3c70c47b 1437 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
72bb6fdd 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);
69af03a2 1442}
1443
1444static void debug_menu_loop(void)
1445{
72bb6fdd 1446 GPUFreeze_t *gpuf;
69af03a2 1447 int inp;
1448
72bb6fdd 1449 gpuf = malloc(sizeof(*gpuf));
1450 if (gpuf == NULL)
1451 return;
1452
69af03a2 1453 while (1)
1454 {
72bb6fdd 1455 menu_draw_begin(0);
1456 draw_frame_debug(gpuf);
69af03a2 1457 menu_draw_end();
1458
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)
72bb6fdd 1462 break;
69af03a2 1463 }
72bb6fdd 1464
1465 free(gpuf);
69af03a2 1466}
1467
51f77282 1468// --------- memcard manager ---------
1469
1470static void draw_mc_icon(int dx, int dy, const u16 *s)
1471{
1472 u16 *d;
1473 int x, y, l, p;
1474
1475 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1476
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++) {
1480 p = s[x];
1481 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1482 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1483 }
1484 }
1485 }
1486}
1487
1488static void draw_mc_bg(void)
1489{
1490 McdBlock *blocks1, *blocks2;
1491 int maxicons = 15;
1492 int i, y, row2;
1493
1494 blocks1 = malloc(15 * sizeof(blocks1[0]));
1495 blocks2 = malloc(15 * sizeof(blocks1[0]));
1496 if (blocks1 == NULL || blocks2 == NULL)
1497 goto out;
1498
1499 for (i = 0; i < 15; i++) {
1500 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1501 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1502 }
1503
1504 menu_draw_begin(1);
1505
1506 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1507
1508 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1509 if (y < 0) {
1510 // doesn't fit..
1511 y = 0;
1512 maxicons = g_menuscreen_h / 32;
1513 }
1514
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);
1519
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);
1522 }
1523
1524 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1525
1526 menu_draw_end();
1527out:
1528 free(blocks1);
1529 free(blocks2);
1530}
1531
1532static void handle_memcard_sel(void)
1533{
1534 Config.Mcd1[0] = 0;
1535 if (memcard1_sel != 0)
1536 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1537 Config.Mcd2[0] = 0;
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);
1541 draw_mc_bg();
1542}
1543
1544static menu_entry e_memcard_options[] =
1545{
1546 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1547 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1548 mee_end,
1549};
1550
1551static int menu_loop_memcards(int id, int keys)
1552{
1553 static int sel = 0;
1554 char *p;
1555 int i;
1556
1557 memcard1_sel = memcard2_sel = 0;
1558 p = strrchr(Config.Mcd1, '/');
1559 if (p != NULL)
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, '/');
1564 if (p != NULL)
1565 for (i = 0; memcards[i] != NULL; i++)
1566 if (strcmp(p + 1, memcards[i]) == 0)
1567 { memcard2_sel = i; break; }
1568
1569 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1570
1571 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1572
1573 return 0;
1574}
1575
1576// --------- main menu help ----------
69af03a2 1577
4f5a1b2a 1578static void menu_bios_warn(void)
1579{
1580 int inp;
1581 static const char msg[] =
cbd45cda 1582 "You don't seem to have copied any BIOS\n"
1583 "files to\n"
1584#ifdef __ARM_ARCH_7A__ // XXX
4f5a1b2a 1585 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
cbd45cda 1586#else
1587 "pcsx_rearmed/bios/\n\n"
1588#endif
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"
1597 "used too.\n\n"
4f5a1b2a 1598 "Press (B) or (X) to continue";
1599
1600 while (1)
1601 {
4f5a1b2a 1602 draw_menu_message(msg, NULL);
4f5a1b2a 1603
1604 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1605 if (inp & (PBTN_MBACK|PBTN_MOK))
1606 return;
1607 }
1608}
1609
1610// ------------ main menu ------------
1611
bd6267e6 1612void OnFile_Exit();
1613
1bd9ee68 1614static void draw_frame_main(void)
1615{
65092fd8 1616 struct tm *tmp;
1617 time_t ltime;
1618 char ltime_s[16];
1619 char buff[64];
1620
1bd9ee68 1621 if (CdromId[0] != 0) {
c22b95ab 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");
1bd9ee68 1625 smalltext_out16(4, 1, buff, 0x105f);
1626 }
65092fd8 1627
1628 if (ready_to_go) {
1629 ltime = time(NULL);
1630 tmp = localtime(&ltime);
1631 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
55b0eeea 1632 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
65092fd8 1633 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1634 }
1bd9ee68 1635}
1636
1637static void draw_frame_credits(void)
1638{
1639 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1640}
1641
4f5a1b2a 1642static const char credits_text[] =
1643 "PCSX-ReARMed\n\n"
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";
69af03a2 1654
e16a7e51 1655static int reset_game(void)
1656{
1657 // sanity check
1658 if (bios_sel == 0 && !Config.HLE)
1659 return -1;
1660
1661 ClosePlugins();
1662 OpenPlugins();
1663 SysReset();
1664 if (CheckCdrom() != -1) {
1665 LoadCdrom();
1666 }
1667 return 0;
1668}
1669
51f77282 1670static int reload_plugins(const char *cdimg)
e16a7e51 1671{
76f7048e 1672 pl_vout_buf = NULL;
e16a7e51 1673
1674 ClosePlugins();
51f77282 1675
1676 set_cd_image(cdimg);
e16a7e51 1677 LoadPlugins();
c22b95ab 1678 pcnt_hook_plugins();
e16a7e51 1679 NetOpened = 0;
1680 if (OpenPlugins() == -1) {
1681 me_update_msg("failed to open plugins");
1682 return -1;
1683 }
1684 plugin_call_rearmed_cbs();
1685
0c2871a7 1686 cdrIsoMultidiskCount = 1;
e16a7e51 1687 CdromId[0] = '\0';
1688 CdromLabel[0] = '\0';
1689
51f77282 1690 return 0;
1691}
1692
1693static int run_bios(void)
1694{
1695 if (bios_sel == 0)
1696 return -1;
1697
1698 ready_to_go = 0;
1699 if (reload_plugins(NULL) != 0)
1700 return -1;
e16a7e51 1701 SysReset();
1702
1703 ready_to_go = 1;
1704 return 0;
1705}
1706
51f77282 1707static int run_exe(void)
69af03a2 1708{
51f77282 1709 const char *fname;
1710
1711 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1712 if (fname == NULL)
1713 return -1;
1714
69af03a2 1715 ready_to_go = 0;
51f77282 1716 if (reload_plugins(NULL) != 0)
1717 return -1;
69af03a2 1718
51f77282 1719 SysReset();
1720 if (Load(fname) != 0) {
1721 me_update_msg("exe load failed, bad file?");
1722 printf("meh\n");
bbd837c6 1723 return -1;
69af03a2 1724 }
51f77282 1725
1726 ready_to_go = 1;
1727 return 0;
1728}
1729
1730static int run_cd_image(const char *fname)
1731{
1732 ready_to_go = 0;
1733 reload_plugins(fname);
69af03a2 1734
76d63edf 1735 // always autodetect, menu_sync_config will override as needed
1736 Config.PsxAuto = 1;
1737
69af03a2 1738 if (CheckCdrom() == -1) {
1739 // Only check the CD if we are starting the console with a CD
1740 ClosePlugins();
1741 me_update_msg("unsupported/invalid CD image");
bbd837c6 1742 return -1;
69af03a2 1743 }
1744
bbd837c6 1745 SysReset();
1746
69af03a2 1747 // Read main executable directly from CDRom and start it
1748 if (LoadCdrom() == -1) {
1749 ClosePlugins();
1750 me_update_msg("failed to load CD image");
bbd837c6 1751 return -1;
69af03a2 1752 }
1753
1754 ready_to_go = 1;
47232ea4 1755 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1756 hud_new_msg = 2;
bbd837c6 1757 return 0;
69af03a2 1758}
1759
bbd837c6 1760static int romsel_run(void)
69af03a2 1761{
bbd837c6 1762 int prev_gpu, prev_spu;
51f77282 1763 const char *fname;
bbd837c6 1764
1765 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1766 if (fname == NULL)
1767 return -1;
69af03a2 1768
bbd837c6 1769 printf("selected file: %s\n", fname);
1770
dc990066 1771 new_dynarec_clear_full();
1772
bbd837c6 1773 if (run_cd_image(fname) != 0)
1774 return -1;
1775
1776 prev_gpu = gpu_plugsel;
1777 prev_spu = spu_plugsel;
1778 if (menu_load_config(1) != 0)
1779 menu_load_config(0);
1780
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)
1786 return -1;
1787 }
1788
bab59f00 1789 if (Config.HLE)
1790 printf("note: running without BIOS, expect compatibility problems\n");
1791
bbd837c6 1792 strcpy(last_selected_fname, rom_fname_reload);
1793 return 0;
1794}
1795
1df403c5 1796static int swap_cd_image(void)
1797{
1798 char *fname;
1799
1800 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1801 if (fname == NULL)
1802 return -1;
1803
1804 printf("selected file: %s\n", fname);
1805
1806 CdromId[0] = '\0';
1807 CdromLabel[0] = '\0';
1808
1809 set_cd_image(fname);
1810 if (ReloadCdromPlugin() < 0) {
1811 me_update_msg("failed to load cdr plugin");
1812 return -1;
1813 }
1814 if (CDR_open() < 0) {
1815 me_update_msg("failed to open cdr plugin");
1816 return -1;
1817 }
1818
1819 SetCdOpenCaseTime(time(NULL) + 2);
1820 LidInterrupt();
1821
1822 strcpy(last_selected_fname, rom_fname_reload);
1823 return 0;
1824}
1825
0c2871a7 1826static int swap_cd_multidisk(void)
1827{
1828 cdrIsoMultidiskSelect++;
1829 CdromId[0] = '\0';
1830 CdromLabel[0] = '\0';
1831
1832 CDR_close();
1833 if (CDR_open() < 0) {
1834 me_update_msg("failed to open cdr plugin");
1835 return -1;
1836 }
1837
1838 SetCdOpenCaseTime(time(NULL) + 2);
1839 LidInterrupt();
1840
1841 return 0;
1842}
1843
bbd837c6 1844static int main_menu_handler(int id, int keys)
1845{
69af03a2 1846 switch (id)
1847 {
1848 case MA_MAIN_RESUME_GAME:
3c70c47b 1849 if (ready_to_go)
1850 return 1;
69af03a2 1851 break;
1852 case MA_MAIN_SAVE_STATE:
1853 if (ready_to_go)
1854 return menu_loop_savestate(0);
1855 break;
1856 case MA_MAIN_LOAD_STATE:
1857 if (ready_to_go)
1858 return menu_loop_savestate(1);
1859 break;
1860 case MA_MAIN_RESET_GAME:
e16a7e51 1861 if (ready_to_go && reset_game() == 0)
3c70c47b 1862 return 1;
69af03a2 1863 break;
1864 case MA_MAIN_LOAD_ROM:
bbd837c6 1865 if (romsel_run() == 0)
69af03a2 1866 return 1;
1867 break;
1df403c5 1868 case MA_MAIN_SWAP_CD:
1869 if (swap_cd_image() == 0)
1870 return 1;
1871 break;
0c2871a7 1872 case MA_MAIN_SWAP_CD_MULTI:
1873 if (swap_cd_multidisk() == 0)
1874 return 1;
1875 break;
e16a7e51 1876 case MA_MAIN_RUN_BIOS:
1877 if (run_bios() == 0)
1878 return 1;
1879 break;
51f77282 1880 case MA_MAIN_RUN_EXE:
1881 if (run_exe() == 0)
1882 return 1;
1883 break;
69af03a2 1884 case MA_MAIN_CREDITS:
4f5a1b2a 1885 draw_menu_message(credits_text, draw_frame_credits);
69af03a2 1886 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1887 break;
1888 case MA_MAIN_EXIT:
bd6267e6 1889 OnFile_Exit();
1890 break;
69af03a2 1891 default:
1892 lprintf("%s: something unknown selected\n", __FUNCTION__);
1893 break;
1894 }
1895
1896 return 0;
1897}
1898
51f77282 1899static menu_entry e_menu_main2[] =
1900{
0c2871a7 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),
51f77282 1905 mee_handler ("Memcard manager", menu_loop_memcards),
1906 mee_end,
1907};
1908
1909static int main_menu2_handler(int id, int keys)
1910{
1911 static int sel = 0;
1912
1913 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
0c2871a7 1914 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
51f77282 1915 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1916
1917 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1918}
1919
1920static const char h_extra[] = "Change CD, manage memcards..\n";
1921
69af03a2 1922static menu_entry e_menu_main[] =
1923{
1924 mee_label (""),
1925 mee_label (""),
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),
51f77282 1933 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
69af03a2 1934 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1935 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1936 mee_end,
1937};
1938
3c70c47b 1939// ----------------------------
1940
bd6267e6 1941static void menu_leave_emu(void);
1942
69af03a2 1943void menu_loop(void)
1944{
1945 static int sel = 0;
1946
bd6267e6 1947 menu_leave_emu();
69af03a2 1948
4f5a1b2a 1949 if (bioses[1] == NULL && !warned_about_bios) {
1950 menu_bios_warn();
1951 warned_about_bios = 1;
1952 }
1953
69af03a2 1954 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
e16a7e51 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]);
69af03a2 1957 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1958
69af03a2 1959 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1960
1961 do {
51f77282 1962 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
69af03a2 1963 } while (!ready_to_go);
1964
1965 /* wait until menu, ok, back is released */
1966 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1967 ;
1968
1969 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1970
3c70c47b 1971 menu_prepare_emu();
1972}
1973
51f77282 1974static int qsort_strcmp(const void *p1, const void *p2)
1975{
1976 char * const *s1 = (char * const *)p1;
1977 char * const *s2 = (char * const *)p2;
1978 return strcasecmp(*s1, *s2);
1979}
1980
e6eb2066 1981static void scan_bios_plugins(void)
bbd837c6 1982{
1983 char fname[MAXPATHLEN];
1984 struct dirent *ent;
51f77282 1985 int bios_i, gpu_i, spu_i, mc_i;
bbd837c6 1986 char *p;
1987 DIR *dir;
1988
e6eb2066 1989 bioses[0] = "HLE";
bbd837c6 1990 gpu_plugins[0] = "builtin_gpu";
1991 spu_plugins[0] = "builtin_spu";
51f77282 1992 memcards[0] = "(none)";
1993 bios_i = gpu_i = spu_i = mc_i = 1;
e6eb2066 1994
1995 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1996 dir = opendir(fname);
1997 if (dir == NULL) {
1998 perror("scan_bios_plugins bios opendir");
1999 goto do_plugins;
2000 }
2001
2002 while (1) {
2003 struct stat st;
2004
2005 errno = 0;
2006 ent = readdir(dir);
2007 if (ent == NULL) {
2008 if (errno != 0)
2009 perror("readdir");
2010 break;
2011 }
2012
2013 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2014 continue;
2015
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);
2019 continue;
2020 }
2021
2022 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2023 bioses[bios_i++] = strdup(ent->d_name);
2024 continue;
2025 }
2026
2027 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2028 }
2029
2030 closedir(dir);
bbd837c6 2031
e6eb2066 2032do_plugins:
bbd837c6 2033 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2034 dir = opendir(fname);
2035 if (dir == NULL) {
51f77282 2036 perror("scan_bios_plugins plugins opendir");
2037 goto do_memcards;
bbd837c6 2038 }
2039
2040 while (1) {
2041 void *h, *tmp;
2042
2043 errno = 0;
2044 ent = readdir(dir);
2045 if (ent == NULL) {
2046 if (errno != 0)
2047 perror("readdir");
2048 break;
2049 }
2050 p = strstr(ent->d_name, ".so");
2051 if (p == NULL)
2052 continue;
2053
2054 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2055 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2056 if (h == NULL) {
2057 fprintf(stderr, "%s\n", dlerror());
2058 continue;
2059 }
2060
2061 // now what do we have here?
2062 tmp = dlsym(h, "GPUinit");
2063 if (tmp) {
2064 dlclose(h);
2065 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2066 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2067 continue;
2068 }
2069
2070 tmp = dlsym(h, "SPUinit");
2071 if (tmp) {
2072 dlclose(h);
2073 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2074 spu_plugins[spu_i++] = strdup(ent->d_name);
2075 continue;
2076 }
2077
2078 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2079 dlclose(h);
2080 }
2081
2082 closedir(dir);
51f77282 2083
2084do_memcards:
2085 dir = opendir("." MEMCARD_DIR);
2086 if (dir == NULL) {
2087 perror("scan_bios_plugins memcards opendir");
2088 return;
2089 }
2090
2091 while (1) {
2092 struct stat st;
2093
2094 errno = 0;
2095 ent = readdir(dir);
2096 if (ent == NULL) {
2097 if (errno != 0)
2098 perror("readdir");
2099 break;
2100 }
2101
2102 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2103 continue;
2104
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);
2108 continue;
2109 }
2110
2111 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2112 memcards[mc_i++] = strdup(ent->d_name);
2113 continue;
2114 }
2115
2116 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2117 }
2118
2119 if (mc_i > 2)
2120 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2121
2122 closedir(dir);
bbd837c6 2123}
2124
3c70c47b 2125void menu_init(void)
2126{
4f3639fa 2127 char buff[MAXPATHLEN];
2128
2129 strcpy(last_selected_fname, "/media");
2130
e6eb2066 2131 scan_bios_plugins();
4f3639fa 2132 pnd_menu_init();
2133 menu_init_common();
2134
3c70c47b 2135 menu_set_defconfig();
2136 menu_load_config(0);
3c70c47b 2137 last_psx_w = 320;
2138 last_psx_h = 240;
bd6267e6 2139 last_psx_bpp = 16;
2140
4f3639fa 2141 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2142 if (g_menubg_src_ptr == NULL)
2143 exit(1);
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);
55b0eeea 2146
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);
2150#else
b944a30e 2151 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
55b0eeea 2152 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2153#endif
3c70c47b 2154}
2155
bd6267e6 2156void menu_notify_mode_change(int w, int h, int bpp)
3c70c47b 2157{
a185be70 2158 float mult;
2159 int imult;
2160
3c70c47b 2161 last_psx_w = w;
2162 last_psx_h = h;
bd6267e6 2163 last_psx_bpp = bpp;
3c70c47b 2164
a185be70 2165 switch (scaling) {
2166 case SCALE_1_1:
3c70c47b 2167 g_layer_w = w; g_layer_h = h;
a185be70 2168 break;
2169
a185be70 2170 case SCALE_4_3v2:
fb005d87 2171 if (h > g_menuscreen_h || (240 < h && h <= 360))
2172 goto fractional_4_3;
2173
a185be70 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);
2182 break;
2183
fb005d87 2184 fractional_4_3:
2185 case SCALE_4_3:
2186 mult = 240.0f / (float)h * 4.0f / 3.0f;
2187 if (h > 256)
2188 mult *= 2.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);
2192 break;
2193
a185be70 2194 case SCALE_FULLSCREEN:
2195 g_layer_w = g_menuscreen_w;
2196 g_layer_h = g_menuscreen_h;
2197 break;
2198
2199 default:
2200 break;
3c70c47b 2201 }
a185be70 2202
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;
3c70c47b 2209}
2210
bd6267e6 2211static void menu_leave_emu(void)
2212{
6d1a1ac2 2213 if (GPU_close != NULL) {
2214 int ret = GPU_close();
2215 if (ret)
2216 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2217 }
bd6267e6 2218
55b0eeea 2219 plat_video_menu_enter(ready_to_go);
2220
4f3639fa 2221 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
76f7048e 2222 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
bd6267e6 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);
4f3639fa 2227 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
76f7048e 2228 u16 *s = pl_vout_buf;
bd6267e6 2229
2230 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
4f3639fa 2231 menu_darken_bg(d, s, w, 0);
bd6267e6 2232 }
fba06457 2233
1bd9ee68 2234 if (ready_to_go)
55b0eeea 2235 cpu_clock = plat_cpu_clock_get();
bd6267e6 2236}
2237
3c70c47b 2238void menu_prepare_emu(void)
2239{
b5e7e49a 2240 R3000Acpu *prev_cpu = psxCpu;
2241
fba06457 2242 plat_video_menu_leave();
2243
a185be70 2244 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
bd6267e6 2245
b5e7e49a 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
2249 psxCpu->Reset();
2250
bd6267e6 2251 // core doesn't care about Config.Cdda changes,
2252 // so handle them manually here
2253 if (Config.Cdda)
2254 CDR_stop();
6d1a1ac2 2255
907b1e90 2256 menu_sync_config();
cefe86b7 2257 apply_lcdrate(Config.PsxType);
2258 apply_filter(filter);
55b0eeea 2259 plat_cpu_clock_apply(cpu_clock);
fba06457 2260
e64dc4c5 2261 // push config to GPU plugin
2262 plugin_call_rearmed_cbs();
2263
6d1a1ac2 2264 if (GPU_open != NULL) {
6d1a1ac2 2265 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2266 if (ret)
2267 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2268 }
384f5f43 2269
4c08b9e7 2270 dfinput_activate();
69af03a2 2271}
2272
2273void me_update_msg(const char *msg)
2274{
2275 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2276 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2277
2278 menu_error_time = plat_get_ticks_ms();
2279 lprintf("msg: %s\n", menu_error_msg);
2280}
2281