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