| 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 | #include <stdio.h>\r |
| 7 | #include <string.h>\r |
| 8 | #include <stdlib.h>\r |
| 9 | #include <stdarg.h>\r |
| 10 | \r |
| 11 | #include "menu.h"\r |
| 12 | #include "fonts.h"\r |
| 13 | #include "readpng.h"\r |
| 14 | #include "lprintf.h"\r |
| 15 | #include "common.h"\r |
| 16 | #include "input.h"\r |
| 17 | #include "emu.h"\r |
| 18 | #include "plat.h"\r |
| 19 | \r |
| 20 | #include <pico/patch.h>\r |
| 21 | \r |
| 22 | char menuErrorMsg[64] = { 0, };\r |
| 23 | \r |
| 24 | // PicoPad[] format: MXYZ SACB RLDU\r |
| 25 | me_bind_action me_ctrl_actions[15] =\r |
| 26 | {\r |
| 27 | { "UP ", 0x0001 },\r |
| 28 | { "DOWN ", 0x0002 },\r |
| 29 | { "LEFT ", 0x0004 },\r |
| 30 | { "RIGHT ", 0x0008 },\r |
| 31 | { "A ", 0x0040 },\r |
| 32 | { "B ", 0x0010 },\r |
| 33 | { "C ", 0x0020 },\r |
| 34 | { "A turbo", 0x4000 },\r |
| 35 | { "B turbo", 0x1000 },\r |
| 36 | { "C turbo", 0x2000 },\r |
| 37 | { "START ", 0x0080 },\r |
| 38 | { "MODE ", 0x0800 },\r |
| 39 | { "X ", 0x0400 },\r |
| 40 | { "Y ", 0x0200 },\r |
| 41 | { "Z ", 0x0100 }\r |
| 42 | };\r |
| 43 | \r |
| 44 | \r |
| 45 | #ifndef UIQ3\r |
| 46 | \r |
| 47 | static unsigned char menu_font_data[10240];\r |
| 48 | static int menu_text_color = 0xffff; // default to white\r |
| 49 | static int menu_sel_color = -1; // disabled\r |
| 50 | \r |
| 51 | // draws text to current bbp16 screen\r |
| 52 | static void text_out16_(int x, int y, const char *text, int color)\r |
| 53 | {\r |
| 54 | int i, l, u, tr, tg, tb, len;\r |
| 55 | unsigned short *dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r |
| 56 | tr = (color & 0xf800) >> 8;\r |
| 57 | tg = (color & 0x07e0) >> 3;\r |
| 58 | tb = (color & 0x001f) << 3;\r |
| 59 | \r |
| 60 | if (text == (void *)1)\r |
| 61 | {\r |
| 62 | // selector symbol\r |
| 63 | text = "";\r |
| 64 | len = 1;\r |
| 65 | }\r |
| 66 | else\r |
| 67 | len = strlen(text);\r |
| 68 | \r |
| 69 | for (i = 0; i < len; i++)\r |
| 70 | {\r |
| 71 | unsigned char *src = menu_font_data + (unsigned int)text[i]*4*10;\r |
| 72 | unsigned short *dst = dest;\r |
| 73 | for (l = 0; l < 10; l++, dst += SCREEN_WIDTH-8)\r |
| 74 | {\r |
| 75 | for (u = 8/2; u > 0; u--, src++)\r |
| 76 | {\r |
| 77 | int c, r, g, b;\r |
| 78 | c = *src >> 4;\r |
| 79 | r = (*dst & 0xf800) >> 8;\r |
| 80 | g = (*dst & 0x07e0) >> 3;\r |
| 81 | b = (*dst & 0x001f) << 3;\r |
| 82 | r = (c^0xf)*r/15 + c*tr/15;\r |
| 83 | g = (c^0xf)*g/15 + c*tg/15;\r |
| 84 | b = (c^0xf)*b/15 + c*tb/15;\r |
| 85 | *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r |
| 86 | c = *src & 0xf;\r |
| 87 | r = (*dst & 0xf800) >> 8;\r |
| 88 | g = (*dst & 0x07e0) >> 3;\r |
| 89 | b = (*dst & 0x001f) << 3;\r |
| 90 | r = (c^0xf)*r/15 + c*tr/15;\r |
| 91 | g = (c^0xf)*g/15 + c*tg/15;\r |
| 92 | b = (c^0xf)*b/15 + c*tb/15;\r |
| 93 | *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r |
| 94 | }\r |
| 95 | }\r |
| 96 | dest += 8;\r |
| 97 | }\r |
| 98 | }\r |
| 99 | \r |
| 100 | void text_out16(int x, int y, const char *texto, ...)\r |
| 101 | {\r |
| 102 | va_list args;\r |
| 103 | char buffer[256];\r |
| 104 | int maxw = (SCREEN_WIDTH - x) / 8;\r |
| 105 | \r |
| 106 | va_start(args, texto);\r |
| 107 | vsnprintf(buffer, sizeof(buffer), texto, args);\r |
| 108 | va_end(args);\r |
| 109 | \r |
| 110 | if (maxw > 255)\r |
| 111 | maxw = 255;\r |
| 112 | buffer[maxw] = 0;\r |
| 113 | \r |
| 114 | text_out16_(x,y,buffer,menu_text_color);\r |
| 115 | }\r |
| 116 | \r |
| 117 | \r |
| 118 | void smalltext_out16(int x, int y, const char *texto, int color)\r |
| 119 | {\r |
| 120 | int i;\r |
| 121 | unsigned char *src;\r |
| 122 | unsigned short *dst;\r |
| 123 | \r |
| 124 | for (i = 0;; i++, x += 6)\r |
| 125 | {\r |
| 126 | unsigned char c = (unsigned char) texto[i];\r |
| 127 | int h = 8;\r |
| 128 | \r |
| 129 | if (!c) break;\r |
| 130 | \r |
| 131 | src = fontdata6x8[c];\r |
| 132 | dst = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r |
| 133 | \r |
| 134 | while (h--)\r |
| 135 | {\r |
| 136 | int w = 0x20;\r |
| 137 | while (w)\r |
| 138 | {\r |
| 139 | if( *src & w ) *dst = color;\r |
| 140 | dst++;\r |
| 141 | w>>=1;\r |
| 142 | }\r |
| 143 | src++;\r |
| 144 | \r |
| 145 | dst += SCREEN_WIDTH-6;\r |
| 146 | }\r |
| 147 | }\r |
| 148 | }\r |
| 149 | \r |
| 150 | void smalltext_out16_lim(int x, int y, const char *texto, int color, int max)\r |
| 151 | {\r |
| 152 | char buffer[SCREEN_WIDTH/6+1];\r |
| 153 | \r |
| 154 | strncpy(buffer, texto, SCREEN_WIDTH/6);\r |
| 155 | if (max > SCREEN_WIDTH/6) max = SCREEN_WIDTH/6;\r |
| 156 | if (max < 0) max = 0;\r |
| 157 | buffer[max] = 0;\r |
| 158 | \r |
| 159 | smalltext_out16(x, y, buffer, color);\r |
| 160 | }\r |
| 161 | \r |
| 162 | void menu_draw_selection(int x, int y, int w)\r |
| 163 | {\r |
| 164 | int i, h;\r |
| 165 | unsigned short *dst, *dest;\r |
| 166 | \r |
| 167 | text_out16_(x, y, (void *)1, (menu_sel_color < 0) ? menu_text_color : menu_sel_color);\r |
| 168 | \r |
| 169 | if (menu_sel_color < 0) return; // no selection hilight\r |
| 170 | \r |
| 171 | if (y > 0) y--;\r |
| 172 | dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH + 14;\r |
| 173 | for (h = 11; h > 0; h--)\r |
| 174 | {\r |
| 175 | dst = dest;\r |
| 176 | for (i = w; i > 0; i--)\r |
| 177 | *dst++ = menu_sel_color;\r |
| 178 | dest += SCREEN_WIDTH;\r |
| 179 | }\r |
| 180 | }\r |
| 181 | \r |
| 182 | static int parse_hex_color(char *buff)\r |
| 183 | {\r |
| 184 | char *endp = buff;\r |
| 185 | int t = (int) strtoul(buff, &endp, 16);\r |
| 186 | if (endp != buff)\r |
| 187 | #ifdef PSP\r |
| 188 | return ((t<<8)&0xf800) | ((t>>5)&0x07e0) | ((t>>19)&0x1f);\r |
| 189 | #else\r |
| 190 | return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);\r |
| 191 | #endif\r |
| 192 | return -1;\r |
| 193 | }\r |
| 194 | \r |
| 195 | void menu_init(void)\r |
| 196 | {\r |
| 197 | int c, l;\r |
| 198 | unsigned char *fd = menu_font_data;\r |
| 199 | char buff[256];\r |
| 200 | FILE *f;\r |
| 201 | \r |
| 202 | // generate default font from fontdata8x8\r |
| 203 | memset(menu_font_data, 0, sizeof(menu_font_data));\r |
| 204 | for (c = 0; c < 256; c++)\r |
| 205 | {\r |
| 206 | for (l = 0; l < 8; l++)\r |
| 207 | {\r |
| 208 | unsigned char fd8x8 = fontdata8x8[c*8+l];\r |
| 209 | if (fd8x8&0x80) *fd |= 0xf0;\r |
| 210 | if (fd8x8&0x40) *fd |= 0x0f; fd++;\r |
| 211 | if (fd8x8&0x20) *fd |= 0xf0;\r |
| 212 | if (fd8x8&0x10) *fd |= 0x0f; fd++;\r |
| 213 | if (fd8x8&0x08) *fd |= 0xf0;\r |
| 214 | if (fd8x8&0x04) *fd |= 0x0f; fd++;\r |
| 215 | if (fd8x8&0x02) *fd |= 0xf0;\r |
| 216 | if (fd8x8&0x01) *fd |= 0x0f; fd++;\r |
| 217 | }\r |
| 218 | fd += 8*2/2; // 2 empty lines\r |
| 219 | }\r |
| 220 | \r |
| 221 | // load custom font and selector (stored as 1st symbol in font table)\r |
| 222 | readpng(menu_font_data, "skin/font.png", READPNG_FONT);\r |
| 223 | memcpy(menu_font_data, menu_font_data + ((int)'>')*4*10, 4*10); // default selector symbol is '>'\r |
| 224 | readpng(menu_font_data, "skin/selector.png", READPNG_SELECTOR);\r |
| 225 | \r |
| 226 | // load custom colors\r |
| 227 | f = fopen("skin/skin.txt", "r");\r |
| 228 | if (f != NULL)\r |
| 229 | {\r |
| 230 | lprintf("found skin.txt\n");\r |
| 231 | while (!feof(f))\r |
| 232 | {\r |
| 233 | fgets(buff, sizeof(buff), f);\r |
| 234 | if (buff[0] == '#' || buff[0] == '/') continue; // comment\r |
| 235 | if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line\r |
| 236 | if (strncmp(buff, "text_color=", 11) == 0)\r |
| 237 | {\r |
| 238 | int tmp = parse_hex_color(buff+11);\r |
| 239 | if (tmp >= 0) menu_text_color = tmp;\r |
| 240 | else lprintf("skin.txt: parse error for text_color\n");\r |
| 241 | }\r |
| 242 | else if (strncmp(buff, "selection_color=", 16) == 0)\r |
| 243 | {\r |
| 244 | int tmp = parse_hex_color(buff+16);\r |
| 245 | if (tmp >= 0) menu_sel_color = tmp;\r |
| 246 | else lprintf("skin.txt: parse error for selection_color\n");\r |
| 247 | }\r |
| 248 | else\r |
| 249 | lprintf("skin.txt: parse error: %s\n", buff);\r |
| 250 | }\r |
| 251 | fclose(f);\r |
| 252 | }\r |
| 253 | }\r |
| 254 | \r |
| 255 | \r |
| 256 | int me_id2offset(const menu_entry *ent, menu_id id)\r |
| 257 | {\r |
| 258 | int i;\r |
| 259 | for (i = 0; ent->name; ent++, i++)\r |
| 260 | if (ent->id == id) return i;\r |
| 261 | \r |
| 262 | lprintf("%s: id %i not found\n", __FUNCTION__, id);\r |
| 263 | return 0;\r |
| 264 | }\r |
| 265 | \r |
| 266 | void me_enable(menu_entry *entries, menu_id id, int enable)\r |
| 267 | {\r |
| 268 | int i = me_id2offset(entries, id);\r |
| 269 | entries[i].enabled = enable;\r |
| 270 | }\r |
| 271 | \r |
| 272 | int me_count(const menu_entry *ent)\r |
| 273 | {\r |
| 274 | int ret;\r |
| 275 | \r |
| 276 | for (ret = 0; ent->name; ent++, ret++)\r |
| 277 | ;\r |
| 278 | \r |
| 279 | return ret;\r |
| 280 | }\r |
| 281 | \r |
| 282 | menu_id me_index2id(const menu_entry *ent, int index)\r |
| 283 | {\r |
| 284 | const menu_entry *last;\r |
| 285 | \r |
| 286 | for (; ent->name; ent++)\r |
| 287 | {\r |
| 288 | if (ent->enabled)\r |
| 289 | {\r |
| 290 | if (index == 0) break;\r |
| 291 | index--;\r |
| 292 | }\r |
| 293 | last = ent;\r |
| 294 | }\r |
| 295 | if (ent->name == NULL)\r |
| 296 | ent = last;\r |
| 297 | return ent->id;\r |
| 298 | }\r |
| 299 | \r |
| 300 | /* TODO rm */\r |
| 301 | void me_draw(const menu_entry *entries, int count, int x, int y, me_draw_custom_f *cust_draw, void *param)\r |
| 302 | {\r |
| 303 | int i, y1 = y;\r |
| 304 | \r |
| 305 | for (i = 0; i < count; i++)\r |
| 306 | {\r |
| 307 | if (!entries[i].enabled) continue;\r |
| 308 | if (entries[i].name == NULL)\r |
| 309 | {\r |
| 310 | if (cust_draw != NULL)\r |
| 311 | cust_draw(&entries[i], x, y1, param);\r |
| 312 | y1 += 10;\r |
| 313 | continue;\r |
| 314 | }\r |
| 315 | text_out16(x, y1, entries[i].name);\r |
| 316 | if (entries[i].beh == MB_OPT_ONOFF)\r |
| 317 | text_out16(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF");\r |
| 318 | else if (entries[i].beh == MB_OPT_RANGE)\r |
| 319 | text_out16(x + 27*8, y1, "%i", *(int *)entries[i].var);\r |
| 320 | y1 += 10;\r |
| 321 | }\r |
| 322 | \r |
| 323 | }\r |
| 324 | \r |
| 325 | static void me_draw2(const menu_entry *entries, int sel)\r |
| 326 | {\r |
| 327 | const menu_entry *ent;\r |
| 328 | int x, y, w = 0, h = 0;\r |
| 329 | int opt_offs = 27*8;\r |
| 330 | const char *name;\r |
| 331 | int asel = 0;\r |
| 332 | int i, n;\r |
| 333 | \r |
| 334 | /* calculate size of menu rect */\r |
| 335 | for (ent = entries, i = n = 0; ent->name; ent++, i++)\r |
| 336 | {\r |
| 337 | int wt;\r |
| 338 | \r |
| 339 | if (!ent->enabled)\r |
| 340 | continue;\r |
| 341 | \r |
| 342 | if (i == sel)\r |
| 343 | asel = n;\r |
| 344 | \r |
| 345 | name = NULL;\r |
| 346 | wt = strlen(ent->name) * 8; /* FIXME: unhardcode font width */\r |
| 347 | if (wt == 0 && ent->generate_name)\r |
| 348 | name = ent->generate_name(1);\r |
| 349 | if (name != NULL)\r |
| 350 | wt = strlen(name) * 8;\r |
| 351 | \r |
| 352 | if (ent->beh != MB_NONE)\r |
| 353 | {\r |
| 354 | if (wt > opt_offs)\r |
| 355 | opt_offs = wt + 8;\r |
| 356 | wt = opt_offs;\r |
| 357 | \r |
| 358 | switch (ent->beh) {\r |
| 359 | case MB_NONE: break;\r |
| 360 | case MB_OPT_ONOFF:\r |
| 361 | case MB_OPT_RANGE: wt += 8*3; break;\r |
| 362 | case MB_OPT_CUSTOM:\r |
| 363 | name = NULL;\r |
| 364 | if (ent->generate_name != NULL)\r |
| 365 | name = ent->generate_name(0);\r |
| 366 | if (name != NULL)\r |
| 367 | wt += strlen(name) * 8;\r |
| 368 | break;\r |
| 369 | }\r |
| 370 | }\r |
| 371 | \r |
| 372 | if (wt > w)\r |
| 373 | w = wt;\r |
| 374 | n++;\r |
| 375 | }\r |
| 376 | h = n * 10;\r |
| 377 | w += 16; /* selector */\r |
| 378 | \r |
| 379 | if (w > SCREEN_WIDTH) {\r |
| 380 | lprintf("width %d > %d\n", w, SCREEN_WIDTH);\r |
| 381 | w = SCREEN_WIDTH;\r |
| 382 | }\r |
| 383 | if (h > SCREEN_HEIGHT) {\r |
| 384 | lprintf("height %d > %d\n", w, SCREEN_HEIGHT);\r |
| 385 | h = SCREEN_HEIGHT;\r |
| 386 | }\r |
| 387 | \r |
| 388 | x = SCREEN_WIDTH / 2 - w / 2;\r |
| 389 | y = SCREEN_HEIGHT / 2 - h / 2;\r |
| 390 | \r |
| 391 | /* draw */\r |
| 392 | plat_video_menu_begin();\r |
| 393 | menu_draw_selection(x, y + asel * 10, w);\r |
| 394 | \r |
| 395 | for (ent = entries; ent->name; ent++)\r |
| 396 | {\r |
| 397 | if (!ent->enabled)\r |
| 398 | continue;\r |
| 399 | \r |
| 400 | name = ent->name;\r |
| 401 | if (strlen(name) == 0) {\r |
| 402 | if (ent->generate_name)\r |
| 403 | name = ent->generate_name(1);\r |
| 404 | }\r |
| 405 | if (name != NULL)\r |
| 406 | text_out16(x + 16, y, name);\r |
| 407 | \r |
| 408 | switch (ent->beh) {\r |
| 409 | case MB_NONE:\r |
| 410 | break;\r |
| 411 | case MB_OPT_ONOFF:\r |
| 412 | text_out16(x + 16 + opt_offs, y, (*(int *)ent->var & ent->mask) ? "ON" : "OFF");\r |
| 413 | break;\r |
| 414 | case MB_OPT_RANGE:\r |
| 415 | text_out16(x + 16 + opt_offs, y, "%i", *(int *)ent->var);\r |
| 416 | break;\r |
| 417 | case MB_OPT_CUSTOM:\r |
| 418 | name = NULL;\r |
| 419 | if (ent->generate_name)\r |
| 420 | name = ent->generate_name(0);\r |
| 421 | if (name != NULL)\r |
| 422 | text_out16(x + 16 + opt_offs, y, "%s", name);\r |
| 423 | break;\r |
| 424 | }\r |
| 425 | \r |
| 426 | y += 10;\r |
| 427 | }\r |
| 428 | \r |
| 429 | plat_video_menu_end();\r |
| 430 | }\r |
| 431 | \r |
| 432 | int me_process(menu_entry *entries, menu_id id, int is_next)\r |
| 433 | {\r |
| 434 | int i = me_id2offset(entries, id);\r |
| 435 | menu_entry *entry = &entries[i];\r |
| 436 | switch (entry->beh)\r |
| 437 | {\r |
| 438 | case MB_OPT_ONOFF:\r |
| 439 | *(int *)entry->var ^= entry->mask;\r |
| 440 | return 1;\r |
| 441 | case MB_OPT_RANGE:\r |
| 442 | *(int *)entry->var += is_next ? 1 : -1;\r |
| 443 | if (*(int *)entry->var < (int)entry->min) *(int *)entry->var = (int)entry->min;\r |
| 444 | if (*(int *)entry->var > (int)entry->max) *(int *)entry->var = (int)entry->max;\r |
| 445 | return 1;\r |
| 446 | default:\r |
| 447 | return 0;\r |
| 448 | }\r |
| 449 | }\r |
| 450 | \r |
| 451 | static void me_loop(menu_entry *menu, int *menu_sel)\r |
| 452 | {\r |
| 453 | int ret, inp, sel = *menu_sel, menu_sel_max;\r |
| 454 | \r |
| 455 | menu_sel_max = me_count(menu) - 1;\r |
| 456 | if (menu_sel_max < 1) {\r |
| 457 | lprintf("no enabled menu entries\n");\r |
| 458 | return;\r |
| 459 | }\r |
| 460 | \r |
| 461 | while (!menu[sel].enabled && sel < menu_sel_max)\r |
| 462 | sel++;\r |
| 463 | \r |
| 464 | /* make sure action buttons are not pressed on entering menu */\r |
| 465 | me_draw2(menu, sel);\r |
| 466 | while (in_menu_wait_any(50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU));\r |
| 467 | \r |
| 468 | for (;;)\r |
| 469 | {\r |
| 470 | me_draw2(menu, sel);\r |
| 471 | inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_MOK|PBTN_MBACK|PBTN_MENU|PBTN_L|PBTN_R);\r |
| 472 | if (inp & PBTN_UP ) {\r |
| 473 | do {\r |
| 474 | sel--;\r |
| 475 | if (sel < 0)\r |
| 476 | sel = menu_sel_max;\r |
| 477 | }\r |
| 478 | while (!menu[sel].enabled);\r |
| 479 | }\r |
| 480 | if (inp & PBTN_DOWN) {\r |
| 481 | do {\r |
| 482 | sel++;\r |
| 483 | if (sel > menu_sel_max)\r |
| 484 | sel = 0;\r |
| 485 | }\r |
| 486 | while (!menu[sel].enabled);\r |
| 487 | }\r |
| 488 | // if ((inp & (PBTN_L|PBTN_R)) == (PBTN_L|PBTN_R)) debug_menu_loop(); // TODO\r |
| 489 | if (inp & (PBTN_MENU|PBTN_MBACK))\r |
| 490 | break;\r |
| 491 | \r |
| 492 | if (inp & PBTN_MOK)\r |
| 493 | {\r |
| 494 | if (menu[sel].submenu_handler != NULL) {\r |
| 495 | ret = menu[sel].submenu_handler(menu[sel].id);\r |
| 496 | if (ret) break;\r |
| 497 | }\r |
| 498 | }\r |
| 499 | // menuErrorMsg[0] = 0; // TODO: clear error msg\r |
| 500 | }\r |
| 501 | *menu_sel = sel;\r |
| 502 | }\r |
| 503 | \r |
| 504 | /* ***************************************** */\r |
| 505 | \r |
| 506 | /* TODO s */\r |
| 507 | int menu_loop_tray(void) { return 0; }\r |
| 508 | void menu_romload_prepare(const char *rom_name) {}\r |
| 509 | void menu_romload_end(void) {}\r |
| 510 | me_bind_action emuctrl_actions[1];\r |
| 511 | menu_entry opt_entries[1];\r |
| 512 | menu_entry opt2_entries[1];\r |
| 513 | menu_entry cdopt_entries[1];\r |
| 514 | menu_entry ctrlopt_entries[1];\r |
| 515 | const int opt_entry_count = 0;\r |
| 516 | const int opt2_entry_count = 0;\r |
| 517 | const int cdopt_entry_count = 0;\r |
| 518 | const int ctrlopt_entry_count = 0;\r |
| 519 | \r |
| 520 | extern int engineState;\r |
| 521 | \r |
| 522 | int savestate_menu_loop(int a) { return 1; }\r |
| 523 | int menu_loop_options() { return 1; }\r |
| 524 | void kc_sel_loop() {}\r |
| 525 | void draw_menu_credits() {}\r |
| 526 | void patches_menu_loop() {}\r |
| 527 | \r |
| 528 | // ------------ main menu ------------\r |
| 529 | \r |
| 530 | static int main_menu_handler(menu_id id)\r |
| 531 | {\r |
| 532 | int ret;\r |
| 533 | \r |
| 534 | switch (id)\r |
| 535 | {\r |
| 536 | case MA_MAIN_RESUME_GAME:\r |
| 537 | if (rom_loaded) {\r |
| 538 | while (in_menu_wait_any(50) & PBTN_MOK);\r |
| 539 | engineState = PGS_Running;\r |
| 540 | return 1;\r |
| 541 | }\r |
| 542 | break;\r |
| 543 | case MA_MAIN_SAVE_STATE:\r |
| 544 | if (rom_loaded) {\r |
| 545 | if (savestate_menu_loop(0))\r |
| 546 | break;\r |
| 547 | engineState = PGS_Running;\r |
| 548 | return 1;\r |
| 549 | }\r |
| 550 | break;\r |
| 551 | case MA_MAIN_LOAD_STATE:\r |
| 552 | if (rom_loaded) {\r |
| 553 | if (savestate_menu_loop(1))\r |
| 554 | break;\r |
| 555 | while (in_menu_wait_any(50) & PBTN_MOK);\r |
| 556 | engineState = PGS_Running;\r |
| 557 | return 1;\r |
| 558 | }\r |
| 559 | break;\r |
| 560 | case MA_MAIN_RESET_GAME:\r |
| 561 | if (rom_loaded) {\r |
| 562 | emu_ResetGame();\r |
| 563 | while (in_menu_wait_any(50) & PBTN_MOK);\r |
| 564 | engineState = PGS_Running;\r |
| 565 | return 1;\r |
| 566 | }\r |
| 567 | break;\r |
| 568 | case MA_MAIN_LOAD_ROM:\r |
| 569 | {\r |
| 570 | /* char curr_path[PATH_MAX], *selfname;\r |
| 571 | FILE *tstf;\r |
| 572 | if ( (tstf = fopen(loadedRomFName, "rb")) )\r |
| 573 | {\r |
| 574 | fclose(tstf);\r |
| 575 | strcpy(curr_path, loadedRomFName);\r |
| 576 | }\r |
| 577 | else\r |
| 578 | getcwd(curr_path, PATH_MAX);\r |
| 579 | selfname = romsel_loop(curr_path);\r |
| 580 | if (selfname) {\r |
| 581 | printf("selected file: %s\n", selfname);\r |
| 582 | engineState = PGS_ReloadRom;\r |
| 583 | return;\r |
| 584 | }*/\r |
| 585 | break;\r |
| 586 | }\r |
| 587 | case MA_MAIN_OPTIONS:\r |
| 588 | ret = menu_loop_options();\r |
| 589 | if (ret == 1) break; // status update\r |
| 590 | if (engineState == PGS_ReloadRom)\r |
| 591 | return 1; // BIOS test\r |
| 592 | break;\r |
| 593 | case MA_MAIN_CONTROLS:\r |
| 594 | kc_sel_loop();\r |
| 595 | break;\r |
| 596 | case MA_MAIN_CREDITS:\r |
| 597 | draw_menu_credits();\r |
| 598 | usleep(500*1000); /* FIXME */\r |
| 599 | in_menu_wait(PBTN_MOK|PBTN_MBACK);\r |
| 600 | break;\r |
| 601 | case MA_MAIN_EXIT:\r |
| 602 | engineState = PGS_Quit;\r |
| 603 | return 1;\r |
| 604 | case MA_MAIN_PATCHES:\r |
| 605 | if (rom_loaded && PicoPatches) {\r |
| 606 | patches_menu_loop();\r |
| 607 | PicoPatchApply();\r |
| 608 | strcpy(menuErrorMsg, "Patches applied");\r |
| 609 | }\r |
| 610 | break;\r |
| 611 | default:\r |
| 612 | lprintf("%s: something unknown selected\n", __FUNCTION__);\r |
| 613 | break;\r |
| 614 | }\r |
| 615 | \r |
| 616 | return 0;\r |
| 617 | }\r |
| 618 | \r |
| 619 | menu_entry e_main_menu[] =\r |
| 620 | {\r |
| 621 | mee_submenu_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),\r |
| 622 | mee_submenu_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),\r |
| 623 | mee_submenu_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),\r |
| 624 | mee_submenu_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),\r |
| 625 | mee_submenu_id("Load new ROM/ISO", MA_MAIN_LOAD_ROM, main_menu_handler),\r |
| 626 | mee_submenu_id("Change options", MA_MAIN_OPTIONS, main_menu_handler),\r |
| 627 | mee_submenu_id("Credits", MA_MAIN_CREDITS, main_menu_handler),\r |
| 628 | mee_submenu_id("Patches / GameGenie",MA_MAIN_PATCHES, main_menu_handler),\r |
| 629 | mee_submenu_id("Exit", MA_MAIN_EXIT, main_menu_handler),\r |
| 630 | mee_end,\r |
| 631 | };\r |
| 632 | \r |
| 633 | void menu_loop(void)\r |
| 634 | {\r |
| 635 | static int sel = 0;\r |
| 636 | \r |
| 637 | me_enable(e_main_menu, MA_MAIN_RESUME_GAME, rom_loaded);\r |
| 638 | me_enable(e_main_menu, MA_MAIN_SAVE_STATE, rom_loaded);\r |
| 639 | me_enable(e_main_menu, MA_MAIN_LOAD_STATE, rom_loaded);\r |
| 640 | me_enable(e_main_menu, MA_MAIN_RESET_GAME, rom_loaded);\r |
| 641 | me_enable(e_main_menu, MA_MAIN_PATCHES, PicoPatches != NULL);\r |
| 642 | \r |
| 643 | plat_video_menu_enter(rom_loaded);\r |
| 644 | in_set_blocking(1);\r |
| 645 | me_loop(e_main_menu, &sel);\r |
| 646 | in_set_blocking(0);\r |
| 647 | \r |
| 648 | if (rom_loaded) {\r |
| 649 | while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MBACK)); // wait until select is released\r |
| 650 | engineState = PGS_Running;\r |
| 651 | }\r |
| 652 | \r |
| 653 | }\r |
| 654 | \r |
| 655 | // ------------ debug menu ------------\r |
| 656 | \r |
| 657 | #include <sys/stat.h>\r |
| 658 | #include <sys/types.h>\r |
| 659 | \r |
| 660 | #include <pico/pico.h>\r |
| 661 | #include <pico/debug.h>\r |
| 662 | \r |
| 663 | void SekStepM68k(void);\r |
| 664 | \r |
| 665 | static void mplayer_loop(void)\r |
| 666 | {\r |
| 667 | emu_startSound();\r |
| 668 | \r |
| 669 | while (1)\r |
| 670 | {\r |
| 671 | PDebugZ80Frame();\r |
| 672 | if (in_menu_wait_any(0) & PBTN_NORTH) break;\r |
| 673 | emu_waitSound();\r |
| 674 | }\r |
| 675 | \r |
| 676 | emu_endSound();\r |
| 677 | }\r |
| 678 | \r |
| 679 | static void draw_text_debug(const char *str, int skip, int from)\r |
| 680 | {\r |
| 681 | const char *p;\r |
| 682 | int len, line;\r |
| 683 | \r |
| 684 | p = str;\r |
| 685 | while (skip-- > 0)\r |
| 686 | {\r |
| 687 | while (*p && *p != '\n') p++;\r |
| 688 | if (*p == 0 || p[1] == 0) return;\r |
| 689 | p++;\r |
| 690 | }\r |
| 691 | \r |
| 692 | str = p;\r |
| 693 | for (line = from; line < SCREEN_HEIGHT/10; line++)\r |
| 694 | {\r |
| 695 | while (*p && *p != '\n') p++;\r |
| 696 | len = p - str;\r |
| 697 | if (len > 55) len = 55;\r |
| 698 | smalltext_out16_lim(1, line*10, str, 0xffff, len);\r |
| 699 | if (*p == 0) break;\r |
| 700 | p++; str = p;\r |
| 701 | }\r |
| 702 | }\r |
| 703 | \r |
| 704 | static void draw_frame_debug(void)\r |
| 705 | {\r |
| 706 | char layer_str[48] = "layers: ";\r |
| 707 | if (PicoDrawMask & PDRAW_LAYERB_ON) memcpy(layer_str + 8, "B", 1);\r |
| 708 | if (PicoDrawMask & PDRAW_LAYERA_ON) memcpy(layer_str + 10, "A", 1);\r |
| 709 | if (PicoDrawMask & PDRAW_SPRITES_LOW_ON) memcpy(layer_str + 12, "spr_lo", 6);\r |
| 710 | if (PicoDrawMask & PDRAW_SPRITES_HI_ON) memcpy(layer_str + 19, "spr_hi", 6);\r |
| 711 | \r |
| 712 | clear_screen();\r |
| 713 | emu_forcedFrame(0);\r |
| 714 | smalltext_out16(4, SCREEN_HEIGHT-8, layer_str, 0xffff);\r |
| 715 | }\r |
| 716 | \r |
| 717 | void debug_menu_loop(void)\r |
| 718 | {\r |
| 719 | int inp, mode = 0;\r |
| 720 | int spr_offs = 0, dumped = 0;\r |
| 721 | char *tmp;\r |
| 722 | \r |
| 723 | while (1)\r |
| 724 | {\r |
| 725 | switch (mode)\r |
| 726 | {\r |
| 727 | case 0: plat_video_menu_begin();\r |
| 728 | tmp = PDebugMain();\r |
| 729 | emu_platformDebugCat(tmp);\r |
| 730 | draw_text_debug(tmp, 0, 0);\r |
| 731 | if (dumped) {\r |
| 732 | smalltext_out16(SCREEN_WIDTH-6*10, SCREEN_HEIGHT-8, "dumped", 0xffff);\r |
| 733 | dumped = 0;\r |
| 734 | }\r |
| 735 | break;\r |
| 736 | case 1: draw_frame_debug(); break;\r |
| 737 | case 2: clear_screen();\r |
| 738 | emu_forcedFrame(0);\r |
| 739 | darken_screen();\r |
| 740 | PDebugShowSpriteStats((unsigned short *)SCREEN_BUFFER + (SCREEN_HEIGHT/2 - 240/2)*SCREEN_WIDTH +\r |
| 741 | SCREEN_WIDTH/2 - 320/2, SCREEN_WIDTH); break;\r |
| 742 | case 3: clear_screen();\r |
| 743 | PDebugShowPalette(SCREEN_BUFFER, SCREEN_WIDTH);\r |
| 744 | PDebugShowSprite((unsigned short *)SCREEN_BUFFER + SCREEN_WIDTH*120+SCREEN_WIDTH/2+16,\r |
| 745 | SCREEN_WIDTH, spr_offs);\r |
| 746 | draw_text_debug(PDebugSpriteList(), spr_offs, 6);\r |
| 747 | break;\r |
| 748 | }\r |
| 749 | plat_video_menu_end();\r |
| 750 | \r |
| 751 | inp = in_menu_wait(PBTN_EAST|PBTN_MBACK|PBTN_WEST|PBTN_NORTH|PBTN_L|PBTN_R|PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT);\r |
| 752 | if (inp & PBTN_MBACK) return;\r |
| 753 | if (inp & PBTN_L) { mode--; if (mode < 0) mode = 3; }\r |
| 754 | if (inp & PBTN_R) { mode++; if (mode > 3) mode = 0; }\r |
| 755 | switch (mode)\r |
| 756 | {\r |
| 757 | case 0:\r |
| 758 | if (inp & PBTN_EAST) SekStepM68k();\r |
| 759 | if (inp & PBTN_NORTH) {\r |
| 760 | while (inp & PBTN_NORTH) inp = in_menu_wait_any(-1);\r |
| 761 | mplayer_loop();\r |
| 762 | }\r |
| 763 | if ((inp & (PBTN_WEST|PBTN_LEFT)) == (PBTN_WEST|PBTN_LEFT)) {\r |
| 764 | mkdir("dumps", 0777);\r |
| 765 | PDebugDumpMem();\r |
| 766 | while (inp & PBTN_WEST) inp = in_menu_wait_any(-1);\r |
| 767 | dumped = 1;\r |
| 768 | }\r |
| 769 | break;\r |
| 770 | case 1:\r |
| 771 | if (inp & PBTN_LEFT) PicoDrawMask ^= PDRAW_LAYERB_ON;\r |
| 772 | if (inp & PBTN_RIGHT) PicoDrawMask ^= PDRAW_LAYERA_ON;\r |
| 773 | if (inp & PBTN_DOWN) PicoDrawMask ^= PDRAW_SPRITES_LOW_ON;\r |
| 774 | if (inp & PBTN_UP) PicoDrawMask ^= PDRAW_SPRITES_HI_ON;\r |
| 775 | if (inp & PBTN_EAST) {\r |
| 776 | PsndOut = NULL; // just in case\r |
| 777 | PicoSkipFrame = 1;\r |
| 778 | PicoFrame();\r |
| 779 | PicoSkipFrame = 0;\r |
| 780 | while (inp & PBTN_EAST) inp = in_menu_wait_any(-1);\r |
| 781 | }\r |
| 782 | break;\r |
| 783 | case 3:\r |
| 784 | if (inp & PBTN_DOWN) spr_offs++;\r |
| 785 | if (inp & PBTN_UP) spr_offs--;\r |
| 786 | if (spr_offs < 0) spr_offs = 0;\r |
| 787 | break;\r |
| 788 | }\r |
| 789 | }\r |
| 790 | }\r |
| 791 | \r |
| 792 | #endif // !UIQ3\r |
| 793 | \r |
| 794 | // ------------ util ------------\r |
| 795 | \r |
| 796 | const char *me_region_name(unsigned int code, int auto_order)\r |
| 797 | {\r |
| 798 | static const char *names[] = { "Auto", " Japan NTSC", " Japan PAL", " USA", " Europe" };\r |
| 799 | static const char *names_short[] = { "", " JP", " JP", " US", " EU" };\r |
| 800 | int u, i = 0;\r |
| 801 | if (code) {\r |
| 802 | code <<= 1;\r |
| 803 | while((code >>= 1)) i++;\r |
| 804 | if (i > 4) return "unknown";\r |
| 805 | return names[i];\r |
| 806 | } else {\r |
| 807 | static char name[24];\r |
| 808 | strcpy(name, "Auto:");\r |
| 809 | for (u = 0; u < 3; u++) {\r |
| 810 | i = 0; code = ((auto_order >> u*4) & 0xf) << 1;\r |
| 811 | while((code >>= 1)) i++;\r |
| 812 | strcat(name, names_short[i]);\r |
| 813 | }\r |
| 814 | return name;\r |
| 815 | }\r |
| 816 | }\r |
| 817 | \r |
| 818 | /* TODO: rename */\r |
| 819 | void menu_darken_bg(void *dst, int pixels, int darker)\r |
| 820 | {\r |
| 821 | unsigned int *screen = dst;\r |
| 822 | pixels /= 2;\r |
| 823 | if (darker)\r |
| 824 | {\r |
| 825 | while (pixels--)\r |
| 826 | {\r |
| 827 | unsigned int p = *screen;\r |
| 828 | *screen++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r |
| 829 | }\r |
| 830 | }\r |
| 831 | else\r |
| 832 | {\r |
| 833 | while (pixels--)\r |
| 834 | {\r |
| 835 | unsigned int p = *screen;\r |
| 836 | *screen++ = (p&0xf79ef79e)>>1;\r |
| 837 | }\r |
| 838 | }\r |
| 839 | }\r |
| 840 | \r |