| 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 |  | 
|---|