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