diff --git a/Changes.txt b/Changes.txt index 2fe5ad2b5..e17995176 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,6 +22,8 @@ a game. This allows the user to save high scores for these games. For each game and variation, the top 10 scores can be saved. (TODO: Doc) + * Added 'Custom' palette, generated from user controlled phase shifts. + * Added 'Turbo' mode, runs the game as fast as the computer allows. * Added selectable dialog fonts diff --git a/docs/index.html b/docs/index.html index 028062bb4..f40f67e0a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1615,7 +1615,7 @@ - Switch palette (Standard/Z26/User) + Switch palette (Standard/Z26/User/Custom) Control + p Control + p @@ -2010,9 +2010,20 @@ -
-palette <standard|z26|user>
+
-palette <standard|z26|user|custom>
Set the palette to either normal Stella, the one used in the z26 - emulator, or a user-defined palette. + emulator, a user-defined palette, or a custom palette generated + from user-defined phase shifts. + + + +
-phase_ntsc <number>
+ Set phase shift for custom NTSC palette. + + + +
-phase_pal <number>
+ Set phase shift for custom PAL palette. @@ -2847,6 +2858,8 @@ ItemBrief descriptionFor more information,
see CommandLine RendererUse specified rendering mode-video PalettePalette for emulation mode-palette + NTSC phasePhase shift for custom NTSC palette-phase_ntsc + PAL phasePhase shift for custom PAL palette-phase_pal InterpolationInterpolation for TIA image-tia.inter ZoomZoom level for emulation mode -tia.zoom V-Size adjustAdjust height of TIA image-tia.vsizeadjust @@ -4124,6 +4137,10 @@ Ms Pac-Man (Stella extended codes): user An external palette file, supplied by the user. + + custom + A palette generate from user-defined phase shift. +

A user-defined palette has certain restrictions, further described as follows: diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index fa1139d66..f32600345 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -492,6 +492,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ScanlinesIncrease, KBDK_0, MOD3}, {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::TogglePalette, KBDK_P, KBDM_CTRL}, + {Event::ColorShiftDecrease, KBDK_9, KBDM_SHIFT | KBDM_CTRL}, + {Event::ColorShiftIncrease, KBDK_9, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 3fe69b147..04962c9bd 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -62,6 +62,7 @@ #include "AudioSettings.hxx" #include "frame-manager/FrameManager.hxx" #include "frame-manager/FrameLayoutDetector.hxx" +#include "GuiObject.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" @@ -84,6 +85,10 @@ Console::Console(OSystem& osystem, unique_ptr& cart, // Load user-defined palette for this ROM loadUserPalette(); + // Generate custom palette + generateCustomPalette(0); + generateCustomPalette(1); + // Create subsystems for the console my6502 = make_unique(myOSystem.settings()); myRiot = make_unique(*this, myOSystem.settings()); @@ -473,6 +478,21 @@ void Console::enableColorLoss(bool state) myTIA->enableColorLoss(state); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int Console::getPaletteNum(const string& name) const +{ + if(name == "z26") + return PaletteType::Z26; + + if(name == "user" && myUserPaletteDefined) + return PaletteType::User; + + if(name == "custom") + return PaletteType::Custom; + + return PaletteType::Standard; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePalette() { @@ -499,7 +519,12 @@ void Console::togglePalette() message = "Standard Stella palette"; } } - else if(palette == "user") // switch to standard + else if(palette == "user") // switch to custom + { + palette = "custom"; + message = "Custom palette"; + } + else if(palette == "custom") // switch to standard { palette = "standard"; message = "Standard Stella palette"; @@ -521,20 +546,20 @@ void Console::setPalette(const string& type) { // Look at all the palettes, since we don't know which one is // currently active - static constexpr BSPF::array2D palettes = {{ - { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, - { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, - { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette } + static constexpr BSPF::array2D palettes = {{ + { &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette }, + { &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 }, + { &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }, + { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } }}; // See which format we should be using - int paletteNum = 0; - if(type == "standard") - paletteNum = 0; - else if(type == "z26") - paletteNum = 1; - else if(type == "user" && myUserPaletteDefined) - paletteNum = 2; + int paletteNum = getPaletteNum(type); + + if(paletteNum == PaletteType::Custom) + { + + } // Now consider the current display format const PaletteArray* palette = @@ -658,6 +683,8 @@ FBInitStatus Console::initializeVideo(bool full) myOSystem.frameBuffer().showFrameStats( myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats")); + generateCustomPalette(0); + generateCustomPalette(1); generateColorLossPalette(); } setPalette(myOSystem.settings().getString("palette")); @@ -805,6 +832,46 @@ void Console::changeScanlineAdjust(int direction) myOSystem.frameBuffer().showMessage(ss.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::changeColorPhaseShift(int direction) +{ + const char DEGREE = 0x1c; + const float NTSC_SHIFT = 26.2F; + const float PAL_SHIFT = 31.3F; // 360 / 11.5 + const bool isNTSC = myDisplayFormat == "NTSC" || myDisplayFormat == "NTSC50"; + const bool isPAL = myDisplayFormat == "PAL" || myDisplayFormat == "PAL60"; + + // SECAM is not supported + if(isNTSC || isPAL) + { + const string key = isNTSC ? "phase_ntsc" : "phase_pal"; + const float shift = isNTSC ? NTSC_SHIFT : PAL_SHIFT; + float phase = myOSystem.settings().getFloat(key); + + if(direction == +1) // increase color phase shift + { + phase += 0.3F; + phase = std::min(phase, shift + 4.5F); + } + else if(direction == -1) // decrease color phase shift + { + phase -= 0.3F; + phase = std::max(phase, shift - 4.5F); + } + myOSystem.settings().setValue(key, phase); + generateCustomPalette(isNTSC ? 0 : 1); + + myOSystem.settings().setValue("palette", "custom"); + setPalette("custom"); + + ostringstream ss; + ss << "Color phase shift at " + << std::fixed << std::setprecision(1) << phase << DEGREE; + + myOSystem.frameBuffer().showMessage(ss.str()); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setTIAProperties() { @@ -1056,15 +1123,129 @@ void Console::loadUserPalette() myUserPaletteDefined = true; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Console::generateCustomPalette(int type) +{ + const int NUM_CHROMA = 16; + const int NUM_LUMA = 8; + const double SATURATION = 0.25; + + double color[NUM_CHROMA][2] = {{0.0}}; + + if(type == 0) + { + // YIQ is YUV shifted by 33° + const double offset = 33 * (2 * M_PI / 360); + const double shift = myOSystem.settings().getFloat("phase_ntsc") * (2 * M_PI / 360); + + // color 0 is grayscale + for(int chroma = 1; chroma < NUM_CHROMA; chroma++) + { + color[chroma][0] = SATURATION * sin(offset + shift * (chroma - 1)); + color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - M_PI)); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const double I = color[chroma][0]; + const double Q = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + + double R = Y + 0.956 * I + 0.621 * Q; + double G = Y - 0.272 * I - 0.647 * Q; + double B = Y - 1.106 * I + 1.703 * Q; + + if(R < 0) R = 0; + if(G < 0) G = 0; + if(B < 0) B = 0; + + R = pow(R, 0.9); + G = pow(G, 0.9); + B = pow(B, 0.9); + + if(R > 1) R = 1; + if(G > 1) G = 1; + if(B > 1) B = 1; + + int r = R * 255.F; + int g = G * 255.F; + int b = B * 255.F; + + ourCustomNTSCPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; + } + } + } + else + { + const double offset = 180 * (2 * M_PI / 360); + const double shift = myOSystem.settings().getFloat("phase_pal") * (2 * M_PI / 360); + const double fixedShift = 22.5 * (2 * M_PI / 360); + + // colors 0, 1, 14 and 15 are grayscale + for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) + { + int idx = NUM_CHROMA - 1 - chroma; + color[idx][0] = SATURATION * sin(offset - fixedShift * chroma); + if ((idx & 1) == 0) + color[idx][1] = SATURATION * sin(offset - shift * (chroma - 3.5) / 2.F); + else + color[idx][1] = SATURATION * -sin(offset - shift * chroma / 2.F); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const double U = color[chroma][0]; + const double V = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + + // Most sources + double R = Y + 1.403 * V; + double G = Y - 0.344 * U - 0.714 * V; + double B = Y + 1.770 * U; + + // German Wikipedia, huh??? + //double B = Y + 1 / 0.493 * U; + //double R = Y + 1 / 0.877 * V; + //double G = 1.704 * Y - 0.590 * R - 0.194 * B; + + if(R < 0) R = 0.0; + if(G < 0) G = 0.0; + if(B < 0) B = 0.0; + + R = pow(R, 1.2); + G = pow(G, 1.2); + B = pow(B, 1.2); + + if(R > 1) R = 1; + if(G > 1) G = 1; + if(B > 1) B = 1; + + int r = R * 255.F; + int g = G * 255.F; + int b = B * 255.F; + + ourCustomPALPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; + } + } + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::generateColorLossPalette() { // Look at all the palettes, since we don't know which one is // currently active - std::array palette = { - ourNTSCPalette.data(), ourPALPalette.data(), ourSECAMPalette.data(), - ourNTSCPaletteZ26.data(), ourPALPaletteZ26.data(), ourSECAMPaletteZ26.data(), - nullptr, nullptr, nullptr + std::array palette = { + ourNTSCPalette.data(), ourPALPalette.data(), ourSECAMPalette.data(), + ourNTSCPaletteZ26.data(), ourPALPaletteZ26.data(), ourSECAMPaletteZ26.data(), + nullptr, nullptr, nullptr, + ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), }; if(myUserPaletteDefined) { @@ -1073,7 +1254,7 @@ void Console::generateColorLossPalette() palette[8] = ourUserSECAMPalette.data(); } - for(int i = 0; i < 9; ++i) + for(int i = 0; i < 3 * PaletteType::NumTypes; ++i) { if(palette[i] == nullptr) continue; @@ -1388,3 +1569,9 @@ PaletteArray Console::ourUserPALPalette = { 0 }; // filled from external file // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray Console::ourUserSECAMPalette = { 0 }; // filled from external file + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray Console::ourCustomNTSCPalette = { 0 }; // filled by function + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray Console::ourCustomPALPalette = { 0 }; // filled by function diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 33c3b117c..9ff4b002c 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -209,6 +209,11 @@ class Console : public Serializable, public ConsoleIO */ void togglePalette(); + /** + Generates a custom palette, based on user defined phase shifts. + */ + void generateCustomPalette(int type); + /** Sets the palette according to the given palette name. @@ -283,6 +288,16 @@ class Console : public Serializable, public ConsoleIO */ void changeScanlineAdjust(int direction); + /** + Change the "phase shift" variable. + Note that there are two of these (NTSC and PAL). The currently + active mode will determine which one is used. + + @param direction +1 indicates increase, -1 indicates decrease. + + */ + void changeColorPhaseShift(int direction); + /** Returns the current framerate. */ @@ -377,10 +392,22 @@ class Console : public Serializable, public ConsoleIO */ void generateColorLossPalette(); + int getPaletteNum(const string& name) const; + + void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const; private: + + enum PaletteType { + Standard, + Z26, + User, + Custom, + NumTypes + }; + // Reference to the osystem object OSystem& myOSystem; @@ -462,6 +489,10 @@ class Console : public Serializable, public ConsoleIO static PaletteArray ourUserPALPalette; static PaletteArray ourUserSECAMPalette; + // Table of RGB values for NTSC, PAL - custom-defined + static PaletteArray ourCustomNTSCPalette; + static PaletteArray ourCustomPALPalette; + private: // Following constructors and assignment operators not supported Console() = delete; diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index c45fc1e0a..915461e97 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -121,6 +121,7 @@ class Event // add new events from here to avoid that user remapped events get overwritten ToggleTurbo, + ColorShiftDecrease, ColorShiftIncrease, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 1a11c604b..c9fa85835 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -435,6 +435,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.console().changeScanlineAdjust(+1); return; + case Event::ColorShiftDecrease: + if (pressed) myOSystem.console().changeColorPhaseShift(-1); + return; + + case Event::ColorShiftIncrease: + if (pressed) myOSystem.console().changeColorPhaseShift(+1); + return; + case Event::ToggleFullScreen: if (pressed && !repeated) myOSystem.frameBuffer().toggleFullscreen(); return; @@ -1915,15 +1923,16 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::OverscanIncrease, "Increase overscan in fullscreen mode", "" }, { Event::VidmodeDecrease, "Previous zoom level", "" }, { Event::VidmodeIncrease, "Next zoom level", "" }, - { Event::ScanlineAdjustIncrease, "Increase vertical display size", "" }, { Event::ScanlineAdjustDecrease, "Decrease vertical display size", "" }, + { Event::ScanlineAdjustIncrease, "Increase vertical display size", "" }, { Event::VCenterDecrease, "Move display up", "" }, { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, { Event::FormatIncrease, "Increase display format", "" }, - { Event::TogglePalette, "Switch palette (Standard/Z26/User)", "" }, + { Event::TogglePalette, "Switch palette (Std./Z26/User/Cust.)", "" }, + { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, + { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, - // TV effects: { Event::VidmodeStd, "Disable TV effects", "" }, { Event::VidmodeRGB, "Select 'RGB' preset", "" }, @@ -2049,7 +2058,8 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::VCenterDecrease, Event::VCenterIncrease, Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, - Event::TogglePalette, Event::ToggleInter + Event::TogglePalette, Event::ColorShiftDecrease, Event::ColorShiftIncrease, + Event::ToggleInter }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 8148fa085..8fe4c7821 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 145 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 149 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index b0e5cd7a6..c1c64dd20 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -46,6 +46,8 @@ Settings::Settings() setPermanent("windowedpos", Common::Point(50, 50)); setPermanent("display", 0); setPermanent("palette", "standard"); + setPermanent("phase_ntsc", "26.2"); + setPermanent("phase_pal", "31.3"); setPermanent("uimessages", "true"); // TIA specific options @@ -356,7 +358,7 @@ void Settings::validate() else if(i > 10) setValue("ssinterval", "10"); s = getString("palette"); - if(s != "standard" && s != "z26" && s != "user") + if(s != "standard" && s != "z26" && s != "user" && s != "custom") setValue("palette", "standard"); s = getString("launcherfont"); @@ -403,8 +405,10 @@ void Settings::usage() const << " -windowedpos Sets the window position in windowed emulator mode\n" << " -display Sets the display for Stella's emulator\n" << " -palette \n" + << " z26|user|\n" + << " custom>\n" + << " -phase_ntsc Phase shift for NTSC custom color palette\n" + << " -phase_pal Phase shift for PAL custom color palette\n" << " -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/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 934b9e645..5c734a52e 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -273,7 +273,9 @@ void CommandDialog::updatePalette() label = "Stella Palette"; else if(BSPF::equalsIgnoreCase(palette, "z26")) label = "Z26 Palette"; - else + else if(BSPF::equalsIgnoreCase(palette, "user")) label = "User Palette"; + else + label = "Custom Palette"; myPaletteButton->setLabel(label); } diff --git a/src/gui/ConsoleBFont.hxx b/src/gui/ConsoleBFont.hxx index c47d4e375..b55797a89 100644 --- a/src/gui/ConsoleBFont.hxx +++ b/src/gui/ConsoleBFont.hxx @@ -42,6 +42,41 @@ namespace GUI { // Font character bitmap data. static const uInt16 consoleB_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): + width 8 + bbx ( 8, 13, 0, -2 ) + + +--------+ + | | + | XXXX | + | XX XX | + | XX XX | + | XX XX | + | XXXX | + | | + | | + | | + | | + | | + | | + | | + +--------+ + */ + 0x0000, + 0b0011110000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0011110000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + /* MODIFIED Character 29 (0x1d): @@ -3386,8 +3421,8 @@ static const FontDesc consoleBDesc = { 13, 8, 13, 0, -2, 11, - 29, - 98, + 28, + 99, consoleB_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/ConsoleMediumBFont.hxx b/src/gui/ConsoleMediumBFont.hxx index 63116d64e..9c8081619 100644 --- a/src/gui/ConsoleMediumBFont.hxx +++ b/src/gui/ConsoleMediumBFont.hxx @@ -42,6 +42,45 @@ namespace GUI { // Font character bitmap data. static const uInt16 consoleMediumB_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): ellipsis + width 9 + bbx ( 9, 15, 0, -3 ) + + +---------+ + | | + | | + | XXXX | + | XX XX | + | XX XX | + | XX XX | + | XXXX | + | | + | | + | | + | | + | | + | | + | | + | | + +---------+ + */ + 0x0000, + 0x0000, + 0b0011110000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0110011000000000, + 0b0011110000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + /* MODIFIED Character 29 (0x1d): ellipsis width 9 @@ -3777,8 +3816,8 @@ static const FontDesc consoleMediumBDesc = { 15, 9, 15, 0, -3, 12, - 29, - 98, + 28, + 99, consoleMediumB_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 2dd607a4b..5badbc513 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -264,8 +264,9 @@ void DeveloperDialog::addTiaTab(const GUI::Font& font) wid.push_back(myPFColorWidget); ypos += lineHeight + VGAP * 1; - mySwapLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, - "Delayed VDEL" + ELLIPSIS + " swap for"); + ostringstream ss; + ss << "Delayed VDEL" << ELLIPSIS << " swap for"; + mySwapLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, ss.str()); wid.push_back(mySwapLabel); ypos += lineHeight + VGAP * 1; diff --git a/src/gui/GuiObject.hxx b/src/gui/GuiObject.hxx index 4e4325132..3f473867b 100644 --- a/src/gui/GuiObject.hxx +++ b/src/gui/GuiObject.hxx @@ -90,8 +90,9 @@ class GuiObject : public CommandReceiver /** Redraw the focus list */ virtual void redrawFocus() { } - /** Special character for menues */ + /** Special characters for menues */ const string ELLIPSIS = "\x1d"; + const string DEGREE = "\x1c"; protected: virtual void releaseFocus() = 0; diff --git a/src/gui/Stella12x24tFont.hxx b/src/gui/Stella12x24tFont.hxx index 88bb67ae4..e1e3e07d7 100644 --- a/src/gui/Stella12x24tFont.hxx +++ b/src/gui/Stella12x24tFont.hxx @@ -42,6 +42,62 @@ namespace GUI { // Font character bitmap data. static const uInt16 stella12x24t_font_bits[] = { // NOLINT : too complicated to convert +/* Character 28 (0x1c): + width 12 + bbx ( 12, 24, 0, -5 ) + + +------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0b0000111000000000, +0b0001101100000000, +0b0011000110000000, +0b0011000110000000, +0b0011000110000000, +0b0001101100000000, +0b0000111000000000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + /* Character 29 (0x1d): width 12 bbx ( 12, 24, 0, -5 ) @@ -5538,8 +5594,8 @@ static const FontDesc stella12x24tDesc = { 24, 12, 24, 0, -5, 19, - 29, - 98, + 28, + 99, stella12x24t_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/Stella14x28tFont.hxx b/src/gui/Stella14x28tFont.hxx index 2ce818d7c..8b1e262a5 100644 --- a/src/gui/Stella14x28tFont.hxx +++ b/src/gui/Stella14x28tFont.hxx @@ -42,7 +42,72 @@ namespace GUI { // Font character bitmap data. static const uInt16 stella14x28t_font_bits[] = { // NOLINT : too complicated to convert -/* Character 32 (0x20): +/* Character 28 (0x1c): + width 14 + bbx ( 14, 28, 0, -6 ) + + +--------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0b0000011110000000, +0b0000111111000000, +0b0001110011100000, +0b0001100001100000, +0b0001100001100000, +0b0001110011100000, +0b0000111111000000, +0b0000011110000000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + + +/* Character 29 (0x1d): width 14 bbx ( 14, 28, 0, -6 ) @@ -6322,8 +6387,8 @@ static const FontDesc stella14x28tDesc = { 28, 14, 28, 0, -6, 22, - 29, - 98, + 28, + 99, stella14x28t_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/Stella16x32tFont.hxx b/src/gui/Stella16x32tFont.hxx index 15c1e7b4c..63708f473 100644 --- a/src/gui/Stella16x32tFont.hxx +++ b/src/gui/Stella16x32tFont.hxx @@ -42,6 +42,78 @@ namespace GUI { // Font character bitmap data. static const uInt16 stella16x32t_font_bits[] = { // NOLINT : too complicated to convert +/* Character 28 (0x1c): + width 16 + bbx ( 16, 32, 0, -6 ) + + +----------------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------------+ +*/ +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0b0000111110000000, +0b0001111111000000, +0b0011110111100000, +0b0011100011100000, +0b0011100011100000, +0b0011110111100000, +0b0001111111000000, +0b0000111110000000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, +0x0000, + /* Character 29 (0x1d): width 16 bbx ( 16, 32, 0, -6 ) @@ -7106,8 +7178,8 @@ static const FontDesc stella16x32tDesc = { 32, 16, 32, 0, -6, 26, - 29, - 98, + 28, + 99, stella16x32t_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/StellaLargeFont.hxx b/src/gui/StellaLargeFont.hxx index 39b181b8f..3c04ffa44 100644 --- a/src/gui/StellaLargeFont.hxx +++ b/src/gui/StellaLargeFont.hxx @@ -42,6 +42,55 @@ namespace GUI { // Font character bitmap data. static const uInt16 stellaLarge_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): + width 10 + bbx ( 10, 20, 0, -4 ) + + +----------+ + | | + | | + | | + | XXXX | + | XX XX | + | XX XX | + | XX XX | + | XX XX | + | XXXX | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +----------+ + */ + 0x0000, + 0x0000, + 0x0000, + 0b0001111000000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0001111000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + /* MODIFIED Character 29 (0x1d): width 10 @@ -4759,8 +4808,8 @@ static const FontDesc stellaLargeDesc = { 20, 10, 20, 0, -4, 16, - 29, - 98, + 28, + 99, stellaLarge_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/StellaMediumFont.hxx b/src/gui/StellaMediumFont.hxx index e0fd43629..e81422454 100644 --- a/src/gui/StellaMediumFont.hxx +++ b/src/gui/StellaMediumFont.hxx @@ -43,6 +43,52 @@ namespace GUI { static const uInt16 stellaMedium_font_bits[] = { // NOLINT : too complicated to convert + /* MODIFIED + Character 28 (0x1c): degree + width 9 + bbx ( 9, 15, 0, -3 ) + + +---------+ + | | + | | + | | + | | + | | + | XXXXXX | + | X X| + | X X| + | XXXXXX | + | | + | | + | | + | XX XX XX| + | XX XX XX| + | | + | | + | | + | | + +---------+ + */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0b0001111000000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0011001100000000, + 0b0001111000000000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + /* MODIFIED Character 29 (0x1d): ellipsis width 9 @@ -4367,8 +4413,8 @@ static const FontDesc stellaMediumDesc = { 18, 9, 18, 0, -4, 14, - 29, - 98, + 28, + 99, stellaMedium_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index b7aa2a2d5..30b7a6ccc 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -89,14 +89,13 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, int xpos, ypos, tabID; int lwidth = font.getStringWidth("V-Size adjust "), - pwidth = font.getStringWidth("XXXXxXXXX"), - swidth = font.getMaxCharWidth() * 10 - 2; + pwidth = font.getStringWidth("XXXXxXXXX"); WidgetArray wid; VariantList items; // Set real dimensions - setSize(60 * fontWidth + HBORDER * 2, + setSize(57 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, _th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, max_w, max_h); @@ -125,11 +124,32 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, VarList::push_back(items, "z26", "z26"); if (instance().checkUserPalette()) VarList::push_back(items, "User", "user"); + VarList::push_back(items, "Custom", "custom"); myTIAPalette = new PopUpWidget(myTab, font, xpos, ypos, pwidth, - lineHeight, items, "Palette ", lwidth); + lineHeight, items, "Palette ", lwidth, kPaletteChanged); wid.push_back(myTIAPalette); ypos += lineHeight + VGAP; + int swidth = myTIAPalette->getWidth() - lwidth; + int plWidth = font.getStringWidth("NTSC phase "); + int pswidth = swidth - INDENT + lwidth - plWidth; + + 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->setTickmarkIntervals(4); + wid.push_back(myPhaseShiftNtsc); + ypos += lineHeight + VGAP; + + 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->setTickmarkIntervals(4); + wid.push_back(myPhaseShiftPal); + ypos += lineHeight + VGAP * 4; + // TIA interpolation myTIAInterpolate = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Interpolation "); wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP; @@ -264,7 +284,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, CREATE_CUSTOM_SLIDERS(Fringe, "Fringing ", 0) CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding ", 0) - xpos += myTVContrast->getWidth() + fontWidth * 4; + xpos += myTVContrast->getWidth() + fontWidth * 6; ypos = VBORDER; lwidth = font.getStringWidth("Intensity "); @@ -287,7 +307,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, xpos += INDENT; CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity ", kScanlinesChanged) - ypos += lineHeight + 2; + ypos += VGAP * 3; // Adjustable presets xpos -= INDENT; @@ -345,6 +365,11 @@ void VideoDialog::loadConfig() myTIAPalette->setSelected( instance().settings().getString("palette"), "standard"); + // Custom Palette + myPhaseShiftNtsc->setValue(instance().settings().getFloat("phase_ntsc") * 10); + myPhaseShiftPal->setValue(instance().settings().getFloat("phase_pal") * 10); + handlePaletteChange(); + // TIA interpolation myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); @@ -417,6 +442,10 @@ void VideoDialog::saveConfig() instance().settings().setValue("palette", myTIAPalette->getSelectedTag().toString()); + // Custom Palette + instance().settings().setValue("phase_ntsc", myPhaseShiftNtsc->getValue() / 10.0); + instance().settings().setValue("phase_pal", myPhaseShiftPal->getValue() / 10.0); + // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getState()); @@ -484,12 +513,21 @@ void VideoDialog::saveConfig() // TV scanline intensity instance().settings().setValue("tv.scanlines", myTVScanIntense->getValueLabel()); - if (instance().hasConsole()) + if(instance().hasConsole()) + { instance().console().setTIAProperties(); - if (vsizeChanged && instance().hasConsole()) { - instance().console().tia().clearFrameBuffer(); - instance().console().initializeVideo(); + if(instance().settings().getString("palette") == "custom") + { + instance().console().generateCustomPalette(0); + instance().console().generateCustomPalette(1); + } + + if(vsizeChanged) + { + instance().console().tia().clearFrameBuffer(); + instance().console().initializeVideo(); + } } // Finally, issue a complete framebuffer re-initialization... @@ -509,6 +547,8 @@ void VideoDialog::setDefaults() myRenderer->setSelectedIndex(0); myTIAZoom->setValue(300); myTIAPalette->setSelected("standard", ""); + myPhaseShiftNtsc->setValue(262); + myPhaseShiftPal->setValue(313); myTIAInterpolate->setState(false); myVSizeAdjust->setValue(0); mySpeed->setValue(0); @@ -521,6 +561,8 @@ void VideoDialog::setDefaults() myCenter->setState(false); myFastSCBios->setState(true); myUseThreads->setState(false); + + handlePaletteChange(); break; } @@ -586,6 +628,15 @@ void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) myTVGamma->setValue(adj.gamma); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::handlePaletteChange() +{ + bool enable = myTIAPalette->getSelectedTag().toString() == "custom"; + + myPhaseShiftNtsc->setEnabled(enable); + myPhaseShiftPal->setEnabled(enable); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleFullScreenChange() { @@ -627,6 +678,28 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, setDefaults(); break; + case kPaletteChanged: + handlePaletteChange(); + break; + + case kNtscShiftChanged: + { + std::ostringstream ss; + + ss << std::setw(4) << std::fixed << std::setprecision(1) + << (0.1 * abs(myPhaseShiftNtsc->getValue())) << DEGREE; + myPhaseShiftNtsc->setValueLabel(ss.str()); + break; + } + case kPalShiftChanged: + { + std::ostringstream ss; + + ss << std::setw(4) << std::fixed << std::setprecision(1) + << (0.1 * abs(myPhaseShiftPal->getValue())) << DEGREE; + myPhaseShiftPal->setValueLabel(ss.str()); + break; + } case kVSizeChanged: { int adjust = myVSizeAdjust->getValue(); diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index 34931481d..429290082 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -45,6 +45,7 @@ class VideoDialog : public Dialog void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); + void handlePaletteChange(); void handleFullScreenChange(); void handleOverscanChange(); void handlePhosphorChange(); @@ -57,6 +58,8 @@ class VideoDialog : public Dialog PopUpWidget* myRenderer{nullptr}; SliderWidget* myTIAZoom{nullptr}; PopUpWidget* myTIAPalette{nullptr}; + SliderWidget* myPhaseShiftNtsc{nullptr}; + SliderWidget* myPhaseShiftPal{nullptr}; CheckboxWidget* myTIAInterpolate{nullptr}; SliderWidget* myVSizeAdjust{nullptr}; SliderWidget* mySpeed{nullptr}; @@ -100,6 +103,9 @@ class VideoDialog : public Dialog ButtonWidget* myCloneCustom{nullptr}; enum { + kPaletteChanged = 'VDpl', + kNtscShiftChanged = 'VDns', + kPalShiftChanged = 'VDps', kSpeedupChanged = 'VDSp', kVSizeChanged = 'VDVs', kFullScreenChanged = 'VDFs',