mapper det. update, cfg update
[libpicofe.git] / gp2x / menu.c
CommitLineData
95151aea 1// (c) Copyright 2006,2007 notaz, All rights reserved.\r
720ee7f6 2// Free for non-commercial use.\r
3\r
4// For commercial use, separate licencing terms must be obtained.\r
5\r
6#include <stdio.h>\r
7#include <string.h>\r
8#include <stdlib.h>\r
9#include <stdarg.h>\r
10#include <unistd.h>\r
11#include <dirent.h>\r
12\r
13#include "gp2x.h"\r
14#include "emu.h"\r
15#include "menu.h"\r
16#include "usbjoy.h"\r
f013066e 17#include "../common/emu.h"\r
c7a4ff64 18#include "../common/menu.h"\r
f013066e 19#include "../common/arm_utils.h"\r
c7a4ff64 20#include "../common/readpng.h"\r
720ee7f6 21#include "version.h"\r
22\r
70d2ecc5 23#include <Pico/PicoInt.h>\r
24#include <Pico/Patch.h>\r
25#include <zlib/zlib.h>\r
720ee7f6 26\r
27#ifndef _DIRENT_HAVE_D_TYPE\r
28#error "need d_type for file browser\r
29#endif\r
30\r
720ee7f6 31extern int mmuhack_status;\r
720ee7f6 32\r
367b6f1f 33const char *keyNames[] = {\r
720ee7f6 34 "UP", "???", "LEFT", "???", "DOWN", "???", "RIGHT", "???",\r
35 "START", "SELECT", "L", "R", "A", "B", "X", "Y",\r
36 "???", "???", "???", "???", "???", "???", "VOL DOWN", "VOL UP",\r
37 "???", "???", "???", "PUSH", "???", "???", "???", "???"\r
38};\r
39\r
f9a37a02 40static void menu_darken_bg(void *dst, int pixels, int darker);\r
13059a60 41static void menu_prepare_bg(int use_game_bg);\r
720ee7f6 42\r
720ee7f6 43static unsigned long inp_prev = 0;\r
44static int inp_prevjoy = 0;\r
45\r
46static unsigned long wait_for_input(unsigned long interesting)\r
47{\r
48 unsigned long ret;\r
5e2e14f2 49 static int repeats = 0, wait = 50*1000;\r
720ee7f6 50 int release = 0, i;\r
51\r
5e2e14f2 52 if (repeats == 2 || repeats == 4) wait /= 2;\r
53 if (repeats == 6) wait = 15 * 1000;\r
720ee7f6 54\r
55 for (i = 0; i < 6 && inp_prev == gp2x_joystick_read(1); i++) {\r
5e2e14f2 56 if (i == 0) repeats++;\r
57 if (wait >= 30*1000) usleep(wait); // usleep sleeps for ~30ms minimum\r
58 else spend_cycles(wait * currentConfig.CPUclock);\r
720ee7f6 59 }\r
60\r
61 while ( !((ret = gp2x_joystick_read(1)) & interesting) ) {\r
62 usleep(50000);\r
63 release = 1;\r
64 }\r
65\r
66 if (release || ret != inp_prev) {\r
67 repeats = 0;\r
5e2e14f2 68 wait = 50*1000;\r
720ee7f6 69 }\r
70 inp_prev = ret;\r
71 inp_prevjoy = 0;\r
72\r
73 // we don't need diagonals in menus\r
74 if ((ret&GP2X_UP) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT;\r
75 if ((ret&GP2X_UP) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
76 if ((ret&GP2X_DOWN) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT;\r
77 if ((ret&GP2X_DOWN) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
78\r
79 return ret;\r
80}\r
81\r
82static unsigned long input2_read(unsigned long interesting, int *joy)\r
83{\r
84 unsigned long ret;\r
85 int i;\r
86\r
87 do\r
88 {\r
89 *joy = 0;\r
90 if ((ret = gp2x_joystick_read(0) & interesting)) break;\r
91 gp2x_usbjoy_update();\r
92 for (i = 0; i < num_of_joys; i++) {\r
93 ret = gp2x_usbjoy_check2(i);\r
94 if (ret) { *joy = i + 1; break; }\r
95 }\r
96 if (ret) break;\r
97 }\r
98 while(0);\r
99\r
100 return ret;\r
101}\r
102\r
103// similar to wait_for_input(), but returns joy num\r
104static unsigned long wait_for_input_usbjoy(unsigned long interesting, int *joy)\r
105{\r
106 unsigned long ret;\r
107 const int wait = 300*1000;\r
108 int i;\r
109\r
110 if (inp_prevjoy == 0) inp_prev &= interesting;\r
111 for (i = 0; i < 6; i++) {\r
112 ret = input2_read(interesting, joy);\r
113 if (*joy != inp_prevjoy || ret != inp_prev) break;\r
114 usleep(wait/6);\r
115 }\r
116\r
117 while ( !(ret = input2_read(interesting, joy)) ) {\r
118 usleep(50000);\r
119 }\r
120\r
121 inp_prev = ret;\r
122 inp_prevjoy = *joy;\r
123\r
367b6f1f 124 // handle only 1 event at a time\r
125 for (i = 1; i != 0; i <<= 1)\r
126 if (ret & i) { ret &= i; break; }\r
127\r
720ee7f6 128 return ret;\r
129}\r
130\r
c7a4ff64 131static void menu_flip(void)\r
132{\r
133 gp2x_video_flush_cache();\r
134 gp2x_video_flip2();\r
135}\r
720ee7f6 136\r
137\r
b9f8cb3d 138// --------- loading ROM screen ----------\r
139\r
677b5dd8 140static int cdload_called = 0;\r
141\r
b9f8cb3d 142static void load_progress_cb(int percent)\r
143{\r
144 int ln, len = percent * 320 / 100;\r
13059a60 145 unsigned short *dst = (unsigned short *)gp2x_screen + 320*20;\r
b9f8cb3d 146\r
147 if (len > 320) len = 320;\r
677b5dd8 148 for (ln = 8; ln > 0; ln--, dst += 320)\r
13059a60 149 memset(dst, 0xff, len*2);\r
150 menu_flip();\r
b9f8cb3d 151}\r
152\r
677b5dd8 153static void cdload_progress_cb(int percent)\r
154{\r
155 int ln, len = percent * 320 / 100;\r
156 unsigned short *dst = (unsigned short *)gp2x_screen + 320*20;\r
157\r
158 memset(dst, 0xff, 320*2*8);\r
159\r
160 smalltext_out16(1, 3*10, "Processing CD image / MP3s", 0xffff);\r
161 smalltext_out16_lim(1, 4*10, romFileName, 0xffff, 80);\r
6245d5a0 162 dst += 320*30;\r
677b5dd8 163\r
164 if (len > 320) len = 320;\r
165 for (ln = 8; ln > 0; ln--, dst += 320)\r
166 memset(dst, 0xff, len*2);\r
6245d5a0 167 menu_flip();\r
677b5dd8 168 cdload_called = 1;\r
169}\r
170\r
b9f8cb3d 171void menu_romload_prepare(const char *rom_name)\r
172{\r
173 const char *p = rom_name + strlen(rom_name);\r
174 while (p > rom_name && *p != '/') p--;\r
175\r
144a28a0 176 if (rom_loaded) gp2x_pd_clone_buffer2();\r
13059a60 177 else memset(gp2x_screen, 0, 320*240*2);\r
178\r
179 smalltext_out16(1, 1, "Loading", 0xffff);\r
180 smalltext_out16_lim(1, 10, p, 0xffff, 53);\r
181 gp2x_memcpy_buffers(3, gp2x_screen, 0, 320*240*2);\r
182 menu_flip();\r
b9f8cb3d 183 PicoCartLoadProgressCB = load_progress_cb;\r
677b5dd8 184 PicoCDLoadProgressCB = cdload_progress_cb;\r
185 cdload_called = 0;\r
b9f8cb3d 186}\r
187\r
188void menu_romload_end(void)\r
189{\r
6245d5a0 190 PicoCartLoadProgressCB = PicoCDLoadProgressCB = NULL;\r
677b5dd8 191 smalltext_out16(1, cdload_called ? 60 : 30, "Starting emulation...", 0xffff);\r
13059a60 192 menu_flip();\r
b9f8cb3d 193}\r
194\r
720ee7f6 195// -------------- ROM selector --------------\r
196\r
13059a60 197// rrrr rggg gggb bbbb\r
198static unsigned short file2color(const char *fname)\r
199{\r
200 const char *ext = fname + strlen(fname) - 3;\r
6d741b32 201 static const char *rom_exts[] = { "zip", "bin", "smd", "gen", "iso", "cso" };\r
13059a60 202 static const char *other_exts[] = { "gmv", "pat" };\r
203 int i;\r
204\r
205 if (ext < fname) ext = fname;\r
206 for (i = 0; i < sizeof(rom_exts)/sizeof(rom_exts[0]); i++)\r
207 if (strcasecmp(ext, rom_exts[i]) == 0) return 0xbdff;\r
208 for (i = 0; i < sizeof(other_exts)/sizeof(other_exts[0]); i++)\r
209 if (strcasecmp(ext, other_exts[i]) == 0) return 0xaff5;\r
210 return 0xffff;\r
211}\r
212\r
720ee7f6 213static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)\r
214{\r
215 int start, i, pos;\r
216\r
217 start = 12 - sel;\r
218 n--; // exclude current dir (".")\r
219\r
f9a37a02 220 gp2x_pd_clone_buffer2();\r
221\r
144a28a0 222 if (!rom_loaded) {\r
f9a37a02 223 menu_darken_bg(gp2x_screen, 320*240, 0);\r
13059a60 224 }\r
225\r
f9a37a02 226 menu_darken_bg((char *)gp2x_screen + 320*120*2, 320*8, 0);\r
720ee7f6 227\r
228 if(start - 2 >= 0)\r
13059a60 229 smalltext_out16_lim(14, (start - 2)*10, curdir, 0xffff, 53-2);\r
720ee7f6 230 for (i = 0; i < n; i++) {\r
231 pos = start + i;\r
232 if (pos < 0) continue;\r
233 if (pos > 23) break;\r
234 if (namelist[i+1]->d_type == DT_DIR) {\r
13059a60 235 smalltext_out16_lim(14, pos*10, "/", 0xfff6, 1);\r
236 smalltext_out16_lim(14+6, pos*10, namelist[i+1]->d_name, 0xfff6, 53-3);\r
720ee7f6 237 } else {\r
13059a60 238 unsigned short color = file2color(namelist[i+1]->d_name);\r
239 smalltext_out16_lim(14, pos*10, namelist[i+1]->d_name, color, 53-2);\r
720ee7f6 240 }\r
241 }\r
13059a60 242 text_out16(5, 120, ">");\r
243 menu_flip();\r
720ee7f6 244}\r
245\r
246static int scandir_cmp(const void *p1, const void *p2)\r
247{\r
248 struct dirent **d1 = (struct dirent **)p1, **d2 = (struct dirent **)p2;\r
249 if ((*d1)->d_type == (*d2)->d_type) return alphasort(d1, d2);\r
250 if ((*d1)->d_type == DT_DIR) return -1; // put before\r
251 if ((*d2)->d_type == DT_DIR) return 1;\r
252 return alphasort(d1, d2);\r
253}\r
254\r
79cad122 255static char *filter_exts[] = {\r
256 ".mp3", ".MP3", ".srm", ".brm", "s.gz", ".mds", "bcfg", ".txt", ".htm", "html",\r
257 ".jpg", ".gpe", ".cue"\r
258};\r
0d0558bd 259\r
260static int scandir_filter(const struct dirent *ent)\r
261{\r
262 const char *p;\r
263 int i;\r
264\r
265 if (ent == NULL || ent->d_name == NULL) return 0;\r
266 if (strlen(ent->d_name) < 5) return 1;\r
267\r
268 p = ent->d_name + strlen(ent->d_name) - 4;\r
269\r
270 for (i = 0; i < sizeof(filter_exts)/sizeof(filter_exts[0]); i++)\r
271 {\r
272 if (strcmp(p, filter_exts[i]) == 0) return 0;\r
273 }\r
274\r
275 return 1;\r
276}\r
720ee7f6 277\r
55c7b464 278static void do_delete(const char *fpath, const char *fname)\r
279{\r
280 int len, inp;\r
281\r
282 gp2x_pd_clone_buffer2();\r
283\r
284 if (!rom_loaded)\r
285 menu_darken_bg(gp2x_screen, 320*240, 0);\r
286\r
287 len = strlen(fname);\r
288 if (len > 320/6) len = 320/6;\r
289\r
290 text_out16(320/2 - 15*8/2, 80, "About to delete");\r
291 smalltext_out16_lim(320/2 - len*6/2, 95, fname, 0xbdff, len);\r
292 text_out16(320/2 - 13*8/2, 110, "Are you sure?");\r
293 text_out16(320/2 - 25*8/2, 120, "(Y - confirm, X - cancel)");\r
294 menu_flip();\r
295\r
296\r
297 while (gp2x_joystick_read(1) & (GP2X_A|GP2X_SELECT)) usleep(50*1000);\r
298 inp = wait_for_input(GP2X_Y|GP2X_X);\r
299 if (inp & GP2X_Y)\r
300 remove(fpath);\r
301}\r
302\r
720ee7f6 303static char *romsel_loop(char *curr_path)\r
304{\r
305 struct dirent **namelist;\r
306 DIR *dir;\r
307 int n, sel = 0;\r
308 unsigned long inp = 0;\r
309 char *ret = NULL, *fname = NULL;\r
310\r
55c7b464 311rescan:\r
720ee7f6 312 // is this a dir or a full path?\r
313 if ((dir = opendir(curr_path))) {\r
314 closedir(dir);\r
315 } else {\r
316 char *p;\r
317 for (p = curr_path + strlen(curr_path) - 1; p > curr_path && *p != '/'; p--);\r
318 *p = 0;\r
319 fname = p+1;\r
320 }\r
321\r
0d0558bd 322 n = scandir(curr_path, &namelist, scandir_filter, scandir_cmp);\r
720ee7f6 323 if (n < 0) {\r
324 // try root\r
0d0558bd 325 n = scandir("/", &namelist, scandir_filter, scandir_cmp);\r
720ee7f6 326 if (n < 0) {\r
327 // oops, we failed\r
328 printf("dir: "); printf(curr_path); printf("\n");\r
329 perror("scandir");\r
330 return NULL;\r
331 }\r
332 }\r
333\r
334 // try to find sel\r
335 if (fname != NULL) {\r
336 int i;\r
337 for (i = 1; i < n; i++) {\r
338 if (strcmp(namelist[i]->d_name, fname) == 0) {\r
339 sel = i - 1;\r
340 break;\r
341 }\r
342 }\r
343 }\r
344\r
345 for (;;)\r
346 {\r
347 draw_dirlist(curr_path, namelist, n, sel);\r
55c7b464 348 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_A|GP2X_B|GP2X_X|GP2X_SELECT);\r
720ee7f6 349 if(inp & GP2X_UP ) { sel--; if (sel < 0) sel = n-2; }\r
350 if(inp & GP2X_DOWN) { sel++; if (sel > n-2) sel = 0; }\r
5e2e14f2 351 if(inp & GP2X_LEFT) { sel-=10; if (sel < 0) sel = 0; }\r
352 if(inp & GP2X_L) { sel-=24; if (sel < 0) sel = 0; }\r
353 if(inp & GP2X_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; }\r
354 if(inp & GP2X_R) { sel+=24; if (sel > n-2) sel = n-2; }\r
55c7b464 355 if ((inp & GP2X_B) || (inp & (GP2X_SELECT|GP2X_A)) == (GP2X_SELECT|GP2X_A)) // enter dir/select || delete\r
356 {\r
720ee7f6 357 again:\r
55c7b464 358 if (namelist[sel+1]->d_type == DT_REG)\r
359 {\r
720ee7f6 360 strcpy(romFileName, curr_path);\r
361 strcat(romFileName, "/");\r
362 strcat(romFileName, namelist[sel+1]->d_name);\r
55c7b464 363 if (inp & GP2X_B) { // return sel\r
364 ret = romFileName;\r
365 break;\r
366 }\r
367 do_delete(romFileName, namelist[sel+1]->d_name);\r
368 if (n > 0) {\r
369 while (n--) free(namelist[n]);\r
370 free(namelist);\r
371 }\r
372 goto rescan;\r
373 }\r
374 else if (namelist[sel+1]->d_type == DT_DIR)\r
375 {\r
376 int newlen;\r
377 char *p, *newdir;\r
378 if (!(inp & GP2X_B)) continue;\r
379 newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;\r
380 newdir = malloc(newlen);\r
720ee7f6 381 if (strcmp(namelist[sel+1]->d_name, "..") == 0) {\r
382 char *start = curr_path;\r
383 p = start + strlen(start) - 1;\r
384 while (*p == '/' && p > start) p--;\r
385 while (*p != '/' && p > start) p--;\r
386 if (p <= start) strcpy(newdir, "/");\r
387 else { strncpy(newdir, start, p-start); newdir[p-start] = 0; }\r
388 } else {\r
389 strcpy(newdir, curr_path);\r
390 p = newdir + strlen(newdir) - 1;\r
391 while (*p == '/' && p >= newdir) *p-- = 0;\r
392 strcat(newdir, "/");\r
393 strcat(newdir, namelist[sel+1]->d_name);\r
394 }\r
395 ret = romsel_loop(newdir);\r
396 free(newdir);\r
397 break;\r
55c7b464 398 }\r
399 else\r
400 {\r
720ee7f6 401 // unknown file type, happens on NTFS mounts. Try to guess.\r
402 FILE *tstf; int tmp;\r
403 strcpy(romFileName, curr_path);\r
404 strcat(romFileName, "/");\r
405 strcat(romFileName, namelist[sel+1]->d_name);\r
406 tstf = fopen(romFileName, "rb");\r
407 if (tstf != NULL)\r
408 {\r
409 if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0)\r
410 namelist[sel+1]->d_type = DT_REG;\r
411 else namelist[sel+1]->d_type = DT_DIR;\r
412 fclose(tstf);\r
413 goto again;\r
414 }\r
415 }\r
416 }\r
417 if(inp & GP2X_X) break; // cancel\r
418 }\r
419\r
420 if (n > 0) {\r
55c7b464 421 while (n--) free(namelist[n]);\r
720ee7f6 422 free(namelist);\r
423 }\r
424\r
425 return ret;\r
426}\r
427\r
0ae6813e 428// ------------ debug menu ------------\r
429\r
430char *debugString(void);\r
431\r
432static void draw_debug(void)\r
433{\r
434 char *p, *str = debugString();\r
435 int len, line;\r
436\r
437 gp2x_pd_clone_buffer2();\r
438\r
439 p = str;\r
440 for (line = 0; line < 24; line++)\r
441 {\r
442 while (*p && *p != '\n') p++;\r
443 len = p - str;\r
444 if (len > 55) len = 55;\r
13059a60 445 smalltext_out16_lim(1, line*10, str, 0xffff, len);\r
0ae6813e 446 if (*p == 0) break;\r
447 p++; str = p;\r
448 }\r
13059a60 449 menu_flip();\r
0ae6813e 450}\r
451\r
452static void debug_menu_loop(void)\r
453{\r
454 draw_debug();\r
455 wait_for_input(GP2X_B|GP2X_X);\r
456}\r
457\r
70d2ecc5 458// ------------ patch/gg menu ------------\r
459\r
460static void draw_patchlist(int sel)\r
461{\r
13059a60 462 int start, i, pos, active;\r
70d2ecc5 463\r
464 start = 12 - sel;\r
465\r
466 gp2x_pd_clone_buffer2();\r
467\r
468 for (i = 0; i < PicoPatchCount; i++) {\r
469 pos = start + i;\r
470 if (pos < 0) continue;\r
471 if (pos > 23) break;\r
13059a60 472 active = PicoPatches[i].active;\r
473 smalltext_out16_lim(14, pos*10, active ? "ON " : "OFF", active ? 0xfff6 : 0xffff, 3);\r
474 smalltext_out16_lim(14+6*4, pos*10, PicoPatches[i].name, active ? 0xfff6 : 0xffff, 53-6);\r
70d2ecc5 475 }\r
476 pos = start + i;\r
13059a60 477 if (pos < 24) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4);\r
70d2ecc5 478\r
13059a60 479 text_out16(5, 120, ">");\r
480 menu_flip();\r
70d2ecc5 481}\r
482\r
483\r
0ae6813e 484static void patches_menu_loop(void)\r
70d2ecc5 485{\r
486 int menu_sel = 0;\r
487 unsigned long inp = 0;\r
488\r
489 for(;;)\r
490 {\r
491 draw_patchlist(menu_sel);\r
492 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_B|GP2X_X);\r
493 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = PicoPatchCount; }\r
494 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > PicoPatchCount) menu_sel = 0; }\r
495 if(inp &(GP2X_LEFT|GP2X_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }\r
496 if(inp &(GP2X_RIGHT|GP2X_R)) { menu_sel+=10; if (menu_sel > PicoPatchCount) menu_sel = PicoPatchCount; }\r
497 if(inp & GP2X_B) { // action\r
498 if (menu_sel < PicoPatchCount)\r
499 PicoPatches[menu_sel].active = !PicoPatches[menu_sel].active;\r
500 else return;\r
501 }\r
502 if(inp & GP2X_X) return;\r
503 }\r
504\r
505}\r
506\r
4ffd2858 507// ------------ savestate loader ------------\r
508\r
4ffd2858 509static int state_slot_flags = 0;\r
510\r
511static void state_check_slots(void)\r
512{\r
513 int slot;\r
514\r
515 state_slot_flags = 0;\r
516\r
517 for (slot = 0; slot < 10; slot++)\r
518 {\r
f013066e 519 if (emu_checkSaveFile(slot))\r
4ffd2858 520 {\r
521 state_slot_flags |= 1 << slot;\r
522 }\r
523 }\r
524}\r
525\r
526static void draw_savestate_bg(int slot)\r
527{\r
528 struct PicoVideo tmp_pv;\r
529 unsigned short tmp_cram[0x40];\r
530 unsigned short tmp_vsram[0x40];\r
531 void *tmp_vram, *file;\r
532 char *fname;\r
533\r
534 fname = emu_GetSaveFName(1, 0, slot);\r
535 if (!fname) return;\r
536\r
537 tmp_vram = malloc(sizeof(Pico.vram));\r
538 if (tmp_vram == NULL) return;\r
539\r
540 memcpy(tmp_vram, Pico.vram, sizeof(Pico.vram));\r
541 memcpy(tmp_cram, Pico.cram, sizeof(Pico.cram));\r
542 memcpy(tmp_vsram, Pico.vsram, sizeof(Pico.vsram));\r
543 memcpy(&tmp_pv, &Pico.video, sizeof(Pico.video));\r
544\r
545 if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) {\r
546 file = gzopen(fname, "rb");\r
f013066e 547 emu_setSaveStateCbs(1);\r
4ffd2858 548 } else {\r
549 file = fopen(fname, "rb");\r
f013066e 550 emu_setSaveStateCbs(0);\r
4ffd2858 551 }\r
552\r
553 if (file) {\r
554 if (PicoMCD & 1) {\r
555 PicoCdLoadStateGfx(file);\r
556 } else {\r
557 areaSeek(file, 0x10020, SEEK_SET); // skip header and RAM in state file\r
558 areaRead(Pico.vram, 1, sizeof(Pico.vram), file);\r
559 areaSeek(file, 0x2000, SEEK_CUR);\r
560 areaRead(Pico.cram, 1, sizeof(Pico.cram), file);\r
561 areaRead(Pico.vsram, 1, sizeof(Pico.vsram), file);\r
562 areaSeek(file, 0x221a0, SEEK_SET);\r
563 areaRead(&Pico.video, 1, sizeof(Pico.video), file);\r
564 }\r
565 areaClose(file);\r
566 }\r
567\r
f013066e 568 emu_forcedFrame();\r
13059a60 569 menu_prepare_bg(1);\r
4ffd2858 570\r
571 memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));\r
572 memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));\r
573 memcpy(Pico.vsram, tmp_vsram, sizeof(Pico.vsram));\r
574 memcpy(&Pico.video, &tmp_pv, sizeof(Pico.video));\r
575 free(tmp_vram);\r
576}\r
577\r
578static void draw_savestate_menu(int menu_sel, int is_loading)\r
579{\r
580 int tl_x = 25, tl_y = 60, y, i;\r
581\r
582 if (state_slot_flags & (1 << menu_sel))\r
583 draw_savestate_bg(menu_sel);\r
584 gp2x_pd_clone_buffer2();\r
585\r
13059a60 586 text_out16(tl_x, 30, is_loading ? "Load state" : "Save state");\r
587\r
c7a4ff64 588 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 108);\r
4ffd2858 589\r
590 /* draw all 10 slots */\r
591 y = tl_y;\r
592 for (i = 0; i < 10; i++, y+=10)\r
593 {\r
13059a60 594 text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");\r
4ffd2858 595 }\r
13059a60 596 text_out16(tl_x, y, "back");\r
4ffd2858 597\r
13059a60 598 menu_flip();\r
4ffd2858 599}\r
600\r
601static int savestate_menu_loop(int is_loading)\r
602{\r
59d0f042 603 static int menu_sel = 10;\r
604 int menu_sel_max = 10;\r
4ffd2858 605 unsigned long inp = 0;\r
606\r
607 state_check_slots();\r
608\r
609 for(;;)\r
610 {\r
611 draw_savestate_menu(menu_sel, is_loading);\r
612 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
613 if(inp & GP2X_UP ) {\r
614 do {\r
615 menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max;\r
616 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
617 }\r
618 if(inp & GP2X_DOWN) {\r
619 do {\r
620 menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0;\r
621 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
622 }\r
623 if(inp & GP2X_B) { // save/load\r
624 if (menu_sel < 10) {\r
625 state_slot = menu_sel;\r
626 if (emu_SaveLoadGame(is_loading, 0)) {\r
627 strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed");\r
628 return 1;\r
629 }\r
630 return 0;\r
631 } else return 1;\r
632 }\r
633 if(inp & GP2X_X) return 1;\r
634 }\r
635}\r
636\r
720ee7f6 637// -------------- key config --------------\r
638\r
639static char *usb_joy_key_name(int joy, int num)\r
640{\r
641 static char name[16];\r
642 switch (num)\r
643 {\r
644 case 0: sprintf(name, "Joy%i UP", joy); break;\r
645 case 1: sprintf(name, "Joy%i DOWN", joy); break;\r
646 case 2: sprintf(name, "Joy%i LEFT", joy); break;\r
647 case 3: sprintf(name, "Joy%i RIGHT", joy); break;\r
648 default:sprintf(name, "Joy%i b%i", joy, num-3); break;\r
649 }\r
650 return name;\r
651}\r
652\r
95151aea 653static char *action_binds(int player_idx, int action_mask)\r
720ee7f6 654{\r
95151aea 655 static char strkeys[32*5];\r
720ee7f6 656 int joy, i;\r
657\r
658 strkeys[0] = 0;\r
95151aea 659 for (i = 0; i < 32; i++) // i is key index\r
720ee7f6 660 {\r
95151aea 661 if (currentConfig.KeyBinds[i] & action_mask)\r
720ee7f6 662 {\r
95151aea 663 if (player_idx >= 0 && ((currentConfig.KeyBinds[i] >> 16) & 3) != player_idx) continue;\r
367b6f1f 664 if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, keyNames[i]); break; }\r
665 else strcpy(strkeys, keyNames[i]);\r
720ee7f6 666 }\r
667 }\r
668 for (joy = 0; joy < num_of_joys; joy++)\r
669 {\r
670 for (i = 0; i < 32; i++)\r
671 {\r
95151aea 672 if (currentConfig.JoyBinds[joy][i] & action_mask)\r
720ee7f6 673 {\r
95151aea 674 if (player_idx >= 0 && ((currentConfig.JoyBinds[joy][i] >> 16) & 3) != player_idx) continue;\r
720ee7f6 675 if (strkeys[0]) {\r
676 strcat(strkeys, ", "); strcat(strkeys, usb_joy_key_name(joy + 1, i));\r
677 break;\r
678 }\r
679 else strcpy(strkeys, usb_joy_key_name(joy + 1, i));\r
680 }\r
681 }\r
682 }\r
683\r
e67f6454 684 // limit..\r
685 strkeys[20] = 0;\r
686\r
95151aea 687 return strkeys;\r
688}\r
689\r
e67f6454 690static void unbind_action(int action, int pl_idx, int joy)\r
95151aea 691{\r
692 int i, u;\r
693\r
e67f6454 694 if (joy <= 0)\r
695 {\r
696 for (i = 0; i < 32; i++) {\r
697 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
698 currentConfig.KeyBinds[i] &= ~action;\r
699 }\r
b4c711c3 700 }\r
e67f6454 701 if (joy < 0)\r
702 {\r
703 for (u = 0; u < 4; u++)\r
704 for (i = 0; i < 32; i++) {\r
705 if (pl_idx >= 0 && (currentConfig.JoyBinds[u][i]&0x30000) != (pl_idx<<16)) continue;\r
706 currentConfig.JoyBinds[u][i] &= ~action;\r
707 }\r
708 }\r
709 else if (joy > 0)\r
710 {\r
b4c711c3 711 for (i = 0; i < 32; i++) {\r
e67f6454 712 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
713 currentConfig.JoyBinds[joy-1][i] &= ~action;\r
b4c711c3 714 }\r
e67f6454 715 }\r
95151aea 716}\r
717\r
b4c711c3 718static int count_bound_keys(int action, int pl_idx, int joy)\r
95151aea 719{\r
720 int i, keys = 0;\r
721\r
722 if (joy)\r
723 {\r
b4c711c3 724 for (i = 0; i < 32; i++) {\r
725 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
95151aea 726 if (currentConfig.JoyBinds[joy-1][i] & action) keys++;\r
b4c711c3 727 }\r
95151aea 728 }\r
729 else\r
730 {\r
b4c711c3 731 for (i = 0; i < 32; i++) {\r
732 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
95151aea 733 if (currentConfig.KeyBinds[i] & action) keys++;\r
b4c711c3 734 }\r
95151aea 735 }\r
736 return keys;\r
737}\r
738\r
367b6f1f 739static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx, int sel)\r
95151aea 740{\r
741 int x, y, tl_y = 40, i;\r
742\r
e5d315a5 743 gp2x_pd_clone_buffer2();\r
95151aea 744 if (player_idx >= 0) {\r
13059a60 745 text_out16(80, 20, "Player %i controls", player_idx + 1);\r
b4c711c3 746 x = 80;\r
95151aea 747 } else {\r
13059a60 748 text_out16(80, 20, "Emulator controls");\r
95151aea 749 x = 40;\r
750 }\r
751\r
c7a4ff64 752 menu_draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 130);\r
13059a60 753\r
95151aea 754 y = tl_y;\r
755 for (i = 0; i < opt_cnt; i++, y+=10)\r
13059a60 756 text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask));\r
95151aea 757\r
13059a60 758 text_out16(x, y, "Done");\r
95151aea 759\r
760 if (sel < opt_cnt) {\r
13059a60 761 text_out16(30, 180, "Press a button to bind/unbind");\r
762 text_out16(30, 190, "Use SELECT to clear");\r
763 text_out16(30, 200, "To bind UP/DOWN, hold SELECT");\r
764 text_out16(30, 210, "Select \"Done\" to exit");\r
95151aea 765 } else {\r
13059a60 766 text_out16(30, 190, "Use Options -> Save cfg");\r
767 text_out16(30, 200, "to save controls");\r
768 text_out16(30, 210, "Press B or X to exit");\r
95151aea 769 }\r
13059a60 770 menu_flip();\r
720ee7f6 771}\r
772\r
367b6f1f 773static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx)\r
720ee7f6 774{\r
95151aea 775 int joy = 0, sel = 0, menu_sel_max = opt_cnt, prev_select = 0, i;\r
720ee7f6 776 unsigned long inp = 0;\r
777\r
778 for (;;)\r
779 {\r
95151aea 780 draw_key_config(opts, opt_cnt, player_idx, sel);\r
720ee7f6 781 inp = wait_for_input_usbjoy(CONFIGURABLE_KEYS, &joy);\r
782 // printf("got %08lX from joy %i\n", inp, joy);\r
783 if (joy == 0) {\r
95151aea 784 if (!(inp & GP2X_SELECT)) {\r
785 prev_select = 0;\r
786 if(inp & GP2X_UP ) { sel--; if (sel < 0) sel = menu_sel_max; continue; }\r
787 if(inp & GP2X_DOWN) { sel++; if (sel > menu_sel_max) sel = 0; continue; }\r
720ee7f6 788 }\r
95151aea 789 if (sel >= opt_cnt) {\r
790 if (inp & (GP2X_B|GP2X_X)) break;\r
791 else continue;\r
792 }\r
793 // if we are here, we want to bind/unbind something\r
794 if ((inp & GP2X_SELECT) && !prev_select)\r
e67f6454 795 unbind_action(opts[sel].mask, player_idx, -1);\r
95151aea 796 prev_select = inp & GP2X_SELECT;\r
720ee7f6 797 inp &= CONFIGURABLE_KEYS;\r
798 inp &= ~GP2X_SELECT;\r
720ee7f6 799 for (i = 0; i < 32; i++)\r
800 if (inp & (1 << i)) {\r
b4c711c3 801 if (count_bound_keys(opts[sel].mask, player_idx, 0) >= 2)\r
95151aea 802 currentConfig.KeyBinds[i] &= ~opts[sel].mask; // allow to unbind only\r
803 else currentConfig.KeyBinds[i] ^= opts[sel].mask;\r
7695af0a 804 if (player_idx >= 0 && (currentConfig.KeyBinds[i] & opts[sel].mask)) {\r
95151aea 805 currentConfig.KeyBinds[i] &= ~(3 << 16);\r
806 currentConfig.KeyBinds[i] |= player_idx << 16;\r
807 }\r
720ee7f6 808 }\r
95151aea 809 }\r
810 else if (sel < opt_cnt)\r
811 {\r
720ee7f6 812 for (i = 0; i < 32; i++)\r
813 if (inp & (1 << i)) {\r
e67f6454 814 int *bind = &currentConfig.JoyBinds[joy-1][i];\r
815 if ((*bind & opts[sel].mask) && (player_idx < 0 || player_idx == ((*bind>>16)&3)))\r
367b6f1f 816 *bind &= ~opts[sel].mask;\r
e67f6454 817 else {\r
818 // override\r
819 unbind_action(opts[sel].mask, player_idx, joy);\r
820 *bind = opts[sel].mask;\r
367b6f1f 821 if (player_idx > 0) *bind |= player_idx << 16;\r
95151aea 822 }\r
720ee7f6 823 }\r
824 }\r
825 }\r
826}\r
827\r
828static void draw_kc_sel(int menu_sel)\r
829{\r
830 int tl_x = 25+40, tl_y = 60, y, i;\r
831 char joyname[36];\r
832\r
833 y = tl_y;\r
e5d315a5 834 gp2x_pd_clone_buffer2();\r
c7a4ff64 835 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 138);\r
720ee7f6 836\r
13059a60 837 text_out16(tl_x, y, "Player 1");\r
838 text_out16(tl_x, (y+=10), "Player 2");\r
839 text_out16(tl_x, (y+=10), "Emulator controls");\r
840 text_out16(tl_x, (y+=10), "Done");\r
720ee7f6 841\r
842 tl_x = 25;\r
13059a60 843 text_out16(tl_x, (y=110), "USB joys detected:");\r
720ee7f6 844 if (num_of_joys > 0) {\r
845 for (i = 0; i < num_of_joys; i++) {\r
846 strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0;\r
13059a60 847 text_out16(tl_x, (y+=10), "%i: %s", i+1, joyname);\r
720ee7f6 848 }\r
849 } else {\r
13059a60 850 text_out16(tl_x, (y+=10), "none");\r
720ee7f6 851 }\r
852\r
13059a60 853 menu_flip();\r
720ee7f6 854}\r
855\r
95151aea 856\r
95151aea 857// player2_flag, ?, ?, ?, ?, ?, ?, menu\r
858// "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE",\r
859// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"\r
367b6f1f 860me_bind_action emuctrl_actions[] =\r
95151aea 861{\r
95151aea 862 { "Load State ", 1<<28 },\r
863 { "Save State ", 1<<27 },\r
95151aea 864 { "Prev Save Slot ", 1<<25 },\r
865 { "Next Save Slot ", 1<<24 },\r
13059a60 866 { "Switch Renderer", 1<<26 },\r
867 { "Volume Down ", 1<<30 },\r
868 { "Volume Up ", 1<<29 },\r
0480e6c9 869 { "Fast forward ", 1<<22 },\r
95151aea 870 { "Enter Menu ", 1<<23 },\r
367b6f1f 871 { NULL, 0 }\r
95151aea 872};\r
873\r
720ee7f6 874static void kc_sel_loop(void)\r
875{\r
95151aea 876 int menu_sel = 3, menu_sel_max = 3;\r
720ee7f6 877 unsigned long inp = 0;\r
0ae25549 878 int is_6button = PicoOpt & 0x020;\r
720ee7f6 879\r
95151aea 880 while (1)\r
720ee7f6 881 {\r
882 draw_kc_sel(menu_sel);\r
883 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
95151aea 884 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
885 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
886 if (inp & GP2X_B) {\r
720ee7f6 887 switch (menu_sel) {\r
367b6f1f 888 case 0: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 0); return;\r
889 case 1: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 1); return;\r
95151aea 890 case 2: key_config_loop(emuctrl_actions,\r
8e708f92 891 sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;\r
144a28a0 892 case 3: if (!rom_loaded) emu_WriteConfig(0); return;\r
720ee7f6 893 default: return;\r
894 }\r
895 }\r
95151aea 896 if (inp & GP2X_X) return;\r
720ee7f6 897 }\r
898}\r
899\r
900\r
daf91588 901// --------- sega/mega cd options ----------\r
902\r
59633198 903menu_entry cdopt_entries[] =\r
daf91588 904{\r
0ae25549 905 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_USA, NULL, 0, 0, 0, 1, 0 },\r
906 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_EUR, NULL, 0, 0, 0, 1, 0 },\r
907 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_JAP, NULL, 0, 0, 0, 1, 0 },\r
908 { "CD LEDs", MB_ONOFF, MA_CDOPT_LEDS, &currentConfig.EmuOpt, 0x0400, 0, 0, 1, 1 },\r
909 { "CDDA audio (using mp3s)", MB_ONOFF, MA_CDOPT_CDDA, &PicoOpt, 0x0800, 0, 0, 1, 1 },\r
910 { "PCM audio", MB_ONOFF, MA_CDOPT_PCM, &PicoOpt, 0x0400, 0, 0, 1, 1 },\r
911 { NULL, MB_NONE, MA_CDOPT_READAHEAD, NULL, 0, 0, 0, 1, 1 },\r
912 { "SaveRAM cart", MB_ONOFF, MA_CDOPT_SAVERAM, &PicoOpt, 0x8000, 0, 0, 1, 1 },\r
913 { "Scale/Rot. fx (slow)", MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&PicoOpt, 0x1000, 0, 0, 1, 1 },\r
914 { "Better sync (slow)", MB_ONOFF, MA_CDOPT_BETTER_SYNC, &PicoOpt, 0x2000, 0, 0, 1, 1 },\r
915 { "done", MB_NONE, MA_CDOPT_DONE, NULL, 0, 0, 0, 1, 0 },\r
59633198 916};\r
917\r
0ae25549 918const int cdopt_entry_count = (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]));\r
59633198 919#define CDOPT_ENTRY_COUNT (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]))\r
920\r
921\r
922struct bios_names_t\r
923{\r
924 char us[32], eu[32], jp[32];\r
925};\r
926\r
927static void menu_cdopt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
928{\r
929 struct bios_names_t *bios_names = param;\r
930 char ra_buff[16];\r
931\r
932 switch (entry->id)\r
933 {\r
13059a60 934 case MA_CDOPT_TESTBIOS_USA: text_out16(x, y, "USA BIOS: %s", bios_names->us); break;\r
935 case MA_CDOPT_TESTBIOS_EUR: text_out16(x, y, "EUR BIOS: %s", bios_names->eu); break;\r
936 case MA_CDOPT_TESTBIOS_JAP: text_out16(x, y, "JAP BIOS: %s", bios_names->jp); break;\r
59633198 937 case MA_CDOPT_READAHEAD:\r
938 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
939 else strcpy(ra_buff, " OFF");\r
13059a60 940 text_out16(x, y, "ReadAhead buffer %s", ra_buff);\r
59633198 941 break;\r
942 default:break;\r
943 }\r
944}\r
945\r
946static void draw_cd_menu_options(int menu_sel, struct bios_names_t *bios_names)\r
947{\r
948 int tl_x = 25, tl_y = 60;\r
949 menu_id selected_id;\r
5f9922e6 950 char ra_buff[16];\r
951\r
952 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
953 else strcpy(ra_buff, " OFF");\r
daf91588 954\r
e5d315a5 955 gp2x_pd_clone_buffer2();\r
956\r
c7a4ff64 957 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 246);\r
daf91588 958\r
13059a60 959 me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names);\r
daf91588 960\r
59633198 961 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
962 if ((selected_id == MA_CDOPT_TESTBIOS_USA && strcmp(bios_names->us, "NOT FOUND")) ||\r
963 (selected_id == MA_CDOPT_TESTBIOS_EUR && strcmp(bios_names->eu, "NOT FOUND")) ||\r
964 (selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND")))\r
13059a60 965 text_out16(tl_x, 210, "Press start to test selected BIOS");\r
daf91588 966\r
13059a60 967 menu_flip();\r
daf91588 968}\r
969\r
970static void cd_menu_loop_options(void)\r
971{\r
59d0f042 972 static int menu_sel = 0;\r
973 int menu_sel_max = 10;\r
daf91588 974 unsigned long inp = 0;\r
59633198 975 struct bios_names_t bios_names;\r
976 menu_id selected_id;\r
977 char *bios, *p;\r
daf91588 978\r
f013066e 979 if (emu_findBios(4, &bios)) { // US\r
daf91588 980 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
59633198 981 strncpy(bios_names.us, p, sizeof(bios_names.us)); bios_names.us[sizeof(bios_names.us)-1] = 0;\r
982 } else strcpy(bios_names.us, "NOT FOUND");\r
daf91588 983\r
f013066e 984 if (emu_findBios(8, &bios)) { // EU\r
daf91588 985 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
59633198 986 strncpy(bios_names.eu, p, sizeof(bios_names.eu)); bios_names.eu[sizeof(bios_names.eu)-1] = 0;\r
987 } else strcpy(bios_names.eu, "NOT FOUND");\r
daf91588 988\r
f013066e 989 if (emu_findBios(1, &bios)) { // JP\r
daf91588 990 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
59633198 991 strncpy(bios_names.jp, p, sizeof(bios_names.jp)); bios_names.jp[sizeof(bios_names.jp)-1] = 0;\r
992 } else strcpy(bios_names.jp, "NOT FOUND");\r
daf91588 993\r
994 for(;;)\r
995 {\r
59633198 996 draw_cd_menu_options(menu_sel, &bios_names);\r
daf91588 997 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A|GP2X_START);\r
59633198 998 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
999 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1000 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
1001 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
1002 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0) &&\r
1003 selected_id == MA_CDOPT_READAHEAD) {\r
1004 if (inp & GP2X_LEFT) {\r
1005 PicoCDBuffers >>= 1;\r
88bfc63d 1006 if (PicoCDBuffers < 2) PicoCDBuffers = 0;\r
59633198 1007 } else {\r
88bfc63d 1008 if (PicoCDBuffers < 2) PicoCDBuffers = 2;\r
59633198 1009 else PicoCDBuffers <<= 1;\r
1010 if (PicoCDBuffers > 8*1024) PicoCDBuffers = 8*1024; // 16M\r
1011 }\r
daf91588 1012 }\r
1013 }\r
59633198 1014 if (inp & GP2X_B) { // toggleable options\r
1015 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, 1) &&\r
1016 selected_id == MA_CDOPT_DONE) {\r
1017 return;\r
1018 }\r
1019 }\r
1020 if (inp & GP2X_START) { // BIOS testers\r
1021 switch (selected_id) {\r
1022 case MA_CDOPT_TESTBIOS_USA:\r
f013066e 1023 if (emu_findBios(4, &bios)) { // test US\r
daf91588 1024 strcpy(romFileName, bios);\r
1025 engineState = PGS_ReloadRom;\r
1026 return;\r
1027 }\r
1028 break;\r
59633198 1029 case MA_CDOPT_TESTBIOS_EUR:\r
f013066e 1030 if (emu_findBios(8, &bios)) { // test EU\r
daf91588 1031 strcpy(romFileName, bios);\r
1032 engineState = PGS_ReloadRom;\r
1033 return;\r
1034 }\r
1035 break;\r
59633198 1036 case MA_CDOPT_TESTBIOS_JAP:\r
f013066e 1037 if (emu_findBios(1, &bios)) { // test JP\r
daf91588 1038 strcpy(romFileName, bios);\r
1039 engineState = PGS_ReloadRom;\r
1040 return;\r
1041 }\r
1042 break;\r
59633198 1043 default:\r
1044 break;\r
daf91588 1045 }\r
1046 }\r
59633198 1047 if (inp & (GP2X_X|GP2X_A)) return;\r
daf91588 1048 }\r
1049}\r
1050\r
1051\r
1052// --------- advanced options ----------\r
1053\r
59633198 1054menu_entry opt2_entries[] =\r
1055{\r
0ae25549 1056 { NULL, MB_NONE, MA_OPT2_GAMMA, NULL, 0, 0, 0, 1, 1 },\r
1057 { "A_SN's gamma curve", MB_ONOFF, MA_OPT2_A_SN_GAMMA, &currentConfig.EmuOpt, 0x1000, 0, 0, 1, 1 },\r
1058 { "Perfect vsync", MB_ONOFF, MA_OPT2_VSYNC, &currentConfig.EmuOpt, 0x2000, 0, 0, 1, 1 },\r
367b6f1f 1059 { "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoOpt, 0x00004, 0, 0, 1, 1 },\r
1060 { "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoOpt, 0x00001, 0, 0, 1, 1 },\r
1061 { "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496,&PicoOpt, 0x00002, 0, 0, 1, 1 },\r
0ae25549 1062 { "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, &currentConfig.EmuOpt, 0x0008, 0, 0, 1, 1 },\r
1063 { "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, &currentConfig.EmuOpt, 0x0020, 0, 0, 1, 1 },\r
1064 { "needs restart:", MB_NONE, MA_NONE, NULL, 0, 0, 0, 1, 0 },\r
1065 { "craigix's RAM timings", MB_ONOFF, MA_OPT2_RAMTIMINGS, &currentConfig.EmuOpt, 0x0100, 0, 0, 1, 1 },\r
1066 { NULL, MB_ONOFF, MA_OPT2_SQUIDGEHACK, &currentConfig.EmuOpt, 0x0010, 0, 0, 1, 1 },\r
367b6f1f 1067 { "SVP dynarec", MB_ONOFF, MA_OPT2_SVP_DYNAREC, &PicoOpt, 0x20000, 0, 0, 1, 1 },\r
0ae25549 1068 { "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1, 0 },\r
59633198 1069};\r
1070\r
1071#define OPT2_ENTRY_COUNT (sizeof(opt2_entries) / sizeof(opt2_entries[0]))\r
0ae25549 1072const int opt2_entry_count = (sizeof(opt2_entries) / sizeof(opt2_entries[0]));\r
59633198 1073\r
1074static void menu_opt2_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
1075{\r
1076 if (entry->id == MA_OPT2_GAMMA)\r
13059a60 1077 text_out16(x, y, "Gamma correction %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100);\r
59633198 1078 else if (entry->id == MA_OPT2_SQUIDGEHACK)\r
0ae25549 1079 text_out16(x, y, "Squidgehack (now %s %s", mmuhack_status ? "active) " : "inactive)",\r
59633198 1080 (currentConfig.EmuOpt&0x0010)?"ON":"OFF");\r
1081}\r
1082\r
1083\r
720ee7f6 1084static void draw_amenu_options(int menu_sel)\r
1085{\r
59633198 1086 int tl_x = 25, tl_y = 50;\r
720ee7f6 1087\r
e5d315a5 1088 gp2x_pd_clone_buffer2();\r
1089\r
c7a4ff64 1090 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);\r
720ee7f6 1091\r
13059a60 1092 me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, menu_opt2_cust_draw, NULL);\r
720ee7f6 1093\r
13059a60 1094 menu_flip();\r
720ee7f6 1095}\r
1096\r
1097static void amenu_loop_options(void)\r
1098{\r
59d0f042 1099 static int menu_sel = 0;\r
59633198 1100 int menu_sel_max;\r
720ee7f6 1101 unsigned long inp = 0;\r
59633198 1102 menu_id selected_id;\r
1103\r
1104 menu_sel_max = me_count_enabled(opt2_entries, OPT2_ENTRY_COUNT) - 1;\r
720ee7f6 1105\r
1106 for(;;)\r
1107 {\r
1108 draw_amenu_options(menu_sel);\r
1109 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
59633198 1110 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1111 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1112 selected_id = me_index2id(opt2_entries, OPT2_ENTRY_COUNT, menu_sel);\r
1113 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
1114 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0) &&\r
1115 selected_id == MA_OPT2_GAMMA) {\r
1116 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
1117 currentConfig.gamma += (inp & GP2X_LEFT) ? -1 : 1;\r
1118 if (currentConfig.gamma < 1) currentConfig.gamma = 1;\r
1119 if (currentConfig.gamma > 300) currentConfig.gamma = 300;\r
1120 draw_amenu_options(menu_sel);\r
1121 usleep(18*1000);\r
1122 }\r
720ee7f6 1123 }\r
1124 }\r
59633198 1125 if (inp & GP2X_B) { // toggleable options\r
1126 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, 1) &&\r
1127 selected_id == MA_OPT2_DONE) {\r
1128 return;\r
720ee7f6 1129 }\r
1130 }\r
59633198 1131 if (inp & (GP2X_X|GP2X_A)) return;\r
720ee7f6 1132 }\r
1133}\r
1134\r
1135// -------------- options --------------\r
1136\r
59633198 1137\r
1138menu_entry opt_entries[] =\r
1139{\r
0ae25549 1140 { NULL, MB_NONE, MA_OPT_RENDERER, NULL, 0, 0, 0, 1, 1 },\r
1141 { NULL, MB_RANGE, MA_OPT_SCALING, &currentConfig.scaling, 0, 0, 3, 1, 1 },\r
1142 { "Accurate timing (slower)", MB_ONOFF, MA_OPT_ACC_TIMING, &PicoOpt, 0x040, 0, 0, 1, 1 },\r
1143 { "Accurate sprites (slower)", MB_ONOFF, MA_OPT_ACC_SPRITES, &PicoOpt, 0x080, 0, 0, 1, 1 },\r
1144 { "Show FPS", MB_ONOFF, MA_OPT_SHOW_FPS, &currentConfig.EmuOpt, 0x002, 0, 0, 1, 1 },\r
1145 { NULL, MB_RANGE, MA_OPT_FRAMESKIP, &currentConfig.Frameskip, 0, -1, 16, 1, 1 },\r
1146 { "Enable sound", MB_ONOFF, MA_OPT_ENABLE_SOUND, &currentConfig.EmuOpt, 0x004, 0, 0, 1, 1 },\r
1147 { NULL, MB_NONE, MA_OPT_SOUND_QUALITY, NULL, 0, 0, 0, 1, 1 },\r
1148 { "Use ARM940 core for sound", MB_ONOFF, MA_OPT_ARM940_SOUND, &PicoOpt, 0x200, 0, 0, 1, 1 },\r
1149 { "6 button pad", MB_ONOFF, MA_OPT_6BUTTON_PAD, &PicoOpt, 0x020, 0, 0, 1, 1 },\r
1150 { NULL, MB_NONE, MA_OPT_REGION, NULL, 0, 0, 0, 1, 1 },\r
1151 { "Use SRAM/BRAM savestates", MB_ONOFF, MA_OPT_SRAM_STATES, &currentConfig.EmuOpt, 0x001, 0, 0, 1, 1 },\r
1152 { NULL, MB_NONE, MA_OPT_CONFIRM_STATES,NULL, 0, 0, 0, 1, 1 },\r
1153 { "Save slot", MB_RANGE, MA_OPT_SAVE_SLOT, &state_slot, 0, 0, 9, 1, 1 },\r
1154 { NULL, MB_NONE, MA_OPT_CPU_CLOCKS, NULL, 0, 0, 0, 1, 1 },\r
1155 { "[Sega/Mega CD options]", MB_NONE, MA_OPT_SCD_OPTS, NULL, 0, 0, 0, 1, 0 },\r
1156 { "[advanced options]", MB_NONE, MA_OPT_ADV_OPTS, NULL, 0, 0, 0, 1, 0 },\r
1157 { NULL, MB_NONE, MA_OPT_SAVECFG, NULL, 0, 0, 0, 1, 0 },\r
1158 { "Save cfg for current game only",MB_NONE,MA_OPT_SAVECFG_GAME,NULL, 0, 0, 0, 1, 0 },\r
1159 { NULL, MB_NONE, MA_OPT_LOADCFG, NULL, 0, 0, 0, 1, 0 },\r
59633198 1160};\r
1161\r
1162#define OPT_ENTRY_COUNT (sizeof(opt_entries) / sizeof(opt_entries[0]))\r
0ae25549 1163const int opt_entry_count = OPT_ENTRY_COUNT;\r
720ee7f6 1164\r
59633198 1165\r
1166static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
720ee7f6 1167{\r
59633198 1168 char *str, str24[24];\r
1169\r
1170 switch (entry->id)\r
1171 {\r
1172 case MA_OPT_RENDERER:\r
0ae25549 1173 if (PicoOpt&0x10)\r
59633198 1174 str = " 8bit fast";\r
1175 else if (currentConfig.EmuOpt&0x80)\r
1176 str = "16bit accurate";\r
1177 else\r
1178 str = " 8bit accurate";\r
13059a60 1179 text_out16(x, y, "Renderer: %s", str);\r
59633198 1180 break;\r
1181 case MA_OPT_SCALING:\r
1182 switch (currentConfig.scaling) {\r
1183 default: str = " OFF"; break;\r
1184 case 1: str = "hw horizontal"; break;\r
1185 case 2: str = "hw horiz. + vert."; break;\r
1186 case 3: str = "sw horizontal"; break;\r
1187 }\r
13059a60 1188 text_out16(x, y, "Scaling: %s", str);\r
59633198 1189 break;\r
1190 case MA_OPT_FRAMESKIP:\r
1191 if (currentConfig.Frameskip < 0)\r
1192 strcpy(str24, "Auto");\r
1193 else sprintf(str24, "%i", currentConfig.Frameskip);\r
13059a60 1194 text_out16(x, y, "Frameskip %s", str24);\r
59633198 1195 break;\r
1196 case MA_OPT_SOUND_QUALITY:\r
0ae25549 1197 str = (PicoOpt&0x08)?"stereo":"mono";\r
1198 text_out16(x, y, "Sound Quality: %5iHz %s", PsndRate, str);\r
59633198 1199 break;\r
1200 case MA_OPT_REGION:\r
0ae25549 1201 text_out16(x, y, "Region: %s", me_region_name(PicoRegionOverride, PicoAutoRgnOrder));\r
59633198 1202 break;\r
1203 case MA_OPT_CONFIRM_STATES:\r
1204 switch ((currentConfig.EmuOpt >> 9) & 5) {\r
1205 default: str = "OFF"; break;\r
1206 case 1: str = "writes"; break;\r
1207 case 4: str = "loads"; break;\r
1208 case 5: str = "both"; break;\r
1209 }\r
13059a60 1210 text_out16(x, y, "Confirm savestate %s", str);\r
59633198 1211 break;\r
1212 case MA_OPT_CPU_CLOCKS:\r
13059a60 1213 text_out16(x, y, "GP2X CPU clocks %iMhz", currentConfig.CPUclock);\r
59633198 1214 break;\r
1215 case MA_OPT_SAVECFG:\r
1216 str24[0] = 0;\r
1217 if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot);\r
13059a60 1218 text_out16(x, y, "Save cfg as default%s", str24);\r
59633198 1219 break;\r
1220 case MA_OPT_LOADCFG:\r
13059a60 1221 text_out16(x, y, "Load cfg from profile %i", config_slot);\r
59633198 1222 break;\r
1223 default:\r
1224 printf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id);\r
1225 break;\r
46ede6a6 1226 }\r
59633198 1227}\r
1228\r
1229\r
1230\r
1231static void draw_menu_options(int menu_sel)\r
1232{\r
13059a60 1233 int tl_x = 25, tl_y = 24;\r
720ee7f6 1234\r
e5d315a5 1235 gp2x_pd_clone_buffer2();\r
1236\r
c7a4ff64 1237 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 284);\r
720ee7f6 1238\r
13059a60 1239 me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL);\r
720ee7f6 1240\r
13059a60 1241 menu_flip();\r
720ee7f6 1242}\r
1243\r
1244static int sndrate_prevnext(int rate, int dir)\r
1245{\r
1246 int i, rates[] = { 8000, 11025, 16000, 22050, 44100 };\r
1247\r
1248 for (i = 0; i < 5; i++)\r
1249 if (rates[i] == rate) break;\r
1250\r
1251 i += dir ? 1 : -1;\r
1252 if (i > 4) return dir ? 44100 : 22050;\r
1253 if (i < 0) return dir ? 11025 : 8000;\r
1254 return rates[i];\r
1255}\r
1256\r
979ba09f 1257static void region_prevnext(int right)\r
1258{\r
1259 // jp_ntsc=1, jp_pal=2, usa=4, eu=8\r
1260 static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 };\r
1261 int i;\r
1262 if (right) {\r
0ae25549 1263 if (!PicoRegionOverride) {\r
979ba09f 1264 for (i = 0; i < 6; i++)\r
1265 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1266 if (i < 5) PicoAutoRgnOrder = rgn_orders[i+1];\r
0ae25549 1267 else PicoRegionOverride=1;\r
979ba09f 1268 }\r
0ae25549 1269 else PicoRegionOverride<<=1;\r
1270 if (PicoRegionOverride > 8) PicoRegionOverride = 8;\r
979ba09f 1271 } else {\r
0ae25549 1272 if (!PicoRegionOverride) {\r
979ba09f 1273 for (i = 0; i < 6; i++)\r
1274 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1275 if (i > 0) PicoAutoRgnOrder = rgn_orders[i-1];\r
1276 }\r
0ae25549 1277 else PicoRegionOverride>>=1;\r
979ba09f 1278 }\r
1279}\r
1280\r
720ee7f6 1281static void menu_options_save(void)\r
1282{\r
426ecc58 1283 if (PicoRegionOverride) {\r
1284 // force setting possibly changed..\r
1285 Pico.m.pal = (PicoRegionOverride == 2 || PicoRegionOverride == 8) ? 1 : 0;\r
1286 }\r
95151aea 1287 if (!(PicoOpt & 0x20)) {\r
1288 // unbind XYZ MODE, just in case\r
e67f6454 1289 unbind_action(0xf00, -1, -1);\r
720ee7f6 1290 }\r
1291}\r
1292\r
daf91588 1293static int menu_loop_options(void)\r
720ee7f6 1294{\r
59d0f042 1295 static int menu_sel = 0;\r
59633198 1296 int menu_sel_max, ret;\r
720ee7f6 1297 unsigned long inp = 0;\r
59633198 1298 menu_id selected_id;\r
720ee7f6 1299\r
144a28a0 1300 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_SAVECFG_GAME, rom_loaded);\r
59633198 1301 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1302 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
95151aea 1303 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
59633198 1304\r
1305 while (1)\r
720ee7f6 1306 {\r
1307 draw_menu_options(menu_sel);\r
1308 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
59633198 1309 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1310 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1311 selected_id = me_index2id(opt_entries, OPT_ENTRY_COUNT, menu_sel);\r
0ae25549 1312 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choice\r
59633198 1313 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0)) {\r
1314 switch (selected_id) {\r
1315 case MA_OPT_RENDERER:\r
1316 if (inp & GP2X_LEFT) {\r
0ae25549 1317 if (PicoOpt&0x10) PicoOpt&= ~0x10;\r
59633198 1318 else if (!(currentConfig.EmuOpt &0x80))currentConfig.EmuOpt |= 0x80;\r
1319 else if ( currentConfig.EmuOpt &0x80) break;\r
1320 } else {\r
0ae25549 1321 if (PicoOpt&0x10) break;\r
1322 else if (!(currentConfig.EmuOpt &0x80))PicoOpt|= 0x10;\r
59633198 1323 else if ( currentConfig.EmuOpt &0x80) currentConfig.EmuOpt &= ~0x80;\r
1324 }\r
1325 break;\r
1326 case MA_OPT_SOUND_QUALITY:\r
0ae25549 1327 if ((inp & GP2X_RIGHT) && PsndRate == 44100 && !(PicoOpt&0x08)) {\r
1328 PsndRate = 8000; PicoOpt|= 0x08;\r
1329 } else if ((inp & GP2X_LEFT) && PsndRate == 8000 && (PicoOpt&0x08)) {\r
1330 PsndRate = 44100; PicoOpt&=~0x08;\r
1331 } else PsndRate = sndrate_prevnext(PsndRate, inp & GP2X_RIGHT);\r
59633198 1332 break;\r
1333 case MA_OPT_REGION:\r
1334 region_prevnext(inp & GP2X_RIGHT);\r
1335 break;\r
1336 case MA_OPT_CONFIRM_STATES: {\r
1337 int n = ((currentConfig.EmuOpt>>9)&1) | ((currentConfig.EmuOpt>>10)&2);\r
1338 n += (inp & GP2X_LEFT) ? -1 : 1;\r
1339 if (n < 0) n = 0; else if (n > 3) n = 3;\r
1340 n |= n << 1; n &= ~2;\r
1341 currentConfig.EmuOpt &= ~0xa00;\r
1342 currentConfig.EmuOpt |= n << 9;\r
1343 break;\r
1344 }\r
1345 case MA_OPT_SAVE_SLOT:\r
1346 if (inp & GP2X_RIGHT) {\r
1347 state_slot++; if (state_slot > 9) state_slot = 0;\r
1348 } else {state_slot--; if (state_slot < 0) state_slot = 9;\r
1349 }\r
1350 break;\r
1351 case MA_OPT_CPU_CLOCKS:\r
1352 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
1353 currentConfig.CPUclock += (inp & GP2X_LEFT) ? -1 : 1;\r
1354 if (currentConfig.CPUclock < 1) currentConfig.CPUclock = 1;\r
1355 draw_menu_options(menu_sel);\r
1356 usleep(50*1000);\r
1357 }\r
1358 break;\r
1359 case MA_OPT_SAVECFG:\r
1360 case MA_OPT_SAVECFG_GAME:\r
1361 case MA_OPT_LOADCFG:\r
1362 config_slot += (inp&GP2X_RIGHT) ? 1 : -1;\r
1363 if (config_slot > 9) config_slot = 0;\r
1364 if (config_slot < 0) config_slot = 9;\r
1365 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1366 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
1367 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
1368 break;\r
1369 default:\r
1370 //printf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1371 break;\r
1372 }\r
1373 }\r
1374 }\r
1375 if (inp & GP2X_B) {\r
1376 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, 1))\r
1377 {\r
1378 switch (selected_id)\r
1379 {\r
1380 case MA_OPT_SCD_OPTS:\r
1381 cd_menu_loop_options();\r
1382 if (engineState == PGS_ReloadRom)\r
1383 return 0; // test BIOS\r
1384 break;\r
1385 case MA_OPT_ADV_OPTS:\r
1386 amenu_loop_options();\r
1387 break;\r
1388 case MA_OPT_SAVECFG: // done (update and write)\r
1389 menu_options_save();\r
1390 if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved");\r
1391 else strcpy(menuErrorMsg, "failed to write config");\r
1392 return 1;\r
1393 case MA_OPT_SAVECFG_GAME: // done (update and write for current game)\r
1394 menu_options_save();\r
1395 if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved");\r
1396 else strcpy(menuErrorMsg, "failed to write config");\r
1397 return 1;\r
1398 case MA_OPT_LOADCFG:\r
95151aea 1399 ret = emu_ReadConfig(1, 1);\r
1400 if (!ret) ret = emu_ReadConfig(0, 1);\r
1401 if (ret) strcpy(menuErrorMsg, "config loaded");\r
59633198 1402 else strcpy(menuErrorMsg, "failed to load config");\r
1403 return 1;\r
1404 default:\r
1405 //printf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1406 break;\r
1407 }\r
720ee7f6 1408 }\r
1409 }\r
979ba09f 1410 if(inp & (GP2X_X|GP2X_A)) {\r
720ee7f6 1411 menu_options_save();\r
daf91588 1412 return 0; // done (update, no write)\r
720ee7f6 1413 }\r
720ee7f6 1414 }\r
1415}\r
1416\r
1417// -------------- credits --------------\r
1418\r
1419static void draw_menu_credits(void)\r
1420{\r
13059a60 1421 int tl_x = 15, tl_y = 64, y;\r
e5d315a5 1422 gp2x_pd_clone_buffer2();\r
720ee7f6 1423\r
13059a60 1424 text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006,2007");\r
720ee7f6 1425 y = tl_y;\r
13059a60 1426 text_out16(tl_x, y, "Credits:");\r
4b8f4f3c 1427 text_out16(tl_x, (y+=10), "fDave: Cyclone 68000 core,");\r
13059a60 1428 text_out16(tl_x, (y+=10), " base code of PicoDrive");\r
1429 text_out16(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");\r
1430 text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");\r
1431 text_out16(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs");\r
1432 text_out16(tl_x, (y+=10), "Stephane Dallongeville:");\r
1433 text_out16(tl_x, (y+=10), " opensource Gens");\r
1434 text_out16(tl_x, (y+=10), "Haze: Genesis hw info");\r
1435 text_out16(tl_x, (y+=10), "rlyeh and others: minimal SDK");\r
1436 text_out16(tl_x, (y+=10), "Squidge: squidgehack");\r
1437 text_out16(tl_x, (y+=10), "Dzz: ARM940 sample");\r
1438 text_out16(tl_x, (y+=10), "GnoStiC / Puck2099: USB joystick");\r
1439 text_out16(tl_x, (y+=10), "craigix: GP2X hardware");\r
f9a37a02 1440 text_out16(tl_x, (y+=10), "ketchupgun: skin design");\r
13059a60 1441\r
1442 menu_flip();\r
720ee7f6 1443}\r
1444\r
1445\r
1446// -------------- root menu --------------\r
1447\r
59633198 1448menu_entry main_entries[] =\r
1449{\r
0ae25549 1450 { "Resume game", MB_NONE, MA_MAIN_RESUME_GAME, NULL, 0, 0, 0, 0, 0 },\r
1451 { "Save State", MB_NONE, MA_MAIN_SAVE_STATE, NULL, 0, 0, 0, 0, 0 },\r
1452 { "Load State", MB_NONE, MA_MAIN_LOAD_STATE, NULL, 0, 0, 0, 0, 0 },\r
1453 { "Reset game", MB_NONE, MA_MAIN_RESET_GAME, NULL, 0, 0, 0, 0, 0 },\r
1454 { "Load new ROM/ISO", MB_NONE, MA_MAIN_LOAD_ROM, NULL, 0, 0, 0, 1, 0 },\r
1455 { "Change options", MB_NONE, MA_MAIN_OPTIONS, NULL, 0, 0, 0, 1, 0 },\r
1456 { "Configure controls", MB_NONE, MA_MAIN_CONTROLS, NULL, 0, 0, 0, 1, 0 },\r
1457 { "Credits", MB_NONE, MA_MAIN_CREDITS, NULL, 0, 0, 0, 1, 0 },\r
1458 { "Patches / GameGenie",MB_NONE, MA_MAIN_PATCHES, NULL, 0, 0, 0, 0, 0 },\r
1459 { "Exit", MB_NONE, MA_MAIN_EXIT, NULL, 0, 0, 0, 1, 0 }\r
59633198 1460};\r
1461\r
1462#define MAIN_ENTRY_COUNT (sizeof(main_entries) / sizeof(main_entries[0]))\r
1463\r
720ee7f6 1464static void draw_menu_root(int menu_sel)\r
1465{\r
59633198 1466 const int tl_x = 70, tl_y = 70;\r
1467\r
e5d315a5 1468 gp2x_pd_clone_buffer2();\r
720ee7f6 1469\r
13059a60 1470 text_out16(tl_x, 20, "PicoDrive v" VERSION);\r
1471\r
c7a4ff64 1472 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 146);\r
720ee7f6 1473\r
59633198 1474 me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);\r
720ee7f6 1475\r
720ee7f6 1476 // error\r
13059a60 1477 if (menuErrorMsg[0]) {\r
1478 memset((char *)gp2x_screen + 320*224*2, 0, 320*16*2);\r
1479 text_out16(5, 226, menuErrorMsg);\r
1480 }\r
1481 menu_flip();\r
720ee7f6 1482}\r
1483\r
1484\r
1485static void menu_loop_root(void)\r
1486{\r
59633198 1487 static int menu_sel = 0;\r
1488 int ret, menu_sel_max;\r
720ee7f6 1489 unsigned long inp = 0;\r
720ee7f6 1490\r
144a28a0 1491 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_loaded);\r
1492 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE, rom_loaded);\r
1493 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_LOAD_STATE, rom_loaded);\r
1494 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESET_GAME, rom_loaded);\r
59633198 1495 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_PATCHES, PicoPatches != NULL);\r
1496\r
1497 menu_sel_max = me_count_enabled(main_entries, MAIN_ENTRY_COUNT) - 1;\r
95151aea 1498 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
720ee7f6 1499\r
79cad122 1500 /* make sure action buttons are not pressed on entering menu */\r
1501 draw_menu_root(menu_sel);\r
1502 while (gp2x_joystick_read(1) & (GP2X_B|GP2X_X|GP2X_SELECT)) usleep(50*1000);\r
1503\r
1504 for (;;)\r
720ee7f6 1505 {\r
1506 draw_menu_root(menu_sel);\r
0ae6813e 1507 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X|GP2X_SELECT|GP2X_L|GP2X_R);\r
59633198 1508 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1509 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
0ae6813e 1510 if((inp & (GP2X_L|GP2X_R)) == (GP2X_L|GP2X_R)) debug_menu_loop();\r
720ee7f6 1511 if(inp &(GP2X_SELECT|GP2X_X)){\r
144a28a0 1512 if (rom_loaded) {\r
720ee7f6 1513 while (gp2x_joystick_read(1) & (GP2X_SELECT|GP2X_X)) usleep(50*1000); // wait until select is released\r
1514 engineState = PGS_Running;\r
1515 break;\r
1516 }\r
1517 }\r
59633198 1518 if(inp & GP2X_B) {\r
1519 switch (me_index2id(main_entries, MAIN_ENTRY_COUNT, menu_sel))\r
1520 {\r
1521 case MA_MAIN_RESUME_GAME:\r
144a28a0 1522 if (rom_loaded) {\r
5e2e14f2 1523 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
1524 engineState = PGS_Running;\r
1525 return;\r
1526 }\r
720ee7f6 1527 break;\r
59633198 1528 case MA_MAIN_SAVE_STATE:\r
144a28a0 1529 if (rom_loaded) {\r
4ffd2858 1530 if(savestate_menu_loop(0))\r
720ee7f6 1531 continue;\r
720ee7f6 1532 engineState = PGS_Running;\r
1533 return;\r
1534 }\r
1535 break;\r
59633198 1536 case MA_MAIN_LOAD_STATE:\r
144a28a0 1537 if (rom_loaded) {\r
4ffd2858 1538 if(savestate_menu_loop(1))\r
720ee7f6 1539 continue;\r
720ee7f6 1540 engineState = PGS_Running;\r
1541 return;\r
1542 }\r
1543 break;\r
59633198 1544 case MA_MAIN_RESET_GAME:\r
144a28a0 1545 if (rom_loaded) {\r
720ee7f6 1546 emu_ResetGame();\r
1547 engineState = PGS_Running;\r
1548 return;\r
1549 }\r
1550 break;\r
59633198 1551 case MA_MAIN_LOAD_ROM:\r
13059a60 1552 {\r
1553 char curr_path[PATH_MAX], *selfname;\r
1554 FILE *tstf;\r
367b6f1f 1555 if ( (tstf = fopen(lastRomFile, "rb")) )\r
13059a60 1556 {\r
1557 fclose(tstf);\r
367b6f1f 1558 strcpy(curr_path, lastRomFile);\r
13059a60 1559 }\r
1560 else\r
1561 getcwd(curr_path, PATH_MAX);\r
720ee7f6 1562 selfname = romsel_loop(curr_path);\r
1563 if (selfname) {\r
1564 printf("selected file: %s\n", selfname);\r
720ee7f6 1565 engineState = PGS_ReloadRom;\r
13059a60 1566 return;\r
720ee7f6 1567 }\r
13059a60 1568 break;\r
1569 }\r
59633198 1570 case MA_MAIN_OPTIONS:\r
daf91588 1571 ret = menu_loop_options();\r
1572 if (ret == 1) continue; // status update\r
1573 if (engineState == PGS_ReloadRom)\r
1574 return; // BIOS test\r
720ee7f6 1575 break;\r
59633198 1576 case MA_MAIN_CONTROLS:\r
720ee7f6 1577 kc_sel_loop();\r
1578 break;\r
59633198 1579 case MA_MAIN_CREDITS:\r
720ee7f6 1580 draw_menu_credits();\r
1581 usleep(500*1000);\r
1582 inp = wait_for_input(GP2X_B|GP2X_X);\r
1583 break;\r
59633198 1584 case MA_MAIN_EXIT:\r
720ee7f6 1585 engineState = PGS_Quit;\r
1586 return;\r
59633198 1587 case MA_MAIN_PATCHES:\r
144a28a0 1588 if (rom_loaded && PicoPatches) {\r
70d2ecc5 1589 patches_menu_loop();\r
1590 PicoPatchApply();\r
1591 strcpy(menuErrorMsg, "Patches applied");\r
1592 continue;\r
1593 }\r
1594 break;\r
59633198 1595 default:\r
1596 printf("%s: something unknown selected\n", __FUNCTION__);\r
1597 break;\r
720ee7f6 1598 }\r
1599 }\r
1600 menuErrorMsg[0] = 0; // clear error msg\r
1601 }\r
1602}\r
1603\r
f9a37a02 1604static void menu_darken_bg(void *dst, int pixels, int darker)\r
720ee7f6 1605{\r
13059a60 1606 unsigned int *screen = dst;\r
1607 pixels /= 2;\r
f9a37a02 1608 if (darker)\r
13059a60 1609 {\r
f9a37a02 1610 while (pixels--)\r
1611 {\r
1612 unsigned int p = *screen;\r
1613 *screen++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r
1614 }\r
1615 }\r
1616 else\r
1617 {\r
1618 while (pixels--)\r
1619 {\r
1620 unsigned int p = *screen;\r
1621 *screen++ = (p&0xf79ef79e)>>1;\r
1622 }\r
13059a60 1623 }\r
1624}\r
e5d315a5 1625\r
13059a60 1626static void menu_prepare_bg(int use_game_bg)\r
1627{\r
1628 if (use_game_bg)\r
1629 {\r
1630 // darken the active framebuffer\r
1631 memset(gp2x_screen, 0, 320*8*2);\r
f9a37a02 1632 menu_darken_bg((char *)gp2x_screen + 320*8*2, 320*224, 1);\r
13059a60 1633 memset((char *)gp2x_screen + 320*232*2, 0, 320*8*2);\r
1634 }\r
1635 else\r
1636 {\r
1637 // should really only happen once, on startup..\r
1638 readpng(gp2x_screen, "skin/background.png", READPNG_BG);\r
4ffd2858 1639 }\r
720ee7f6 1640\r
13059a60 1641 // copy to buffer2\r
1642 gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2);\r
4ffd2858 1643}\r
1644\r
1645static void menu_gfx_prepare(void)\r
1646{\r
144a28a0 1647 menu_prepare_bg(rom_loaded);\r
4ffd2858 1648\r
13059a60 1649 // switch to 16bpp\r
1650 gp2x_video_changemode2(16);\r
79cad122 1651 gp2x_video_RGB_setscaling(0, 320, 240);\r
13059a60 1652 menu_flip();\r
e5d315a5 1653}\r
1654\r
1655\r
1656void menu_loop(void)\r
1657{\r
1658 menu_gfx_prepare();\r
720ee7f6 1659\r
1660 menu_loop_root();\r
1661\r
1662 menuErrorMsg[0] = 0;\r
1663}\r
5e2e14f2 1664\r
1665\r
1666// --------- CD tray close menu ----------\r
1667\r
1668static void draw_menu_tray(int menu_sel)\r
1669{\r
1670 int tl_x = 70, tl_y = 90, y;\r
13059a60 1671 memset(gp2x_screen, 0, 320*240*2);\r
5e2e14f2 1672\r
13059a60 1673 text_out16(tl_x, 20, "The unit is about to");\r
1674 text_out16(tl_x, 30, "close the CD tray.");\r
5e2e14f2 1675\r
1676 y = tl_y;\r
13059a60 1677 text_out16(tl_x, y, "Load new CD image");\r
1678 text_out16(tl_x, (y+=10), "Insert nothing");\r
5e2e14f2 1679\r
1680 // draw cursor\r
13059a60 1681 text_out16(tl_x - 16, tl_y + menu_sel*10, ">");\r
5e2e14f2 1682 // error\r
13059a60 1683 if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg);\r
1684 menu_flip();\r
5e2e14f2 1685}\r
1686\r
1687\r
1688int menu_loop_tray(void)\r
1689{\r
1690 int menu_sel = 0, menu_sel_max = 1;\r
1691 unsigned long inp = 0;\r
1692 char curr_path[PATH_MAX], *selfname;\r
1693 FILE *tstf;\r
1694\r
c7a4ff64 1695 gp2x_memset_all_buffers(0, 0, 320*240*2);\r
5e2e14f2 1696 menu_gfx_prepare();\r
1697\r
367b6f1f 1698 if ( (tstf = fopen(lastRomFile, "rb")) )\r
5e2e14f2 1699 {\r
1700 fclose(tstf);\r
367b6f1f 1701 strcpy(curr_path, lastRomFile);\r
5e2e14f2 1702 }\r
1703 else\r
1704 {\r
1705 getcwd(curr_path, PATH_MAX);\r
1706 }\r
1707\r
1708 /* make sure action buttons are not pressed on entering menu */\r
1709 draw_menu_tray(menu_sel);\r
1710 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
1711\r
1712 for (;;)\r
1713 {\r
1714 draw_menu_tray(menu_sel);\r
1715 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B);\r
1716 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1717 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1718 if(inp & GP2X_B ) {\r
1719 switch (menu_sel) {\r
1720 case 0: // select image\r
1721 selfname = romsel_loop(curr_path);\r
1722 if (selfname) {\r
1723 int ret = -1, cd_type;\r
f013066e 1724 cd_type = emu_cdCheck(NULL);\r
5e2e14f2 1725 if (cd_type > 0)\r
1726 ret = Insert_CD(romFileName, cd_type == 2);\r
1727 if (ret != 0) {\r
1728 sprintf(menuErrorMsg, "Load failed, invalid CD image?");\r
1729 printf("%s\n", menuErrorMsg);\r
1730 continue;\r
1731 }\r
1732 engineState = PGS_RestartRun;\r
1733 return 1;\r
1734 }\r
1735 break;\r
1736 case 1: // insert nothing\r
1737 engineState = PGS_RestartRun;\r
1738 return 0;\r
1739 }\r
1740 }\r
1741 menuErrorMsg[0] = 0; // clear error msg\r
1742 }\r
1743}\r
1744\r
1745\r