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