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