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