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