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