diff --git a/docs/graphics/options_video_palettes.png b/docs/graphics/options_video_palettes.png index 2a6f66be8..9c231eb92 100644 Binary files a/docs/graphics/options_video_palettes.png and b/docs/graphics/options_video_palettes.png differ diff --git a/docs/index.html b/docs/index.html index 67ad5604f..53a393266 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2608,6 +2608,16 @@ Adjust gamma of current palette (range -1.0 to 1.0). + +
-detectpal60 <1|0>
+ Enable autodetection of PAL-60 based on colors used.. + + + +
-detectntsc50 <1|0>
+ Enable autodetection of NTSC-50 based on colors used.. + +
-speed <number>
Control the emulation speed (as a percentage, 10 - 1000). @@ -3642,15 +3652,17 @@ - - - - + + + + +
ItemBrief descriptionFor more information,
see Command Line
PalettePalette used for emulation mode-palette
NTSC/PAL phaseAdjust phase shift of 'Custom' NTSC or PAL (depends on game) palette. -pal.phase_ntsc, -pal.phase_pal
RAdjust red scale and shift of 'Custom' palette-pal.red_scale, -pal.red_shift
GAdjust green scale and shift of 'Custom' palette-pal.green_scale, -pal.green_shift
BAdjust blue scale and shift of 'Custom' palette-pal.blue_scale, -pal.blue_shift
NTSC/PAL phaseAdjust phase shift of 'Custom' NTSC or PAL (depends on game) palette.-pal.phase_ntsc
-pal.phase_pal
RAdjust red scale and shift of 'Custom' palette-pal.red_scale
-pal.red_shift
GAdjust green scale and shift of 'Custom' palette-pal.green_scale
-pal.green_shift
BAdjust blue scale and shift of 'Custom' palette-pal.blue_scale
-pal.blue_shift
HueAdjust hue of currently selected palette-pal.hue
SaturationAdjust saturation of currently selected palette-pal.saturation
ContrastAdjust contrast of currently selected palette-pal.contrast
BrightnessAdjust brightness of currently selected palette-pal.brightness
GammaAdjust gamma of currently selected palette-pal.gamma
AutodetectionEnable autodetection of PAL-60/NTSC-50 based on colors used.
+ Note: The detection is not very reliable and therefore uses very conservative parameters to avoid false positives.
-detectpal60
-detectntsc50
@@ -3666,7 +3678,7 @@ - + diff --git a/src/common/main.cxx b/src/common/main.cxx index 1354801f7..b2ebb5e58 100644 --- a/src/common/main.cxx +++ b/src/common/main.cxx @@ -74,6 +74,15 @@ void checkForCustomBaseDir(Settings::Options& options); */ bool isProfilingRun(int ac, char* av[]); +/** + In Windows, attach console to allow command line output (e.g. for -help). + This is needed since by default Windows doesn't set up stdout/stderr + correctly. +*/ +void attachConsole(); +void freeConsole(); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void parseCommandLine(int ac, char* av[], Settings::Options& globalOpts, Settings::Options& localOpts) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index edb160d1e..6dcfbb238 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -280,25 +280,54 @@ void Console::autodetectFrameLayout(bool reset) // We turn off the SuperCharger progress bars, otherwise the SC BIOS // will take over 250 frames! // The 'fastscbios' option must be changed before the system is reset - bool fastscbios = myOSystem.settings().getBool("fastscbios"); - myOSystem.settings().setValue("fastscbios", true); + Settings& settings = myOSystem.settings(); + bool fastscbios = settings.getBool("fastscbios"); + settings.setValue("fastscbios", true); FrameLayoutDetector frameLayoutDetector; - myTIA->setFrameManager(&frameLayoutDetector); + myTIA->setFrameManager(&frameLayoutDetector, true); if (reset) { mySystem->reset(true); myRiot->update(); } - for(int i = 0; i < 60; ++i) myTIA->update(); + // Sample colors, ratio is 1/5 title (if existing), 4/5 game screen. + for(int i = 0; i < 20; ++i) + myTIA->update(); + + frameLayoutDetector.simulateInput(*myRiot, myOSystem.eventHandler(), true); + myTIA->update(); + frameLayoutDetector.simulateInput(*myRiot, myOSystem.eventHandler(), false); + + for(int i = 0; i < 40; ++i) + myTIA->update(); + + switch(frameLayoutDetector.detectedLayout( + settings.getBool("detectpal60"), settings.getBool("detectntsc50"), + myProperties.get(PropType::Cart_Name))) + { + case FrameLayout::pal: + myDisplayFormat = "PAL"; + break; + + case FrameLayout::pal60: + myDisplayFormat = "PAL60"; + break; + + case FrameLayout::ntsc50: + myDisplayFormat = "NTSC50"; + break; + + default: + myDisplayFormat = "NTSC"; + break; + } myTIA->setFrameManager(myFrameManager.get()); - myDisplayFormat = frameLayoutDetector.detectedLayout() == FrameLayout::pal ? "PAL" : "NTSC"; - // Don't forget to reset the SC progress bars again - myOSystem.settings().setValue("fastscbios", fastscbios); + settings.setValue("fastscbios", fastscbios); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/ProfilingRunner.cxx b/src/emucore/ProfilingRunner.cxx index 95c43ba99..b64b80845 100644 --- a/src/emucore/ProfilingRunner.cxx +++ b/src/emucore/ProfilingRunner.cxx @@ -157,6 +157,9 @@ bool ProfilingRunner::runOne(const ProfilingRun& run) cout << "PAL"; consoleTiming = ConsoleTiming::pal; break; + + default: // TODO: add other layouts here + break; } (cout << endl).flush(); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index d6e31cd31..2613eb512 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -92,6 +92,9 @@ Settings::Settings() setPermanent("tv.fringing", "0.0"); setPermanent("tv.bleed", "0.0"); + setPermanent("detectpal60", "false"); + setPermanent("detectntsc50", "false"); + // Sound options setPermanent(AudioSettings::SETTING_ENABLED, AudioSettings::DEFAULT_ENABLED); setPermanent(AudioSettings::SETTING_VOLUME, AudioSettings::DEFAULT_VOLUME); @@ -516,6 +519,9 @@ void Settings::usage() const << " -pal.brightness <-1.0 - 1.0> Adjust brightness of current palette\n" << " -pal.gamma <-1.0 - 1.0> Adjust gamma of current palette\n" << endl + << " -detectpal60 <1|0> Enable PAL-60 autodetection\n" + << " -detectntsc50 <1|0> Enable NTSC-50 autodetection\n" + << endl << " -speed Run emulation at the given speed\n" << " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n" << " -uimessages <1|0> Show onscreen UI messages for different events\n" diff --git a/src/emucore/tia/FrameLayout.hxx b/src/emucore/tia/FrameLayout.hxx index affbf7da1..6c6dabba4 100644 --- a/src/emucore/tia/FrameLayout.hxx +++ b/src/emucore/tia/FrameLayout.hxx @@ -19,8 +19,10 @@ #define FRAME_LAYOUT enum class FrameLayout { - ntsc, // ROM display has NTSC timings (~60Hz, ~262 scanlines, etc) - pal // ROM display has PAL timings (~50Hz, ~312 scanlines, etc) + ntsc, // ROM display has NTSC timings (~60Hz, ~262 scanlines, etc) + pal, // ROM display has PAL timings (~50Hz, ~312 scanlines, etc) + pal60, // ROM display has NTSC timings (~60Hz, ~262 scanlines, etc), but uses PAL colors + ntsc50 // ROM display has PAL timings (~50Hz, ~312 scanlines, etc), but uses NTSC colors }; #endif // FRAME_LAYOUT diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index 4c61e197f..5b94814a0 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -88,11 +88,12 @@ TIA::TIA(ConsoleIO& console, const ConsoleTimingProvider& timingProvider, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::setFrameManager(AbstractFrameManager* frameManager) +void TIA::setFrameManager(AbstractFrameManager* frameManager, bool layoutDetector) { clearFrameManager(); myFrameManager = frameManager; + myIsLayoutDetector = layoutDetector; myFrameManager->setHandlers( [this] () { @@ -1559,12 +1560,21 @@ void TIA::nextLine() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::cloneLastLine() { - const auto y = myFrameManager->getY(); + if(myIsLayoutDetector) + { + // y is always 0 in FrameLayoutDetector + for(uInt32 i = 0 ; i < TIAConstants::H_PIXEL; ++i) + myFrameManager->pixelColor(myBackBuffer[i]); + } + else + { + const auto y = myFrameManager->getY(); - if (!myFrameManager->isRendering() || y == 0) return; + if(!myFrameManager->isRendering() || y == 0) return; - std::copy_n(myBackBuffer.begin() + (y-1) * TIAConstants::H_PIXEL, TIAConstants::H_PIXEL, - myBackBuffer.begin() + y * TIAConstants::H_PIXEL); + std::copy_n(myBackBuffer.begin() + (y - 1) * TIAConstants::H_PIXEL, TIAConstants::H_PIXEL, + myBackBuffer.begin() + y * TIAConstants::H_PIXEL); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1642,6 +1652,8 @@ void TIA::renderPixel(uInt32 x, uInt32 y) } myBackBuffer[y * TIAConstants::H_PIXEL + x] = color; + if (myIsLayoutDetector) + myFrameManager->pixelColor(color); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index 3c80163a4..77714b132 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -123,7 +123,7 @@ class TIA : public Device /** Configure the frame manager. */ - void setFrameManager(AbstractFrameManager* frameManager); + void setFrameManager(AbstractFrameManager* frameManager, bool layoutDetector = false); /** Set the audio queue. This needs to be dynamic as the queue is created after @@ -794,6 +794,11 @@ class TIA : public Device */ AbstractFrameManager* myFrameManager{nullptr}; + /** + * The frame manager type. + */ + bool myIsLayoutDetector{false}; + /** * The various TIA objects. */ diff --git a/src/emucore/tia/frame-manager/AbstractFrameManager.hxx b/src/emucore/tia/frame-manager/AbstractFrameManager.hxx index a69b5118c..bcaef4589 100644 --- a/src/emucore/tia/frame-manager/AbstractFrameManager.hxx +++ b/src/emucore/tia/frame-manager/AbstractFrameManager.hxx @@ -69,6 +69,11 @@ class AbstractFrameManager : public Serializable */ void setVsync(bool vsync, uInt64 cycles); + /** + * Called when a pixel is rendered. + */ + virtual void pixelColor(uInt8 color) {} + /** * Should the TIA render its frame? This is buffered in a flag for * performance reasons; descendants must update the flag. diff --git a/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx b/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx index 6861ff8bb..5bce1774c 100644 --- a/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx +++ b/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx @@ -15,13 +15,122 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "EventHandler.hxx" +#include "Logger.hxx" +#include "M6532.hxx" + #include "FrameLayoutDetector.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameLayout FrameLayoutDetector::detectedLayout() const +void FrameLayoutDetector::simulateInput(M6532& riot, EventHandler& eventHandler, bool pressed) const { - // We choose the mode that was detected for the majority of frames. - return myPalFrames > myNtscFrames ? FrameLayout::pal : FrameLayout::ntsc; + // Console + eventHandler.handleEvent(Event::ConsoleSelect, pressed); + eventHandler.handleEvent(Event::ConsoleReset, pressed); + // Various controller types + eventHandler.handleEvent(Event::LeftJoystickFire, pressed); + eventHandler.handleEvent(Event::RightJoystickFire, pressed); + // Required for Console::redetectFrameLayout + eventHandler.handleEvent(Event::LeftPaddleAFire, pressed); + eventHandler.handleEvent(Event::LeftPaddleBFire, pressed); + eventHandler.handleEvent(Event::RightPaddleAFire, pressed); + eventHandler.handleEvent(Event::RightPaddleBFire, pressed); + eventHandler.handleEvent(Event::LeftDrivingFire, pressed); + eventHandler.handleEvent(Event::RightDrivingFire, pressed); + riot.update(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FrameLayout FrameLayoutDetector::detectedLayout(bool detectPal60, bool detectNtsc50, const string& name) const +{ +#if 0 // debug + cerr << endl << name << endl; + int i = 0; + for(auto count : myColorCount) + { + if(i % 8 == 0) + cerr << std::uppercase << std::setw(2) << std::hex << (i >> 3) << "x: "; + cerr << std::setw(6) << std::dec << count; + if(++i % 8 == 0) + cerr << endl; + else + cerr << ", "; + } + cerr << endl; +#endif +#if 0 // save sampled color values + std::ofstream file; + + file.open("d:/Users/Thomas/Documents/Atari/Games/test/autodetect/colors.csv", std::ios::app); + if(file.is_open()) + { + file << name; + for(auto count : myColorCount) + file << "; " << count; + file << "\n"; + file.close(); + } +#endif + + // Multiply each hue's count with its NTSC and PAL stats and aggregate results + // If NTSC/PAL results differ significantly, overrule frame result + FrameLayout layout = myPalFrames > myNtscFrames ? FrameLayout::pal : FrameLayout::ntsc; + + constexpr std::array ntscColorFactor{ + 0.00000, 0.05683, 0.06220, 0.05505, 0.06162, 0.02874, 0.03532, 0.03716, + 0.15568, 0.06471, 0.02886, 0.03224, 0.06903, 0.11478, 0.02632, 0.01675 + }; // ignore black = 0x00! + constexpr std::array palColorFactor{ + 0.00000, 0.00450, 0.09962, 0.07603, 0.06978, 0.13023, 0.09638, 0.02268, + 0.02871, 0.04700, 0.02950, 0.11974, 0.03474, 0.08025, 0.00642, 0.00167 + }; // ignore black = 0x00! + // Calculation weights and params (optimum based on sampled ROMs optimized for PAL-60) + constexpr double POWER_FACTOR = 0.17; // Level the color counts (large values become less relevant) + constexpr uInt32 SUM_DIV = 20; // Skip too small counts + constexpr uInt32 MIN_VALID = 3; // Minimum number of different hues with significant counts + constexpr double SUM_FACTOR = 2.0; // Minimum sum difference which triggers a layout change + + double ntscSum{0}, palSum{0}; + std::array hueSum{0}; + double totalHueSum = 0; + uInt32 validHues = 0; + + // Aggregate hues + for(int hue = 0; hue < NUM_HUES; ++hue) + { + for(int lum = 0; lum < NUM_LUMS; ++lum) + if(hue || lum) // skip 0x00 + hueSum[hue] += myColorCount[hue * NUM_LUMS + lum]; + hueSum[hue] = std::pow(hueSum[hue], POWER_FACTOR); + totalHueSum += hueSum[hue]; + } + // Calculate hue sums + for(int hue = 0; hue < NUM_HUES; ++hue) + { + if(hueSum[hue] > totalHueSum / SUM_DIV) + validHues++; + ntscSum += hueSum[hue] * ntscColorFactor[hue]; + palSum += hueSum[hue] * palColorFactor[hue]; + } + // Correct layout if enough valid hues and significant sum difference + // TODO: Use fractional scanline counts for intermediate values around 285 scanlines, e.g. + // Desert Falcon, Dumbo's Flying Circus, Dungeon, Firefox, Millipede, Popeye, RS Basketball, Star Trek, Stunt Cycle + if(validHues >= MIN_VALID) + { + if(detectPal60 && layout == FrameLayout::ntsc && ntscSum * SUM_FACTOR < palSum) + { + layout = FrameLayout::pal60; + Logger::debug("Changed layout from NTSC into PAL-60"); + } + // Note: three false positives (Berzerk, Canyon Bomber, Jawbreaker) for NTSC-50 after + // optimizing for PAL-60 + else if(detectNtsc50 && layout == FrameLayout::pal && palSum * SUM_FACTOR < ntscSum) + { + layout = FrameLayout::ntsc50; + Logger::debug("Changed layout from PAL into NTSC-50"); + } + } + return layout; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -36,6 +145,8 @@ void FrameLayoutDetector::onReset() myState = State::waitForVsyncStart; myNtscFrames = myPalFrames = 0; myLinesWaitingForVsyncToStart = 0; + myColorCount.fill(0); + myIsRendering = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -73,6 +184,16 @@ void FrameLayoutDetector::onNextLine() } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameLayoutDetector::pixelColor(uInt8 color) +{ + if(myTotalFrames > Metrics::initialGarbageFrames) + myColorCount[color >> 1]++; + // Ideas: + // - contrast to previous pixels (left/top) + // - ??? +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameLayoutDetector::setState(State state) { @@ -112,15 +233,15 @@ void FrameLayoutDetector::finalizeFrame() if (std::min(deltaNTSC, deltaPAL) <= Metrics::tvModeDetectionTolerance) layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); else if ( - // If scanline count is odd and lies between the PAL and NTSC windows we assume - // it is NTSC (it would cause color loss on PAL CRTs) + // If scanline count is odd and lies between the PAL and NTSC windows we assume + // it is NTSC (it would cause color loss on PAL CRTs) (myCurrentFrameFinalLines < frameLinesPAL) && (myCurrentFrameFinalLines > frameLinesNTSC) && (myCurrentFrameFinalLines % 2) ) layout(FrameLayout::ntsc); else - // Take the nearest layout if all else fails + // Take the nearest layout if all else fails layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); switch (layout()) { diff --git a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx index da72a0cf9..bdb8ad391 100644 --- a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx +++ b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx @@ -18,6 +18,9 @@ #ifndef TIA_FRAME_LAYOUT_DETECTOR #define TIA_FRAME_LAYOUT_DETECTOR +class M6532; +class EventHandler; + #include "FrameLayout.hxx" #include "AbstractFrameManager.hxx" #include "TIAConstants.hxx" @@ -37,7 +40,13 @@ class FrameLayoutDetector: public AbstractFrameManager /** * Return the detected frame layout. */ - FrameLayout detectedLayout() const; + FrameLayout detectedLayout(bool detectPal60 = false, bool detectNtsc50 = false, + const string& name = EmptyString) const; + + /** + * Simulate some input to pass a potential title screen. + */ + void simulateInput(M6532& riot, EventHandler& eventHandler, bool pressed) const; protected: @@ -56,6 +65,11 @@ class FrameLayoutDetector: public AbstractFrameManager */ void onNextLine() override; + /** + * Called when a pixel is rendered. + */ + void pixelColor(uInt8 color) override; + private: /** @@ -118,6 +132,16 @@ class FrameLayoutDetector: public AbstractFrameManager */ uInt32 myLinesWaitingForVsyncToStart{0}; + /** + * We count the number of pixels for each colors used. These are + * evaluated against statistical color distributions and, if + * decisive, allow overruling the scanline results. + */ + static constexpr int NUM_HUES = 16; + static constexpr int NUM_LUMS = 8; + + std::array myColorCount{0}; + private: FrameLayoutDetector(const FrameLayoutDetector&) = delete; diff --git a/src/emucore/tia/frame-manager/JitterEmulation.cxx b/src/emucore/tia/frame-manager/JitterEmulation.cxx index b151cb7e7..b31a20852 100644 --- a/src/emucore/tia/frame-manager/JitterEmulation.cxx +++ b/src/emucore/tia/frame-manager/JitterEmulation.cxx @@ -56,10 +56,10 @@ void JitterEmulation::setSensitivity(Int32 sensitivity) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JitterEmulation::frameComplete(Int32 scanlineCount, Int32 vsyncCycles) { -#ifdef DEBUG_BUILD - const int vsyncLines = round((vsyncCycles - 2) / 76.0); - cerr << "TV jitter " << myJitter << " - " << scanlineCount << ", " << vsyncCycles << ", " << vsyncLines << endl; -#endif +//#ifdef DEBUG_BUILD +// const int vsyncLines = round((vsyncCycles - 2) / 76.0); +// cerr << "TV jitter " << myJitter << " - " << scanlineCount << ", " << vsyncCycles << ", " << vsyncLines << endl; +//#endif // Check if current frame size is stable compared to previous frame const bool scanlinesStable = scanlineCount == myLastFrameScanlines; diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index e9192c223..eb83b563c 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -148,16 +148,16 @@ void GameInfoDialog::addEmulationTab() VarList::push_back(items, "NTSC", "NTSC"); VarList::push_back(items, "PAL", "PAL"); VarList::push_back(items, "SECAM", "SECAM"); - VarList::push_back(items, "NTSC50", "NTSC50"); - VarList::push_back(items, "PAL60", "PAL60"); - VarList::push_back(items, "SECAM60", "SECAM60"); + VarList::push_back(items, "NTSC-50", "NTSC50"); + VarList::push_back(items, "PAL-60", "PAL60"); + VarList::push_back(items, "SECAM-60", "SECAM60"); myFormat = new PopUpWidget(myTab, _font, t->getRight(), ypos, pwidth, lineHeight, items); myFormat->setToolTip(Event::FormatDecrease, Event::FormatIncrease); wid.push_back(myFormat); myFormatDetected = new StaticTextWidget(myTab, ifont, myFormat->getRight() + fontWidth, ypos + 4, - "SECAM60 detected"); + "SECAM-60 detected"); // Phosphor ypos += lineHeight + VGAP; diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 971011d87..9b0fe23f1 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -65,7 +65,7 @@ VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent, // Set real dimensions setSize(44 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, - _th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, + _th + VGAP * 5 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, max_w, max_h); // The tab widget @@ -312,6 +312,17 @@ void VideoAudioDialog::addPaletteTab() CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated) + ypos += VGAP; + StaticTextWidget* s = new StaticTextWidget(myTab, _font, xpos, ypos + 1, "Autodetection"); + + myDetectPal60 = new CheckboxWidget(myTab, _font, s->getRight() + fontWidth * 2, ypos + 1, "PAL-60"); + myDetectPal60 ->setToolTip("Enable autodetection of PAL-60 based on colors used."); + wid.push_back(myDetectPal60 ); + + myDetectNtsc50 = new CheckboxWidget(myTab, _font, myDetectPal60->getRight() + fontWidth * 2, ypos + 1, "NTSC-50"); + myDetectNtsc50 ->setToolTip("Enable autodetection of NTSC-50 based on colors used."); + wid.push_back(myDetectNtsc50 ); + // The resulting palette xpos = myPhaseShift->getRight() + fontWidth * 2; addPalette(xpos, VBORDER, _w - 2 * 2 - HBORDER - xpos, @@ -644,6 +655,10 @@ void VideoAudioDialog::loadConfig() handlePaletteChange(); colorPalette(); + // Autodetection + myDetectPal60->setState(settings.getBool("detectpal60")); + myDetectNtsc50->setState(settings.getBool("detectntsc50")); + ///////////////////////////////////////////////////////////////////////////// // TV Effects tab // TV Mode @@ -758,6 +773,10 @@ void VideoAudioDialog::saveConfig() Logger::debug("Saving palette settings..."); instance().frameBuffer().tiaSurface().paletteHandler().saveConfig(settings); + // Autodetection + settings.setValue("detectpal60", myDetectPal60->getState()); + settings.setValue("detectntsc50", myDetectNtsc50->getState()); + ///////////////////////////////////////////////////////////////////////////// // TV Effects tab // TV Mode @@ -893,6 +912,8 @@ void VideoAudioDialog::setDefaults() myTVGamma->setValue(50); handlePaletteChange(); handlePaletteUpdate(); + myDetectPal60->setState(false); + myDetectNtsc50->setState(false); break; } diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 098658145..7370e21fd 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -106,6 +106,8 @@ class VideoAudioDialog : public Dialog // Palettes PopUpWidget* myTIAPalette{nullptr}; + CheckboxWidget* myDetectPal60{nullptr}; + CheckboxWidget* myDetectNtsc50{nullptr}; SliderWidget* myPhaseShift{nullptr}; SliderWidget* myTVRedScale{nullptr}; SliderWidget* myTVRedShift{nullptr};
ItemBrief descriptionFor more information,
see Command Line
TV modeDisable TV effects, or select TV preset-tv.filter
Adjustable slidersSet specific attribute in 'Custom' TV mode-tv.sharpness, -tv.resolution, etc.
Adjustable slidersSet specific attribute in 'Custom' TV mode-tv.sharpness
-tv.resolution, etc.
Phosphor for all ROMsEnable phosphor mode for all ROMs-tv.phosphor
Blend (phosphor)Blend level to use in phosphor mode for all ROMs (needs to be manually adjusted for your particular hardware)-tv.phosblend