From 85f438f6930f04e61deaad46178e531782a461b9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 19:53:59 +0200 Subject: [PATCH] added interactive palette display to VideoDialog --- src/common/PaletteHandler.cxx | 147 +++++++++++++----------- src/common/PaletteHandler.hxx | 26 +++-- src/gui/ColorWidget.cxx | 18 ++- src/gui/ColorWidget.hxx | 3 +- src/gui/VideoDialog.cxx | 210 ++++++++++++++++++++++++---------- src/gui/VideoDialog.hxx | 12 ++ 6 files changed, 274 insertions(+), 142 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index b260842b1..e6bce1494 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -46,7 +46,7 @@ PaletteHandler::PaletteType PaletteHandler::toPaletteType(const string& name) co // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PaletteHandler::toPaletteName(PaletteType type) const { - string SETTING_NAMES[int(PaletteType::NumTypes)] = { + const string SETTING_NAMES[int(PaletteType::NumTypes)] = { SETTING_STANDARD, SETTING_Z26, SETTING_USER, SETTING_CUSTOM }; @@ -56,7 +56,7 @@ string PaletteHandler::toPaletteName(PaletteType type) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changePalette(bool increase) { - string MESSAGES[PaletteType::NumTypes] = { + const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" }; @@ -98,7 +98,7 @@ void PaletteHandler::changePalette(bool increase) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::selectAdjustable(bool next) { - bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); + const bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); do { if(next) @@ -154,10 +154,54 @@ void PaletteHandler::changeAdjustable(bool increase) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeColorPhaseShift(bool increase) +{ + const ConsoleTiming timing = myOSystem.console().timing(); + + // SECAM is not supported + if(timing != ConsoleTiming::secam) + { + constexpr char DEGREE = 0x1c; + const bool isNTSC = timing == ConsoleTiming::ntsc; + const float shift = isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT; + float phase = isNTSC ? myPhaseNTSC : myPhasePAL; + + if(increase) // increase color phase shift + { + phase += 0.3F; + phase = std::min(phase, shift + MAX_SHIFT); + } + else // decrease color phase shift + { + phase -= 0.3F; + phase = std::max(phase, shift - MAX_SHIFT); + } + if(isNTSC) + myPhaseNTSC = phase; + else + myPhasePAL = phase; + + generateCustomPalette(timing); + setPalette("custom"); + + ostringstream ss; + ss << "Color phase shift at " + << std::fixed << std::setprecision(1) << phase << DEGREE; + + myOSystem.frameBuffer().showMessage(ss.str()); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::loadConfig(const Settings& settings) { // Load adjustables + myPhaseNTSC = BSPF::clamp(settings.getFloat("tv.phase_ntsc"), + DEF_NTSC_SHIFT - MAX_SHIFT, DEF_NTSC_SHIFT + MAX_SHIFT); + myPhasePAL = BSPF::clamp(settings.getFloat("tv.phase_pal"), + DEF_PAL_SHIFT - MAX_SHIFT, DEF_PAL_SHIFT + MAX_SHIFT); + myHue = BSPF::clamp(settings.getFloat("tv.hue"), -1.0F, 1.0F); mySaturation = BSPF::clamp(settings.getFloat("tv.saturation"), -1.0F, 1.0F); myContrast = BSPF::clamp(settings.getFloat("tv.contrast"), -1.0F, 1.0F); @@ -169,6 +213,9 @@ void PaletteHandler::loadConfig(const Settings& settings) void PaletteHandler::saveConfig(Settings& settings) const { // Save adjustables + settings.setValue("tv.phase_ntsc", myPhaseNTSC); + settings.setValue("tv.phase_pal", myPhasePAL); + settings.setValue("tv.hue", myHue); settings.setValue("tv.saturation", mySaturation); settings.setValue("tv.contrast", myContrast); @@ -177,8 +224,11 @@ void PaletteHandler::saveConfig(Settings& settings) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::setAdjustables(Adjustable& adjustable) +void PaletteHandler::setAdjustables(const Adjustable& adjustable) { + myPhaseNTSC = adjustable.phaseNtsc / 10.F; + myPhasePAL = adjustable.phasePal / 10.F; + myHue = scaleFrom100(adjustable.hue); mySaturation = scaleFrom100(adjustable.saturation); myContrast = scaleFrom100(adjustable.contrast); @@ -189,6 +239,9 @@ void PaletteHandler::setAdjustables(Adjustable& adjustable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::getAdjustables(Adjustable& adjustable) const { + adjustable.phaseNtsc = myPhaseNTSC * 10.F; + adjustable.phasePal = myPhasePAL * 10.F; + adjustable.hue = scaleTo100(myHue); adjustable.saturation = scaleTo100(mySaturation); adjustable.contrast = scaleTo100(myContrast); @@ -196,46 +249,6 @@ void PaletteHandler::getAdjustables(Adjustable& adjustable) const adjustable.gamma = scaleTo100(myGamma); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeColorPhaseShift(bool increase) -{ - const ConsoleTiming timing = myOSystem.console().timing(); - - // SECAM is not supported - if(timing != ConsoleTiming::secam) - { - const char DEGREE = 0x1c; - const float NTSC_SHIFT = 26.2F; - const float PAL_SHIFT = 31.3F; // 360 / 11.5 - const bool isNTSC = timing == ConsoleTiming::ntsc; - const string key = isNTSC ? "tv.phase_ntsc" : "tv.phase_pal"; - const float shift = isNTSC ? NTSC_SHIFT : PAL_SHIFT; - float phase = myOSystem.settings().getFloat(key); - - if(increase) // increase color phase shift - { - phase += 0.3F; - phase = std::min(phase, shift + 4.5F); - } - else // decrease color phase shift - { - phase -= 0.3F; - phase = std::max(phase, shift - 4.5F); - } - myOSystem.settings().setValue(key, phase); - generateCustomPalette(timing); - - setPalette("custom"); - - ostringstream ss; - ss << "Color phase shift at " - << std::fixed << std::setprecision(1) << phase << DEGREE; - - myOSystem.frameBuffer().showMessage(ss.str()); - } -} - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::setPalette(const string& name) { @@ -251,7 +264,7 @@ void PaletteHandler::setPalette() // Look at all the palettes, since we don't know which one is // currently active - static constexpr BSPF::array2D palettes = {{ + static constexpr BSPF::array2D palettes = {{ { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, @@ -274,19 +287,19 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) { PaletteArray destPalette; // Constants for saturation and gray scale calculation - const float PR = .2989F; - const float PG = .5870F; - const float PB = .1140F; + constexpr float PR = .2989F; + constexpr float PG = .5870F; + constexpr float PB = .1140F; // Generate adjust table - const int ADJUST_SIZE = 256; - const int RGB_UNIT = 1 << 8; - const float RGB_OFFSET = 0.5F; + constexpr int ADJUST_SIZE = 256; + constexpr int RGB_UNIT = 1 << 8; + constexpr float RGB_OFFSET = 0.5F; const float brightness = myBrightness * (0.5F * RGB_UNIT) + RGB_OFFSET; const float contrast = myContrast * (0.5F * RGB_UNIT) + RGB_UNIT; const float saturation = mySaturation + 1; const float gamma = 1.1333F - myGamma * 0.5F; /* match common PC's 2.2 gamma to TV's 2.65 gamma */ - const float toFloat = 1.F / (ADJUST_SIZE - 1); + constexpr float toFloat = 1.F / (ADJUST_SIZE - 1); std::array adjust; for(int i = 0; i < ADJUST_SIZE; i++) @@ -341,13 +354,13 @@ void PaletteHandler::loadUserPalette() for(int i = 0; i < 128; i++) // NTSC palette { in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserNTSCPalette[(i<<1)] = pixel; } for(int i = 0; i < 128; i++) // PAL palette { in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserPALPalette[(i<<1)] = pixel; } @@ -355,7 +368,7 @@ void PaletteHandler::loadUserPalette() for(int i = 0; i < 8; i++) // SECAM palette { in.read(reinterpret_cast(pixbuf.data()), 3); - uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); + const uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); secam[(i<<1)] = pixel; secam[(i<<1)+1] = 0; } @@ -383,8 +396,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) { // YIQ is YUV shifted by 33° constexpr float offset = 33 * (2 * BSPF::PI_f / 360); - const float shift = myOSystem.settings().getFloat("tv.phase_ntsc") * - (2 * BSPF::PI_f / 360); + const float shift = myPhaseNTSC * (2 * BSPF::PI_f / 360); // color 0 is grayscale for(int chroma = 1; chroma < NUM_CHROMA; chroma++) @@ -429,8 +441,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) else if(timing == ConsoleTiming::pal) { constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - float shift = myOSystem.settings().getFloat("tv.phase_pal") * - (2 * BSPF::PI_f / 360); + const float shift = myPhasePAL * (2 * BSPF::PI_f / 360); constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); // colors 0, 1, 14 and 15 are grayscale @@ -453,11 +464,10 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) { const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - // Most sources + // Most sources float R = Y + 1.403F * V; float G = Y - 0.344F * U - 0.714F * V; float B = Y + 1.770F * U; - // German Wikipedia, huh??? //float B = Y + 1 / 0.493 * U; //float R = Y + 1 / 0.877 * V; @@ -504,8 +514,7 @@ void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) constexpr float PR = .2989F; constexpr float PG = .5870F; constexpr float PB = .1140F; - - float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; + const float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; R = P + (R - P) * change; G = P + (G - P) * change; @@ -517,7 +526,7 @@ void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourNTSCPalette = { +const PaletteArray PaletteHandler::ourNTSCPalette = { 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, 0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0, 0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0, @@ -553,7 +562,7 @@ PaletteArray PaletteHandler::ourNTSCPalette = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourPALPalette = { +const PaletteArray PaletteHandler::ourPALPalette = { 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 180 0 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, // was 0x111111..0xcccccc 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 198 1 @@ -589,7 +598,7 @@ PaletteArray PaletteHandler::ourPALPalette = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourSECAMPalette = { +const PaletteArray PaletteHandler::ourSECAMPalette = { 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, @@ -625,7 +634,7 @@ PaletteArray PaletteHandler::ourSECAMPalette = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourNTSCPaletteZ26 = { +const PaletteArray PaletteHandler::ourNTSCPaletteZ26 = { 0x000000, 0, 0x505050, 0, 0x646464, 0, 0x787878, 0, 0x8c8c8c, 0, 0xa0a0a0, 0, 0xb4b4b4, 0, 0xc8c8c8, 0, 0x445400, 0, 0x586800, 0, 0x6c7c00, 0, 0x809000, 0, @@ -661,7 +670,7 @@ PaletteArray PaletteHandler::ourNTSCPaletteZ26 = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourPALPaletteZ26 = { +const PaletteArray PaletteHandler::ourPALPaletteZ26 = { 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, @@ -697,7 +706,7 @@ PaletteArray PaletteHandler::ourPALPaletteZ26 = { }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::ourSECAMPaletteZ26 = { +const PaletteArray PaletteHandler::ourSECAMPaletteZ26 = { 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 995018e1e..7c0f69dfc 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -20,6 +20,7 @@ #include "bspf.hxx" #include "OSystem.hxx" +#include "ConsoleTiming.hxx" class PaletteHandler { @@ -29,6 +30,10 @@ class PaletteHandler static constexpr const char* SETTING_USER = "user"; static constexpr const char* SETTING_CUSTOM = "custom"; + static constexpr float DEF_NTSC_SHIFT = 26.2F; + static constexpr float DEF_PAL_SHIFT = 31.3F; // 360 / 11.5 + static constexpr float MAX_SHIFT = 4.5F; + enum DisplayType { NTSC, PAL, @@ -37,6 +42,7 @@ class PaletteHandler }; struct Adjustable { + float phaseNtsc, phasePal; uInt32 hue, saturation, contrast, brightness, gamma; }; @@ -55,7 +61,7 @@ class PaletteHandler void loadConfig(const Settings& settings); void saveConfig(Settings& settings) const; - void setAdjustables(Adjustable& adjustable); + void setAdjustables(const Adjustable& adjustable); void getAdjustables(Adjustable& adjustable) const; /** @@ -114,7 +120,7 @@ class PaletteHandler private: - static const int NUM_ADJUSTABLES = 6; + static constexpr int NUM_ADJUSTABLES = 6; OSystem& myOSystem; @@ -133,11 +139,13 @@ class PaletteHandler { "gamma", &myGamma }, } }; + float myPhaseNTSC{0.0F}; + float myPhasePAL{0.0F}; // range -1.0 to +1.0 (as in AtariNTSC) // Basic parameters - float myContrast{0.0F}; // -1 = dark (0.5) +1 = light (1.5) float myHue{0.0F}; // -1 = -180 degrees +1 = +180 degrees float mySaturation{0.0F}; // -1 = grayscale (0.0) +1 = oversaturated colors (2.0) + float myContrast{0.0F}; // -1 = dark (0.5) +1 = light (1.5) float myBrightness{0.0F}; // -1 = dark (0.5) +1 = light (1.5) // Advanced parameters float myGamma{0.0F}; // -1 = dark (1.5) +1 = light (0.5) @@ -147,14 +155,14 @@ class PaletteHandler bool myUserPaletteDefined{false}; // Table of RGB values for NTSC, PAL and SECAM - static PaletteArray ourNTSCPalette; - static PaletteArray ourPALPalette; - static PaletteArray ourSECAMPalette; + static const PaletteArray ourNTSCPalette; + static const PaletteArray ourPALPalette; + static const PaletteArray ourSECAMPalette; // Table of RGB values for NTSC, PAL and SECAM - Z26 version - static PaletteArray ourNTSCPaletteZ26; - static PaletteArray ourPALPaletteZ26; - static PaletteArray ourSECAMPaletteZ26; + static const PaletteArray ourNTSCPaletteZ26; + static const PaletteArray ourPALPaletteZ26; + static const PaletteArray ourSECAMPaletteZ26; // Table of RGB values for NTSC, PAL and SECAM - user-defined static PaletteArray ourUserNTSCPalette; diff --git a/src/gui/ColorWidget.cxx b/src/gui/ColorWidget.cxx index 6aa58a049..8052bf029 100644 --- a/src/gui/ColorWidget.cxx +++ b/src/gui/ColorWidget.cxx @@ -25,10 +25,11 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ColorWidget::ColorWidget(GuiObject* boss, const GUI::Font& font, - int x, int y, int w, int h, int cmd) + int x, int y, int w, int h, int cmd, bool framed) : Widget(boss, font, x, y, w, h), CommandSender(boss), - _cmd(cmd) + _cmd(cmd), + _framed(framed) { _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS; } @@ -46,11 +47,18 @@ void ColorWidget::drawWidget(bool hilite) FBSurface& s = dialog().surface(); bool onTop = _boss->dialog().isOnTop(); + if(_framed) + { // Draw a thin frame around us. - s.frameRect(_x, _y, _w, _h + 1, kColor); + s.frameRect(_x, _y, _w, _h + 1, kColor); - // Show the currently selected color - s.fillRect(_x+1, _y+1, _w-2, _h-1, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo); + // Show the currently selected color + s.fillRect(_x + 1, _y + 1, _w - 2, _h - 1, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo); + } + else + { + s.fillRect(_x, _y, _w, _h, onTop ? isEnabled() ? _color : kWidColor : kBGColorLo); + } // Cross out the grid? if(_crossGrid) diff --git a/src/gui/ColorWidget.hxx b/src/gui/ColorWidget.hxx index 7691ff6ad..9169c2153 100644 --- a/src/gui/ColorWidget.hxx +++ b/src/gui/ColorWidget.hxx @@ -36,7 +36,7 @@ class ColorWidget : public Widget, public CommandSender public: ColorWidget(GuiObject* boss, const GUI::Font& font, - int x, int y, int w, int h, int cmd = 0); + int x, int y, int w, int h, int cmd = 0, bool framed = true); virtual ~ColorWidget() = default; void setColor(ColorId color); @@ -49,6 +49,7 @@ class ColorWidget : public Widget, public CommandSender protected: ColorId _color{kNone}; + bool _framed{true}; int _cmd{0}; bool _crossGrid{false}; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 26ed93a33..41460d9ba 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -18,12 +18,14 @@ #include #include "bspf.hxx" +#include "Base.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" +#include "ColorWidget.hxx" #include "Console.hxx" #include "PaletteHandler.hxx" #include "TIA.hxx" @@ -104,6 +106,14 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, addPaletteTab(); addTVEffectsTab(); + //const int req_w = std::max(myFastSCBios->getRight(), myCloneBad->getRight()) + HBORDER + 1; + //const int req_h = _th + VGAP * 3 + // + std::max(myUseVSync->getBottom(), myTVScanIntense->getBottom()) + // + buttonHeight + VBORDER * 2; + //// Set real dimensions + //setSize(req_w, req_h, max_w, max_h); + + // Add Defaults, OK and Cancel buttons WidgetArray wid; addDefaultsOKCancelBGroup(wid, _font); @@ -266,7 +276,8 @@ void VideoDialog::addPaletteTab() myPhaseShiftNtsc = new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, "NTSC phase", plWidth, kNtscShiftChanged, fontWidth * 5); - myPhaseShiftNtsc->setMinValue(262 - 45); myPhaseShiftNtsc->setMaxValue(262 + 45); + myPhaseShiftNtsc->setMinValue((PaletteHandler::DEF_NTSC_SHIFT - PaletteHandler::MAX_SHIFT) * 10); + myPhaseShiftNtsc->setMaxValue((PaletteHandler::DEF_NTSC_SHIFT + PaletteHandler::MAX_SHIFT) * 10); myPhaseShiftNtsc->setTickmarkIntervals(4); wid.push_back(myPhaseShiftNtsc); ypos += lineHeight + VGAP; @@ -274,7 +285,8 @@ void VideoDialog::addPaletteTab() myPhaseShiftPal = new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, "PAL phase", plWidth, kPalShiftChanged, fontWidth * 5); - myPhaseShiftPal->setMinValue(313 - 45); myPhaseShiftPal->setMaxValue(313 + 45); + myPhaseShiftPal->setMinValue((PaletteHandler::DEF_PAL_SHIFT - PaletteHandler::MAX_SHIFT) * 10); + myPhaseShiftPal->setMaxValue((PaletteHandler::DEF_PAL_SHIFT + PaletteHandler::MAX_SHIFT) * 10); myPhaseShiftPal->setTickmarkIntervals(4); wid.push_back(myPhaseShiftPal); ypos += lineHeight + VGAP; @@ -288,11 +300,15 @@ void VideoDialog::addPaletteTab() wid.push_back(myTV ## obj); \ ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Hue, "Hue ", 0) - CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", 0) - CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", 0) - CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", 0) - CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", 0) + CREATE_CUSTOM_SLIDERS(Hue, "Hue ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", kPaletteUpdated) + CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated) + + // The resulting palette + addPalette(myPhaseShiftNtsc->getRight() + fontWidth * 2, VBORDER, + fontWidth * 2 * 8, myTVGamma->getBottom() - myTIAPalette->getTop()); // Add items for tab 2 addToFocusList(wid, myTab, tabID); @@ -412,13 +428,20 @@ void VideoDialog::loadConfig() myTIAZoom->setValue(instance().settings().getFloat("tia.zoom") * 100); // TIA Palette - myTIAPalette->setSelected( - instance().settings().getString("palette"), "standard"); + myPalette = instance().settings().getString("palette"); + myTIAPalette->setSelected(myPalette, "standard"); - // Custom Palette - myPhaseShiftNtsc->setValue(instance().settings().getFloat("tv.phase_ntsc") * 10); - myPhaseShiftPal->setValue(instance().settings().getFloat("tv.phase_pal") * 10); + // Palette adjustables + instance().frameBuffer().tiaSurface().paletteHandler().getAdjustables(myPaletteAdj); + myPhaseShiftNtsc->setValue(myPaletteAdj.phaseNtsc); + myPhaseShiftPal->setValue(myPaletteAdj.phasePal); + myTVHue->setValue(myPaletteAdj.hue); + myTVBright->setValue(myPaletteAdj.brightness); + myTVContrast->setValue(myPaletteAdj.contrast); + myTVSatur->setValue(myPaletteAdj.saturation); + myTVGamma->setValue(myPaletteAdj.gamma); handlePaletteChange(); + colorPalette(); // TIA interpolation myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); @@ -459,15 +482,6 @@ void VideoDialog::loadConfig() int preset = instance().settings().getInt("tv.filter"); handleTVModeChange(NTSCFilter::Preset(preset)); - // Palette adjustables - PaletteHandler::Adjustable paletteAdj; - instance().frameBuffer().tiaSurface().paletteHandler().getAdjustables(paletteAdj); - myTVHue->setValue(paletteAdj.hue); - myTVBright->setValue(paletteAdj.brightness); - myTVContrast->setValue(paletteAdj.contrast); - myTVSatur->setValue(paletteAdj.saturation); - myTVGamma->setValue(paletteAdj.gamma); - // TV Custom adjustables loadTVAdjustables(NTSCFilter::Preset::CUSTOM); @@ -491,31 +505,12 @@ void VideoDialog::saveConfig() instance().settings().setValue("video", myRenderer->getSelectedTag().toString()); - // TIA zoom levels - instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); - - // TIA Palette - instance().settings().setValue("palette", - myTIAPalette->getSelectedTag().toString()); - - // Custom Palette - instance().settings().setValue("tv.phase_ntsc", myPhaseShiftNtsc->getValue() / 10.0); - instance().settings().setValue("tv.phase_pal", myPhaseShiftPal->getValue() / 10.0); - // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getState()); - // Aspect ratio setting (NTSC and PAL) - int oldAdjust = instance().settings().getInt("tia.vsizeadjust"); - int newAdjust = myVSizeAdjust->getValue(); - bool vsizeChanged = oldAdjust != newAdjust; - instance().settings().setValue("tia.vsizeadjust", newAdjust); + // Note: Palette values are saved directly when changed! - // Speed - int speedup = mySpeed->getValue(); - instance().settings().setValue("speed", unmapSpeed(speedup)); - if (instance().hasConsole()) instance().console().initializeAudio(); // Fullscreen instance().settings().setValue("fullscreen", myFullscreen->getState()); @@ -524,6 +519,22 @@ void VideoDialog::saveConfig() // Fullscreen overscan instance().settings().setValue("tia.fs_overscan", myTVOverscan->getValueLabel()); + // TIA zoom levels + instance().settings().setValue("tia.zoom", myTIAZoom->getValue() / 100.0); + + // Aspect ratio setting (NTSC and PAL) + const int oldAdjust = instance().settings().getInt("tia.vsizeadjust"); + const int newAdjust = myVSizeAdjust->getValue(); + const bool vsizeChanged = oldAdjust != newAdjust; + + instance().settings().setValue("tia.vsizeadjust", newAdjust); + + // Speed + const int speedup = mySpeed->getValue(); + instance().settings().setValue("speed", unmapSpeed(speedup)); + if (instance().hasConsole()) + instance().console().initializeAudio(); + // Use sync to vertical blank instance().settings().setValue("vsync", myUseVSync->getState()); @@ -541,16 +552,6 @@ void VideoDialog::saveConfig() // TV Mode instance().settings().setValue("tv.filter", myTVMode->getSelectedTag().toString()); - - // Palette adjustables - PaletteHandler::Adjustable paletteAdj; - paletteAdj.hue = myTVHue->getValue(); - paletteAdj.saturation = myTVSatur->getValue(); - paletteAdj.contrast = myTVContrast->getValue(); - paletteAdj.brightness = myTVBright->getValue(); - paletteAdj.gamma = myTVGamma->getValue(); - instance().frameBuffer().tiaSurface().paletteHandler().setAdjustables(paletteAdj); - // TV Custom adjustables NTSCFilter::Adjustable ntscAdj; ntscAdj.sharpness = myTVSharp->getValue(); @@ -596,32 +597,36 @@ void VideoDialog::setDefaults() case 0: // General { myRenderer->setSelectedIndex(0); - myTIAZoom->setValue(300); myTIAInterpolate->setState(false); - myVSizeAdjust->setValue(0); - mySpeed->setValue(0); - + // screen size myFullscreen->setState(false); //myFullScreenMode->setSelectedIndex(0); myUseStretch->setState(false); + myTVOverscan->setValue(0); + myTIAZoom->setValue(300); + myVSizeAdjust->setValue(0); + // speed + mySpeed->setValue(0); myUseVSync->setState(true); + // misc myUIMessages->setState(true); myFastSCBios->setState(true); myUseThreads->setState(false); - handlePaletteChange(); + handleFullScreenChange(); break; } case 1: // Palettes myTIAPalette->setSelected("standard", ""); - myPhaseShiftNtsc->setValue(262); - myPhaseShiftPal->setValue(313); + myPhaseShiftNtsc->setValue(PaletteHandler::DEF_NTSC_SHIFT * 10); + myPhaseShiftPal->setValue(PaletteHandler::DEF_PAL_SHIFT * 10); myTVHue->setValue(50); myTVSatur->setValue(50); myTVContrast->setValue(50); myTVBright->setValue(50); myTVGamma->setValue(50); + handlePaletteChange(); break; case 2: // TV effects @@ -685,6 +690,27 @@ void VideoDialog::handlePaletteChange() myPhaseShiftPal->setEnabled(enable); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::handlePaletteUpdate() +{ + // TIA Palette + instance().settings().setValue("palette", + myTIAPalette->getSelectedTag().toString()); + // Palette adjustables + PaletteHandler::Adjustable paletteAdj; + paletteAdj.phaseNtsc = myPhaseShiftNtsc->getValue(); + paletteAdj.phasePal = myPhaseShiftPal->getValue(); + paletteAdj.hue = myTVHue->getValue(); + paletteAdj.saturation = myTVSatur->getValue(); + paletteAdj.contrast = myTVContrast->getValue(); + paletteAdj.brightness = myTVBright->getValue(); + paletteAdj.gamma = myTVGamma->getValue(); + instance().frameBuffer().tiaSurface().paletteHandler().setAdjustables(paletteAdj); + + if(instance().hasConsole()) + instance().frameBuffer().tiaSurface().paletteHandler().setPalette(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleFullScreenChange() { @@ -722,12 +748,24 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, close(); break; + case GuiObject::kCloseCmd: + // restore palette settings + instance().frameBuffer().tiaSurface().paletteHandler().setAdjustables(myPaletteAdj); + instance().frameBuffer().tiaSurface().paletteHandler().setPalette(myPalette); + Dialog::handleCommand(sender, cmd, data, 0); + break; + case GuiObject::kDefaultsCmd: setDefaults(); break; case kPaletteChanged: handlePaletteChange(); + handlePaletteUpdate(); + break; + + case kPaletteUpdated: + handlePaletteUpdate(); break; case kNtscShiftChanged: @@ -737,6 +775,7 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, ss << std::setw(4) << std::fixed << std::setprecision(1) << (0.1 * abs(myPhaseShiftNtsc->getValue())) << DEGREE; myPhaseShiftNtsc->setValueLabel(ss.str()); + handlePaletteUpdate(); break; } case kPalShiftChanged: @@ -746,6 +785,7 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, ss << std::setw(4) << std::fixed << std::setprecision(1) << (0.1 * abs(myPhaseShiftPal->getValue())) << DEGREE; myPhaseShiftPal->setValueLabel(ss.str()); + handlePaletteUpdate(); break; } case kVSizeChanged: @@ -818,3 +858,57 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, break; } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::addPalette(int x, int y, int w, int h) +{ + if(instance().hasConsole()) + { + constexpr int NUM_LUMA = 8; + constexpr int NUM_CHROMA = 16; + const GUI::Font& ifont = instance().frameBuffer().infoFont(); + const int lwidth = ifont.getMaxCharWidth() * 1.5; + const float COLW = float(w - lwidth) / NUM_LUMA; + const float COLH = float(h) / NUM_CHROMA; + const int yofs = (COLH - ifont.getFontHeight() + 1) / 2; + + for(int idx = 0; idx < NUM_CHROMA; ++idx) + { + myColorLbl[idx] = new StaticTextWidget(myTab, ifont, x, y + yofs + idx * COLH, " "); + for(int lum = 0; lum < NUM_LUMA; ++lum) + { + myColor[idx][lum] = new ColorWidget(myTab, _font, x + lwidth + lum * COLW, y + idx * COLH, + COLW + 1, COLH + 1, 0, false); + } + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::colorPalette() +{ + if(instance().hasConsole()) + { + constexpr int NUM_LUMA = 8; + constexpr int NUM_CHROMA = 16; + const int order[2][NUM_CHROMA] = + { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {0, 1, 2, 4, 6, 8, 10, 12, 13, 11, 9, 7, 5, 3, 14, 15} + }; + const int type = instance().console().timing() == ConsoleTiming::pal ? 1 : 0; + + for(int idx = 0; idx < NUM_CHROMA; ++idx) + { + ostringstream ss; + const int color = order[type][idx]; + + ss << Common::Base::HEX1 << std::uppercase << color; + myColorLbl[idx]->setLabel(ss.str()); + for(int lum = 0; lum < NUM_LUMA; ++lum) + { + myColor[idx][lum]->setColor(color * NUM_CHROMA + lum * 2); // skip grayscale colors + } + } + } +} diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index d780a508f..7d01b6808 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -20,6 +20,7 @@ class CommandSender; class CheckboxWidget; +class ColorWidget; class DialogContainer; class PopUpWidget; class RadioButtonGroup; @@ -29,6 +30,7 @@ class TabWidget; class OSystem; #include "Dialog.hxx" +#include "PaletteHandler.hxx" #include "NTSCFilter.hxx" #include "bspf.hxx" @@ -50,10 +52,13 @@ class VideoDialog : public Dialog void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handlePaletteChange(); + void handlePaletteUpdate(); void handleFullScreenChange(); void handleOverscanChange(); void handlePhosphorChange(); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + void addPalette(int x, int y, int h, int w); + void colorPalette(); private: TabWidget* myTab; @@ -77,6 +82,9 @@ class VideoDialog : public Dialog CheckboxWidget* myUIMessages{nullptr}; CheckboxWidget* myFastSCBios{nullptr}; CheckboxWidget* myUseThreads{nullptr}; + std::array myColorLbl{nullptr}; + //std::array myColor{nullptr}; + ColorWidget* myColor[16][8]{nullptr}; // TV effects adjustables (custom mode) PopUpWidget* myTVMode{nullptr}; @@ -106,10 +114,14 @@ class VideoDialog : public Dialog ButtonWidget* myCloneBad{nullptr}; ButtonWidget* myCloneCustom{nullptr}; + string myPalette; + PaletteHandler::Adjustable myPaletteAdj{0.0F}; + enum { kPaletteChanged = 'VDpl', kNtscShiftChanged = 'VDns', kPalShiftChanged = 'VDps', + kPaletteUpdated = 'VDpu', kSpeedupChanged = 'VDSp', kVSizeChanged = 'VDVs', kFullScreenChanged = 'VDFs',