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