| 1 | //============================================================================ |
| 2 | // |
| 3 | // SSSS tt lll lll |
| 4 | // SS SS tt ll ll |
| 5 | // SS tttttt eeee ll ll aaaa |
| 6 | // SSSS tt ee ee ll ll aa |
| 7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
| 8 | // SS SS tt ee ll ll aa aa |
| 9 | // SSSS ttt eeeee llll llll aaaaa |
| 10 | // |
| 11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
| 12 | // and the Stella Team |
| 13 | // |
| 14 | // See the file "License.txt" for information on usage and redistribution of |
| 15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
| 16 | //============================================================================ |
| 17 | |
| 18 | #include <cassert> |
| 19 | #include <stdexcept> |
| 20 | |
| 21 | #include "AtariVox.hxx" |
| 22 | #include "Booster.hxx" |
| 23 | #include "Cart.hxx" |
| 24 | #include "Control.hxx" |
| 25 | #include "Cart.hxx" |
| 26 | #include "Driving.hxx" |
| 27 | #include "Event.hxx" |
| 28 | #include "EventHandler.hxx" |
| 29 | #include "ControllerDetector.hxx" |
| 30 | #include "Joystick.hxx" |
| 31 | #include "Keyboard.hxx" |
| 32 | #include "KidVid.hxx" |
| 33 | #include "Genesis.hxx" |
| 34 | #include "MindLink.hxx" |
| 35 | #include "CompuMate.hxx" |
| 36 | #include "M6502.hxx" |
| 37 | #include "M6532.hxx" |
| 38 | #include "TIA.hxx" |
| 39 | #include "Paddles.hxx" |
| 40 | #include "Props.hxx" |
| 41 | #include "PropsSet.hxx" |
| 42 | #include "SaveKey.hxx" |
| 43 | #include "Settings.hxx" |
| 44 | #include "Sound.hxx" |
| 45 | #include "Switches.hxx" |
| 46 | #include "System.hxx" |
| 47 | #include "AmigaMouse.hxx" |
| 48 | #include "AtariMouse.hxx" |
| 49 | #include "TrakBall.hxx" |
| 50 | #include "FrameBuffer.hxx" |
| 51 | #include "TIASurface.hxx" |
| 52 | #include "OSystem.hxx" |
| 53 | #include "Serializable.hxx" |
| 54 | #include "Serializer.hxx" |
| 55 | #include "TimerManager.hxx" |
| 56 | #include "Version.hxx" |
| 57 | #include "TIAConstants.hxx" |
| 58 | #include "FrameLayout.hxx" |
| 59 | #include "AudioQueue.hxx" |
| 60 | #include "AudioSettings.hxx" |
| 61 | #include "frame-manager/FrameManager.hxx" |
| 62 | #include "frame-manager/FrameLayoutDetector.hxx" |
| 63 | #include "frame-manager/YStartDetector.hxx" |
| 64 | |
| 65 | #ifdef CHEATCODE_SUPPORT |
| 66 | #include "CheatManager.hxx" |
| 67 | #endif |
| 68 | #ifdef DEBUGGER_SUPPORT |
| 69 | #include "Debugger.hxx" |
| 70 | #endif |
| 71 | |
| 72 | #include "Console.hxx" |
| 73 | |
| 74 | namespace { |
| 75 | constexpr uInt8 = 2; |
| 76 | } |
| 77 | |
| 78 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 79 | Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart, |
| 80 | const Properties& props, AudioSettings& audioSettings) |
| 81 | : myOSystem(osystem), |
| 82 | myEvent(osystem.eventHandler().event()), |
| 83 | myProperties(props), |
| 84 | myCart(std::move(cart)), |
| 85 | myDisplayFormat("" ), // Unknown TV format @ start |
| 86 | myCurrentFormat(0), // Unknown format @ start, |
| 87 | myAutodetectedYstart(0), |
| 88 | myYStartAutodetected(false), |
| 89 | myFormatAutodetected(false), |
| 90 | myUserPaletteDefined(false), |
| 91 | myConsoleTiming(ConsoleTiming::ntsc), |
| 92 | myAudioSettings(audioSettings) |
| 93 | { |
| 94 | // Load user-defined palette for this ROM |
| 95 | loadUserPalette(); |
| 96 | |
| 97 | // Create subsystems for the console |
| 98 | my6502 = make_unique<M6502>(myOSystem.settings()); |
| 99 | myRiot = make_unique<M6532>(*this, myOSystem.settings()); |
| 100 | myTIA = make_unique<TIA>(*this, [this]() { return timing(); }, myOSystem.settings()); |
| 101 | myFrameManager = make_unique<FrameManager>(); |
| 102 | mySwitches = make_unique<Switches>(myEvent, myProperties, myOSystem.settings()); |
| 103 | |
| 104 | myTIA->setFrameManager(myFrameManager.get()); |
| 105 | |
| 106 | // Reinitialize the RNG |
| 107 | myOSystem.random().initSeed(static_cast<uInt32>(TimerManager::getTicks())); |
| 108 | |
| 109 | // Construct the system and components |
| 110 | mySystem = make_unique<System>(myOSystem.random(), *my6502, *myRiot, *myTIA, *myCart); |
| 111 | |
| 112 | // The real controllers for this console will be added later |
| 113 | // For now, we just add dummy joystick controllers, since autodetection |
| 114 | // runs the emulation for a while, and this may interfere with 'smart' |
| 115 | // controllers such as the AVox and SaveKey |
| 116 | myLeftControl = make_unique<Joystick>(Controller::Jack::Left, myEvent, *mySystem); |
| 117 | myRightControl = make_unique<Joystick>(Controller::Jack::Right, myEvent, *mySystem); |
| 118 | |
| 119 | // Let the cart know how to query for the 'Cartridge.StartBank' property |
| 120 | myCart->setStartBankFromPropsFunc([this]() { |
| 121 | const string& startbank = myProperties.get(PropType::Cart_StartBank); |
| 122 | return startbank == EmptyString ? -1 : atoi(startbank.c_str()); |
| 123 | }); |
| 124 | |
| 125 | // We can only initialize after all the devices/components have been created |
| 126 | mySystem->initialize(); |
| 127 | |
| 128 | // Auto-detect NTSC/PAL mode if it's requested |
| 129 | string autodetected = "" ; |
| 130 | myDisplayFormat = myProperties.get(PropType::Display_Format); |
| 131 | |
| 132 | // Add the real controllers for this system |
| 133 | // This must be done before the debugger is initialized |
| 134 | const string& md5 = myProperties.get(PropType::Cart_MD5); |
| 135 | setControllers(md5); |
| 136 | |
| 137 | // Mute audio and clear framebuffer while autodetection runs |
| 138 | myOSystem.sound().mute(1); |
| 139 | myOSystem.frameBuffer().clear(); |
| 140 | |
| 141 | if(myDisplayFormat == "AUTO" || myOSystem.settings().getBool("rominfo" )) |
| 142 | { |
| 143 | autodetectFrameLayout(); |
| 144 | |
| 145 | if(myProperties.get(PropType::Display_Format) == "AUTO" ) |
| 146 | { |
| 147 | autodetected = "*" ; |
| 148 | myCurrentFormat = 0; |
| 149 | myFormatAutodetected = true; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | if (atoi(myProperties.get(PropType::Display_YStart).c_str()) == 0) { |
| 154 | autodetectYStart(); |
| 155 | } |
| 156 | |
| 157 | myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; |
| 158 | |
| 159 | // Set up the correct properties used when toggling format |
| 160 | // Note that this can be overridden if a format is forced |
| 161 | // For example, if a PAL ROM is forced to be NTSC, it will use NTSC-like |
| 162 | // properties (60Hz, 262 scanlines, etc), but likely result in flicker |
| 163 | if(myDisplayFormat == "NTSC" ) |
| 164 | { |
| 165 | myCurrentFormat = 1; |
| 166 | myConsoleTiming = ConsoleTiming::ntsc; |
| 167 | } |
| 168 | else if(myDisplayFormat == "PAL" ) |
| 169 | { |
| 170 | myCurrentFormat = 2; |
| 171 | myConsoleTiming = ConsoleTiming::pal; |
| 172 | } |
| 173 | else if(myDisplayFormat == "SECAM" ) |
| 174 | { |
| 175 | myCurrentFormat = 3; |
| 176 | myConsoleTiming = ConsoleTiming::secam; |
| 177 | } |
| 178 | else if(myDisplayFormat == "NTSC50" ) |
| 179 | { |
| 180 | myCurrentFormat = 4; |
| 181 | myConsoleTiming = ConsoleTiming::ntsc; |
| 182 | } |
| 183 | else if(myDisplayFormat == "PAL60" ) |
| 184 | { |
| 185 | myCurrentFormat = 5; |
| 186 | myConsoleTiming = ConsoleTiming::pal; |
| 187 | } |
| 188 | else if(myDisplayFormat == "SECAM60" ) |
| 189 | { |
| 190 | myCurrentFormat = 6; |
| 191 | myConsoleTiming = ConsoleTiming::secam; |
| 192 | } |
| 193 | |
| 194 | setTIAProperties(); |
| 195 | |
| 196 | bool joyallow4 = myOSystem.settings().getBool("joyallow4" ); |
| 197 | myOSystem.eventHandler().allowAllDirections(joyallow4); |
| 198 | |
| 199 | // Reset the system to its power-on state |
| 200 | mySystem->reset(); |
| 201 | myRiot->update(); |
| 202 | |
| 203 | // Finally, add remaining info about the console |
| 204 | myConsoleInfo.CartName = myProperties.get(PropType::Cart_Name); |
| 205 | myConsoleInfo.CartMD5 = myProperties.get(PropType::Cart_MD5); |
| 206 | bool swappedPorts = properties().get(PropType::Console_SwapPorts) == "YES" ; |
| 207 | myConsoleInfo.Control0 = myLeftControl->about(swappedPorts); |
| 208 | myConsoleInfo.Control1 = myRightControl->about(swappedPorts); |
| 209 | myConsoleInfo.BankSwitch = myCart->about(); |
| 210 | |
| 211 | // Some carts have an associated nvram file |
| 212 | myCart->setNVRamFile(myOSystem.nvramDir(), myConsoleInfo.CartName); |
| 213 | |
| 214 | // Let the other devices know about the new console |
| 215 | mySystem->consoleChanged(myConsoleTiming); |
| 216 | } |
| 217 | |
| 218 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 219 | Console::~Console() |
| 220 | { |
| 221 | // Some smart controllers need to be informed that the console is going away |
| 222 | myLeftControl->close(); |
| 223 | myRightControl->close(); |
| 224 | |
| 225 | // Close audio to prevent invalid access to myConsoleTiming from the audio |
| 226 | // callback |
| 227 | myOSystem.sound().close(); |
| 228 | } |
| 229 | |
| 230 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 231 | void Console::autodetectFrameLayout(bool reset) |
| 232 | { |
| 233 | // Run the TIA, looking for PAL scanline patterns |
| 234 | // We turn off the SuperCharger progress bars, otherwise the SC BIOS |
| 235 | // will take over 250 frames! |
| 236 | // The 'fastscbios' option must be changed before the system is reset |
| 237 | bool fastscbios = myOSystem.settings().getBool("fastscbios" ); |
| 238 | myOSystem.settings().setValue("fastscbios" , true); |
| 239 | |
| 240 | FrameLayoutDetector frameLayoutDetector; |
| 241 | myTIA->setFrameManager(&frameLayoutDetector); |
| 242 | |
| 243 | if (reset) { |
| 244 | mySystem->reset(true); |
| 245 | myRiot->update(); |
| 246 | } |
| 247 | |
| 248 | for(int i = 0; i < 60; ++i) myTIA->update(); |
| 249 | |
| 250 | myTIA->setFrameManager(myFrameManager.get()); |
| 251 | |
| 252 | myDisplayFormat = frameLayoutDetector.detectedLayout() == FrameLayout::pal ? "PAL" : "NTSC" ; |
| 253 | |
| 254 | // Don't forget to reset the SC progress bars again |
| 255 | myOSystem.settings().setValue("fastscbios" , fastscbios); |
| 256 | } |
| 257 | |
| 258 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 259 | void Console::redetectFrameLayout() |
| 260 | { |
| 261 | Serializer s; |
| 262 | |
| 263 | myOSystem.sound().close(); |
| 264 | save(s); |
| 265 | |
| 266 | autodetectFrameLayout(false); |
| 267 | if (myYStartAutodetected) autodetectYStart(); |
| 268 | |
| 269 | load(s); |
| 270 | initializeAudio(); |
| 271 | } |
| 272 | |
| 273 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 274 | void Console::autodetectYStart(bool reset) |
| 275 | { |
| 276 | // We turn off the SuperCharger progress bars, otherwise the SC BIOS |
| 277 | // will take over 250 frames! |
| 278 | // The 'fastscbios' option must be changed before the system is reset |
| 279 | bool fastscbios = myOSystem.settings().getBool("fastscbios" ); |
| 280 | myOSystem.settings().setValue("fastscbios" , true); |
| 281 | |
| 282 | YStartDetector ystartDetector; |
| 283 | ystartDetector.setLayout(myDisplayFormat == "PAL" ? FrameLayout::pal : FrameLayout::ntsc); |
| 284 | myTIA->setFrameManager(&ystartDetector); |
| 285 | |
| 286 | if (reset) { |
| 287 | mySystem->reset(true); |
| 288 | myRiot->update(); |
| 289 | } |
| 290 | |
| 291 | for (int i = 0; i < 80; i++) myTIA->update(); |
| 292 | |
| 293 | myTIA->setFrameManager(myFrameManager.get()); |
| 294 | |
| 295 | myAutodetectedYstart = ystartDetector.detectedYStart() - YSTART_EXTRA; |
| 296 | |
| 297 | // Don't forget to reset the SC progress bars again |
| 298 | myOSystem.settings().setValue("fastscbios" , fastscbios); |
| 299 | } |
| 300 | |
| 301 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 302 | void Console::redetectYStart() |
| 303 | { |
| 304 | Serializer s; |
| 305 | |
| 306 | myOSystem.sound().close(); |
| 307 | save(s); |
| 308 | |
| 309 | autodetectYStart(false); |
| 310 | |
| 311 | load(s); |
| 312 | initializeAudio(); |
| 313 | } |
| 314 | |
| 315 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 316 | bool Console::save(Serializer& out) const |
| 317 | { |
| 318 | try |
| 319 | { |
| 320 | // First save state for the system |
| 321 | if(!mySystem->save(out)) |
| 322 | return false; |
| 323 | |
| 324 | // Now save the console controllers and switches |
| 325 | if(!(myLeftControl->save(out) && myRightControl->save(out) && |
| 326 | mySwitches->save(out))) |
| 327 | return false; |
| 328 | } |
| 329 | catch(...) |
| 330 | { |
| 331 | cerr << "ERROR: Console::save" << endl; |
| 332 | return false; |
| 333 | } |
| 334 | |
| 335 | return true; // success |
| 336 | } |
| 337 | |
| 338 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 339 | bool Console::load(Serializer& in) |
| 340 | { |
| 341 | try |
| 342 | { |
| 343 | // First load state for the system |
| 344 | if(!mySystem->load(in)) |
| 345 | return false; |
| 346 | |
| 347 | // Then load the console controllers and switches |
| 348 | if(!(myLeftControl->load(in) && myRightControl->load(in) && |
| 349 | mySwitches->load(in))) |
| 350 | return false; |
| 351 | } |
| 352 | catch(...) |
| 353 | { |
| 354 | cerr << "ERROR: Console::load" << endl; |
| 355 | return false; |
| 356 | } |
| 357 | |
| 358 | return true; // success |
| 359 | } |
| 360 | |
| 361 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 362 | void Console::toggleFormat(int direction) |
| 363 | { |
| 364 | string saveformat, message; |
| 365 | uInt32 format = myCurrentFormat; |
| 366 | |
| 367 | if(direction == 1) |
| 368 | format = (myCurrentFormat + 1) % 7; |
| 369 | else if(direction == -1) |
| 370 | format = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; |
| 371 | |
| 372 | setFormat(format); |
| 373 | } |
| 374 | |
| 375 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 376 | void Console::setFormat(uInt32 format) |
| 377 | { |
| 378 | if(myCurrentFormat == format) |
| 379 | return; |
| 380 | |
| 381 | string saveformat, message; |
| 382 | string autodetected = "" ; |
| 383 | |
| 384 | myCurrentFormat = format; |
| 385 | switch(myCurrentFormat) |
| 386 | { |
| 387 | case 0: // auto-detect |
| 388 | { |
| 389 | if (myFormatAutodetected) return; |
| 390 | |
| 391 | string oldDisplayFormat = myDisplayFormat; |
| 392 | redetectFrameLayout(); |
| 393 | myFormatAutodetected = true; |
| 394 | saveformat = "AUTO" ; |
| 395 | autodetected = "*" ; |
| 396 | myConsoleTiming = myDisplayFormat == "PAL" ? ConsoleTiming::pal : ConsoleTiming::ntsc; |
| 397 | message = "Auto-detect mode: " + myDisplayFormat; |
| 398 | break; |
| 399 | } |
| 400 | case 1: |
| 401 | saveformat = myDisplayFormat = "NTSC" ; |
| 402 | myConsoleTiming = ConsoleTiming::ntsc; |
| 403 | message = "NTSC mode" ; |
| 404 | myFormatAutodetected = false; |
| 405 | break; |
| 406 | case 2: |
| 407 | saveformat = myDisplayFormat = "PAL" ; |
| 408 | myConsoleTiming = ConsoleTiming::pal; |
| 409 | message = "PAL mode" ; |
| 410 | myFormatAutodetected = false; |
| 411 | break; |
| 412 | case 3: |
| 413 | saveformat = myDisplayFormat = "SECAM" ; |
| 414 | myConsoleTiming = ConsoleTiming::secam; |
| 415 | message = "SECAM mode" ; |
| 416 | myFormatAutodetected = false; |
| 417 | break; |
| 418 | case 4: |
| 419 | saveformat = myDisplayFormat = "NTSC50" ; |
| 420 | myConsoleTiming = ConsoleTiming::ntsc; |
| 421 | message = "NTSC50 mode" ; |
| 422 | myFormatAutodetected = false; |
| 423 | break; |
| 424 | case 5: |
| 425 | saveformat = myDisplayFormat = "PAL60" ; |
| 426 | myConsoleTiming = ConsoleTiming::pal; |
| 427 | message = "PAL60 mode" ; |
| 428 | myFormatAutodetected = false; |
| 429 | break; |
| 430 | case 6: |
| 431 | saveformat = myDisplayFormat = "SECAM60" ; |
| 432 | myConsoleTiming = ConsoleTiming::secam; |
| 433 | message = "SECAM60 mode" ; |
| 434 | myFormatAutodetected = false; |
| 435 | break; |
| 436 | } |
| 437 | myProperties.set(PropType::Display_Format, saveformat); |
| 438 | |
| 439 | myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; |
| 440 | |
| 441 | setPalette(myOSystem.settings().getString("palette" )); |
| 442 | setTIAProperties(); |
| 443 | initializeVideo(); // takes care of refreshing the screen |
| 444 | initializeAudio(); // ensure that audio synthesis is set up to match emulation speed |
| 445 | myOSystem.resetFps(); // Reset FPS measurement |
| 446 | |
| 447 | myOSystem.frameBuffer().showMessage(message); |
| 448 | |
| 449 | // Let the other devices know about the console change |
| 450 | mySystem->consoleChanged(myConsoleTiming); |
| 451 | } |
| 452 | |
| 453 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 454 | void Console::toggleColorLoss() |
| 455 | { |
| 456 | bool colorloss = !myTIA->colorLossEnabled(); |
| 457 | if(myTIA->enableColorLoss(colorloss)) |
| 458 | { |
| 459 | myOSystem.settings().setValue( |
| 460 | myOSystem.settings().getBool("dev.settings" ) ? "dev.colorloss" : "plr.colorloss" , colorloss); |
| 461 | |
| 462 | string message = string("PAL color-loss " ) + |
| 463 | (colorloss ? "enabled" : "disabled" ); |
| 464 | myOSystem.frameBuffer().showMessage(message); |
| 465 | } |
| 466 | else |
| 467 | myOSystem.frameBuffer().showMessage( |
| 468 | "PAL color-loss not available in non PAL modes" ); |
| 469 | } |
| 470 | |
| 471 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 472 | void Console::enableColorLoss(bool state) |
| 473 | { |
| 474 | myTIA->enableColorLoss(state); |
| 475 | } |
| 476 | |
| 477 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 478 | void Console::togglePalette() |
| 479 | { |
| 480 | string palette, message; |
| 481 | palette = myOSystem.settings().getString("palette" ); |
| 482 | |
| 483 | if(palette == "standard" ) // switch to z26 |
| 484 | { |
| 485 | palette = "z26" ; |
| 486 | message = "Z26 palette" ; |
| 487 | } |
| 488 | else if(palette == "z26" ) // switch to user or standard |
| 489 | { |
| 490 | // If we have a user-defined palette, it will come next in |
| 491 | // the sequence; otherwise loop back to the standard one |
| 492 | if(myUserPaletteDefined) |
| 493 | { |
| 494 | palette = "user" ; |
| 495 | message = "User-defined palette" ; |
| 496 | } |
| 497 | else |
| 498 | { |
| 499 | palette = "standard" ; |
| 500 | message = "Standard Stella palette" ; |
| 501 | } |
| 502 | } |
| 503 | else if(palette == "user" ) // switch to standard |
| 504 | { |
| 505 | palette = "standard" ; |
| 506 | message = "Standard Stella palette" ; |
| 507 | } |
| 508 | else // switch to standard mode if we get this far |
| 509 | { |
| 510 | palette = "standard" ; |
| 511 | message = "Standard Stella palette" ; |
| 512 | } |
| 513 | |
| 514 | myOSystem.settings().setValue("palette" , palette); |
| 515 | myOSystem.frameBuffer().showMessage(message); |
| 516 | |
| 517 | setPalette(palette); |
| 518 | } |
| 519 | |
| 520 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 521 | void Console::setPalette(const string& type) |
| 522 | { |
| 523 | // Look at all the palettes, since we don't know which one is |
| 524 | // currently active |
| 525 | static uInt32* palettes[3][3] = { |
| 526 | { &ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0] }, |
| 527 | { &ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0] }, |
| 528 | { &ourUserNTSCPalette[0], &ourUserPALPalette[0], &ourUserSECAMPalette[0] } |
| 529 | }; |
| 530 | |
| 531 | // See which format we should be using |
| 532 | int paletteNum = 0; |
| 533 | if(type == "standard" ) |
| 534 | paletteNum = 0; |
| 535 | else if(type == "z26" ) |
| 536 | paletteNum = 1; |
| 537 | else if(type == "user" && myUserPaletteDefined) |
| 538 | paletteNum = 2; |
| 539 | |
| 540 | // Now consider the current display format |
| 541 | const uInt32* palette = |
| 542 | (myDisplayFormat.compare(0, 3, "PAL" ) == 0) ? palettes[paletteNum][1] : |
| 543 | (myDisplayFormat.compare(0, 5, "SECAM" ) == 0) ? palettes[paletteNum][2] : |
| 544 | palettes[paletteNum][0]; |
| 545 | |
| 546 | myOSystem.frameBuffer().setPalette(palette); |
| 547 | |
| 548 | if(myTIA->usingFixedColors()) |
| 549 | myTIA->enableFixedColors(true); |
| 550 | } |
| 551 | |
| 552 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 553 | void Console::togglePhosphor() |
| 554 | { |
| 555 | if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled()) |
| 556 | { |
| 557 | myProperties.set(PropType::Display_Phosphor, "NO" ); |
| 558 | myOSystem.frameBuffer().tiaSurface().enablePhosphor(false); |
| 559 | myOSystem.frameBuffer().showMessage("Phosphor effect disabled" ); |
| 560 | } |
| 561 | else |
| 562 | { |
| 563 | myProperties.set(PropType::Display_Phosphor, "YES" ); |
| 564 | myOSystem.frameBuffer().tiaSurface().enablePhosphor(true); |
| 565 | myOSystem.frameBuffer().showMessage("Phosphor effect enabled" ); |
| 566 | } |
| 567 | } |
| 568 | |
| 569 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 570 | void Console::changePhosphor(int direction) |
| 571 | { |
| 572 | int blend = atoi(myProperties.get(PropType::Display_PPBlend).c_str()); |
| 573 | |
| 574 | if(direction == +1) // increase blend |
| 575 | { |
| 576 | if(blend >= 100) |
| 577 | { |
| 578 | myOSystem.frameBuffer().showMessage("Phosphor blend at maximum" ); |
| 579 | myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, 100); |
| 580 | return; |
| 581 | } |
| 582 | else |
| 583 | blend = std::min(blend+2, 100); |
| 584 | } |
| 585 | else if(direction == -1) // decrease blend |
| 586 | { |
| 587 | if(blend <= 2) |
| 588 | { |
| 589 | myOSystem.frameBuffer().showMessage("Phosphor blend at minimum" ); |
| 590 | myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, 0); |
| 591 | return; |
| 592 | } |
| 593 | else |
| 594 | blend = std::max(blend-2, 0); |
| 595 | } |
| 596 | else |
| 597 | return; |
| 598 | |
| 599 | ostringstream val; |
| 600 | val << blend; |
| 601 | myProperties.set(PropType::Display_PPBlend, val.str()); |
| 602 | myOSystem.frameBuffer().showMessage("Phosphor blend " + val.str()); |
| 603 | myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); |
| 604 | } |
| 605 | |
| 606 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 607 | void Console::setProperties(const Properties& props) |
| 608 | { |
| 609 | myProperties = props; |
| 610 | } |
| 611 | |
| 612 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 613 | FBInitStatus Console::initializeVideo(bool full) |
| 614 | { |
| 615 | FBInitStatus fbstatus = FBInitStatus::Success; |
| 616 | |
| 617 | if(full) |
| 618 | { |
| 619 | bool devSettings = myOSystem.settings().getBool("dev.settings" ); |
| 620 | const string& title = string("Stella " ) + STELLA_VERSION + |
| 621 | ": \"" + myProperties.get(PropType::Cart_Name) + "\"" ; |
| 622 | fbstatus = myOSystem.frameBuffer().createDisplay(title, |
| 623 | TIAConstants::viewableWidth, TIAConstants::viewableHeight, false); |
| 624 | if(fbstatus != FBInitStatus::Success) |
| 625 | return fbstatus; |
| 626 | |
| 627 | myOSystem.frameBuffer().showFrameStats( |
| 628 | myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats" )); |
| 629 | generateColorLossPalette(); |
| 630 | } |
| 631 | setPalette(myOSystem.settings().getString("palette" )); |
| 632 | |
| 633 | return fbstatus; |
| 634 | } |
| 635 | |
| 636 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 637 | void Console::initializeAudio() |
| 638 | { |
| 639 | myOSystem.sound().close(); |
| 640 | |
| 641 | myEmulationTiming |
| 642 | .updatePlaybackRate(myAudioSettings.sampleRate()) |
| 643 | .updatePlaybackPeriod(myAudioSettings.fragmentSize()) |
| 644 | .updateAudioQueueExtraFragments(myAudioSettings.bufferSize()) |
| 645 | .updateAudioQueueHeadroom(myAudioSettings.headroom()) |
| 646 | .updateSpeedFactor(myOSystem.settings().getFloat("speed" )); |
| 647 | |
| 648 | createAudioQueue(); |
| 649 | myTIA->setAudioQueue(myAudioQueue); |
| 650 | |
| 651 | myOSystem.sound().open(myAudioQueue, &myEmulationTiming); |
| 652 | } |
| 653 | |
| 654 | /* Original frying research and code by Fred Quimby. |
| 655 | I've tried the following variations on this code: |
| 656 | - Both OR and Exclusive OR instead of AND. This generally crashes the game |
| 657 | without ever giving us realistic "fried" effects. |
| 658 | - Loop only over the RIOT RAM. This still gave us frying-like effects, but |
| 659 | it seemed harder to duplicate most effects. I have no idea why, but |
| 660 | munging the TIA regs seems to have some effect (I'd think it wouldn't). |
| 661 | |
| 662 | Fred says he also tried mangling the PC and registers, but usually it'd just |
| 663 | crash the game (e.g. black screen, no way out of it). |
| 664 | |
| 665 | It's definitely easier to get some effects (e.g. 255 lives in Battlezone) |
| 666 | with this code than it is on a real console. My guess is that most "good" |
| 667 | frying effects come from a RIOT location getting cleared to 0. Fred's |
| 668 | code is more likely to accomplish this than frying a real console is... |
| 669 | |
| 670 | Until someone comes up with a more accurate way to emulate frying, I'm |
| 671 | leaving this as Fred posted it. -- B. |
| 672 | */ |
| 673 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 674 | void Console::fry() const |
| 675 | { |
| 676 | for(int i = 0; i < 0x100; i += mySystem->randGenerator().next() % 4) |
| 677 | mySystem->poke(i, mySystem->peek(i) & mySystem->randGenerator().next()); |
| 678 | } |
| 679 | |
| 680 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 681 | void Console::changeYStart(int direction) |
| 682 | { |
| 683 | uInt32 ystart = myTIA->ystart(); |
| 684 | |
| 685 | if(direction == +1) // increase YStart |
| 686 | { |
| 687 | if(ystart >= TIAConstants::maxYStart) |
| 688 | { |
| 689 | myOSystem.frameBuffer().showMessage("YStart at maximum" ); |
| 690 | return; |
| 691 | } |
| 692 | |
| 693 | ++ystart; |
| 694 | myYStartAutodetected = false; |
| 695 | } |
| 696 | else if(direction == -1) // decrease YStart |
| 697 | { |
| 698 | if(ystart == 0) |
| 699 | { |
| 700 | throw runtime_error("cannot happen" ); |
| 701 | } |
| 702 | |
| 703 | --ystart; |
| 704 | myYStartAutodetected = false; |
| 705 | } |
| 706 | else |
| 707 | return; |
| 708 | |
| 709 | if(ystart == 0) { |
| 710 | redetectYStart(); |
| 711 | ystart = myAutodetectedYstart; |
| 712 | myYStartAutodetected = true; |
| 713 | |
| 714 | myProperties.set(PropType::Display_YStart, "0" ); |
| 715 | } |
| 716 | else { |
| 717 | ostringstream ss; |
| 718 | ss << ystart; |
| 719 | |
| 720 | myProperties.set(PropType::Display_YStart, ss.str()); |
| 721 | } |
| 722 | |
| 723 | if (ystart != myTIA->ystart()) myTIA->setYStart(ystart); |
| 724 | |
| 725 | ostringstream ss; |
| 726 | |
| 727 | if(myAutodetectedYstart == ystart) ss << "YStart " << ystart << " (Auto)" ; |
| 728 | else ss << "YStart " << ystart; |
| 729 | |
| 730 | myOSystem.frameBuffer().showMessage(ss.str()); |
| 731 | } |
| 732 | |
| 733 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 734 | void Console::updateYStart(uInt32 ystart) |
| 735 | { |
| 736 | if (ystart > TIAConstants::maxYStart) return; |
| 737 | |
| 738 | if (ystart == 0) { |
| 739 | if (myYStartAutodetected) return; |
| 740 | |
| 741 | redetectYStart(); |
| 742 | myYStartAutodetected = true; |
| 743 | ystart = myAutodetectedYstart; |
| 744 | } else |
| 745 | myYStartAutodetected = false; |
| 746 | |
| 747 | if (ystart != myTIA->ystart()) myTIA->setYStart(ystart); |
| 748 | } |
| 749 | |
| 750 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 751 | void Console::setTIAProperties() |
| 752 | { |
| 753 | // FIXME - ystart is probably disappearing soon, or at least autodetection is |
| 754 | uInt32 ystart = atoi(myProperties.get(PropType::Display_YStart).c_str()); |
| 755 | if(ystart != 0) |
| 756 | ystart = BSPF::clamp(ystart, 0u, TIAConstants::maxYStart); |
| 757 | else { |
| 758 | ystart = myAutodetectedYstart; |
| 759 | myYStartAutodetected = true; |
| 760 | } |
| 761 | |
| 762 | if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" || |
| 763 | myDisplayFormat == "SECAM60" ) |
| 764 | { |
| 765 | // Assume we've got ~262 scanlines (NTSC-like format) |
| 766 | myTIA->setLayout(FrameLayout::ntsc); |
| 767 | } |
| 768 | else |
| 769 | { |
| 770 | // Assume we've got ~312 scanlines (PAL-like format) |
| 771 | myTIA->setLayout(FrameLayout::pal); |
| 772 | } |
| 773 | |
| 774 | myTIA->setYStart(ystart); |
| 775 | |
| 776 | myEmulationTiming.updateFrameLayout(myTIA->frameLayout()); |
| 777 | myEmulationTiming.updateConsoleTiming(myConsoleTiming); |
| 778 | } |
| 779 | |
| 780 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 781 | void Console::createAudioQueue() |
| 782 | { |
| 783 | bool useStereo = myOSystem.settings().getBool(AudioSettings::SETTING_STEREO) |
| 784 | || myProperties.get(PropType::Cart_Sound) == "STEREO" ; |
| 785 | |
| 786 | myAudioQueue = make_shared<AudioQueue>( |
| 787 | myEmulationTiming.audioFragmentSize(), |
| 788 | myEmulationTiming.audioQueueCapacity(), |
| 789 | useStereo |
| 790 | ); |
| 791 | } |
| 792 | |
| 793 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 794 | void Console::setControllers(const string& romMd5) |
| 795 | { |
| 796 | // Check for CompuMate scheme; it is special in that a handler creates both |
| 797 | // controllers for us, and associates them with the bankswitching class |
| 798 | if(myCart->detectedType() == "CM" ) |
| 799 | { |
| 800 | myCMHandler = make_shared<CompuMate>(*this, myEvent, *mySystem); |
| 801 | |
| 802 | // A somewhat ugly bit of code that casts to CartridgeCM to |
| 803 | // add the CompuMate, and then back again for the actual |
| 804 | // Cartridge |
| 805 | unique_ptr<CartridgeCM> cartcm(static_cast<CartridgeCM*>(myCart.release())); |
| 806 | cartcm->setCompuMate(myCMHandler); |
| 807 | myCart = std::move(cartcm); |
| 808 | |
| 809 | myLeftControl = std::move(myCMHandler->leftController()); |
| 810 | myRightControl = std::move(myCMHandler->rightController()); |
| 811 | myOSystem.eventHandler().defineKeyControllerMappings(Controller::Type::CompuMate, Controller::Jack::Left); |
| 812 | myOSystem.eventHandler().defineJoyControllerMappings(Controller::Type::CompuMate, Controller::Jack::Left); |
| 813 | } |
| 814 | else |
| 815 | { |
| 816 | // Setup the controllers based on properties |
| 817 | Controller::Type leftType = Controller::getType(myProperties.get(PropType::Controller_Left)); |
| 818 | Controller::Type rightType = Controller::getType(myProperties.get(PropType::Controller_Right)); |
| 819 | size_t size = 0; |
| 820 | const uInt8* image = myCart->getImage(size); |
| 821 | const bool swappedPorts = myProperties.get(PropType::Console_SwapPorts) == "YES" ; |
| 822 | |
| 823 | // Try to detect controllers |
| 824 | if(image != nullptr || size != 0) |
| 825 | { |
| 826 | leftType = ControllerDetector::detectType(image, size, leftType, |
| 827 | !swappedPorts ? Controller::Jack::Left : Controller::Jack::Right, myOSystem.settings()); |
| 828 | rightType = ControllerDetector::detectType(image, size, rightType, |
| 829 | !swappedPorts ? Controller::Jack::Right : Controller::Jack::Left, myOSystem.settings()); |
| 830 | } |
| 831 | |
| 832 | unique_ptr<Controller> leftC = getControllerPort(leftType, Controller::Jack::Left, romMd5), |
| 833 | rightC = getControllerPort(rightType, Controller::Jack::Right, romMd5); |
| 834 | |
| 835 | // Swap the ports if necessary |
| 836 | if(!swappedPorts) |
| 837 | { |
| 838 | myLeftControl = std::move(leftC); |
| 839 | myRightControl = std::move(rightC); |
| 840 | } |
| 841 | else |
| 842 | { |
| 843 | myLeftControl = std::move(rightC); |
| 844 | myRightControl = std::move(leftC); |
| 845 | } |
| 846 | } |
| 847 | |
| 848 | myTIA->bindToControllers(); |
| 849 | |
| 850 | // now that we know the controllers, enable the event mappings |
| 851 | myOSystem.eventHandler().enableEmulationKeyMappings(); |
| 852 | myOSystem.eventHandler().enableEmulationJoyMappings(); |
| 853 | |
| 854 | myOSystem.eventHandler().setMouseControllerMode(myOSystem.settings().getString("usemouse" )); |
| 855 | } |
| 856 | |
| 857 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 858 | unique_ptr<Controller> Console::getControllerPort(const Controller::Type type, |
| 859 | const Controller::Jack port, const string& romMd5) |
| 860 | { |
| 861 | unique_ptr<Controller> controller; |
| 862 | |
| 863 | myOSystem.eventHandler().defineKeyControllerMappings(type, port); |
| 864 | myOSystem.eventHandler().defineJoyControllerMappings(type, port); |
| 865 | |
| 866 | switch(type) |
| 867 | { |
| 868 | case Controller::Type::BoosterGrip: |
| 869 | controller = make_unique<BoosterGrip>(port, myEvent, *mySystem); |
| 870 | break; |
| 871 | |
| 872 | case Controller::Type::Driving: |
| 873 | controller = make_unique<Driving>(port, myEvent, *mySystem); |
| 874 | break; |
| 875 | |
| 876 | case Controller::Type::Keyboard: |
| 877 | controller = make_unique<Keyboard>(port, myEvent, *mySystem); |
| 878 | break; |
| 879 | |
| 880 | case Controller::Type::Paddles: |
| 881 | case Controller::Type::PaddlesIAxis: |
| 882 | case Controller::Type::PaddlesIAxDr: |
| 883 | { |
| 884 | // Also check if we should swap the paddles plugged into a jack |
| 885 | bool swapPaddles = myProperties.get(PropType::Controller_SwapPaddles) == "YES" ; |
| 886 | bool swapAxis = false, swapDir = false; |
| 887 | if(type == Controller::Type::PaddlesIAxis) |
| 888 | swapAxis = true; |
| 889 | else if(type == Controller::Type::PaddlesIAxDr) |
| 890 | swapAxis = swapDir = true; |
| 891 | controller = make_unique<Paddles>(port, myEvent, *mySystem, |
| 892 | swapPaddles, swapAxis, swapDir); |
| 893 | break; |
| 894 | } |
| 895 | case Controller::Type::AmigaMouse: |
| 896 | controller = make_unique<AmigaMouse>(port, myEvent, *mySystem); |
| 897 | break; |
| 898 | |
| 899 | case Controller::Type::AtariMouse: |
| 900 | controller = make_unique<AtariMouse>(port, myEvent, *mySystem); |
| 901 | break; |
| 902 | |
| 903 | case Controller::Type::TrakBall: |
| 904 | controller = make_unique<TrakBall>(port, myEvent, *mySystem); |
| 905 | break; |
| 906 | |
| 907 | case Controller::Type::AtariVox: |
| 908 | { |
| 909 | const string& nvramfile = myOSystem.nvramDir() + "atarivox_eeprom.dat" ; |
| 910 | Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) { |
| 911 | bool devSettings = os.settings().getBool("dev.settings" ); |
| 912 | if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess" )) |
| 913 | os.frameBuffer().showMessage(msg); |
| 914 | }; |
| 915 | controller = make_unique<AtariVox>(port, myEvent, *mySystem, |
| 916 | myOSystem.settings().getString("avoxport" ), nvramfile, callback); |
| 917 | break; |
| 918 | } |
| 919 | case Controller::Type::SaveKey: |
| 920 | { |
| 921 | const string& nvramfile = myOSystem.nvramDir() + "savekey_eeprom.dat" ; |
| 922 | Controller::onMessageCallback callback = [&os = myOSystem](const string& msg) { |
| 923 | bool devSettings = os.settings().getBool("dev.settings" ); |
| 924 | if(os.settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess" )) |
| 925 | os.frameBuffer().showMessage(msg); |
| 926 | }; |
| 927 | controller = make_unique<SaveKey>(port, myEvent, *mySystem, nvramfile, callback); |
| 928 | break; |
| 929 | } |
| 930 | case Controller::Type::Genesis: |
| 931 | controller = make_unique<Genesis>(port, myEvent, *mySystem); |
| 932 | break; |
| 933 | |
| 934 | case Controller::Type::KidVid: |
| 935 | controller = make_unique<KidVid>(port, myEvent, *mySystem, romMd5); |
| 936 | break; |
| 937 | |
| 938 | case Controller::Type::MindLink: |
| 939 | controller = make_unique<MindLink>(port, myEvent, *mySystem); |
| 940 | break; |
| 941 | |
| 942 | default: |
| 943 | // What else can we do? |
| 944 | // always create because it may have been changed by user dialog |
| 945 | controller = make_unique<Joystick>(port, myEvent, *mySystem); |
| 946 | } |
| 947 | |
| 948 | return controller; |
| 949 | } |
| 950 | |
| 951 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 952 | void Console::loadUserPalette() |
| 953 | { |
| 954 | const string& palette = myOSystem.paletteFile(); |
| 955 | ifstream in(palette, std::ios::binary); |
| 956 | if(!in) |
| 957 | return; |
| 958 | |
| 959 | // Make sure the contains enough data for the NTSC, PAL and SECAM palettes |
| 960 | // This means 128 colours each for NTSC and PAL, at 3 bytes per pixel |
| 961 | // and 8 colours for SECAM at 3 bytes per pixel |
| 962 | in.seekg(0, std::ios::end); |
| 963 | std::streampos length = in.tellg(); |
| 964 | in.seekg(0, std::ios::beg); |
| 965 | if(length < 128 * 3 * 2 + 8 * 3) |
| 966 | { |
| 967 | cerr << "ERROR: invalid palette file " << palette << endl; |
| 968 | return; |
| 969 | } |
| 970 | |
| 971 | // Now that we have valid data, create the user-defined palettes |
| 972 | uInt8 pixbuf[3]; // Temporary buffer for one 24-bit pixel |
| 973 | |
| 974 | for(int i = 0; i < 128; i++) // NTSC palette |
| 975 | { |
| 976 | in.read(reinterpret_cast<char*>(pixbuf), 3); |
| 977 | uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); |
| 978 | ourUserNTSCPalette[(i<<1)] = pixel; |
| 979 | } |
| 980 | for(int i = 0; i < 128; i++) // PAL palette |
| 981 | { |
| 982 | in.read(reinterpret_cast<char*>(pixbuf), 3); |
| 983 | uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); |
| 984 | ourUserPALPalette[(i<<1)] = pixel; |
| 985 | } |
| 986 | |
| 987 | uInt32 secam[16]; // All 8 24-bit pixels, plus 8 colorloss pixels |
| 988 | for(int i = 0; i < 8; i++) // SECAM palette |
| 989 | { |
| 990 | in.read(reinterpret_cast<char*>(pixbuf), 3); |
| 991 | uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); |
| 992 | secam[(i<<1)] = pixel; |
| 993 | secam[(i<<1)+1] = 0; |
| 994 | } |
| 995 | uInt32* ptr = ourUserSECAMPalette; |
| 996 | for(int i = 0; i < 16; ++i) |
| 997 | { |
| 998 | uInt32* s = secam; |
| 999 | for(int j = 0; j < 16; ++j) |
| 1000 | *ptr++ = *s++; |
| 1001 | } |
| 1002 | |
| 1003 | myUserPaletteDefined = true; |
| 1004 | } |
| 1005 | |
| 1006 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1007 | void Console::generateColorLossPalette() |
| 1008 | { |
| 1009 | // Look at all the palettes, since we don't know which one is |
| 1010 | // currently active |
| 1011 | uInt32* palette[9] = { |
| 1012 | &ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0], |
| 1013 | &ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0], |
| 1014 | nullptr, nullptr, nullptr |
| 1015 | }; |
| 1016 | if(myUserPaletteDefined) |
| 1017 | { |
| 1018 | palette[6] = &ourUserNTSCPalette[0]; |
| 1019 | palette[7] = &ourUserPALPalette[0]; |
| 1020 | palette[8] = &ourUserSECAMPalette[0]; |
| 1021 | } |
| 1022 | |
| 1023 | for(int i = 0; i < 9; ++i) |
| 1024 | { |
| 1025 | if(palette[i] == nullptr) |
| 1026 | continue; |
| 1027 | |
| 1028 | // Fill the odd numbered palette entries with gray values (calculated |
| 1029 | // using the standard RGB -> grayscale conversion formula) |
| 1030 | for(int j = 0; j < 128; ++j) |
| 1031 | { |
| 1032 | uInt32 pixel = palette[i][(j<<1)]; |
| 1033 | uInt8 r = (pixel >> 16) & 0xff; |
| 1034 | uInt8 g = (pixel >> 8) & 0xff; |
| 1035 | uInt8 b = (pixel >> 0) & 0xff; |
| 1036 | uInt8 sum = uInt8((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); |
| 1037 | palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; |
| 1038 | } |
| 1039 | } |
| 1040 | } |
| 1041 | |
| 1042 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1043 | float Console::getFramerate() const |
| 1044 | { |
| 1045 | return |
| 1046 | (myConsoleTiming == ConsoleTiming::ntsc ? 262.f * 60.f : 312.f * 50.f) / |
| 1047 | myTIA->frameBufferScanlinesLastFrame(); |
| 1048 | } |
| 1049 | |
| 1050 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1051 | void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const |
| 1052 | { |
| 1053 | bool result = myTIA->toggleBit(bit); |
| 1054 | string message = bitname + (result ? " enabled" : " disabled" ); |
| 1055 | myOSystem.frameBuffer().showMessage(message); |
| 1056 | } |
| 1057 | |
| 1058 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1059 | void Console::toggleBits() const |
| 1060 | { |
| 1061 | bool enabled = myTIA->toggleBits(); |
| 1062 | string message = string("TIA bits" ) + (enabled ? " enabled" : " disabled" ); |
| 1063 | myOSystem.frameBuffer().showMessage(message); |
| 1064 | } |
| 1065 | |
| 1066 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1067 | void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show) const |
| 1068 | { |
| 1069 | bool result = myTIA->toggleCollision(bit); |
| 1070 | string message = bitname + (result ? " collision enabled" : " collision disabled" ); |
| 1071 | myOSystem.frameBuffer().showMessage(message); |
| 1072 | } |
| 1073 | |
| 1074 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1075 | void Console::toggleCollisions() const |
| 1076 | { |
| 1077 | bool enabled = myTIA->toggleCollisions(); |
| 1078 | string message = string("TIA collisions" ) + (enabled ? " enabled" : " disabled" ); |
| 1079 | myOSystem.frameBuffer().showMessage(message); |
| 1080 | } |
| 1081 | |
| 1082 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1083 | void Console::toggleFixedColors() const |
| 1084 | { |
| 1085 | if(myTIA->toggleFixedColors()) |
| 1086 | myOSystem.frameBuffer().showMessage("Fixed debug colors enabled" ); |
| 1087 | else |
| 1088 | myOSystem.frameBuffer().showMessage("Fixed debug colors disabled" ); |
| 1089 | } |
| 1090 | |
| 1091 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1092 | void Console::toggleJitter() const |
| 1093 | { |
| 1094 | bool enabled = myTIA->toggleJitter(); |
| 1095 | string message = string("TV scanline jitter" ) + (enabled ? " enabled" : " disabled" ); |
| 1096 | myOSystem.frameBuffer().showMessage(message); |
| 1097 | } |
| 1098 | |
| 1099 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1100 | void Console::attachDebugger(Debugger& dbg) |
| 1101 | { |
| 1102 | #ifdef DEBUGGER_SUPPORT |
| 1103 | // myOSystem.createDebugger(*this); |
| 1104 | mySystem->m6502().attach(dbg); |
| 1105 | #endif |
| 1106 | } |
| 1107 | |
| 1108 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1109 | void Console::stateChanged(EventHandlerState state) |
| 1110 | { |
| 1111 | // only the CompuMate used to care about state changes |
| 1112 | } |
| 1113 | |
| 1114 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1115 | uInt32 Console::ourNTSCPalette[256] = { |
| 1116 | 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, |
| 1117 | 0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0, |
| 1118 | 0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0, |
| 1119 | 0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0, |
| 1120 | 0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0, |
| 1121 | 0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0, |
| 1122 | 0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0, |
| 1123 | 0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0, |
| 1124 | 0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0, |
| 1125 | 0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0, |
| 1126 | 0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0, |
| 1127 | 0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0, |
| 1128 | 0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0, |
| 1129 | 0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0, |
| 1130 | 0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0, |
| 1131 | 0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0, |
| 1132 | 0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0, |
| 1133 | 0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0, |
| 1134 | 0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0, |
| 1135 | 0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0, |
| 1136 | 0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0, |
| 1137 | 0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0, |
| 1138 | 0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0, |
| 1139 | 0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0, |
| 1140 | 0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0, |
| 1141 | 0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0, |
| 1142 | 0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0, |
| 1143 | 0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0, |
| 1144 | 0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0, |
| 1145 | 0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0, |
| 1146 | 0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0, |
| 1147 | 0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0 |
| 1148 | }; |
| 1149 | |
| 1150 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1151 | uInt32 Console::ourPALPalette[256] = { |
| 1152 | 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 180 0 |
| 1153 | 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, // was 0x111111..0xcccccc |
| 1154 | 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 198 1 |
| 1155 | 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, |
| 1156 | 0x1d0f00, 0, 0x3f2700, 0, 0x614900, 0, 0x836b01, 0, // 1b0 2 |
| 1157 | 0xa58d23, 0, 0xc7af45, 0, 0xe9d167, 0, 0xffe789, 0, // was ..0xfff389 |
| 1158 | 0x002400, 0, 0x004600, 0, 0x216800, 0, 0x438a07, 0, // 1c8 3 |
| 1159 | 0x65ac29, 0, 0x87ce4b, 0, 0xa9f06d, 0, 0xcbff8f, 0, |
| 1160 | 0x340000, 0, 0x561400, 0, 0x783602, 0, 0x9a5824, 0, // 1e0 4 |
| 1161 | 0xbc7a46, 0, 0xde9c68, 0, 0xffbe8a, 0, 0xffd0ad, 0, // was ..0xffe0ac |
| 1162 | 0x002700, 0, 0x004900, 0, 0x0c6b0c, 0, 0x2e8d2e, 0, // 1f8 5 |
| 1163 | 0x50af50, 0, 0x72d172, 0, 0x94f394, 0, 0xb6ffb6, 0, |
| 1164 | 0x3d0008, 0, 0x610511, 0, 0x832733, 0, 0xa54955, 0, // 210 6 |
| 1165 | 0xc76b77, 0, 0xe98d99, 0, 0xffafbb, 0, 0xffd1d7, 0, // was 0x3f0000..0xffd1dd |
| 1166 | 0x001e12, 0, 0x004228, 0, 0x046540, 0, 0x268762, 0, // 228 7 |
| 1167 | 0x48a984, 0, 0x6acba6, 0, 0x8cedc8, 0, 0xafffe0, 0, // was 0x002100, 0x00431e..0xaeffff |
| 1168 | 0x300025, 0, 0x5f0047, 0, 0x811e69, 0, 0xa3408b, 0, // 240 8 |
| 1169 | 0xc562ad, 0, 0xe784cf, 0, 0xffa8ea, 0, 0xffc9f2, 0, // was ..0xffa6f1, 0xffc8ff |
| 1170 | 0x001431, 0, 0x003653, 0, 0x0a5875, 0, 0x2c7a97, 0, // 258 9 |
| 1171 | 0x4e9cb9, 0, 0x70bedb, 0, 0x92e0fd, 0, 0xb4ffff, 0, |
| 1172 | 0x2c0052, 0, 0x4e0074, 0, 0x701d96, 0, 0x923fb8, 0, // 270 a |
| 1173 | 0xb461da, 0, 0xd683fc, 0, 0xe2a5ff, 0, 0xeec9ff, 0, // was ..0xf8a5ff, 0xffc7ff |
| 1174 | 0x001759, 0, 0x00247c, 0, 0x1d469e, 0, 0x3f68c0, 0, // 288 b |
| 1175 | 0x618ae2, 0, 0x83acff, 0, 0xa5ceff, 0, 0xc7f0ff, 0, |
| 1176 | 0x12006d, 0, 0x34038f, 0, 0x5625b1, 0, 0x7847d3, 0, // 2a0 c |
| 1177 | 0x9a69f5, 0, 0xb48cff, 0, 0xc9adff, 0, 0xe1d1ff, 0, // was ..0xbc8bff, 0xdeadff, 0xffcfff, |
| 1178 | 0x000070, 0, 0x161292, 0, 0x3834b4, 0, 0x5a56d6, 0, // 2b8 d |
| 1179 | 0x7c78f8, 0, 0x9e9aff, 0, 0xc0bcff, 0, 0xe2deff, 0, |
| 1180 | 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2d0 e |
| 1181 | 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, |
| 1182 | 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2e8 f |
| 1183 | 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, |
| 1184 | }; |
| 1185 | |
| 1186 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1187 | uInt32 Console::ourSECAMPalette[256] = { |
| 1188 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1189 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1190 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1191 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1192 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1193 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1194 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1195 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1196 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1197 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1198 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1199 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1200 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1201 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1202 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1203 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1204 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1205 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1206 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1207 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1208 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1209 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1210 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1211 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1212 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1213 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1214 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1215 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1216 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1217 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1218 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, |
| 1219 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 |
| 1220 | }; |
| 1221 | |
| 1222 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1223 | uInt32 Console::ourNTSCPaletteZ26[256] = { |
| 1224 | 0x000000, 0, 0x505050, 0, 0x646464, 0, 0x787878, 0, |
| 1225 | 0x8c8c8c, 0, 0xa0a0a0, 0, 0xb4b4b4, 0, 0xc8c8c8, 0, |
| 1226 | 0x445400, 0, 0x586800, 0, 0x6c7c00, 0, 0x809000, 0, |
| 1227 | 0x94a414, 0, 0xa8b828, 0, 0xbccc3c, 0, 0xd0e050, 0, |
| 1228 | 0x673900, 0, 0x7b4d00, 0, 0x8f6100, 0, 0xa37513, 0, |
| 1229 | 0xb78927, 0, 0xcb9d3b, 0, 0xdfb14f, 0, 0xf3c563, 0, |
| 1230 | 0x7b2504, 0, 0x8f3918, 0, 0xa34d2c, 0, 0xb76140, 0, |
| 1231 | 0xcb7554, 0, 0xdf8968, 0, 0xf39d7c, 0, 0xffb190, 0, |
| 1232 | 0x7d122c, 0, 0x912640, 0, 0xa53a54, 0, 0xb94e68, 0, |
| 1233 | 0xcd627c, 0, 0xe17690, 0, 0xf58aa4, 0, 0xff9eb8, 0, |
| 1234 | 0x730871, 0, 0x871c85, 0, 0x9b3099, 0, 0xaf44ad, 0, |
| 1235 | 0xc358c1, 0, 0xd76cd5, 0, 0xeb80e9, 0, 0xff94fd, 0, |
| 1236 | 0x5d0b92, 0, 0x711fa6, 0, 0x8533ba, 0, 0x9947ce, 0, |
| 1237 | 0xad5be2, 0, 0xc16ff6, 0, 0xd583ff, 0, 0xe997ff, 0, |
| 1238 | 0x401599, 0, 0x5429ad, 0, 0x683dc1, 0, 0x7c51d5, 0, |
| 1239 | 0x9065e9, 0, 0xa479fd, 0, 0xb88dff, 0, 0xcca1ff, 0, |
| 1240 | 0x252593, 0, 0x3939a7, 0, 0x4d4dbb, 0, 0x6161cf, 0, |
| 1241 | 0x7575e3, 0, 0x8989f7, 0, 0x9d9dff, 0, 0xb1b1ff, 0, |
| 1242 | 0x0f3480, 0, 0x234894, 0, 0x375ca8, 0, 0x4b70bc, 0, |
| 1243 | 0x5f84d0, 0, 0x7398e4, 0, 0x87acf8, 0, 0x9bc0ff, 0, |
| 1244 | 0x04425a, 0, 0x18566e, 0, 0x2c6a82, 0, 0x407e96, 0, |
| 1245 | 0x5492aa, 0, 0x68a6be, 0, 0x7cbad2, 0, 0x90cee6, 0, |
| 1246 | 0x044f30, 0, 0x186344, 0, 0x2c7758, 0, 0x408b6c, 0, |
| 1247 | 0x549f80, 0, 0x68b394, 0, 0x7cc7a8, 0, 0x90dbbc, 0, |
| 1248 | 0x0f550a, 0, 0x23691e, 0, 0x377d32, 0, 0x4b9146, 0, |
| 1249 | 0x5fa55a, 0, 0x73b96e, 0, 0x87cd82, 0, 0x9be196, 0, |
| 1250 | 0x1f5100, 0, 0x336505, 0, 0x477919, 0, 0x5b8d2d, 0, |
| 1251 | 0x6fa141, 0, 0x83b555, 0, 0x97c969, 0, 0xabdd7d, 0, |
| 1252 | 0x344600, 0, 0x485a00, 0, 0x5c6e14, 0, 0x708228, 0, |
| 1253 | 0x84963c, 0, 0x98aa50, 0, 0xacbe64, 0, 0xc0d278, 0, |
| 1254 | 0x463e00, 0, 0x5a5205, 0, 0x6e6619, 0, 0x827a2d, 0, |
| 1255 | 0x968e41, 0, 0xaaa255, 0, 0xbeb669, 0, 0xd2ca7d, 0 |
| 1256 | }; |
| 1257 | |
| 1258 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1259 | uInt32 Console::ourPALPaletteZ26[256] = { |
| 1260 | 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, |
| 1261 | 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, |
| 1262 | 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, |
| 1263 | 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, |
| 1264 | 0x533a00, 0, 0x674e00, 0, 0x7b6203, 0, 0x8f7617, 0, |
| 1265 | 0xa38a2b, 0, 0xb79e3f, 0, 0xcbb253, 0, 0xdfc667, 0, |
| 1266 | 0x1b5800, 0, 0x2f6c00, 0, 0x438001, 0, 0x579415, 0, |
| 1267 | 0x6ba829, 0, 0x7fbc3d, 0, 0x93d051, 0, 0xa7e465, 0, |
| 1268 | 0x6a2900, 0, 0x7e3d12, 0, 0x925126, 0, 0xa6653a, 0, |
| 1269 | 0xba794e, 0, 0xce8d62, 0, 0xe2a176, 0, 0xf6b58a, 0, |
| 1270 | 0x075b00, 0, 0x1b6f11, 0, 0x2f8325, 0, 0x439739, 0, |
| 1271 | 0x57ab4d, 0, 0x6bbf61, 0, 0x7fd375, 0, 0x93e789, 0, |
| 1272 | 0x741b2f, 0, 0x882f43, 0, 0x9c4357, 0, 0xb0576b, 0, |
| 1273 | 0xc46b7f, 0, 0xd87f93, 0, 0xec93a7, 0, 0xffa7bb, 0, |
| 1274 | 0x00572e, 0, 0x106b42, 0, 0x247f56, 0, 0x38936a, 0, |
| 1275 | 0x4ca77e, 0, 0x60bb92, 0, 0x74cfa6, 0, 0x88e3ba, 0, |
| 1276 | 0x6d165f, 0, 0x812a73, 0, 0x953e87, 0, 0xa9529b, 0, |
| 1277 | 0xbd66af, 0, 0xd17ac3, 0, 0xe58ed7, 0, 0xf9a2eb, 0, |
| 1278 | 0x014c5e, 0, 0x156072, 0, 0x297486, 0, 0x3d889a, 0, |
| 1279 | 0x519cae, 0, 0x65b0c2, 0, 0x79c4d6, 0, 0x8dd8ea, 0, |
| 1280 | 0x5f1588, 0, 0x73299c, 0, 0x873db0, 0, 0x9b51c4, 0, |
| 1281 | 0xaf65d8, 0, 0xc379ec, 0, 0xd78dff, 0, 0xeba1ff, 0, |
| 1282 | 0x123b87, 0, 0x264f9b, 0, 0x3a63af, 0, 0x4e77c3, 0, |
| 1283 | 0x628bd7, 0, 0x769feb, 0, 0x8ab3ff, 0, 0x9ec7ff, 0, |
| 1284 | 0x451e9d, 0, 0x5932b1, 0, 0x6d46c5, 0, 0x815ad9, 0, |
| 1285 | 0x956eed, 0, 0xa982ff, 0, 0xbd96ff, 0, 0xd1aaff, 0, |
| 1286 | 0x2a2b9e, 0, 0x3e3fb2, 0, 0x5253c6, 0, 0x6667da, 0, |
| 1287 | 0x7a7bee, 0, 0x8e8fff, 0, 0xa2a3ff, 0, 0xb6b7ff, 0, |
| 1288 | 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, |
| 1289 | 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, |
| 1290 | 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, |
| 1291 | 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0 |
| 1292 | }; |
| 1293 | |
| 1294 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1295 | uInt32 Console::ourSECAMPaletteZ26[256] = { |
| 1296 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1297 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1298 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1299 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1300 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1301 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1302 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1303 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1304 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1305 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1306 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1307 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1308 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1309 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1310 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1311 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1312 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1313 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1314 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1315 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1316 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1317 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1318 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1319 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1320 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1321 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1322 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1323 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1324 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1325 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, |
| 1326 | 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, |
| 1327 | 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 |
| 1328 | }; |
| 1329 | |
| 1330 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1331 | uInt32 Console::ourUserNTSCPalette[256] = { 0 }; // filled from external file |
| 1332 | |
| 1333 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1334 | uInt32 Console::ourUserPALPalette[256] = { 0 }; // filled from external file |
| 1335 | |
| 1336 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1337 | uInt32 Console::ourUserSECAMPalette[256] = { 0 }; // filled from external file |
| 1338 | |