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