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