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