| 1 | /* |
| 2 | * (C) GraÅžvydas "notaz" Ignotas, 2010-2011 |
| 3 | * |
| 4 | * This work is licensed under the terms of any of these licenses |
| 5 | * (at your option): |
| 6 | * - GNU GPL, version 2 or later. |
| 7 | * - GNU LGPL, version 2.1 or later. |
| 8 | * See the COPYING file in the top-level directory. |
| 9 | */ |
| 10 | |
| 11 | #include <stdio.h> |
| 12 | #include <stdlib.h> |
| 13 | #include <string.h> |
| 14 | #include <errno.h> |
| 15 | #include <sys/stat.h> |
| 16 | |
| 17 | #include "main.h" |
| 18 | #include "menu.h" |
| 19 | #include "input.h" |
| 20 | #include "settings.h" |
| 21 | #include "config.h" |
| 22 | #include "args.h" |
| 23 | #include "dface.h" |
| 24 | #include "../libpicofe/plat.h" |
| 25 | #include "../libpicofe/input.h" |
| 26 | #include "../../state.h" |
| 27 | #include "../../general.h" |
| 28 | #include "../../input.h" |
| 29 | #include "../../palette.h" |
| 30 | #include "../../fce.h" |
| 31 | #include "revision.h" |
| 32 | |
| 33 | #define array_size(x) (sizeof(x) / sizeof(x[0])) |
| 34 | |
| 35 | #define state_slot CurrentState |
| 36 | extern uint8 Exit; |
| 37 | |
| 38 | typedef enum |
| 39 | { |
| 40 | MA_NONE = 1, |
| 41 | MA_CTRL_PLAYER1, |
| 42 | MA_CTRL_PLAYER2, |
| 43 | MA_CTRL_EMU, |
| 44 | MA_CTRL_DEADZONE, |
| 45 | MA_OPT_SAVECFG, |
| 46 | MA_OPT_SAVECFG_GAME, |
| 47 | MA_CTRL_DEV_FIRST, |
| 48 | MA_CTRL_DEV_NEXT, |
| 49 | MA_OPT_NTSC_COLOR, |
| 50 | MA_OPT_NTSC_TINT, |
| 51 | MA_OPT_NTSC_HUE, |
| 52 | MA_OPT_SREND_N, |
| 53 | MA_OPT_EREND_N, |
| 54 | MA_OPT_SREND_P, |
| 55 | MA_OPT_EREND_P, |
| 56 | MA_OPT_CLIP, |
| 57 | MA_OPT_NO8LIM, |
| 58 | MA_OPT_GG, |
| 59 | MA_OPT_SHOWFPS, |
| 60 | MA_OPT_FSKIP, |
| 61 | MA_OPT_SWFILTER, |
| 62 | MA_OPT_HWFILTER, |
| 63 | MA_OPT_SCALING, |
| 64 | MA_OPT_RENDERER, |
| 65 | MA_OPT_SOUNDON, |
| 66 | MA_OPT_SOUNDRATE, |
| 67 | MA_OPT_REGION, |
| 68 | MA_OPT_TURBO, |
| 69 | MA_OPT_SSTATE, |
| 70 | MA_OPT_SSLOT, |
| 71 | MA_OPT_GAMMA, |
| 72 | MA_MAIN_RESUME_GAME, |
| 73 | MA_MAIN_SAVE_STATE, |
| 74 | MA_MAIN_LOAD_STATE, |
| 75 | MA_MAIN_RESET_GAME, |
| 76 | MA_MAIN_LOAD_ROM, |
| 77 | MA_MAIN_CHEATS, |
| 78 | MA_MAIN_CREDITS, |
| 79 | MA_MAIN_EXIT, |
| 80 | } menu_id; |
| 81 | |
| 82 | void emu_make_path(char *buff, const char *end, int size) |
| 83 | { |
| 84 | int pos, end_len; |
| 85 | |
| 86 | end_len = strlen(end); |
| 87 | pos = plat_get_root_dir(buff, size); |
| 88 | strncpy(buff + pos, end, size - pos); |
| 89 | buff[size - 1] = 0; |
| 90 | if (pos + end_len > size - 1) |
| 91 | printf("Warning: path truncated: %s\n", buff); |
| 92 | } |
| 93 | |
| 94 | static int emu_check_save_file(int slot, int *time) |
| 95 | { |
| 96 | struct stat status; |
| 97 | char *fname; |
| 98 | FILE *st; |
| 99 | int retval = 0; |
| 100 | int ret; |
| 101 | |
| 102 | fname = FCEU_MakeFName(FCEUMKF_STATE, slot, 0); |
| 103 | st = fopen(fname,"rb"); |
| 104 | if (st == NULL) |
| 105 | goto out; |
| 106 | fclose(st); |
| 107 | |
| 108 | retval = 1; |
| 109 | if (time == NULL) |
| 110 | goto out; |
| 111 | |
| 112 | ret = stat(fname, &status); |
| 113 | if (ret != 0) |
| 114 | goto out; |
| 115 | |
| 116 | if (status.st_mtime < 1347000000) |
| 117 | goto out; // probably bad rtc like on some Caanoos |
| 118 | |
| 119 | *time = status.st_mtime; |
| 120 | |
| 121 | out: |
| 122 | free(fname); |
| 123 | return retval; |
| 124 | } |
| 125 | |
| 126 | static int emu_save_load_game(int load, int unused) |
| 127 | { |
| 128 | if (load) |
| 129 | FCEUI_LoadState(); |
| 130 | else |
| 131 | FCEUI_SaveState(); |
| 132 | |
| 133 | return 0; |
| 134 | } |
| 135 | |
| 136 | // rrrr rggg gggb bbbb |
| 137 | static unsigned short fname2color(const char *fname) |
| 138 | { |
| 139 | static const char *rom_exts[] = { ".zip", ".nes", ".fds", ".unf", |
| 140 | ".nez", ".unif" }; |
| 141 | static const char *other_exts[] = { ".nsf", ".ips", ".fcm" }; |
| 142 | const char *ext = strrchr(fname, '.'); |
| 143 | int i; |
| 144 | |
| 145 | if (ext == NULL) |
| 146 | return 0xffff; |
| 147 | for (i = 0; i < array_size(rom_exts); i++) |
| 148 | if (strcasecmp(ext, rom_exts[i]) == 0) |
| 149 | return 0xbdff; |
| 150 | for (i = 0; i < array_size(other_exts); i++) |
| 151 | if (strcasecmp(ext, other_exts[i]) == 0) |
| 152 | return 0xaff5; |
| 153 | return 0xffff; |
| 154 | } |
| 155 | |
| 156 | static const char *filter_exts[] = { |
| 157 | ".txt", ".srm", ".pnd" |
| 158 | }; |
| 159 | |
| 160 | #define MENU_ALIGN_LEFT |
| 161 | #ifdef __ARM_ARCH_7A__ // assume hires device |
| 162 | #define MENU_X2 1 |
| 163 | #else |
| 164 | #define MENU_X2 0 |
| 165 | #endif |
| 166 | |
| 167 | #include "../libpicofe/menu.c" |
| 168 | |
| 169 | static void draw_savestate_bg(int slot) |
| 170 | { |
| 171 | } |
| 172 | |
| 173 | static void debug_menu_loop(void) |
| 174 | { |
| 175 | } |
| 176 | |
| 177 | // ------------ patch/gg menu ------------ |
| 178 | |
| 179 | extern void *cheats; |
| 180 | static int cheat_count, cheat_start, cheat_pos; |
| 181 | |
| 182 | static int countcallb(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data) |
| 183 | { |
| 184 | cheat_count++; |
| 185 | return 1; |
| 186 | } |
| 187 | |
| 188 | static int clistcallb(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data) |
| 189 | { |
| 190 | int pos; |
| 191 | |
| 192 | pos = cheat_start + cheat_pos; |
| 193 | cheat_pos++; |
| 194 | if (pos < 0) return 1; |
| 195 | if (pos >= g_menuscreen_h / me_sfont_h) return 0; |
| 196 | |
| 197 | smalltext_out16(14, pos * me_sfont_h, s ? "ON " : "OFF", 0xffff); |
| 198 | smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h, type ? "S" : "R", 0xffff); |
| 199 | smalltext_out16(14 + me_sfont_w*6, pos * me_sfont_h, name, 0xffff); |
| 200 | |
| 201 | return 1; |
| 202 | } |
| 203 | |
| 204 | static void draw_patchlist(int sel) |
| 205 | { |
| 206 | int pos, max_cnt; |
| 207 | |
| 208 | menu_draw_begin(1, 1); |
| 209 | |
| 210 | max_cnt = g_menuscreen_h / me_sfont_h; |
| 211 | cheat_start = max_cnt / 2 - sel; |
| 212 | cheat_pos = 0; |
| 213 | FCEUI_ListCheats(clistcallb, 0); |
| 214 | |
| 215 | pos = cheat_start + cheat_pos; |
| 216 | if (pos < max_cnt) |
| 217 | smalltext_out16(14, pos * me_sfont_h, "done", 0xffff); |
| 218 | |
| 219 | text_out16(5, max_cnt / 2 * me_sfont_h, ">"); |
| 220 | menu_draw_end(); |
| 221 | } |
| 222 | |
| 223 | void patches_menu_loop(void) |
| 224 | { |
| 225 | static int menu_sel = 0; |
| 226 | int inp; |
| 227 | |
| 228 | cheat_count = 0; |
| 229 | FCEUI_ListCheats(countcallb, 0); |
| 230 | |
| 231 | for (;;) |
| 232 | { |
| 233 | draw_patchlist(menu_sel); |
| 234 | inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R |
| 235 | |PBTN_MOK|PBTN_MBACK, NULL, 33); |
| 236 | if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = cheat_count; } |
| 237 | if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > cheat_count) menu_sel = 0; } |
| 238 | if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; } |
| 239 | if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > cheat_count) menu_sel = cheat_count; } |
| 240 | if (inp & PBTN_MOK) { // action |
| 241 | if (menu_sel < cheat_count) |
| 242 | FCEUI_ToggleCheat(menu_sel); |
| 243 | else break; |
| 244 | } |
| 245 | if (inp & PBTN_MBACK) |
| 246 | break; |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | // -------------- key config -------------- |
| 251 | |
| 252 | // b_turbo,a_turbo RLDU SEBA |
| 253 | me_bind_action me_ctrl_actions[] = |
| 254 | { |
| 255 | { "UP ", NKEY_UP }, |
| 256 | { "DOWN ", NKEY_DOWN }, |
| 257 | { "LEFT ", NKEY_LEFT }, |
| 258 | { "RIGHT ", NKEY_RIGHT }, |
| 259 | { "A ", NKEY_A }, |
| 260 | { "B ", NKEY_B }, |
| 261 | { "A TURBO", NKEY_A_TURBO }, |
| 262 | { "B TURBO", NKEY_B_TURBO }, |
| 263 | { "START ", NKEY_START }, |
| 264 | { "SELECT ", NKEY_SELECT }, |
| 265 | { NULL, 0 } |
| 266 | }; |
| 267 | |
| 268 | me_bind_action emuctrl_actions[] = |
| 269 | { |
| 270 | { "Save State ", EACT_SAVE_STATE }, |
| 271 | { "Load State ", EACT_LOAD_STATE }, |
| 272 | { "Next State Slot ", EACT_NEXT_SLOT }, |
| 273 | { "Prev State Slot ", EACT_PREV_SLOT }, |
| 274 | { "FDS Insert/Eject ", EACT_FDS_INSERT }, |
| 275 | { "FDS Select Disk ", EACT_FDS_SELECT }, |
| 276 | { "VSUni Insert Coin", EACT_INSERT_COIN }, |
| 277 | { "Enter Menu ", EACT_ENTER_MENU }, |
| 278 | { NULL, 0 } |
| 279 | }; |
| 280 | |
| 281 | static int key_config_loop_wrap(int id, int keys) |
| 282 | { |
| 283 | switch (id) { |
| 284 | case MA_CTRL_PLAYER1: |
| 285 | key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0); |
| 286 | break; |
| 287 | case MA_CTRL_PLAYER2: |
| 288 | key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1); |
| 289 | break; |
| 290 | case MA_CTRL_EMU: |
| 291 | key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1); |
| 292 | break; |
| 293 | default: |
| 294 | break; |
| 295 | } |
| 296 | return 0; |
| 297 | } |
| 298 | |
| 299 | static const char *mgn_dev_name(int id, int *offs) |
| 300 | { |
| 301 | const char *name = NULL; |
| 302 | static int it = 0; |
| 303 | |
| 304 | if (id == MA_CTRL_DEV_FIRST) |
| 305 | it = 0; |
| 306 | |
| 307 | for (; it < IN_MAX_DEVS; it++) { |
| 308 | name = in_get_dev_name(it, 1, 1); |
| 309 | if (name != NULL) |
| 310 | break; |
| 311 | } |
| 312 | |
| 313 | it++; |
| 314 | return name; |
| 315 | } |
| 316 | |
| 317 | static const char *mgn_saveloadcfg(int id, int *offs) |
| 318 | { |
| 319 | return ""; |
| 320 | } |
| 321 | |
| 322 | static void config_commit(void); |
| 323 | |
| 324 | static int mh_savecfg(int id, int keys) |
| 325 | { |
| 326 | const char *fname = NULL; |
| 327 | if (id == MA_OPT_SAVECFG_GAME) |
| 328 | fname = lastLoadedGameName; |
| 329 | |
| 330 | config_commit(); |
| 331 | if (SaveConfig(fname) == 0) |
| 332 | menu_update_msg("config saved"); |
| 333 | else |
| 334 | menu_update_msg("failed to write config"); |
| 335 | |
| 336 | return 1; |
| 337 | } |
| 338 | |
| 339 | static int mh_input_rescan(int id, int keys) |
| 340 | { |
| 341 | //menu_sync_config(); |
| 342 | in_probe(); |
| 343 | menu_update_msg("rescan complete."); |
| 344 | |
| 345 | return 0; |
| 346 | } |
| 347 | |
| 348 | static menu_entry e_menu_keyconfig[] = |
| 349 | { |
| 350 | mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap), |
| 351 | mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap), |
| 352 | mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap), |
| 353 | mee_label (""), |
| 354 | // mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99), |
| 355 | mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg), |
| 356 | mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg), |
| 357 | mee_handler ("Rescan devices:", mh_input_rescan), |
| 358 | mee_label (""), |
| 359 | mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name), |
| 360 | mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name), |
| 361 | mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name), |
| 362 | mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name), |
| 363 | mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name), |
| 364 | mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name), |
| 365 | mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name), |
| 366 | mee_end, |
| 367 | }; |
| 368 | |
| 369 | static int menu_loop_keyconfig(int id, int keys) |
| 370 | { |
| 371 | static int sel = 0; |
| 372 | |
| 373 | me_loop(e_menu_keyconfig, &sel); |
| 374 | return 0; |
| 375 | } |
| 376 | |
| 377 | // --------- FCEU options ---------- |
| 378 | |
| 379 | extern int ntsccol,ntschue,ntsctint; |
| 380 | extern int srendlinev[2]; |
| 381 | extern int erendlinev[2]; |
| 382 | extern int eoptions; |
| 383 | extern char *cpalette; |
| 384 | extern void LoadCPalette(void); |
| 385 | |
| 386 | static menu_entry e_menu_fceu_options[] = |
| 387 | { |
| 388 | //gp2x_text_out15(tl_x, y, "Custom palette: %s", cpal); |
| 389 | mee_onoff ("NTSC Color Emulation", MA_OPT_NTSC_COLOR, ntsccol, 1), |
| 390 | mee_range (" Tint (default: 56)", MA_OPT_NTSC_TINT, ntsctint, 0, 128), |
| 391 | mee_range (" Hue (default: 72)", MA_OPT_NTSC_HUE, ntschue, 0, 128), |
| 392 | mee_range ("First visible line (NTSC)", MA_OPT_SREND_N, srendlinev[0], 0, 239), |
| 393 | mee_range ("Last visible line (NTSC)", MA_OPT_EREND_N, erendlinev[0], 0, 239), |
| 394 | mee_range ("First visible line (PAL)", MA_OPT_SREND_P, srendlinev[1], 0, 239), |
| 395 | mee_range ("Last visible line (PAL)", MA_OPT_EREND_P, erendlinev[1], 0, 239), |
| 396 | mee_onoff ("Clip 8 left/right columns", MA_OPT_CLIP, eoptions, EO_CLIPSIDES), |
| 397 | mee_onoff ("Disable 8 sprite limit", MA_OPT_NO8LIM, eoptions, EO_NO8LIM), |
| 398 | mee_onoff ("Enable authentic GameGenie",MA_OPT_GG, eoptions, EO_GG), |
| 399 | mee_end, |
| 400 | }; |
| 401 | |
| 402 | static int menu_loop_fceu_options(int id, int keys) |
| 403 | { |
| 404 | static int sel = 0; |
| 405 | int i; |
| 406 | |
| 407 | FCEUI_GetNTSCTH(&ntsctint, &ntschue); |
| 408 | |
| 409 | me_loop(e_menu_fceu_options, &sel); |
| 410 | |
| 411 | for(i = 0; i < 2; i++) |
| 412 | { |
| 413 | if (srendlinev[i] < 0 || srendlinev[i] > 239) |
| 414 | srendlinev[i] = 0; |
| 415 | if (erendlinev[i] < srendlinev[i] || erendlinev[i] > 239) |
| 416 | erendlinev[i] = 239; |
| 417 | } |
| 418 | FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue); |
| 419 | FCEUI_SetRenderedLines(srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]); |
| 420 | FCEUI_DisableSpriteLimitation(eoptions&EO_NO8LIM); |
| 421 | FCEUI_SetGameGenie(eoptions&EO_GG); |
| 422 | //if (cpalette) LoadCPalette(); |
| 423 | //else |
| 424 | FCEUI_SetPaletteArray(0); // set to default |
| 425 | FCEU_ResetPalette(); |
| 426 | |
| 427 | return 0; |
| 428 | } |
| 429 | |
| 430 | // -------------- options -------------- |
| 431 | |
| 432 | static const char *men_frameskip[] = { "Auto", "0", "1", "2", "3", "4", NULL }; |
| 433 | static const char *men_swfilter[] = { "none", "Scale2x", "Eagle2x", NULL }; |
| 434 | static const char *men_scaling[] = { "1x", "proportional", "4:3 scaled", "fullscreen", NULL }; |
| 435 | static const char *men_rates[] = { "8000", "11025", "16000", "22050", "44100", NULL }; |
| 436 | static const int men_rates_i[] = { 8000 , 11025 , 16000 , 22050 , 44100 }; |
| 437 | static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL }; |
| 438 | static const char *men_sstate[] = { "OFF", "writes", "loads", "both", NULL }; |
| 439 | static const char h_renderer[] = "ROM reload required for this\n" |
| 440 | "setting to take effect"; |
| 441 | |
| 442 | static int sndrate_i; |
| 443 | static int sndon; |
| 444 | static int turbo_i; |
| 445 | static int frameskip_i; |
| 446 | |
| 447 | static void config_commit(void) |
| 448 | { |
| 449 | Settings.sound_rate = men_rates_i[sndrate_i]; |
| 450 | soundvol = sndon ? 50 : 0; |
| 451 | Settings.turbo_rate_add = (turbo_i * 2 << 24) / 60 + 1; |
| 452 | Settings.frameskip = frameskip_i - 1; |
| 453 | |
| 454 | if (Settings.region_force) |
| 455 | FCEUI_SetVidSystem(Settings.region_force - 1); |
| 456 | } |
| 457 | |
| 458 | static menu_entry e_menu_options[] = |
| 459 | { |
| 460 | // mee_onoff ("Show FPS", MA_OPT_SHOWFPS, Settings.showfps, 1), |
| 461 | mee_enum ("Frameskip", MA_OPT_FSKIP, frameskip_i, men_frameskip), |
| 462 | mee_enum ("Softwere filter", MA_OPT_SWFILTER, Settings.sw_filter, men_swfilter), |
| 463 | mee_enum ("Hardware filter", MA_OPT_HWFILTER, Settings.hw_filter, NULL), |
| 464 | mee_enum ("Scaling", MA_OPT_SCALING, Settings.scaling, men_scaling), |
| 465 | mee_onoff_h ("Accurate renderer (slow)",MA_OPT_RENDERER, Settings.accurate_mode, 1, h_renderer), |
| 466 | mee_onoff ("Enable sound", MA_OPT_SOUNDON, sndon, 1), |
| 467 | mee_enum ("Sound Rate", MA_OPT_SOUNDRATE, sndrate_i, men_rates), |
| 468 | mee_enum ("Region", MA_OPT_REGION, Settings.region_force, men_region), |
| 469 | mee_range ("Turbo rate (Hz)", MA_OPT_TURBO, turbo_i, 1, 30), |
| 470 | mee_enum ("Confirm savestate", MA_OPT_SSTATE, Settings.sstate_confirm, men_sstate), |
| 471 | mee_range ("Save slot", MA_OPT_SSLOT, CurrentState, 0, 9), |
| 472 | // mee_range ("Gamma correction", MA_OPT_GAMMA, Settings.gamma, 0, 300), |
| 473 | mee_handler ("[FCE Ultra options]", menu_loop_fceu_options), |
| 474 | mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg), |
| 475 | mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg), |
| 476 | mee_end, |
| 477 | }; |
| 478 | |
| 479 | static int menu_loop_options(int id, int keys) |
| 480 | { |
| 481 | static int sel = 0; |
| 482 | int oldrate; |
| 483 | int i; |
| 484 | |
| 485 | i = me_id2offset(e_menu_options, MA_OPT_HWFILTER); |
| 486 | e_menu_options[i].data = plat_target.filters; |
| 487 | me_enable(e_menu_options, MA_OPT_HWFILTER, plat_target.filters != NULL); |
| 488 | |
| 489 | oldrate = Settings.sound_rate; |
| 490 | for (i = 0; i < array_size(men_rates_i); i++) { |
| 491 | if (Settings.sound_rate == men_rates_i[i]) { |
| 492 | sndrate_i = i; |
| 493 | break; |
| 494 | } |
| 495 | } |
| 496 | sndon = soundvol != 0; |
| 497 | turbo_i = (Settings.turbo_rate_add * 60 / 2) >> 24; |
| 498 | frameskip_i = Settings.frameskip + 1; |
| 499 | |
| 500 | me_loop(e_menu_options, &sel); |
| 501 | |
| 502 | config_commit(); |
| 503 | if (oldrate != Settings.sound_rate) |
| 504 | InitSound(); |
| 505 | |
| 506 | return 0; |
| 507 | } |
| 508 | |
| 509 | // -------------- root menu -------------- |
| 510 | |
| 511 | static void draw_frame_main(void) |
| 512 | { |
| 513 | struct tm *tmp; |
| 514 | time_t ltime; |
| 515 | int capacity = -1; |
| 516 | char ltime_s[16]; |
| 517 | char buff[128]; |
| 518 | char *out; |
| 519 | |
| 520 | if (!fceugi || !GameInterface) |
| 521 | return; |
| 522 | |
| 523 | buff[0] = 0; |
| 524 | GameInterface(GI_INFOSTRING, buff); |
| 525 | |
| 526 | smalltext_out16(4, 1, buff, 0xf7de); |
| 527 | |
| 528 | if (plat_target.get_bat_capacity) |
| 529 | capacity = plat_target.get_bat_capacity(); |
| 530 | ltime = time(NULL); |
| 531 | tmp = localtime(<ime); |
| 532 | strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp); |
| 533 | if (capacity >= 0) { |
| 534 | snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity); |
| 535 | out = buff; |
| 536 | } |
| 537 | else |
| 538 | out = ltime_s; |
| 539 | smalltext_out16(4, 1 + me_sfont_h, out, 0xf7de); |
| 540 | } |
| 541 | |
| 542 | static const char credits_text[] = |
| 543 | "GPFCE " REV "\n" |
| 544 | "(c) notaz, 2007,2012\n\n" |
| 545 | "Based on various FCE Ultra\n" |
| 546 | " / FCEUX versions\n\n" |
| 547 | " - Credits -\n" |
| 548 | "Bero: FCE\n" |
| 549 | "Xodnizel: FCE Ultra\n" |
| 550 | "FCEUX team: FCEUX\n" |
| 551 | "CaH4e3: mappers\n" |
| 552 | "FCA author: 6502 core\n" |
| 553 | "M-HT: NEON scalers\n"; |
| 554 | |
| 555 | static void draw_frame_credits(void) |
| 556 | { |
| 557 | smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc); |
| 558 | } |
| 559 | |
| 560 | static int romsel_run(void) |
| 561 | { |
| 562 | const char *fname; |
| 563 | |
| 564 | fname = menu_loop_romsel(lastLoadedGameName, sizeof(lastLoadedGameName)); |
| 565 | if (fname == NULL) |
| 566 | return -1; |
| 567 | |
| 568 | printf("selected file: %s\n", fname); |
| 569 | //keys_load_all(cfg); |
| 570 | |
| 571 | strcpy(lastLoadedGameName, rom_fname_reload); |
| 572 | return 0; |
| 573 | } |
| 574 | |
| 575 | static int menu_loop_ret; |
| 576 | |
| 577 | static int main_menu_handler(int id, int keys) |
| 578 | { |
| 579 | switch (id) |
| 580 | { |
| 581 | case MA_MAIN_RESUME_GAME: |
| 582 | if (fceugi) |
| 583 | return 1; |
| 584 | break; |
| 585 | case MA_MAIN_SAVE_STATE: |
| 586 | if (fceugi) { |
| 587 | return menu_loop_savestate(0); |
| 588 | } |
| 589 | break; |
| 590 | case MA_MAIN_LOAD_STATE: |
| 591 | if (fceugi) { |
| 592 | return menu_loop_savestate(1); |
| 593 | } |
| 594 | break; |
| 595 | case MA_MAIN_RESET_GAME: |
| 596 | if (fceugi) { |
| 597 | FCEU_DoSimpleCommand(FCEUNPCMD_RESET); |
| 598 | return 1; |
| 599 | } |
| 600 | break; |
| 601 | case MA_MAIN_LOAD_ROM: |
| 602 | if (romsel_run() == 0) { |
| 603 | menu_loop_ret = 2; |
| 604 | return 1; |
| 605 | } |
| 606 | break; |
| 607 | case MA_MAIN_CREDITS: |
| 608 | draw_menu_message(credits_text, draw_frame_credits); |
| 609 | in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70); |
| 610 | break; |
| 611 | case MA_MAIN_EXIT: |
| 612 | menu_loop_ret = 1; |
| 613 | return 1; |
| 614 | default: |
| 615 | lprintf("%s: something unknown selected\n", __FUNCTION__); |
| 616 | break; |
| 617 | } |
| 618 | |
| 619 | return 0; |
| 620 | } |
| 621 | |
| 622 | static menu_entry e_menu_main[] = |
| 623 | { |
| 624 | mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler), |
| 625 | mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler), |
| 626 | mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler), |
| 627 | mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler), |
| 628 | mee_handler_id("Load ROM", MA_MAIN_LOAD_ROM, main_menu_handler), |
| 629 | mee_handler ("Options", menu_loop_options), |
| 630 | mee_handler ("Controls", menu_loop_keyconfig), |
| 631 | mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler), |
| 632 | mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler), |
| 633 | mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler), |
| 634 | mee_end, |
| 635 | }; |
| 636 | |
| 637 | // ---------------------------- |
| 638 | |
| 639 | int menu_loop(void) |
| 640 | { |
| 641 | static int sel = 0; |
| 642 | |
| 643 | menu_loop_ret = 0; |
| 644 | |
| 645 | me_enable(e_menu_main, MA_MAIN_RESUME_GAME, fceugi != NULL); |
| 646 | me_enable(e_menu_main, MA_MAIN_SAVE_STATE, fceugi != NULL); |
| 647 | me_enable(e_menu_main, MA_MAIN_LOAD_STATE, fceugi != NULL); |
| 648 | me_enable(e_menu_main, MA_MAIN_RESET_GAME, fceugi != NULL); |
| 649 | me_enable(e_menu_main, MA_MAIN_CHEATS, fceugi && cheats); |
| 650 | |
| 651 | plat_video_menu_enter(fceugi != NULL); |
| 652 | memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2); |
| 653 | in_set_config_int(0, IN_CFG_BLOCKING, 1); |
| 654 | |
| 655 | do { |
| 656 | me_loop_d(e_menu_main, &sel, NULL, draw_frame_main); |
| 657 | } while (!fceugi && menu_loop_ret == 0); |
| 658 | |
| 659 | /* wait until menu, ok, back is released */ |
| 660 | while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK)) |
| 661 | ; |
| 662 | |
| 663 | in_set_config_int(0, IN_CFG_BLOCKING, 0); |
| 664 | plat_video_menu_leave(); |
| 665 | |
| 666 | Exit = 0; |
| 667 | return menu_loop_ret; |
| 668 | } |
| 669 | |
| 670 | void menu_init(void) |
| 671 | { |
| 672 | char buff[256]; |
| 673 | |
| 674 | g_border_style = 1; |
| 675 | menu_init_base(); |
| 676 | |
| 677 | //menu_load_config(0); |
| 678 | |
| 679 | g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1); |
| 680 | g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1); |
| 681 | if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) { |
| 682 | fprintf(stderr, "OOM\n"); |
| 683 | exit(1); |
| 684 | } |
| 685 | |
| 686 | emu_make_path(buff, "skin/background.png", sizeof(buff)); |
| 687 | readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h); |
| 688 | } |
| 689 | |
| 690 | void menu_update_msg(const char *msg) |
| 691 | { |
| 692 | strncpy(menu_error_msg, msg, sizeof(menu_error_msg)); |
| 693 | menu_error_msg[sizeof(menu_error_msg) - 1] = 0; |
| 694 | |
| 695 | menu_error_time = plat_get_ticks_ms(); |
| 696 | lprintf("msg: %s\n", menu_error_msg); |
| 697 | } |
| 698 | |