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 @@
Item | Brief description | For more information, see CommandLine |
Renderer | Use specified rendering mode | -video |
Palette | Palette for emulation mode | -palette |
+ NTSC phase | Phase shift for custom NTSC palette | -phase_ntsc |
+ PAL phase | Phase shift for custom PAL palette | -phase_pal |
Interpolation | Interpolation for TIA image | -tia.inter |
Zoom | Zoom level for emulation mode | -tia.zoom |
V-Size adjust | Adjust 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',