main.cpp (21833B)
1/* 2 * Gearboy - Nintendo Game Boy Emulator 3 * Copyright (C) 2012 Ignacio Sanchez 4 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * any later version. 9 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see http://www.gnu.org/licenses/ 17 * 18 */ 19 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <math.h> 24#include <assert.h> 25#include <unistd.h> 26#include <iostream> 27#include <iomanip> 28#include <stdlib.h> 29#include <sys/time.h> 30#include <SDL2/SDL.h> 31#include <libconfig.h++> 32#include "bcm_host.h" 33#include "GLES/gl.h" 34#include "EGL/egl.h" 35#include "EGL/eglext.h" 36 37#include "gearboy.h" 38#include "../audio-shared/Sound_Queue.h" 39 40using namespace std; 41using namespace libconfig; 42 43bool running = true; 44bool paused = false; 45 46EGLDisplay display; 47EGLSurface surface; 48EGLContext context; 49 50static const char *output_file = "gearboy.cfg"; 51 52const float kGB_Width = 160.0f; 53const float kGB_Height = 144.0f; 54const float kGB_TexWidth = kGB_Width / 256.0f; 55const float kGB_TexHeight = kGB_Height / 256.0f; 56const GLfloat kQuadTex[8] = { 0, 0, kGB_TexWidth, 0, kGB_TexWidth, kGB_TexHeight, 0, kGB_TexHeight}; 57GLshort quadVerts[8]; 58 59GearboyCore* theGearboyCore; 60Sound_Queue* theSoundQueue; 61u16* theFrameBuffer; 62GLuint theGBTexture; 63s16 theSampleBufffer[AUDIO_BUFFER_SIZE]; 64 65bool audioEnabled = true; 66 67struct palette_color 68{ 69 int red; 70 int green; 71 int blue; 72 int alpha; 73}; 74 75palette_color dmg_palette[4]; 76 77SDL_Joystick* game_pad = NULL; 78SDL_Keycode kc_keypad_left, kc_keypad_right, kc_keypad_up, kc_keypad_down, kc_keypad_a, kc_keypad_b, kc_keypad_start, kc_keypad_select, kc_emulator_pause, kc_emulator_quit; 79bool jg_x_axis_invert, jg_y_axis_invert; 80int jg_a, jg_b, jg_start, jg_select, jg_x_axis, jg_y_axis; 81 82uint32_t screen_width, screen_height; 83 84SDL_Window* theWindow; 85 86void update(void) 87{ 88 SDL_Event keyevent; 89 90 while (SDL_PollEvent(&keyevent)) 91 { 92 switch(keyevent.type) 93 { 94 case SDL_QUIT: 95 running = false; 96 break; 97 98 case SDL_JOYBUTTONDOWN: 99 { 100 if (keyevent.jbutton.button == jg_b) 101 theGearboyCore->KeyPressed(B_Key); 102 else if (keyevent.jbutton.button == jg_a) 103 theGearboyCore->KeyPressed(A_Key); 104 else if (keyevent.jbutton.button == jg_select) 105 theGearboyCore->KeyPressed(Select_Key); 106 else if (keyevent.jbutton.button == jg_start) 107 theGearboyCore->KeyPressed(Start_Key); 108 } 109 break; 110 111 case SDL_JOYBUTTONUP: 112 { 113 if (keyevent.jbutton.button == jg_b) 114 theGearboyCore->KeyReleased(B_Key); 115 else if (keyevent.jbutton.button == jg_a) 116 theGearboyCore->KeyReleased(A_Key); 117 else if (keyevent.jbutton.button == jg_select) 118 theGearboyCore->KeyReleased(Select_Key); 119 else if (keyevent.jbutton.button == jg_start) 120 theGearboyCore->KeyReleased(Start_Key); 121 } 122 break; 123 124 case SDL_JOYAXISMOTION: 125 { 126 if(keyevent.jaxis.axis == jg_x_axis) 127 { 128 int x_motion = keyevent.jaxis.value * (jg_x_axis_invert ? -1 : 1); 129 if (x_motion < 0) 130 theGearboyCore->KeyPressed(Left_Key); 131 else if (x_motion > 0) 132 theGearboyCore->KeyPressed(Right_Key); 133 else 134 { 135 theGearboyCore->KeyReleased(Left_Key); 136 theGearboyCore->KeyReleased(Right_Key); 137 } 138 } 139 else if(keyevent.jaxis.axis == jg_y_axis) 140 { 141 int y_motion = keyevent.jaxis.value * (jg_y_axis_invert ? -1 : 1); 142 if (y_motion < 0) 143 theGearboyCore->KeyPressed(Up_Key); 144 else if (y_motion > 0) 145 theGearboyCore->KeyPressed(Down_Key); 146 else 147 { 148 theGearboyCore->KeyReleased(Up_Key); 149 theGearboyCore->KeyReleased(Down_Key); 150 } 151 } 152 } 153 break; 154 155 case SDL_KEYDOWN: 156 { 157 if (keyevent.key.keysym.sym == kc_keypad_left) 158 theGearboyCore->KeyPressed(Left_Key); 159 else if (keyevent.key.keysym.sym == kc_keypad_right) 160 theGearboyCore->KeyPressed(Right_Key); 161 else if (keyevent.key.keysym.sym == kc_keypad_up) 162 theGearboyCore->KeyPressed(Up_Key); 163 else if (keyevent.key.keysym.sym == kc_keypad_down) 164 theGearboyCore->KeyPressed(Down_Key); 165 else if (keyevent.key.keysym.sym == kc_keypad_b) 166 theGearboyCore->KeyPressed(B_Key); 167 else if (keyevent.key.keysym.sym == kc_keypad_a) 168 theGearboyCore->KeyPressed(A_Key); 169 else if (keyevent.key.keysym.sym == kc_keypad_select) 170 theGearboyCore->KeyPressed(Select_Key); 171 else if (keyevent.key.keysym.sym == kc_keypad_start) 172 theGearboyCore->KeyPressed(Start_Key); 173 174 if (keyevent.key.keysym.sym == kc_emulator_quit) 175 running = false; 176 else if (keyevent.key.keysym.sym == kc_emulator_pause) 177 { 178 paused = !paused; 179 theGearboyCore->Pause(paused); 180 } 181 } 182 break; 183 184 case SDL_KEYUP: 185 { 186 if (keyevent.key.keysym.sym == kc_keypad_left) 187 theGearboyCore->KeyReleased(Left_Key); 188 else if (keyevent.key.keysym.sym == kc_keypad_right) 189 theGearboyCore->KeyReleased(Right_Key); 190 else if (keyevent.key.keysym.sym == kc_keypad_up) 191 theGearboyCore->KeyReleased(Up_Key); 192 else if (keyevent.key.keysym.sym == kc_keypad_down) 193 theGearboyCore->KeyReleased(Down_Key); 194 else if (keyevent.key.keysym.sym == kc_keypad_b) 195 theGearboyCore->KeyReleased(B_Key); 196 else if (keyevent.key.keysym.sym == kc_keypad_a) 197 theGearboyCore->KeyReleased(A_Key); 198 else if (keyevent.key.keysym.sym == kc_keypad_select) 199 theGearboyCore->KeyReleased(Select_Key); 200 else if (keyevent.key.keysym.sym == kc_keypad_start) 201 theGearboyCore->KeyReleased(Start_Key); 202 } 203 break; 204 } 205 } 206 207 int sampleCount = 0; 208 209 theGearboyCore->RunToVBlank(theFrameBuffer, theSampleBufffer, &sampleCount); 210 211 if (audioEnabled && (sampleCount > 0)) 212 { 213 theSoundQueue->write(theSampleBufffer, sampleCount); 214 } 215 216 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 160, 144, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (GLvoid*) theFrameBuffer); 217 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 218 eglSwapBuffers(display, surface); 219} 220 221void init_sdl(void) 222{ 223 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) 224 { 225 Log("SDL Error Init: %s", SDL_GetError()); 226 } 227 228 theWindow = SDL_CreateWindow(GEARBOY_TITLE, 0, 0, 0, 0, 0); 229 230 if (theWindow == NULL) 231 { 232 Log("SDL Error Video: %s", SDL_GetError()); 233 } 234 235 SDL_ShowCursor(SDL_DISABLE); 236 237 game_pad = SDL_JoystickOpen(0); 238 239 if(game_pad == NULL) 240 { 241 Log("Warning: Unable to open game controller! SDL Error: %s\n", SDL_GetError()); 242 } 243 244 kc_keypad_left = SDLK_LEFT; 245 kc_keypad_right = SDLK_RIGHT; 246 kc_keypad_up = SDLK_UP; 247 kc_keypad_down = SDLK_DOWN; 248 kc_keypad_a = SDLK_a; 249 kc_keypad_b = SDLK_s; 250 kc_keypad_start = SDLK_RETURN; 251 kc_keypad_select = SDLK_SPACE; 252 kc_emulator_pause = SDLK_p; 253 kc_emulator_quit = SDLK_ESCAPE; 254 255 jg_x_axis_invert = false; 256 jg_y_axis_invert = false; 257 jg_a = 1; 258 jg_b = 2; 259 jg_start = 9; 260 jg_select = 8; 261 jg_x_axis = 0; 262 jg_y_axis = 1; 263 264 dmg_palette[0].red = 0xEF; 265 dmg_palette[0].green = 0xF3; 266 dmg_palette[0].blue = 0xD5; 267 dmg_palette[0].alpha = 0xFF; 268 269 dmg_palette[1].red = 0xA3; 270 dmg_palette[1].green = 0xB6; 271 dmg_palette[1].blue = 0x7A; 272 dmg_palette[1].alpha = 0xFF; 273 274 dmg_palette[2].red = 0x37; 275 dmg_palette[2].green = 0x61; 276 dmg_palette[2].blue = 0x3B; 277 dmg_palette[2].alpha = 0xFF; 278 279 dmg_palette[3].red = 0x04; 280 dmg_palette[3].green = 0x1C; 281 dmg_palette[3].blue = 0x16; 282 dmg_palette[3].alpha = 0xFF; 283 284 Config cfg; 285 286 try 287 { 288 cfg.readFile(output_file); 289 290 try 291 { 292 const Setting& root = cfg.getRoot(); 293 const Setting &gearboy = root[GEARBOY_TITLE]; 294 295 string keypad_left, keypad_right, keypad_up, keypad_down, keypad_a, keypad_b, 296 keypad_start, keypad_select, emulator_pause, emulator_quit; 297 gearboy.lookupValue("keypad_left", keypad_left); 298 gearboy.lookupValue("keypad_right", keypad_right); 299 gearboy.lookupValue("keypad_up", keypad_up); 300 gearboy.lookupValue("keypad_down", keypad_down); 301 gearboy.lookupValue("keypad_a", keypad_a); 302 gearboy.lookupValue("keypad_b", keypad_b); 303 gearboy.lookupValue("keypad_start", keypad_start); 304 gearboy.lookupValue("keypad_select", keypad_select); 305 306 gearboy.lookupValue("joystick_gamepad_a", jg_a); 307 gearboy.lookupValue("joystick_gamepad_b", jg_b); 308 gearboy.lookupValue("joystick_gamepad_start", jg_start); 309 gearboy.lookupValue("joystick_gamepad_select", jg_select); 310 gearboy.lookupValue("joystick_gamepad_x_axis", jg_x_axis); 311 gearboy.lookupValue("joystick_gamepad_y_axis", jg_y_axis); 312 gearboy.lookupValue("joystick_gamepad_x_axis_invert", jg_x_axis_invert); 313 gearboy.lookupValue("joystick_gamepad_y_axis_invert", jg_y_axis_invert); 314 315 gearboy.lookupValue("emulator_pause", emulator_pause); 316 gearboy.lookupValue("emulator_quit", emulator_quit); 317 318 gearboy.lookupValue("emulator_pal0_red", dmg_palette[0].red); 319 gearboy.lookupValue("emulator_pal0_green", dmg_palette[0].green); 320 gearboy.lookupValue("emulator_pal0_blue", dmg_palette[0].blue); 321 gearboy.lookupValue("emulator_pal1_red", dmg_palette[1].red); 322 gearboy.lookupValue("emulator_pal1_green", dmg_palette[1].green); 323 gearboy.lookupValue("emulator_pal1_blue", dmg_palette[1].blue); 324 gearboy.lookupValue("emulator_pal2_red", dmg_palette[2].red); 325 gearboy.lookupValue("emulator_pal2_green", dmg_palette[2].green); 326 gearboy.lookupValue("emulator_pal2_blue", dmg_palette[2].blue); 327 gearboy.lookupValue("emulator_pal3_red", dmg_palette[3].red); 328 gearboy.lookupValue("emulator_pal3_green", dmg_palette[3].green); 329 gearboy.lookupValue("emulator_pal3_blue", dmg_palette[3].blue); 330 331 kc_keypad_left = SDL_GetKeyFromName(keypad_left.c_str()); 332 kc_keypad_right = SDL_GetKeyFromName(keypad_right.c_str()); 333 kc_keypad_up = SDL_GetKeyFromName(keypad_up.c_str()); 334 kc_keypad_down = SDL_GetKeyFromName(keypad_down.c_str()); 335 kc_keypad_a = SDL_GetKeyFromName(keypad_a.c_str()); 336 kc_keypad_b = SDL_GetKeyFromName(keypad_b.c_str()); 337 kc_keypad_start = SDL_GetKeyFromName(keypad_start.c_str()); 338 kc_keypad_select = SDL_GetKeyFromName(keypad_select.c_str()); 339 340 kc_emulator_pause = SDL_GetKeyFromName(emulator_pause.c_str()); 341 kc_emulator_quit = SDL_GetKeyFromName(emulator_quit.c_str()); 342 } 343 catch(const SettingNotFoundException &nfex) 344 { 345 std::cerr << "Setting not found" << std::endl; 346 } 347 } 348 catch(const FileIOException &fioex) 349 { 350 Log("I/O error while reading file: %s", output_file); 351 } 352 catch(const ParseException &pex) 353 { 354 std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() 355 << " - " << pex.getError() << std::endl; 356 } 357} 358 359void init_ogl(void) 360{ 361 int32_t success = 0; 362 EGLBoolean result; 363 EGLint num_config; 364 365 static EGL_DISPMANX_WINDOW_T nativewindow; 366 367 DISPMANX_ELEMENT_HANDLE_T dispman_element; 368 DISPMANX_DISPLAY_HANDLE_T dispman_display; 369 DISPMANX_UPDATE_HANDLE_T dispman_update; 370 VC_DISPMANX_ALPHA_T alpha; 371 VC_RECT_T dst_rect; 372 VC_RECT_T src_rect; 373 374 static const EGLint attribute_list[] = 375 { 376 EGL_RED_SIZE, 8, 377 EGL_GREEN_SIZE, 8, 378 EGL_BLUE_SIZE, 8, 379 EGL_ALPHA_SIZE, 8, 380 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 381 EGL_NONE 382 }; 383 384 EGLConfig config; 385 386 // Get an EGL display connection 387 display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 388 assert(display!=EGL_NO_DISPLAY); 389 390 // Initialize the EGL display connection 391 result = eglInitialize(display, NULL, NULL); 392 assert(EGL_FALSE != result); 393 394 // Get an appropriate EGL frame buffer configuration 395 result = eglChooseConfig(display, attribute_list, &config, 1, &num_config); 396 assert(EGL_FALSE != result); 397 398 // Create an EGL rendering context 399 context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL); 400 assert(context!=EGL_NO_CONTEXT); 401 402 // Create an EGL window surface 403 success = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height); 404 assert( success >= 0 ); 405 406 int32_t zoom = screen_width / GAMEBOY_WIDTH; 407 int32_t zoom2 = screen_height / GAMEBOY_HEIGHT; 408 409 if (zoom2 < zoom) 410 zoom = zoom2; 411 412 int32_t display_width = GAMEBOY_WIDTH * zoom; 413 int32_t display_height = GAMEBOY_HEIGHT * zoom; 414 int32_t display_offset_x = (screen_width / 2) - (display_width / 2); 415 int32_t display_offset_y = (screen_height / 2) - (display_height / 2); 416 417 dst_rect.x = 0; 418 dst_rect.y = 0; 419 dst_rect.width = screen_width; 420 dst_rect.height = screen_height; 421 422 src_rect.x = 0; 423 src_rect.y = 0; 424 src_rect.width = screen_width << 16; 425 src_rect.height = screen_height << 16; 426 427 dispman_display = vc_dispmanx_display_open( 0 /* LCD */); 428 dispman_update = vc_dispmanx_update_start( 0 ); 429 430 alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; 431 alpha.opacity = 255; 432 alpha.mask = 0; 433 434 dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, 435 0/*layer*/, &dst_rect, 0/*src*/, 436 &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0/*clamp*/, DISPMANX_NO_ROTATE/*transform*/); 437 438 nativewindow.element = dispman_element; 439 nativewindow.width = screen_width; 440 nativewindow.height = screen_height; 441 vc_dispmanx_update_submit_sync( dispman_update ); 442 443 surface = eglCreateWindowSurface( display, config, &nativewindow, NULL ); 444 assert(surface != EGL_NO_SURFACE); 445 446 // Connect the context to the surface 447 result = eglMakeCurrent(display, surface, surface, context); 448 assert(EGL_FALSE != result); 449 450 eglSwapInterval(display, 1); 451 452 glGenTextures(1, &theGBTexture); 453 454 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 455 456 glEnable(GL_TEXTURE_2D); 457 glBindTexture(GL_TEXTURE_2D, theGBTexture); 458 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (GLvoid*) NULL); 459 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 460 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 461 462 glMatrixMode(GL_PROJECTION); 463 glLoadIdentity(); 464 glOrthof(0.0f, screen_width, screen_height, 0.0f, -1.0f, 1.0f); 465 glMatrixMode(GL_MODELVIEW); 466 glLoadIdentity(); 467 glViewport(0.0f, 0.0f, screen_width, screen_height); 468 469 quadVerts[0] = display_offset_x; 470 quadVerts[1] = display_offset_y; 471 quadVerts[2] = display_offset_x + display_width; 472 quadVerts[3] = display_offset_y; 473 quadVerts[4] = display_offset_x + display_width; 474 quadVerts[5] = display_offset_y + display_height; 475 quadVerts[6] = display_offset_x; 476 quadVerts[7] = display_offset_y + display_height; 477 478 glVertexPointer(2, GL_SHORT, 0, quadVerts); 479 glEnableClientState(GL_VERTEX_ARRAY); 480 481 glTexCoordPointer(2, GL_FLOAT, 0, kQuadTex); 482 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 483 484 glClear(GL_COLOR_BUFFER_BIT); 485} 486 487void init(void) 488{ 489 490 bcm_host_init(); 491 init_ogl(); 492 init_sdl(); 493 494 theGearboyCore = new GearboyCore(); 495 theGearboyCore->Init(); 496 497 theSoundQueue = new Sound_Queue(); 498 theSoundQueue->start(44100, 2); 499 500 theFrameBuffer = new u16[GAMEBOY_WIDTH * GAMEBOY_HEIGHT]; 501 502 for (int i = 0; i < (GAMEBOY_WIDTH * GAMEBOY_HEIGHT); ++i) 503 { 504 theFrameBuffer[i] = 0; 505 } 506} 507 508void end(void) 509{ 510 Config cfg; 511 512 Setting &root = cfg.getRoot(); 513 Setting &address = root.add(GEARBOY_TITLE, Setting::TypeGroup); 514 515 address.add("keypad_left", Setting::TypeString) = SDL_GetKeyName(kc_keypad_left); 516 address.add("keypad_right", Setting::TypeString) = SDL_GetKeyName(kc_keypad_right); 517 address.add("keypad_up", Setting::TypeString) = SDL_GetKeyName(kc_keypad_up); 518 address.add("keypad_down", Setting::TypeString) = SDL_GetKeyName(kc_keypad_down); 519 address.add("keypad_a", Setting::TypeString) = SDL_GetKeyName(kc_keypad_a); 520 address.add("keypad_b", Setting::TypeString) = SDL_GetKeyName(kc_keypad_b); 521 address.add("keypad_start", Setting::TypeString) = SDL_GetKeyName(kc_keypad_start); 522 address.add("keypad_select", Setting::TypeString) = SDL_GetKeyName(kc_keypad_select); 523 524 address.add("joystick_gamepad_a", Setting::TypeInt) = jg_a; 525 address.add("joystick_gamepad_b", Setting::TypeInt) = jg_b; 526 address.add("joystick_gamepad_start", Setting::TypeInt) = jg_start; 527 address.add("joystick_gamepad_select", Setting::TypeInt) = jg_select; 528 address.add("joystick_gamepad_x_axis", Setting::TypeInt) = jg_x_axis; 529 address.add("joystick_gamepad_y_axis", Setting::TypeInt) = jg_y_axis; 530 address.add("joystick_gamepad_x_axis_invert", Setting::TypeBoolean) = jg_x_axis_invert; 531 address.add("joystick_gamepad_y_axis_invert", Setting::TypeBoolean) = jg_y_axis_invert; 532 533 address.add("emulator_pause", Setting::TypeString) = SDL_GetKeyName(kc_emulator_pause); 534 address.add("emulator_quit", Setting::TypeString) = SDL_GetKeyName(kc_emulator_quit); 535 536 address.add("emulator_pal0_red", Setting::TypeInt) = dmg_palette[0].red; 537 address.add("emulator_pal0_green", Setting::TypeInt) = dmg_palette[0].green; 538 address.add("emulator_pal0_blue", Setting::TypeInt) = dmg_palette[0].blue; 539 address.add("emulator_pal1_red", Setting::TypeInt) = dmg_palette[1].red; 540 address.add("emulator_pal1_green", Setting::TypeInt) = dmg_palette[1].green; 541 address.add("emulator_pal1_blue", Setting::TypeInt) = dmg_palette[1].blue; 542 address.add("emulator_pal2_red", Setting::TypeInt) = dmg_palette[2].red; 543 address.add("emulator_pal2_green", Setting::TypeInt) = dmg_palette[2].green; 544 address.add("emulator_pal2_blue", Setting::TypeInt) = dmg_palette[2].blue; 545 address.add("emulator_pal3_red", Setting::TypeInt) = dmg_palette[3].red; 546 address.add("emulator_pal3_green", Setting::TypeInt) = dmg_palette[3].green; 547 address.add("emulator_pal3_blue", Setting::TypeInt) = dmg_palette[3].blue; 548 549 try 550 { 551 cfg.writeFile(output_file); 552 } 553 catch(const FileIOException &fioex) 554 { 555 Log("I/O error while writing file: %s", output_file); 556 } 557 558 SDL_JoystickClose(game_pad); 559 560 SafeDeleteArray(theFrameBuffer); 561 SafeDelete(theSoundQueue); 562 SafeDelete(theGearboyCore); 563 SDL_DestroyWindow(theWindow); 564 SDL_Quit(); 565 bcm_host_deinit(); 566} 567 568int main(int argc, char** argv) 569{ 570 init(); 571 572 if (argc < 2 || argc > 4) 573 { 574 end(); 575 printf("usage: %s rom_path [options]\n", argv[0]); 576 printf("options:\n-nosound\n-forcedmg\n"); 577 return -1; 578 } 579 580 bool forcedmg = false; 581 582 if (argc > 2) 583 { 584 for (int i = 2; i < argc; i++) 585 { 586 if (strcmp("-nosound", argv[i]) == 0) 587 audioEnabled = false; 588 else if (strcmp("-forcedmg", argv[i]) == 0) 589 forcedmg = true; 590 else 591 { 592 end(); 593 printf("invalid option: %s\n", argv[i]); 594 return -1; 595 } 596 } 597 } 598 599 if (theGearboyCore->LoadROM(argv[1], forcedmg)) 600 { 601 GB_Color color1; 602 GB_Color color2; 603 GB_Color color3; 604 GB_Color color4; 605 606 color1.red = dmg_palette[0].red; 607 color1.green = dmg_palette[0].green; 608 color1.blue = dmg_palette[0].blue; 609 color2.red = dmg_palette[1].red; 610 color2.green = dmg_palette[1].green; 611 color2.blue = dmg_palette[1].blue; 612 color3.red = dmg_palette[2].red; 613 color3.green = dmg_palette[2].green; 614 color3.blue = dmg_palette[2].blue; 615 color4.red = dmg_palette[3].red; 616 color4.green = dmg_palette[3].green; 617 color4.blue = dmg_palette[3].blue; 618 619 theGearboyCore->SetDMGPalette(color1, color2, color3, color4); 620 theGearboyCore->LoadRam(); 621 622 while (running) 623 { 624 update(); 625 } 626 627 theGearboyCore->SaveRam(); 628 } 629 630 end(); 631 632 return 0; 633}