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