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