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