From 754cd90f901bc726809f7dc326b1847f35a00598 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 7 May 2020 23:09:11 +0200 Subject: [PATCH 01/42] fix window position saving when changing zoom via hotkey --- docs/index.html | 4 ++-- src/emucore/FrameBuffer.cxx | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/index.html b/docs/index.html index 851aea9dc..82b8c4a38 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1621,13 +1621,13 @@ - Decrease custom palette phase shift (switches to 'Custom' palette) + Decrease 'Custom' palette's phase shift Shift-Control + 9 Shift-Control + 9 - Increase custom palette phase shift (switches to 'Custom' palette) + Increase 'Custom' palette's phase shift Control + 9 Control + 9 diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 250a895cf..ce2d4cf46 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -939,6 +939,8 @@ bool FrameBuffer::changeVidMode(int direction) else return false; + saveCurrentWindowPosition(); + // Changing the video mode can take some time, during which the last // sound played may get 'stuck' // So we mute the sound until the operation completes From 2770845f6b4492280f8d05bad58df58a57dd4ab4 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 8 May 2020 02:12:58 -0230 Subject: [PATCH 02/42] Use our own version of PI, since M_PI isn't defined everywhere. Fixes #630. Also, consistently use float instead of mixing float and double (compiler complains otherwise). --- src/emucore/Console.cxx | 70 +++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 29fe2bfac..46078f09d 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -1120,45 +1120,46 @@ void Console::loadUserPalette() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::generateCustomPalette(int type) { - const int NUM_CHROMA = 16; - const int NUM_LUMA = 8; - const double SATURATION = 0.25; + constexpr int NUM_CHROMA = 16; + constexpr int NUM_LUMA = 8; + constexpr float SATURATION = 0.25F; - double color[NUM_CHROMA][2] = {{0.0}}; + float color[NUM_CHROMA][2] = {{0.0F}}; 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); + constexpr float offset = 33 * (2 * BSPF::PI_f / 360); + const float shift = myOSystem.settings().getFloat("phase_ntsc") * + (2 * BSPF::PI_f / 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)); + color[chroma][1] = SATURATION * sin(offset + shift * (chroma - 1 - BSPF::PI_f)); } for(int chroma = 0; chroma < NUM_CHROMA; chroma++) { - const double I = color[chroma][0]; - const double Q = color[chroma][1]; + const float I = color[chroma][0]; + const float Q = color[chroma][1]; for(int luma = 0; luma < NUM_LUMA; luma++) { - const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + const float Y = 0.05F + luma / 8.24F; // 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; + float R = Y + 0.956F * I + 0.621F * Q; + float G = Y - 0.272F * I - 0.647F * Q; + float B = Y - 1.106F * I + 1.703F * 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); + R = powf(R, 0.9F); + G = powf(G, 0.9F); + B = powf(B, 0.9F); if(R > 1) R = 1; if(G > 1) G = 1; @@ -1174,47 +1175,48 @@ void Console::generateCustomPalette(int type) } 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); + constexpr float offset = 180 * (2 * BSPF::PI_f / 360); + float shift = myOSystem.settings().getFloat("phase_pal") * + (2 * BSPF::PI_f / 360); + constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 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); + color[idx][0] = SATURATION * sinf(offset - fixedShift * chroma); if ((idx & 1) == 0) - color[idx][1] = SATURATION * sin(offset - shift * (chroma - 3.5) / 2.F); + color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); else - color[idx][1] = SATURATION * -sin(offset - shift * chroma / 2.F); + color[idx][1] = SATURATION * -sinf(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]; + const float U = color[chroma][0]; + const float V = color[chroma][1]; for(int luma = 0; luma < NUM_LUMA; luma++) { - const double Y = 0.05 + luma / 8.24; // 0.05..~0.90 + const float Y = 0.05F + luma / 8.24F; // 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; + float R = Y + 1.403F * V; + float G = Y - 0.344F * U - 0.714F * V; + float B = Y + 1.770F * 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; + //float B = Y + 1 / 0.493 * U; + //float R = Y + 1 / 0.877 * V; + //float 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); + R = powf(R, 1.2); + G = powf(G, 1.2); + B = powf(B, 1.2); if(R > 1) R = 1; if(G > 1) G = 1; From 825c0e516a7211519d834235b05d485c03d1dc95 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Fri, 8 May 2020 17:51:19 +0200 Subject: [PATCH 03/42] refactor palette handling into own class convert brightness, contrast, saturation and gamma --- src/common/PKeyboardHandler.cxx | 3 +- src/common/PaletteHandler.cxx | 721 +++++++++++++++++++++++++++++ src/common/PaletteHandler.hxx | 155 +++++++ src/common/module.mk | 1 + src/emucore/Console.cxx | 574 +---------------------- src/emucore/Console.hxx | 82 +--- src/emucore/ConsoleTiming.hxx | 3 +- src/emucore/Event.hxx | 4 +- src/emucore/EventHandler.cxx | 19 +- src/emucore/EventHandler.hxx | 2 +- src/emucore/Settings.cxx | 2 +- src/gui/CommandDialog.cxx | 3 +- src/gui/HelpDialog.cxx | 2 +- src/gui/VideoDialog.cxx | 5 +- src/windows/Stella.vcxproj | 2 + src/windows/Stella.vcxproj.filters | 6 + 16 files changed, 925 insertions(+), 659 deletions(-) create mode 100644 src/common/PaletteHandler.cxx create mode 100644 src/common/PaletteHandler.hxx diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index f32600345..639d8ae31 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -491,7 +491,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ScanlinesDecrease, KBDK_0, KBDM_SHIFT | MOD3}, {Event::ScanlinesIncrease, KBDK_0, MOD3}, {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, - {Event::TogglePalette, KBDK_P, KBDM_CTRL}, + {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, + {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, {Event::ColorShiftDecrease, KBDK_9, KBDM_SHIFT | KBDM_CTRL}, {Event::ColorShiftIncrease, KBDK_9, KBDM_CTRL}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx new file mode 100644 index 000000000..e1d71f123 --- /dev/null +++ b/src/common/PaletteHandler.cxx @@ -0,0 +1,721 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + + +#include "Console.hxx" +#include "FrameBuffer.hxx" + +#include "PaletteHandler.hxx" + +PaletteHandler::PaletteHandler(OSystem& system) + : myOSystem(system) +{ + // Load user-defined palette for this ROM + loadUserPalette(); + + //// Generate custom palette + //generateCustomPalette(ConsoleTiming::ntsc); + //generateCustomPalette(ConsoleTiming::pal); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteHandler::PaletteType PaletteHandler::toPaletteType(const string& name) const +{ + if(name == SETTING_Z26) + return PaletteType::Z26; + + if(name == SETTING_USER && myUserPaletteDefined) + return PaletteType::User; + + if(name == SETTING_CUSTOM) + return PaletteType::Custom; + + return PaletteType::Standard; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string PaletteHandler::toPaletteName(PaletteType type) const +{ + string SETTING_NAMES[int(PaletteType::NumTypes)] = { + SETTING_STANDARD, SETTING_Z26, SETTING_USER, SETTING_CUSTOM + }; + + return SETTING_NAMES[type]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changePalette(bool increase) +{ + string MESSAGES[PaletteType::NumTypes] = { + "Standard Stella", "Z26", "User-defined", "Custom" + }; + + string palette, message; + palette = myOSystem.settings().getString("palette"); + + + int type = toPaletteType(myOSystem.settings().getString("palette")); + + if(increase) + { + if(type == PaletteType::MaxType) + type = PaletteType::Standard; + else + type++; + // If we have no user-defined palette, we will skip it + if(type == PaletteType::User && !myUserPaletteDefined) + type++; + } + else + { + if(type == PaletteType::MinType) + type = PaletteType::MaxType; + else + type--; + // If we have no user-defined palette, we will skip it + if(type == PaletteType::User && !myUserPaletteDefined) + type--; + } + + palette = toPaletteName(PaletteType(type)); + message = MESSAGES[type] + " palette"; + + myOSystem.frameBuffer().showMessage(message); + + setPalette(palette); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::generatePalettes() +{ + generateCustomPalette(ConsoleTiming::ntsc); + generateCustomPalette(ConsoleTiming::pal); + generateColorLossPalette(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeColorPhaseShift(bool increase) +{ + const char DEGREE = 0x1c; + const float NTSC_SHIFT = 26.2F; + const float PAL_SHIFT = 31.3F; // 360 / 11.5 + const ConsoleTiming timing = myOSystem.console().timing(); + const bool isNTSC = timing == ConsoleTiming::ntsc; + const bool isPAL = timing == ConsoleTiming::pal; + + // 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(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) +{ + myOSystem.settings().setValue("palette", name); + + setPalette(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::setPalette() +{ + const string& name = myOSystem.settings().getString("palette"); + + // 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 }, + { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } + }}; + // See which format we should be using + const ConsoleTiming timing = myOSystem.console().timing(); + const PaletteType paletteType = toPaletteType(name); + // Now consider the current display format + const PaletteArray* palette = palettes[paletteType][int(timing)]; + + myOSystem.frameBuffer().setTIAPalette(adjustPalette(*palette)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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; + // Generate adjust table + const int ADJUST_SIZE = 256; + const int RGB_UNIT = 1 << 8; + const 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); + std::array adjust; + + for(int i = 0; i < ADJUST_SIZE; i++) + adjust[i] = powf(i * toFloat, gamma) * contrast + brightness; + + // Transform original palette into destination palette + for(int i = 0; i < destPalette.size(); i += 2) + { + const uInt32 pixel = palette[i]; + int r = (pixel >> 16) & 0xff; + int g = (pixel >> 8) & 0xff; + int b = (pixel >> 0) & 0xff; + + // TOOD: adjust hue (different for NTSC and PAL?) + + // adjust saturation + float P = sqrt(r * r * PR + g * g * PG + b * b * PB) ; + + r = P + (r - P) * saturation; + g = P + (g - P) * saturation; + b = P + (b - P) * saturation; + + r = BSPF::clamp(r, 0, 255); + g = BSPF::clamp(g, 0, 255); + b = BSPF::clamp(b, 0, 255); + + // adjust contrast, brightness, gamma + r = adjust[r]; + g = adjust[g]; + b = adjust[b]; + + r = BSPF::clamp(r, 0, 255); + g = BSPF::clamp(g, 0, 255); + b = BSPF::clamp(b, 0, 255); + + destPalette[i] = (r << 16) + (g << 8) + b; + + // Fill the odd numbered palette entries with gray values (calculated + // using the standard RGB -> grayscale conversion formula) + const uInt8 lum = static_cast((r * PR) + (g * PG) + (b * PB)); + + destPalette[i + 1] = (lum << 16) + (lum << 8) + lum; + } + return destPalette; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::loadUserPalette() +{ + if (!myOSystem.checkUserPalette(true)) + return; + + const string& palette = myOSystem.paletteFile(); + ifstream in(palette, std::ios::binary); + + // Now that we have valid data, create the user-defined palettes + std::array pixbuf; // Temporary buffer for one 24-bit pixel + + 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]); + 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]); + ourUserPALPalette[(i<<1)] = pixel; + } + + std::array secam; // All 8 24-bit pixels, plus 8 colorloss pixels + 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]); + secam[(i<<1)] = pixel; + secam[(i<<1)+1] = 0; + } + uInt32* ptr = ourUserSECAMPalette.data(); + for(int i = 0; i < 16; ++i) + { + const uInt32* s = secam.data(); + for(int j = 0; j < 16; ++j) + *ptr++ = *s++; + } + + myUserPaletteDefined = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::generateCustomPalette(ConsoleTiming timing) +{ + constexpr int NUM_CHROMA = 16; + constexpr int NUM_LUMA = 8; + constexpr float SATURATION = 0.25F; + + float color[NUM_CHROMA][2] = {{0.0F}}; + + if(timing == ConsoleTiming::ntsc) + { + // YIQ is YUV shifted by 33° + constexpr float offset = 33 * (2 * BSPF::PI_f / 360); + const float shift = myOSystem.settings().getFloat("phase_ntsc") * + (2 * BSPF::PI_f / 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 - BSPF::PI_f)); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const float I = color[chroma][0]; + const float Q = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 + + float R = Y + 0.956F * I + 0.621F * Q; + float G = Y - 0.272F * I - 0.647F * Q; + float B = Y - 1.106F * I + 1.703F * Q; + + if(R < 0) R = 0; + if(G < 0) G = 0; + if(B < 0) B = 0; + + R = powf(R, 0.9F); + G = powf(G, 0.9F); + B = powf(B, 0.9F); + + 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 + { + constexpr float offset = 180 * (2 * BSPF::PI_f / 360); + float shift = myOSystem.settings().getFloat("phase_pal") * + (2 * BSPF::PI_f / 360); + constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 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 * sinf(offset - fixedShift * chroma); + if ((idx & 1) == 0) + color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); + else + color[idx][1] = SATURATION * -sinf(offset - shift * chroma / 2.F); + } + + for(int chroma = 0; chroma < NUM_CHROMA; chroma++) + { + const float U = color[chroma][0]; + const float V = color[chroma][1]; + + for(int luma = 0; luma < NUM_LUMA; luma++) + { + const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 + + // 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; + //float 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 = powf(R, 1.2F); + G = powf(G, 1.2F); + B = powf(B, 1.2F); + + 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 PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) +{ + // public-domain function by Darel Rex Finley + // + // The passed-in RGB values can be on any desired scale, such as 0 to + // to 1, or 0 to 255. (But use the same scale for all three!) + // + // The "change" parameter works like this: + // 0.0 creates a black-and-white image. + // 0.5 reduces the color saturation by half. + // 1.0 causes no change. + // 2.0 doubles the color saturation. + // Note: A "change" value greater than 1.0 may project your RGB values + // beyond their normal range, in which case you probably should truncate + // them to the desired range before trying to use them in an image. + constexpr float PR = .2989F; + constexpr float PG = .5870F; + constexpr float PB = .1140F; + + float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; + + R = P + (R - P) * change; + G = P + (G - P) * change; + B = P + (B - P) * change; + + R = BSPF::clamp(R, 0, 255); + G = BSPF::clamp(G, 0, 255); + B = BSPF::clamp(B, 0, 255); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeSaturation(float& R, float& G, float& 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) ; + + R = P + (R - P) * change; + G = P + (G - P) * change; + B = P + (B - P) * change; + + if(R < 0) R = 0; + if(G < 0) G = 0; + if(B < 0) B = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::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, + ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), + }; + + if(myUserPaletteDefined) + { + int idx = PaletteType::User * int(ConsoleTiming::numTimings); + palette[idx + int(ConsoleTiming::ntsc)] = ourUserNTSCPalette.data(); + palette[idx + int(ConsoleTiming::pal)] = ourUserPALPalette.data(); + palette[idx + int(ConsoleTiming::secam)] = ourUserSECAMPalette.data(); + } + + for(int i = 0; i < int(ConsoleTiming::numTimings) * PaletteType::NumTypes; ++i) + { + if(palette[i] == nullptr) + continue; + + // Fill the odd numbered palette entries with gray values (calculated + // using the standard RGB -> grayscale conversion formula) + for(int j = 0; j < 128; ++j) + { + const uInt32 pixel = palette[i][(j<<1)]; + const uInt8 r = (pixel >> 16) & 0xff; + const uInt8 g = (pixel >> 8) & 0xff; + const uInt8 b = (pixel >> 0) & 0xff; + const uInt8 sum = static_cast((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); + palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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, + 0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0, + 0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0, + 0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0, + 0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0, + 0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0, + 0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0, + 0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0, + 0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0, + 0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0, + 0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0, + 0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0, + 0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0, + 0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0, + 0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0, + 0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0, + 0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0, + 0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0, + 0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0, + 0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0, + 0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0, + 0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0, + 0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0, + 0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0, + 0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0, + 0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0, + 0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0, + 0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0, + 0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0, + 0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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 + 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, + 0x1d0f00, 0, 0x3f2700, 0, 0x614900, 0, 0x836b01, 0, // 1b0 2 + 0xa58d23, 0, 0xc7af45, 0, 0xe9d167, 0, 0xffe789, 0, // was ..0xfff389 + 0x002400, 0, 0x004600, 0, 0x216800, 0, 0x438a07, 0, // 1c8 3 + 0x65ac29, 0, 0x87ce4b, 0, 0xa9f06d, 0, 0xcbff8f, 0, + 0x340000, 0, 0x561400, 0, 0x783602, 0, 0x9a5824, 0, // 1e0 4 + 0xbc7a46, 0, 0xde9c68, 0, 0xffbe8a, 0, 0xffd0ad, 0, // was ..0xffe0ac + 0x002700, 0, 0x004900, 0, 0x0c6b0c, 0, 0x2e8d2e, 0, // 1f8 5 + 0x50af50, 0, 0x72d172, 0, 0x94f394, 0, 0xb6ffb6, 0, + 0x3d0008, 0, 0x610511, 0, 0x832733, 0, 0xa54955, 0, // 210 6 + 0xc76b77, 0, 0xe98d99, 0, 0xffafbb, 0, 0xffd1d7, 0, // was 0x3f0000..0xffd1dd + 0x001e12, 0, 0x004228, 0, 0x046540, 0, 0x268762, 0, // 228 7 + 0x48a984, 0, 0x6acba6, 0, 0x8cedc8, 0, 0xafffe0, 0, // was 0x002100, 0x00431e..0xaeffff + 0x300025, 0, 0x5f0047, 0, 0x811e69, 0, 0xa3408b, 0, // 240 8 + 0xc562ad, 0, 0xe784cf, 0, 0xffa8ea, 0, 0xffc9f2, 0, // was ..0xffa6f1, 0xffc8ff + 0x001431, 0, 0x003653, 0, 0x0a5875, 0, 0x2c7a97, 0, // 258 9 + 0x4e9cb9, 0, 0x70bedb, 0, 0x92e0fd, 0, 0xb4ffff, 0, + 0x2c0052, 0, 0x4e0074, 0, 0x701d96, 0, 0x923fb8, 0, // 270 a + 0xb461da, 0, 0xd683fc, 0, 0xe2a5ff, 0, 0xeec9ff, 0, // was ..0xf8a5ff, 0xffc7ff + 0x001759, 0, 0x00247c, 0, 0x1d469e, 0, 0x3f68c0, 0, // 288 b + 0x618ae2, 0, 0x83acff, 0, 0xa5ceff, 0, 0xc7f0ff, 0, + 0x12006d, 0, 0x34038f, 0, 0x5625b1, 0, 0x7847d3, 0, // 2a0 c + 0x9a69f5, 0, 0xb48cff, 0, 0xc9adff, 0, 0xe1d1ff, 0, // was ..0xbc8bff, 0xdeadff, 0xffcfff, + 0x000070, 0, 0x161292, 0, 0x3834b4, 0, 0x5a56d6, 0, // 2b8 d + 0x7c78f8, 0, 0x9e9aff, 0, 0xc0bcff, 0, 0xe2deff, 0, + 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2d0 e + 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, + 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2e8 f + 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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, + 0x94a414, 0, 0xa8b828, 0, 0xbccc3c, 0, 0xd0e050, 0, + 0x673900, 0, 0x7b4d00, 0, 0x8f6100, 0, 0xa37513, 0, + 0xb78927, 0, 0xcb9d3b, 0, 0xdfb14f, 0, 0xf3c563, 0, + 0x7b2504, 0, 0x8f3918, 0, 0xa34d2c, 0, 0xb76140, 0, + 0xcb7554, 0, 0xdf8968, 0, 0xf39d7c, 0, 0xffb190, 0, + 0x7d122c, 0, 0x912640, 0, 0xa53a54, 0, 0xb94e68, 0, + 0xcd627c, 0, 0xe17690, 0, 0xf58aa4, 0, 0xff9eb8, 0, + 0x730871, 0, 0x871c85, 0, 0x9b3099, 0, 0xaf44ad, 0, + 0xc358c1, 0, 0xd76cd5, 0, 0xeb80e9, 0, 0xff94fd, 0, + 0x5d0b92, 0, 0x711fa6, 0, 0x8533ba, 0, 0x9947ce, 0, + 0xad5be2, 0, 0xc16ff6, 0, 0xd583ff, 0, 0xe997ff, 0, + 0x401599, 0, 0x5429ad, 0, 0x683dc1, 0, 0x7c51d5, 0, + 0x9065e9, 0, 0xa479fd, 0, 0xb88dff, 0, 0xcca1ff, 0, + 0x252593, 0, 0x3939a7, 0, 0x4d4dbb, 0, 0x6161cf, 0, + 0x7575e3, 0, 0x8989f7, 0, 0x9d9dff, 0, 0xb1b1ff, 0, + 0x0f3480, 0, 0x234894, 0, 0x375ca8, 0, 0x4b70bc, 0, + 0x5f84d0, 0, 0x7398e4, 0, 0x87acf8, 0, 0x9bc0ff, 0, + 0x04425a, 0, 0x18566e, 0, 0x2c6a82, 0, 0x407e96, 0, + 0x5492aa, 0, 0x68a6be, 0, 0x7cbad2, 0, 0x90cee6, 0, + 0x044f30, 0, 0x186344, 0, 0x2c7758, 0, 0x408b6c, 0, + 0x549f80, 0, 0x68b394, 0, 0x7cc7a8, 0, 0x90dbbc, 0, + 0x0f550a, 0, 0x23691e, 0, 0x377d32, 0, 0x4b9146, 0, + 0x5fa55a, 0, 0x73b96e, 0, 0x87cd82, 0, 0x9be196, 0, + 0x1f5100, 0, 0x336505, 0, 0x477919, 0, 0x5b8d2d, 0, + 0x6fa141, 0, 0x83b555, 0, 0x97c969, 0, 0xabdd7d, 0, + 0x344600, 0, 0x485a00, 0, 0x5c6e14, 0, 0x708228, 0, + 0x84963c, 0, 0x98aa50, 0, 0xacbe64, 0, 0xc0d278, 0, + 0x463e00, 0, 0x5a5205, 0, 0x6e6619, 0, 0x827a2d, 0, + 0x968e41, 0, 0xaaa255, 0, 0xbeb669, 0, 0xd2ca7d, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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, + 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, + 0x533a00, 0, 0x674e00, 0, 0x7b6203, 0, 0x8f7617, 0, + 0xa38a2b, 0, 0xb79e3f, 0, 0xcbb253, 0, 0xdfc667, 0, + 0x1b5800, 0, 0x2f6c00, 0, 0x438001, 0, 0x579415, 0, + 0x6ba829, 0, 0x7fbc3d, 0, 0x93d051, 0, 0xa7e465, 0, + 0x6a2900, 0, 0x7e3d12, 0, 0x925126, 0, 0xa6653a, 0, + 0xba794e, 0, 0xce8d62, 0, 0xe2a176, 0, 0xf6b58a, 0, + 0x075b00, 0, 0x1b6f11, 0, 0x2f8325, 0, 0x439739, 0, + 0x57ab4d, 0, 0x6bbf61, 0, 0x7fd375, 0, 0x93e789, 0, + 0x741b2f, 0, 0x882f43, 0, 0x9c4357, 0, 0xb0576b, 0, + 0xc46b7f, 0, 0xd87f93, 0, 0xec93a7, 0, 0xffa7bb, 0, + 0x00572e, 0, 0x106b42, 0, 0x247f56, 0, 0x38936a, 0, + 0x4ca77e, 0, 0x60bb92, 0, 0x74cfa6, 0, 0x88e3ba, 0, + 0x6d165f, 0, 0x812a73, 0, 0x953e87, 0, 0xa9529b, 0, + 0xbd66af, 0, 0xd17ac3, 0, 0xe58ed7, 0, 0xf9a2eb, 0, + 0x014c5e, 0, 0x156072, 0, 0x297486, 0, 0x3d889a, 0, + 0x519cae, 0, 0x65b0c2, 0, 0x79c4d6, 0, 0x8dd8ea, 0, + 0x5f1588, 0, 0x73299c, 0, 0x873db0, 0, 0x9b51c4, 0, + 0xaf65d8, 0, 0xc379ec, 0, 0xd78dff, 0, 0xeba1ff, 0, + 0x123b87, 0, 0x264f9b, 0, 0x3a63af, 0, 0x4e77c3, 0, + 0x628bd7, 0, 0x769feb, 0, 0x8ab3ff, 0, 0x9ec7ff, 0, + 0x451e9d, 0, 0x5932b1, 0, 0x6d46c5, 0, 0x815ad9, 0, + 0x956eed, 0, 0xa982ff, 0, 0xbd96ff, 0, 0xd1aaff, 0, + 0x2a2b9e, 0, 0x3e3fb2, 0, 0x5253c6, 0, 0x6667da, 0, + 0x7a7bee, 0, 0x8e8fff, 0, 0xa2a3ff, 0, 0xb6b7ff, 0, + 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, + 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, + 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, + 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +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, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, + 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, + 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourUserNTSCPalette = { 0 }; // filled from external file + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourUserPALPalette = { 0 }; // filled from external file + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourUserSECAMPalette = { 0 }; // filled from external file + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourCustomNTSCPalette = { 0 }; // filled by function + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PaletteArray PaletteHandler::ourCustomPALPalette = { 0 }; // filled by function diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx new file mode 100644 index 000000000..6b26b918a --- /dev/null +++ b/src/common/PaletteHandler.hxx @@ -0,0 +1,155 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef PALETTE_HANDLER_HXX +#define PALETTE_HANDLER_HXX + +#include "bspf.hxx" +#include "OSystem.hxx" + +class PaletteHandler +{ + public: + static constexpr const char* SETTING_STANDARD = "standard"; + static constexpr const char* SETTING_Z26 = "z26"; + static constexpr const char* SETTING_USER = "user"; + static constexpr const char* SETTING_CUSTOM = "custom"; + + enum DisplayType { + NTSC, + PAL, + SECAM, + NumDisplayTypes + }; + + + public: + PaletteHandler(OSystem& system); + virtual ~PaletteHandler() = default; + + /** + Switch between the available palettes. + */ + void changePalette(bool increase = true); + + + /** + 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 increase increase if true, else decrease. + */ + void changeColorPhaseShift(bool increase = true); + + void changeSaturation(int& R, int& G, int& B, float change); + void changeSaturation(float& R, float& G, float& B, float change); + + /** + Sets the palette according to the given palette name. + + @param palette The palette to switch to. + */ + void setPalette(const string& name); + + + /** + Sets the palette from current settings. + */ + void setPalette(); + + + void generatePalettes(); + + /** + Loads all defined palettes with PAL color-loss data, even those that + normally can't have it enabled (NTSC), since it's also used for + 'greying out' the frame in the debugger. + */ + void generateColorLossPalette(); + + + /** + Generates a custom palette, based on user defined phase shifts. + */ + void generateCustomPalette(ConsoleTiming timing); + + private: + enum PaletteType { + Standard, + Z26, + User, + Custom, + NumTypes, + MinType = Standard, + MaxType = Custom + }; + + PaletteType toPaletteType(const string& name) const; + string toPaletteName(PaletteType type) const; + + PaletteArray adjustPalette(const PaletteArray& source); + + /** + Loads a user-defined palette file (from OSystem::paletteFile), filling the + appropriate user-defined palette arrays. + */ + void loadUserPalette(); + + + private: + OSystem& myOSystem; + + // range -1.0 to +1.0 (as in AtariNTSC) + float myContrast{0.0F}; + float myBrightness{0.0F}; + float myHue{0.0F}; + float mySaturation{0.0F}; + float myGamma{0.0F}; + + // Indicates whether an external palette was found and + // successfully loaded + bool myUserPaletteDefined{false}; + + // Table of RGB values for NTSC, PAL and SECAM + static PaletteArray ourNTSCPalette; + static PaletteArray ourPALPalette; + static PaletteArray ourSECAMPalette; + + // Table of RGB values for NTSC, PAL and SECAM - Z26 version + static PaletteArray ourNTSCPaletteZ26; + static PaletteArray ourPALPaletteZ26; + static PaletteArray ourSECAMPaletteZ26; + + // Table of RGB values for NTSC, PAL and SECAM - user-defined + static PaletteArray ourUserNTSCPalette; + static PaletteArray ourUserPALPalette; + static PaletteArray ourUserSECAMPalette; + + // Table of RGB values for NTSC, PAL - custom-defined + static PaletteArray ourCustomNTSCPalette; + static PaletteArray ourCustomPALPalette; + + private: + PaletteHandler() = delete; + PaletteHandler(const PaletteHandler&) = delete; + PaletteHandler(PaletteHandler&&) = delete; + PaletteHandler& operator=(const PaletteHandler&) = delete; + PaletteHandler& operator=(const PaletteHandler&&) = delete; +}; + +#endif // PALETTE_HANDLER_HXX diff --git a/src/common/module.mk b/src/common/module.mk index f7a228189..1aae6cd0a 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -11,6 +11,7 @@ MODULE_OBJS := \ src/common/Logger.o \ src/common/main.o \ src/common/MouseControl.o \ + src/common/PaletteHandler.o \ src/common/PhosphorHandler.o \ src/common/PhysicalJoystick.o \ src/common/PJoystickHandler.o \ diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 46078f09d..299b1ea3a 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 "PaletteHandler.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" @@ -81,19 +82,13 @@ Console::Console(OSystem& osystem, unique_ptr& cart, myCart(std::move(cart)), myAudioSettings(audioSettings) { - // 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()); myTIA = make_unique(*this, [this]() { return timing(); }, myOSystem.settings()); myFrameManager = make_unique(); mySwitches = make_unique(myEvent, myProperties, myOSystem.settings()); + myPaletteHandler = make_unique(myOSystem); myTIA->setFrameManager(myFrameManager.get()); @@ -441,7 +436,7 @@ void Console::setFormat(uInt32 format) myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; - setPalette(myOSystem.settings().getString("palette")); + myPaletteHandler->setPalette(); setTIAProperties(); initializeVideo(); // takes care of refreshing the screen initializeAudio(); // ensure that audio synthesis is set up to match emulation speed @@ -477,96 +472,6 @@ 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() -{ - string palette, message; - palette = myOSystem.settings().getString("palette"); - - if(palette == "standard") // switch to z26 - { - palette = "z26"; - message = "Z26 palette"; - } - else if(palette == "z26") // switch to user or standard - { - // If we have a user-defined palette, it will come next in - // the sequence; otherwise loop back to the standard one - if(myUserPaletteDefined) - { - palette = "user"; - message = "User-defined palette"; - } - else - { - palette = "custom"; - message = "Custom palette"; - } - } - else if(palette == "user") // switch to custom - { - palette = "custom"; - message = "Custom palette"; - } - else // switch to standard mode if we get this far - { - palette = "standard"; - message = "Standard Stella palette"; - } - - myOSystem.settings().setValue("palette", palette); - myOSystem.frameBuffer().showMessage(message); - - setPalette(palette); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -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 }, - { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } - }}; - - // See which format we should be using - int paletteNum = getPaletteNum(type); - - if(paletteNum == PaletteType::Custom) - { - - } - - // Now consider the current display format - const PaletteArray* palette = - (myDisplayFormat.compare(0, 3, "PAL") == 0) ? palettes[paletteNum][1] : - (myDisplayFormat.compare(0, 5, "SECAM") == 0) ? palettes[paletteNum][2] : - palettes[paletteNum][0]; - - myOSystem.frameBuffer().setTIAPalette(*palette); - - if(myTIA->usingFixedColors()) - myTIA->enableFixedColors(true); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleInter() { @@ -677,11 +582,9 @@ FBInitStatus Console::initializeVideo(bool full) myOSystem.frameBuffer().showFrameStats( myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats")); - generateCustomPalette(0); - generateCustomPalette(1); - generateColorLossPalette(); + myPaletteHandler->generatePalettes(); } - setPalette(myOSystem.settings().getString("palette")); + myPaletteHandler->setPalette(); return fbstatus; } @@ -826,46 +729,6 @@ 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() { @@ -1073,202 +936,6 @@ unique_ptr Console::getControllerPort(const Controller::Type type, return controller; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::loadUserPalette() -{ - if (!myOSystem.checkUserPalette(true)) - return; - - const string& palette = myOSystem.paletteFile(); - ifstream in(palette, std::ios::binary); - - // Now that we have valid data, create the user-defined palettes - std::array pixbuf; // Temporary buffer for one 24-bit pixel - - 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]); - 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]); - ourUserPALPalette[(i<<1)] = pixel; - } - - std::array secam; // All 8 24-bit pixels, plus 8 colorloss pixels - 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]); - secam[(i<<1)] = pixel; - secam[(i<<1)+1] = 0; - } - uInt32* ptr = ourUserSECAMPalette.data(); - for(int i = 0; i < 16; ++i) - { - const uInt32* s = secam.data(); - for(int j = 0; j < 16; ++j) - *ptr++ = *s++; - } - - myUserPaletteDefined = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::generateCustomPalette(int type) -{ - constexpr int NUM_CHROMA = 16; - constexpr int NUM_LUMA = 8; - constexpr float SATURATION = 0.25F; - - float color[NUM_CHROMA][2] = {{0.0F}}; - - if(type == 0) - { - // YIQ is YUV shifted by 33° - constexpr float offset = 33 * (2 * BSPF::PI_f / 360); - const float shift = myOSystem.settings().getFloat("phase_ntsc") * - (2 * BSPF::PI_f / 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 - BSPF::PI_f)); - } - - for(int chroma = 0; chroma < NUM_CHROMA; chroma++) - { - const float I = color[chroma][0]; - const float Q = color[chroma][1]; - - for(int luma = 0; luma < NUM_LUMA; luma++) - { - const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - - float R = Y + 0.956F * I + 0.621F * Q; - float G = Y - 0.272F * I - 0.647F * Q; - float B = Y - 1.106F * I + 1.703F * Q; - - if(R < 0) R = 0; - if(G < 0) G = 0; - if(B < 0) B = 0; - - R = powf(R, 0.9F); - G = powf(G, 0.9F); - B = powf(B, 0.9F); - - 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 - { - constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - float shift = myOSystem.settings().getFloat("phase_pal") * - (2 * BSPF::PI_f / 360); - constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 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 * sinf(offset - fixedShift * chroma); - if ((idx & 1) == 0) - color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F); - else - color[idx][1] = SATURATION * -sinf(offset - shift * chroma / 2.F); - } - - for(int chroma = 0; chroma < NUM_CHROMA; chroma++) - { - const float U = color[chroma][0]; - const float V = color[chroma][1]; - - for(int luma = 0; luma < NUM_LUMA; luma++) - { - const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90 - - // 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; - //float 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 = powf(R, 1.2); - G = powf(G, 1.2); - B = powf(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, - ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), - }; - if(myUserPaletteDefined) - { - palette[6] = ourUserNTSCPalette.data(); - palette[7] = ourUserPALPalette.data(); - palette[8] = ourUserSECAMPalette.data(); - } - - for(int i = 0; i < 3 * PaletteType::NumTypes; ++i) - { - if(palette[i] == nullptr) - continue; - - // Fill the odd numbered palette entries with gray values (calculated - // using the standard RGB -> grayscale conversion formula) - for(int j = 0; j < 128; ++j) - { - const uInt32 pixel = palette[i][(j<<1)]; - const uInt8 r = (pixel >> 16) & 0xff; - const uInt8 g = (pixel >> 8) & 0xff; - const uInt8 b = (pixel >> 0) & 0xff; - const uInt8 sum = static_cast((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); - palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; - } - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - float Console::getFramerate() const { @@ -1340,234 +1007,3 @@ void Console::stateChanged(EventHandlerState state) { // only the CompuMate used to care about state changes } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::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, - 0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0, - 0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0, - 0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0, - 0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0, - 0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0, - 0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0, - 0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0, - 0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0, - 0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0, - 0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0, - 0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0, - 0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0, - 0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0, - 0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0, - 0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0, - 0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0, - 0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0, - 0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0, - 0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0, - 0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0, - 0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0, - 0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0, - 0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0, - 0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0, - 0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0, - 0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0, - 0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0, - 0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0, - 0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::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 - 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, - 0x1d0f00, 0, 0x3f2700, 0, 0x614900, 0, 0x836b01, 0, // 1b0 2 - 0xa58d23, 0, 0xc7af45, 0, 0xe9d167, 0, 0xffe789, 0, // was ..0xfff389 - 0x002400, 0, 0x004600, 0, 0x216800, 0, 0x438a07, 0, // 1c8 3 - 0x65ac29, 0, 0x87ce4b, 0, 0xa9f06d, 0, 0xcbff8f, 0, - 0x340000, 0, 0x561400, 0, 0x783602, 0, 0x9a5824, 0, // 1e0 4 - 0xbc7a46, 0, 0xde9c68, 0, 0xffbe8a, 0, 0xffd0ad, 0, // was ..0xffe0ac - 0x002700, 0, 0x004900, 0, 0x0c6b0c, 0, 0x2e8d2e, 0, // 1f8 5 - 0x50af50, 0, 0x72d172, 0, 0x94f394, 0, 0xb6ffb6, 0, - 0x3d0008, 0, 0x610511, 0, 0x832733, 0, 0xa54955, 0, // 210 6 - 0xc76b77, 0, 0xe98d99, 0, 0xffafbb, 0, 0xffd1d7, 0, // was 0x3f0000..0xffd1dd - 0x001e12, 0, 0x004228, 0, 0x046540, 0, 0x268762, 0, // 228 7 - 0x48a984, 0, 0x6acba6, 0, 0x8cedc8, 0, 0xafffe0, 0, // was 0x002100, 0x00431e..0xaeffff - 0x300025, 0, 0x5f0047, 0, 0x811e69, 0, 0xa3408b, 0, // 240 8 - 0xc562ad, 0, 0xe784cf, 0, 0xffa8ea, 0, 0xffc9f2, 0, // was ..0xffa6f1, 0xffc8ff - 0x001431, 0, 0x003653, 0, 0x0a5875, 0, 0x2c7a97, 0, // 258 9 - 0x4e9cb9, 0, 0x70bedb, 0, 0x92e0fd, 0, 0xb4ffff, 0, - 0x2c0052, 0, 0x4e0074, 0, 0x701d96, 0, 0x923fb8, 0, // 270 a - 0xb461da, 0, 0xd683fc, 0, 0xe2a5ff, 0, 0xeec9ff, 0, // was ..0xf8a5ff, 0xffc7ff - 0x001759, 0, 0x00247c, 0, 0x1d469e, 0, 0x3f68c0, 0, // 288 b - 0x618ae2, 0, 0x83acff, 0, 0xa5ceff, 0, 0xc7f0ff, 0, - 0x12006d, 0, 0x34038f, 0, 0x5625b1, 0, 0x7847d3, 0, // 2a0 c - 0x9a69f5, 0, 0xb48cff, 0, 0xc9adff, 0, 0xe1d1ff, 0, // was ..0xbc8bff, 0xdeadff, 0xffcfff, - 0x000070, 0, 0x161292, 0, 0x3834b4, 0, 0x5a56d6, 0, // 2b8 d - 0x7c78f8, 0, 0x9e9aff, 0, 0xc0bcff, 0, 0xe2deff, 0, - 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2d0 e - 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, - 0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 2e8 f - 0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::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, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::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, - 0x94a414, 0, 0xa8b828, 0, 0xbccc3c, 0, 0xd0e050, 0, - 0x673900, 0, 0x7b4d00, 0, 0x8f6100, 0, 0xa37513, 0, - 0xb78927, 0, 0xcb9d3b, 0, 0xdfb14f, 0, 0xf3c563, 0, - 0x7b2504, 0, 0x8f3918, 0, 0xa34d2c, 0, 0xb76140, 0, - 0xcb7554, 0, 0xdf8968, 0, 0xf39d7c, 0, 0xffb190, 0, - 0x7d122c, 0, 0x912640, 0, 0xa53a54, 0, 0xb94e68, 0, - 0xcd627c, 0, 0xe17690, 0, 0xf58aa4, 0, 0xff9eb8, 0, - 0x730871, 0, 0x871c85, 0, 0x9b3099, 0, 0xaf44ad, 0, - 0xc358c1, 0, 0xd76cd5, 0, 0xeb80e9, 0, 0xff94fd, 0, - 0x5d0b92, 0, 0x711fa6, 0, 0x8533ba, 0, 0x9947ce, 0, - 0xad5be2, 0, 0xc16ff6, 0, 0xd583ff, 0, 0xe997ff, 0, - 0x401599, 0, 0x5429ad, 0, 0x683dc1, 0, 0x7c51d5, 0, - 0x9065e9, 0, 0xa479fd, 0, 0xb88dff, 0, 0xcca1ff, 0, - 0x252593, 0, 0x3939a7, 0, 0x4d4dbb, 0, 0x6161cf, 0, - 0x7575e3, 0, 0x8989f7, 0, 0x9d9dff, 0, 0xb1b1ff, 0, - 0x0f3480, 0, 0x234894, 0, 0x375ca8, 0, 0x4b70bc, 0, - 0x5f84d0, 0, 0x7398e4, 0, 0x87acf8, 0, 0x9bc0ff, 0, - 0x04425a, 0, 0x18566e, 0, 0x2c6a82, 0, 0x407e96, 0, - 0x5492aa, 0, 0x68a6be, 0, 0x7cbad2, 0, 0x90cee6, 0, - 0x044f30, 0, 0x186344, 0, 0x2c7758, 0, 0x408b6c, 0, - 0x549f80, 0, 0x68b394, 0, 0x7cc7a8, 0, 0x90dbbc, 0, - 0x0f550a, 0, 0x23691e, 0, 0x377d32, 0, 0x4b9146, 0, - 0x5fa55a, 0, 0x73b96e, 0, 0x87cd82, 0, 0x9be196, 0, - 0x1f5100, 0, 0x336505, 0, 0x477919, 0, 0x5b8d2d, 0, - 0x6fa141, 0, 0x83b555, 0, 0x97c969, 0, 0xabdd7d, 0, - 0x344600, 0, 0x485a00, 0, 0x5c6e14, 0, 0x708228, 0, - 0x84963c, 0, 0x98aa50, 0, 0xacbe64, 0, 0xc0d278, 0, - 0x463e00, 0, 0x5a5205, 0, 0x6e6619, 0, 0x827a2d, 0, - 0x968e41, 0, 0xaaa255, 0, 0xbeb669, 0, 0xd2ca7d, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::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, - 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, - 0x533a00, 0, 0x674e00, 0, 0x7b6203, 0, 0x8f7617, 0, - 0xa38a2b, 0, 0xb79e3f, 0, 0xcbb253, 0, 0xdfc667, 0, - 0x1b5800, 0, 0x2f6c00, 0, 0x438001, 0, 0x579415, 0, - 0x6ba829, 0, 0x7fbc3d, 0, 0x93d051, 0, 0xa7e465, 0, - 0x6a2900, 0, 0x7e3d12, 0, 0x925126, 0, 0xa6653a, 0, - 0xba794e, 0, 0xce8d62, 0, 0xe2a176, 0, 0xf6b58a, 0, - 0x075b00, 0, 0x1b6f11, 0, 0x2f8325, 0, 0x439739, 0, - 0x57ab4d, 0, 0x6bbf61, 0, 0x7fd375, 0, 0x93e789, 0, - 0x741b2f, 0, 0x882f43, 0, 0x9c4357, 0, 0xb0576b, 0, - 0xc46b7f, 0, 0xd87f93, 0, 0xec93a7, 0, 0xffa7bb, 0, - 0x00572e, 0, 0x106b42, 0, 0x247f56, 0, 0x38936a, 0, - 0x4ca77e, 0, 0x60bb92, 0, 0x74cfa6, 0, 0x88e3ba, 0, - 0x6d165f, 0, 0x812a73, 0, 0x953e87, 0, 0xa9529b, 0, - 0xbd66af, 0, 0xd17ac3, 0, 0xe58ed7, 0, 0xf9a2eb, 0, - 0x014c5e, 0, 0x156072, 0, 0x297486, 0, 0x3d889a, 0, - 0x519cae, 0, 0x65b0c2, 0, 0x79c4d6, 0, 0x8dd8ea, 0, - 0x5f1588, 0, 0x73299c, 0, 0x873db0, 0, 0x9b51c4, 0, - 0xaf65d8, 0, 0xc379ec, 0, 0xd78dff, 0, 0xeba1ff, 0, - 0x123b87, 0, 0x264f9b, 0, 0x3a63af, 0, 0x4e77c3, 0, - 0x628bd7, 0, 0x769feb, 0, 0x8ab3ff, 0, 0x9ec7ff, 0, - 0x451e9d, 0, 0x5932b1, 0, 0x6d46c5, 0, 0x815ad9, 0, - 0x956eed, 0, 0xa982ff, 0, 0xbd96ff, 0, 0xd1aaff, 0, - 0x2a2b9e, 0, 0x3e3fb2, 0, 0x5253c6, 0, 0x6667da, 0, - 0x7a7bee, 0, 0x8e8fff, 0, 0xa2a3ff, 0, 0xb6b7ff, 0, - 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, - 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, - 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, - 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::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, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, - 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, - 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray Console::ourUserNTSCPalette = { 0 }; // filled from external file - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -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 9ff4b002c..36c680539 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -29,6 +29,7 @@ class CompuMate; class Debugger; class AudioQueue; class AudioSettings; +class PaletteHandler; #include "bspf.hxx" #include "ConsoleIO.hxx" @@ -186,6 +187,11 @@ class Console : public Serializable, public ConsoleIO */ EmulationTiming& emulationTiming() { return myEmulationTiming; } + /** + Retrieve palette handler. + */ + PaletteHandler& paletteHandler() const { return *myPaletteHandler; } + public: /** Toggle between NTSC/PAL/SECAM (and variants) display format. @@ -204,23 +210,6 @@ class Console : public Serializable, public ConsoleIO */ string getFormatString() const { return myDisplayFormat; } - /** - Toggle between the available palettes. - */ - 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. - - @param palette The palette to switch to. - */ - void setPalette(const string& palette); - /** Toggle interpolation on/off */ @@ -288,16 +277,6 @@ 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. */ @@ -379,35 +358,10 @@ class Console : public Serializable, public ConsoleIO unique_ptr getControllerPort(const Controller::Type type, const Controller::Jack port, const string& romMd5); - /** - Loads a user-defined palette file (from OSystem::paletteFile), filling the - appropriate user-defined palette arrays. - */ - void loadUserPalette(); - - /** - Loads all defined palettes with PAL color-loss data, even those that - normally can't have it enabled (NTSC), since it's also used for - 'greying out' the frame in the debugger. - */ - 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; @@ -457,10 +411,6 @@ class Console : public Serializable, public ConsoleIO // Is the TV format autodetected? bool myFormatAutodetected{false}; - // Indicates whether an external palette was found and - // successfully loaded - bool myUserPaletteDefined{false}; - // Contains detailed info about this console ConsoleInfo myConsoleInfo; @@ -474,24 +424,8 @@ class Console : public Serializable, public ConsoleIO // The audio settings AudioSettings& myAudioSettings; - // Table of RGB values for NTSC, PAL and SECAM - static PaletteArray ourNTSCPalette; - static PaletteArray ourPALPalette; - static PaletteArray ourSECAMPalette; - - // Table of RGB values for NTSC, PAL and SECAM - Z26 version - static PaletteArray ourNTSCPaletteZ26; - static PaletteArray ourPALPaletteZ26; - static PaletteArray ourSECAMPaletteZ26; - - // Table of RGB values for NTSC, PAL and SECAM - user-defined - static PaletteArray ourUserNTSCPalette; - static PaletteArray ourUserPALPalette; - static PaletteArray ourUserSECAMPalette; - - // Table of RGB values for NTSC, PAL - custom-defined - static PaletteArray ourCustomNTSCPalette; - static PaletteArray ourCustomPALPalette; + // The palette handling + unique_ptrmyPaletteHandler; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/ConsoleTiming.hxx b/src/emucore/ConsoleTiming.hxx index 1f75db469..fd43caa98 100644 --- a/src/emucore/ConsoleTiming.hxx +++ b/src/emucore/ConsoleTiming.hxx @@ -25,7 +25,8 @@ enum class ConsoleTiming { ntsc, // console with CPU running at 1.193182 MHz, NTSC colours pal, // console with CPU running at 1.182298 MHz, PAL colours - secam // console with CPU running at 1.187500 MHz, SECAM colours + secam, // console with CPU running at 1.187500 MHz, SECAM colours + numTimings }; #endif // CONSOLE_TIMING_HXX diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 915461e97..5dbb71126 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -100,7 +100,7 @@ class Event Unwind1Menu, Unwind10Menu, UnwindAllMenu, RewindPause, UnwindPause, - FormatDecrease, FormatIncrease, TogglePalette, ToggleColorLoss, + FormatDecrease, FormatIncrease, PaletteIncrease, ToggleColorLoss, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, VCenterDecrease, VCenterIncrease, ScanlineAdjustDecrease, ScanlineAdjustIncrease, OverscanDecrease, OverscanIncrease, @@ -120,7 +120,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten - ToggleTurbo, + ToggleTurbo, PaletteDecrease, ColorShiftDecrease, ColorShiftIncrease, LastType diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index c9fa85835..04dd852d0 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -22,6 +22,7 @@ #include "Base.hxx" #include "Console.hxx" +#include "PaletteHandler.hxx" #include "FrameBuffer.hxx" #include "FSNode.hxx" #include "OSystem.hxx" @@ -436,11 +437,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ColorShiftDecrease: - if (pressed) myOSystem.console().changeColorPhaseShift(-1); + if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(false); return; case Event::ColorShiftIncrease: - if (pressed) myOSystem.console().changeColorPhaseShift(+1); + if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(); return; case Event::ToggleFullScreen: @@ -539,8 +540,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed && !repeated) myOSystem.console().toggleColorLoss(); return; - case Event::TogglePalette: - if (pressed && !repeated) myOSystem.console().togglePalette(); + case Event::PaletteDecrease: + if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(false); + return; + + case Event::PaletteIncrease: + if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(); return; case Event::ToggleInter: @@ -1929,7 +1934,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, { Event::FormatIncrease, "Increase display format", "" }, - { Event::TogglePalette, "Switch palette (Std./Z26/User/Cust.)", "" }, + { Event::PaletteDecrease, "Switch to previous palette", "" }, + { Event::PaletteIncrease, "Switch to next palette", "" }, { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, @@ -2058,7 +2064,8 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::VCenterDecrease, Event::VCenterIncrease, Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, - Event::TogglePalette, Event::ColorShiftDecrease, Event::ColorShiftIncrease, + Event::PaletteDecrease, Event::PaletteIncrease, + Event::ColorShiftDecrease, Event::ColorShiftIncrease, Event::ToggleInter }; diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 8fe4c7821..10259780a 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 = 149 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 150 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index c1c64dd20..a8100d99d 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -64,12 +64,12 @@ Settings::Settings() setPermanent("tv.phosphor", "byrom"); setPermanent("tv.phosblend", "50"); setPermanent("tv.scanlines", "25"); - // TV options when using 'custom' mode setPermanent("tv.contrast", "0.0"); setPermanent("tv.brightness", "0.0"); setPermanent("tv.hue", "0.0"); setPermanent("tv.saturation", "0.0"); setPermanent("tv.gamma", "0.0"); + // TV options when using 'custom' mode setPermanent("tv.sharpness", "0.0"); setPermanent("tv.resolution", "0.0"); setPermanent("tv.artifacts", "0.0"); diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 5c734a52e..9efa56a7b 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "Console.hxx" +#include "PaletteHandler.hxx" #include "TIA.hxx" #include "Switches.hxx" #include "Dialog.hxx" @@ -203,7 +204,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, break; case kPaletteCmd: - instance().console().togglePalette(); + instance().console().paletteHandler().changePalette(); updatePalette(); break; diff --git a/src/gui/HelpDialog.cxx b/src/gui/HelpDialog.cxx index 5c9a6b1d3..77c01f174 100644 --- a/src/gui/HelpDialog.cxx +++ b/src/gui/HelpDialog.cxx @@ -121,7 +121,7 @@ void HelpDialog::updateStrings(uInt8 page, uInt8 lines, string& title) case 2: title = "Special commands"; ADD_EVENT(Event::FormatIncrease, "Switch between NTSC/PAL/SECAM"); - ADD_EVENT(Event::TogglePalette, "Switch palette"); + ADD_EVENT(Event::PaletteIncrease, "Switch to next palette"); ADD_EVENT(Event::TogglePhosphor, "Toggle 'phosphor' effect"); ADD_LINE(); ADD_EVENT(Event::ToggleGrabMouse, "Grab mouse (keep in window)"); diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 30b7a6ccc..606553562 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -25,6 +25,7 @@ #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "Console.hxx" +#include "PaletteHandler.hxx" #include "TIA.hxx" #include "Settings.hxx" #include "Widget.hxx" @@ -519,8 +520,8 @@ void VideoDialog::saveConfig() if(instance().settings().getString("palette") == "custom") { - instance().console().generateCustomPalette(0); - instance().console().generateCustomPalette(1); + instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); + instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::pal); } if(vsizeChanged) diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 1095f2c09..bc0724d09 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -503,6 +503,7 @@ + @@ -1503,6 +1504,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index fb763da4c..62e324fa4 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1002,6 +1002,9 @@ Source Files\emucore + + Source Files + @@ -2057,6 +2060,9 @@ Header Files\emucore + + Header Files + From 2ae04d7450aca3f8941e4fd582fac51930d1d9d8 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 9 May 2020 15:13:08 -0230 Subject: [PATCH 04/42] Don't create an array of size 0. --- src/emucore/CartEnhanced.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index f5c38c9a3..0bd964890 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -52,7 +52,8 @@ void CartridgeEnhanced::install(System& system) myCurrentSegOffset = make_unique(myBankSegs); // Allocate array for the RAM area - myRAM = make_unique(myRamSize); + if(myRamSize > 0) + myRAM = make_unique(myRamSize); mySystem = &system; @@ -101,7 +102,8 @@ void CartridgeEnhanced::install(System& system) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEnhanced::reset() { - initializeRAM(myRAM.get(), myRamSize); + if(myRamSize > 0) + initializeRAM(myRAM.get(), myRamSize); initializeStartBank(getStartBank()); From 123d2ec9f6fd1c7737f8bd748c4be8787efe332d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 9 May 2020 21:36:22 +0200 Subject: [PATCH 05/42] remove palette functionality from NTSCFilter load and save config values in PaletteHandler --- src/common/KeyMap.hxx | 1 + src/common/PKeyboardHandler.cxx | 34 +++-- src/common/PaletteHandler.cxx | 194 +++++++++++++++------------ src/common/PaletteHandler.hxx | 59 +++++--- src/common/tv_filters/AtariNTSC.cxx | 43 +++++- src/common/tv_filters/AtariNTSC.hxx | 12 ++ src/common/tv_filters/NTSCFilter.cxx | 45 ++++--- src/common/tv_filters/NTSCFilter.hxx | 8 ++ src/emucore/Console.cxx | 6 - src/emucore/Console.hxx | 10 -- src/emucore/Event.hxx | 13 +- src/emucore/EventHandler.cxx | 45 ++++++- src/emucore/EventHandler.hxx | 4 +- src/emucore/OSystem.cxx | 3 + src/emucore/Settings.cxx | 4 +- src/emucore/TIASurface.cxx | 32 +++++ src/emucore/TIASurface.hxx | 17 ++- src/gui/CommandDialog.cxx | 2 +- src/gui/VideoDialog.cxx | 59 ++++---- src/gui/Widget.hxx | 1 + 20 files changed, 389 insertions(+), 203 deletions(-) diff --git a/src/common/KeyMap.hxx b/src/common/KeyMap.hxx index 94d3b4242..0b7eff2fe 100644 --- a/src/common/KeyMap.hxx +++ b/src/common/KeyMap.hxx @@ -21,6 +21,7 @@ #include #include "Event.hxx" #include "EventHandlerConstants.hxx" +#include "StellaKeys.hxx" /** This class handles keyboard mappings in Stella. diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 639d8ae31..1a0fe6499 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -15,15 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "OSystem.hxx" -#include "Console.hxx" -#include "Settings.hxx" #include "EventHandler.hxx" -#include "Sound.hxx" -#include "StateManager.hxx" -#include "StellaKeys.hxx" -#include "TIASurface.hxx" -#include "PNGLibrary.hxx" #include "PKeyboardHandler.hxx" #ifdef DEBUGGER_SUPPORT @@ -475,16 +467,22 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleFullScreen, KBDK_RETURN, MOD3}, {Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT}, {Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT}, - {Event::VidmodeStd, KBDK_1, MOD3}, - {Event::VidmodeRGB, KBDK_2, MOD3}, - {Event::VidmodeSVideo, KBDK_3, MOD3}, - {Event::VidModeComposite, KBDK_4, MOD3}, - {Event::VidModeBad, KBDK_5, MOD3}, - {Event::VidModeCustom, KBDK_6, MOD3}, - {Event::PreviousAttribute, KBDK_7, KBDM_SHIFT | MOD3}, - {Event::NextAttribute, KBDK_7, MOD3}, - {Event::DecreaseAttribute, KBDK_8, KBDM_SHIFT | MOD3}, - {Event::IncreaseAttribute, KBDK_8, MOD3}, + //{Event::VidmodeStd, KBDK_1, MOD3}, + //{Event::VidmodeRGB, KBDK_2, MOD3}, + //{Event::VidmodeSVideo, KBDK_3, MOD3}, + //{Event::VidModeComposite, KBDK_4, MOD3}, + //{Event::VidModeBad, KBDK_5, MOD3}, + //{Event::VidModeCustom, KBDK_6, MOD3}, + {Event::PreviousVideoMode, KBDK_1, KBDM_SHIFT | MOD3}, + {Event::NextVideoMode, KBDK_1, MOD3}, + {Event::PreviousAttribute, KBDK_2, KBDM_SHIFT | MOD3}, + {Event::NextAttribute, KBDK_2, MOD3}, + {Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3}, + {Event::IncreaseAttribute, KBDK_3, MOD3}, + {Event::PreviousPaletteAttribute, KBDK_4, KBDM_SHIFT | MOD3}, + {Event::NextPaletteAttribute, KBDK_4, MOD3}, + {Event::PaletteAttributeDecrease, KBDK_5, KBDM_SHIFT | MOD3}, + {Event::PaletteAttributeIncrease, KBDK_5, MOD3}, {Event::PhosphorDecrease, KBDK_9, KBDM_SHIFT | MOD3}, {Event::PhosphorIncrease, KBDK_9, MOD3}, {Event::TogglePhosphor, KBDK_P, MOD3}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index e1d71f123..4e61199d0 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -26,10 +26,6 @@ PaletteHandler::PaletteHandler(OSystem& system) { // Load user-defined palette for this ROM loadUserPalette(); - - //// Generate custom palette - //generateCustomPalette(ConsoleTiming::ntsc); - //generateCustomPalette(ConsoleTiming::pal); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -100,27 +96,118 @@ void PaletteHandler::changePalette(bool increase) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::generatePalettes() +void PaletteHandler::selectAdjustable(bool next) { - generateCustomPalette(ConsoleTiming::ntsc); - generateCustomPalette(ConsoleTiming::pal); - generateColorLossPalette(); + if(next) + { + if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) + myCurrentAdjustable = 0; + else + myCurrentAdjustable++; + } + else + { + if(myCurrentAdjustable == 0) + myCurrentAdjustable = NUM_ADJUSTABLES - 1; + else + myCurrentAdjustable--; + } + + ostringstream buf; + buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].type + << "' selected"; + + myOSystem.frameBuffer().showMessage(buf.str()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeAdjustable(bool increase) +{ + + if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) + changeColorPhaseShift(increase); + else + { + float newVal = (*myAdjustables[myCurrentAdjustable].value); + + if(increase) + { + newVal += 0.05F; + if(newVal > 1.0F) + newVal = 1.0F; + } + else + { + newVal -= 0.05F; + if(newVal < -1.0F) + newVal = -1.0F; + } + *myAdjustables[myCurrentAdjustable].value = newVal; + + ostringstream buf; + buf << "Custom '" << myAdjustables[myCurrentAdjustable].type + << "' set to " << int((newVal + 1.0F) * 100.0F + 0.5F) << "%"; + + myOSystem.frameBuffer().showMessage(buf.str()); + setPalette(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::loadConfig(const Settings& settings) +{ + // Load adjustables + 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); + myBrightness = BSPF::clamp(settings.getFloat("tv.brightness"), -1.0F, 1.0F); + myGamma = BSPF::clamp(settings.getFloat("tv.gamma"), -1.0F, 1.0F); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::saveConfig(Settings& settings) const +{ + // Save adjustables + settings.setValue("tv.hue", myHue); + settings.setValue("tv.saturation", mySaturation); + settings.setValue("tv.contrast", myContrast); + settings.setValue("tv.brightness", myBrightness); + settings.setValue("tv.gamma", myGamma); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::setAdjustables(Adjustable& adjustable) +{ + myHue = scaleFrom100(adjustable.hue); + mySaturation = scaleFrom100(adjustable.saturation); + myContrast = scaleFrom100(adjustable.contrast); + myBrightness = scaleFrom100(adjustable.brightness); + myGamma = scaleFrom100(adjustable.gamma); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::getAdjustables(Adjustable& adjustable) const +{ + adjustable.hue = scaleTo100(myHue); + adjustable.saturation = scaleTo100(mySaturation); + adjustable.contrast = scaleTo100(myContrast); + adjustable.brightness = scaleTo100(myBrightness); + adjustable.gamma = scaleTo100(myGamma); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changeColorPhaseShift(bool increase) { - const char DEGREE = 0x1c; - const float NTSC_SHIFT = 26.2F; - const float PAL_SHIFT = 31.3F; // 360 / 11.5 const ConsoleTiming timing = myOSystem.console().timing(); - const bool isNTSC = timing == ConsoleTiming::ntsc; - const bool isPAL = timing == ConsoleTiming::pal; // SECAM is not supported - if(isNTSC || isPAL) + if(timing != ConsoleTiming::secam) { - const string key = isNTSC ? "phase_ntsc" : "phase_pal"; + 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); @@ -175,6 +262,9 @@ void PaletteHandler::setPalette() // Now consider the current display format const PaletteArray* palette = palettes[paletteType][int(timing)]; + if(paletteType == PaletteType::Custom) + generateCustomPalette(timing); + myOSystem.frameBuffer().setTIAPalette(adjustPalette(*palette)); } @@ -212,15 +302,7 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) // TOOD: adjust hue (different for NTSC and PAL?) // adjust saturation - float P = sqrt(r * r * PR + g * g * PG + b * b * PB) ; - - r = P + (r - P) * saturation; - g = P + (g - P) * saturation; - b = P + (b - P) * saturation; - - r = BSPF::clamp(r, 0, 255); - g = BSPF::clamp(g, 0, 255); - b = BSPF::clamp(b, 0, 255); + changeSaturation(r, g, b, saturation); // adjust contrast, brightness, gamma r = adjust[r]; @@ -235,6 +317,7 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) // Fill the odd numbered palette entries with gray values (calculated // using the standard RGB -> grayscale conversion formula) + // Used for PAL color-loss data and 'greying out' the frame in the debugger. const uInt8 lum = static_cast((r * PR) + (g * PG) + (b * PB)); destPalette[i + 1] = (lum << 16) + (lum << 8) + lum; @@ -299,7 +382,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("phase_ntsc") * + const float shift = myOSystem.settings().getFloat("tv.phase_ntsc") * (2 * BSPF::PI_f / 360); // color 0 is grayscale @@ -342,10 +425,10 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } } } - else + else if(timing == ConsoleTiming::pal) { constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - float shift = myOSystem.settings().getFloat("phase_pal") * + float shift = myOSystem.settings().getFloat("tv.phase_pal") * (2 * BSPF::PI_f / 360); constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); @@ -432,63 +515,6 @@ void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) B = BSPF::clamp(B, 0, 255); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeSaturation(float& R, float& G, float& 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) ; - - R = P + (R - P) * change; - G = P + (G - P) * change; - B = P + (B - P) * change; - - if(R < 0) R = 0; - if(G < 0) G = 0; - if(B < 0) B = 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::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, - ourCustomNTSCPalette.data(), ourCustomPALPalette.data(), ourSECAMPalette.data(), - }; - - if(myUserPaletteDefined) - { - int idx = PaletteType::User * int(ConsoleTiming::numTimings); - palette[idx + int(ConsoleTiming::ntsc)] = ourUserNTSCPalette.data(); - palette[idx + int(ConsoleTiming::pal)] = ourUserPALPalette.data(); - palette[idx + int(ConsoleTiming::secam)] = ourUserSECAMPalette.data(); - } - - for(int i = 0; i < int(ConsoleTiming::numTimings) * PaletteType::NumTypes; ++i) - { - if(palette[i] == nullptr) - continue; - - // Fill the odd numbered palette entries with gray values (calculated - // using the standard RGB -> grayscale conversion formula) - for(int j = 0; j < 128; ++j) - { - const uInt32 pixel = palette[i][(j<<1)]; - const uInt8 r = (pixel >> 16) & 0xff; - const uInt8 g = (pixel >> 8) & 0xff; - const uInt8 b = (pixel >> 0) & 0xff; - const uInt8 sum = static_cast((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); - palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; - } - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourNTSCPalette = { 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 6b26b918a..d8e5518c0 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -36,6 +36,9 @@ class PaletteHandler NumDisplayTypes }; + struct Adjustable { + uInt32 hue, saturation, contrast, brightness, gamma; + }; public: PaletteHandler(OSystem& system); @@ -46,6 +49,14 @@ class PaletteHandler */ void changePalette(bool increase = true); + void selectAdjustable(bool next = true); + void changeAdjustable(bool increase = true); + + + void loadConfig(const Settings& settings); + void saveConfig(Settings& settings) const; + void setAdjustables(Adjustable& adjustable); + void getAdjustables(Adjustable& adjustable) const; /** Change the "phase shift" variable. @@ -56,9 +67,6 @@ class PaletteHandler */ void changeColorPhaseShift(bool increase = true); - void changeSaturation(int& R, int& G, int& B, float change); - void changeSaturation(float& R, float& G, float& B, float change); - /** Sets the palette according to the given palette name. @@ -72,17 +80,6 @@ class PaletteHandler */ void setPalette(); - - void generatePalettes(); - - /** - Loads all defined palettes with PAL color-loss data, even those that - normally can't have it enabled (NTSC), since it's also used for - 'greying out' the frame in the debugger. - */ - void generateColorLossPalette(); - - /** Generates a custom palette, based on user defined phase shifts. */ @@ -99,11 +96,16 @@ class PaletteHandler MaxType = Custom }; + float scaleFrom100(float x) const { return (x / 100.F) - 1.F; } + uInt32 scaleTo100(float x) const { return uInt32(100 * (x + 1.F)); } + PaletteType toPaletteType(const string& name) const; string toPaletteName(PaletteType type) const; PaletteArray adjustPalette(const PaletteArray& source); + void changeSaturation(int& R, int& G, int& B, float change); + /** Loads a user-defined palette file (from OSystem::paletteFile), filling the appropriate user-defined palette arrays. @@ -112,14 +114,33 @@ class PaletteHandler private: + static const int NUM_ADJUSTABLES = 6; + OSystem& myOSystem; + uInt32 myCurrentAdjustable{0}; + struct AdjustableTag { + const char* const type{nullptr}; + float* value{nullptr}; + }; + const std::array myAdjustables = + { { + { "contrast", &myContrast }, + { "brightness", &myBrightness }, + { "hue", &myHue }, + { "saturation", &mySaturation }, + { "gamma", &myGamma }, + { "phase shift", nullptr }, + } }; + // range -1.0 to +1.0 (as in AtariNTSC) - float myContrast{0.0F}; - float myBrightness{0.0F}; - float myHue{0.0F}; - float mySaturation{0.0F}; - float myGamma{0.0F}; + // 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 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) // Indicates whether an external palette was found and // successfully loaded diff --git a/src/common/tv_filters/AtariNTSC.cxx b/src/common/tv_filters/AtariNTSC.cxx index a0b9ef169..ad57a12f8 100644 --- a/src/common/tv_filters/AtariNTSC.cxx +++ b/src/common/tv_filters/AtariNTSC.cxx @@ -57,9 +57,15 @@ void AtariNTSC::generateKernels() const uInt8* ptr = myRGBPalette.data(); for(size_t entry = 0; entry < myRGBPalette.size() / 3; ++entry) { + #ifdef BLARGG_PALETTE float r = myImpl.to_float[*ptr++], g = myImpl.to_float[*ptr++], b = myImpl.to_float[*ptr++]; + #else + float r = (*ptr++) / 255.F * rgb_unit + rgb_offset, + g = (*ptr++) / 255.F * rgb_unit + rgb_offset, + b = (*ptr++) / 255.F * rgb_unit + rgb_offset; + #endif float y, i, q; RGB_TO_YIQ( r, g, b, y, i, q ); // Generate kernel @@ -319,8 +325,10 @@ void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::init(init_t& impl, const Setup& setup) { +#ifdef BLARGG_PALETTE impl.brightness = setup.brightness * (0.5F * rgb_unit) + rgb_offset; impl.contrast = setup.contrast * (0.5F * rgb_unit) + rgb_unit; +#endif impl.artifacts = setup.artifacts; if ( impl.artifacts > 0 ) @@ -334,6 +342,7 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) initFilters(impl, setup); +#ifdef BLARGG_PALETTE /* generate gamma table */ if (true) /* was (gamma_size > 1) */ { @@ -341,19 +350,22 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) float const gamma = 1.1333F - setup.gamma * 0.5F; /* match common PC's 2.2 gamma to TV's 2.65 gamma */ int i; - for ( i = 0; i < gamma_size; i++ ) - impl.to_float [i] = - powf( i * to_float, gamma ) * impl.contrast + impl.brightness; + for(i = 0; i < gamma_size; i++) + impl.to_float[i] = + powf(i * to_float, gamma) * impl.contrast + impl.brightness; } +#endif /* setup decoder matricies */ { + #ifdef BLARGG_PALETTE float hue = setup.hue * BSPF::PI_f + BSPF::PI_f / 180 * ext_decoder_hue; float sat = setup.saturation + 1; hue += BSPF::PI_f / 180 * (std_decoder_hue - ext_decoder_hue); - float s = sinf( hue ) * sat; - float c = cosf( hue ) * sat; + float s = sinf(hue)*sat; + float c = cosf(hue)*sat; + #endif float* out = impl.to_rgb.data(); int n; @@ -366,8 +378,13 @@ void AtariNTSC::init(init_t& impl, const Setup& setup) { float i = *in++; float q = *in++; + #ifdef BLARGG_PALETTE *out++ = i * c - q * s; *out++ = i * s + q * c; + #else + *out++ = i ; + *out++ = q; + #endif } while ( --n2 ); #if 0 // burst_count is always 0 @@ -544,16 +561,32 @@ void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const AtariNTSC::Setup AtariNTSC::TV_Composite = { +#ifdef BLARGG_PALETTE 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.15F, 0.0F, 0.0F, 0.0F +#else + 0.0F, 0.15F, 0.0F, 0.0F, 0.0F +#endif }; const AtariNTSC::Setup AtariNTSC::TV_SVideo = { +#ifdef BLARGG_PALETTE 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.45F, -1.0F, -1.0F, 0.0F +#else + 0.0F, 0.45F, -1.0F, -1.0F, 0.0F +#endif }; const AtariNTSC::Setup AtariNTSC::TV_RGB = { +#ifdef BLARGG_PALETTE 0.0F, 0.0F, 0.0F, 0.0F, 0.2F, 0.0F, 0.70F, -1.0F, -1.0F, -1.0F +#else + 0.2F, 0.70F, -1.0F, -1.0F, -1.0F +#endif }; const AtariNTSC::Setup AtariNTSC::TV_Bad = { +#ifdef BLARGG_PALETTE 0.1F, -0.3F, 0.3F, 0.25F, 0.2F, 0.0F, 0.1F, 0.5F, 0.5F, 0.5F +#else + 0.2F, 0.1F, 0.5F, 0.5F, 0.5F +#endif }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/AtariNTSC.hxx b/src/common/tv_filters/AtariNTSC.hxx index 4ae7b666f..eb75bce3d 100644 --- a/src/common/tv_filters/AtariNTSC.hxx +++ b/src/common/tv_filters/AtariNTSC.hxx @@ -46,6 +46,8 @@ #include "FrameBufferConstants.hxx" #include "bspf.hxx" +//#define BLARGG_PALETTE // also modify contrast, brightness, saturation, gamma and hue when defined + class AtariNTSC { public: @@ -57,14 +59,18 @@ class AtariNTSC struct Setup { // Basic parameters + #ifdef BLARGG_PALETTE float hue{0.F}; // -1 = -180 degrees +1 = +180 degrees float saturation{0.F}; // -1 = grayscale (0.0) +1 = oversaturated colors (2.0) float contrast{0.F}; // -1 = dark (0.5) +1 = light (1.5) float brightness{0.F}; // -1 = dark (0.5) +1 = light (1.5) + #endif float sharpness{0.F}; // edge contrast enhancement/blurring // Advanced parameters + #ifdef BLARGG_PALETTE float gamma{0.F}; // -1 = dark (1.5) +1 = light (0.5) + #endif float resolution{0.F}; // image resolution float artifacts{0.F}; // artifacts caused by color changes float fringing{0.F}; // color artifacts caused by brightness changes @@ -127,7 +133,9 @@ class AtariNTSC burst_size = entry_size / burst_count, kernel_half = 16, kernel_size = kernel_half * 2 + 1, + #ifdef BLARGG_PALETTE gamma_size = 256, + #endif rgb_builder = ((1 << 21) | (1 << 11) | (1 << 1)), rgb_kernel_size = burst_size / alignment_count, @@ -162,16 +170,20 @@ class AtariNTSC struct init_t { std::array to_rgb{0.F}; + #ifdef BLARGG_PALETTE std::array to_float{0.F}; float contrast{0.F}; float brightness{0.F}; + #endif float artifacts{0.F}; float fringing{0.F}; std::array kernel{0.F}; init_t() { to_rgb.fill(0.0); + #ifdef BLARGG_PALETTE to_float.fill(0.0); + #endif kernel.fill(0.0); } }; diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 6ec1afc8c..9e46b6426 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -140,13 +140,16 @@ string NTSCFilter::decreaseAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::loadConfig(const Settings& settings) { + // Load adjustables for custom mode +#ifdef BLARGG_PALETTE myCustomSetup.hue = BSPF::clamp(settings.getFloat("tv.hue"), -1.0F, 1.0F); myCustomSetup.saturation = BSPF::clamp(settings.getFloat("tv.saturation"), -1.0F, 1.0F); myCustomSetup.contrast = BSPF::clamp(settings.getFloat("tv.contrast"), -1.0F, 1.0F); myCustomSetup.brightness = BSPF::clamp(settings.getFloat("tv.brightness"), -1.0F, 1.0F); - myCustomSetup.sharpness = BSPF::clamp(settings.getFloat("tv.sharpness"), -1.0F, 1.0F); myCustomSetup.gamma = BSPF::clamp(settings.getFloat("tv.gamma"), -1.0F, 1.0F); +#endif + myCustomSetup.sharpness = BSPF::clamp(settings.getFloat("tv.sharpness"), -1.0F, 1.0F); myCustomSetup.resolution = BSPF::clamp(settings.getFloat("tv.resolution"), -1.0F, 1.0F); myCustomSetup.artifacts = BSPF::clamp(settings.getFloat("tv.artifacts"), -1.0F, 1.0F); myCustomSetup.fringing = BSPF::clamp(settings.getFloat("tv.fringing"), -1.0F, 1.0F); @@ -157,12 +160,14 @@ void NTSCFilter::loadConfig(const Settings& settings) void NTSCFilter::saveConfig(Settings& settings) const { // Save adjustables for custom mode - settings.setValue("tv.hue", myCustomSetup.hue); - settings.setValue("tv.saturation", myCustomSetup.saturation); - settings.setValue("tv.contrast", myCustomSetup.contrast); - settings.setValue("tv.brightness", myCustomSetup.brightness); +#ifdef BLARGG_PALETTE + //settings.setValue("tv.hue", myCustomSetup.hue); + //settings.setValue("tv.saturation", myCustomSetup.saturation); + //settings.setValue("tv.contrast", myCustomSetup.contrast); + //settings.setValue("tv.brightness", myCustomSetup.brightness); + //settings.setValue("tv.gamma", myCustomSetup.gamma); +#endif settings.setValue("tv.sharpness", myCustomSetup.sharpness); - settings.setValue("tv.gamma", myCustomSetup.gamma); settings.setValue("tv.resolution", myCustomSetup.resolution); settings.setValue("tv.artifacts", myCustomSetup.artifacts); settings.setValue("tv.fringing", myCustomSetup.fringing); @@ -192,12 +197,14 @@ void NTSCFilter::getAdjustables(Adjustable& adjustable, Preset preset) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::setCustomAdjustables(Adjustable& adjustable) { - myCustomSetup.hue = scaleFrom100(adjustable.hue); - myCustomSetup.saturation = scaleFrom100(adjustable.saturation); - myCustomSetup.contrast = scaleFrom100(adjustable.contrast); - myCustomSetup.brightness = scaleFrom100(adjustable.brightness); +#ifdef BLARGG_PALETTE + //myCustomSetup.hue = scaleFrom100(adjustable.hue); + //myCustomSetup.saturation = scaleFrom100(adjustable.saturation); + //myCustomSetup.contrast = scaleFrom100(adjustable.contrast); + //myCustomSetup.brightness = scaleFrom100(adjustable.brightness); + //myCustomSetup.gamma = scaleFrom100(adjustable.gamma); +#endif myCustomSetup.sharpness = scaleFrom100(adjustable.sharpness); - myCustomSetup.gamma = scaleFrom100(adjustable.gamma); myCustomSetup.resolution = scaleFrom100(adjustable.resolution); myCustomSetup.artifacts = scaleFrom100(adjustable.artifacts); myCustomSetup.fringing = scaleFrom100(adjustable.fringing); @@ -208,12 +215,14 @@ void NTSCFilter::setCustomAdjustables(Adjustable& adjustable) void NTSCFilter::convertToAdjustable(Adjustable& adjustable, const AtariNTSC::Setup& setup) const { - adjustable.hue = scaleTo100(setup.hue); - adjustable.saturation = scaleTo100(setup.saturation); - adjustable.contrast = scaleTo100(setup.contrast); - adjustable.brightness = scaleTo100(setup.brightness); +#ifdef BLARGG_PALETTE + //adjustable.hue = scaleTo100(setup.hue); + //adjustable.saturation = scaleTo100(setup.saturation); + //adjustable.contrast = scaleTo100(setup.contrast); + //adjustable.brightness = scaleTo100(setup.brightness); + //adjustable.gamma = scaleTo100(setup.gamma); +#endif adjustable.sharpness = scaleTo100(setup.sharpness); - adjustable.gamma = scaleTo100(setup.gamma); adjustable.resolution = scaleTo100(setup.resolution); adjustable.artifacts = scaleTo100(setup.artifacts); adjustable.fringing = scaleTo100(setup.fringing); @@ -224,12 +233,16 @@ void NTSCFilter::convertToAdjustable(Adjustable& adjustable, AtariNTSC::Setup NTSCFilter::myCustomSetup = AtariNTSC::TV_Composite; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#ifdef BLARGG_PALETTE const std::array NTSCFilter::ourCustomAdjustables = { { { "contrast", &myCustomSetup.contrast }, { "brightness", &myCustomSetup.brightness }, { "hue", &myCustomSetup.hue }, { "saturation", &myCustomSetup.saturation }, { "gamma", &myCustomSetup.gamma }, +#else +const std::array NTSCFilter::ourCustomAdjustables = { { +#endif { "sharpness", &myCustomSetup.sharpness }, { "resolution", &myCustomSetup.resolution }, { "artifacts", &myCustomSetup.artifacts }, diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index b4a5e0e3d..f7e897916 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -51,8 +51,12 @@ class NTSCFilter /* Normally used in conjunction with custom mode, contains all aspects currently adjustable in NTSC TV emulation. */ struct Adjustable { + #ifdef BLARGG_PALETTE uInt32 hue, saturation, contrast, brightness, gamma, sharpness, resolution, artifacts, fringing, bleed; + #else + uInt32 sharpness, resolution, artifacts, fringing, bleed; + #endif }; public: @@ -139,7 +143,11 @@ class NTSCFilter float* value{nullptr}; }; uInt32 myCurrentAdjustable{0}; + #ifdef BLARGG_PALETTE static const std::array ourCustomAdjustables; + #else + static const std::array ourCustomAdjustables; + #endif private: // Following constructors and assignment operators not supported diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 299b1ea3a..bf7d20abf 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -62,7 +62,6 @@ #include "AudioSettings.hxx" #include "frame-manager/FrameManager.hxx" #include "frame-manager/FrameLayoutDetector.hxx" -#include "PaletteHandler.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" @@ -88,7 +87,6 @@ Console::Console(OSystem& osystem, unique_ptr& cart, myTIA = make_unique(*this, [this]() { return timing(); }, myOSystem.settings()); myFrameManager = make_unique(); mySwitches = make_unique(myEvent, myProperties, myOSystem.settings()); - myPaletteHandler = make_unique(myOSystem); myTIA->setFrameManager(myFrameManager.get()); @@ -436,7 +434,6 @@ void Console::setFormat(uInt32 format) myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; - myPaletteHandler->setPalette(); setTIAProperties(); initializeVideo(); // takes care of refreshing the screen initializeAudio(); // ensure that audio synthesis is set up to match emulation speed @@ -582,10 +579,7 @@ FBInitStatus Console::initializeVideo(bool full) myOSystem.frameBuffer().showFrameStats( myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats")); - myPaletteHandler->generatePalettes(); } - myPaletteHandler->setPalette(); - return fbstatus; } diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 36c680539..ac26415d7 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -29,7 +29,6 @@ class CompuMate; class Debugger; class AudioQueue; class AudioSettings; -class PaletteHandler; #include "bspf.hxx" #include "ConsoleIO.hxx" @@ -40,7 +39,6 @@ class PaletteHandler; #include "FrameBufferConstants.hxx" #include "Serializable.hxx" #include "EventHandlerConstants.hxx" -#include "NTSCFilter.hxx" #include "EmulationTiming.hxx" #include "ConsoleTiming.hxx" #include "frame-manager/AbstractFrameManager.hxx" @@ -187,11 +185,6 @@ class Console : public Serializable, public ConsoleIO */ EmulationTiming& emulationTiming() { return myEmulationTiming; } - /** - Retrieve palette handler. - */ - PaletteHandler& paletteHandler() const { return *myPaletteHandler; } - public: /** Toggle between NTSC/PAL/SECAM (and variants) display format. @@ -424,9 +417,6 @@ class Console : public Serializable, public ConsoleIO // The audio settings AudioSettings& myAudioSettings; - // The palette handling - unique_ptrmyPaletteHandler; - private: // Following constructors and assignment operators not supported Console() = delete; diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 5dbb71126..ae82ef810 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -22,7 +22,6 @@ #include #include "bspf.hxx" -#include "StellaKeys.hxx" /** @author Stephen Anthony, Christian Speckner, Thomas Jentzsch @@ -92,6 +91,7 @@ class Event TogglePauseMode, StartPauseMode, OptionsMenuMode, CmdMenuMode, DebuggerMode, ExitMode, TakeSnapshot, ToggleContSnapshots, ToggleContSnapshotsFrame, + ToggleTurbo, NextState, PreviousState, LoadState, SaveState, SaveAllStates, LoadAllStates, @@ -100,12 +100,16 @@ class Event Unwind1Menu, Unwind10Menu, UnwindAllMenu, RewindPause, UnwindPause, - FormatDecrease, FormatIncrease, PaletteIncrease, ToggleColorLoss, + FormatDecrease, FormatIncrease, PaletteDecrease, PaletteIncrease, ToggleColorLoss, + ColorShiftDecrease, ColorShiftIncrease, + PreviousPaletteAttribute, NextPaletteAttribute, + PaletteAttributeDecrease, PaletteAttributeIncrease, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, VCenterDecrease, VCenterIncrease, ScanlineAdjustDecrease, ScanlineAdjustIncrease, OverscanDecrease, OverscanIncrease, VidmodeStd, VidmodeRGB, VidmodeSVideo, VidModeComposite, VidModeBad, VidModeCustom, + PreviousVideoMode, NextVideoMode, PreviousAttribute, NextAttribute, DecreaseAttribute, IncreaseAttribute, ScanlinesDecrease, ScanlinesIncrease, PhosphorDecrease, PhosphorIncrease, TogglePhosphor, ToggleInter, ToggleJitter, @@ -118,10 +122,7 @@ class Event ToggleCollisions, ToggleBits, ToggleFixedColors, ToggleFrameStats, ToggleSAPortOrder, ExitGame, - // add new events from here to avoid that user remapped events get overwritten - ToggleTurbo, PaletteDecrease, - ColorShiftDecrease, ColorShiftIncrease, LastType }; @@ -136,7 +137,7 @@ class Event }; // Event list version, update only if the id of existing(!) event types changed - static constexpr Int32 VERSION = 3; + static constexpr Int32 VERSION = 4; using EventSet = std::set; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 04dd852d0..325438765 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -436,12 +436,28 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.console().changeScanlineAdjust(+1); return; + case Event::PreviousPaletteAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(false); + return; + + case Event::NextPaletteAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(true); + return; + + case Event::PaletteAttributeDecrease: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); + return; + + case Event::PaletteAttributeIncrease: + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); + return; + case Event::ColorShiftDecrease: - if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(false); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(false); return; case Event::ColorShiftIncrease: - if (pressed) myOSystem.console().paletteHandler().changeColorPhaseShift(); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(true); return; case Event::ToggleFullScreen: @@ -456,6 +472,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.frameBuffer().changeOverscan(1); return; + case Event::PreviousVideoMode: + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(false); + return; + + case Event::NextVideoMode: + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(true); + return; + case Event::VidmodeStd: if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::OFF); return; @@ -541,11 +565,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(false); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(false); return; case Event::PaletteIncrease: - if (pressed && !repeated) myOSystem.console().paletteHandler().changePalette(); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(true); return; case Event::ToggleInter: @@ -1934,22 +1958,30 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, { Event::FormatIncrease, "Increase display format", "" }, + // Palette settings { Event::PaletteDecrease, "Switch to previous palette", "" }, { Event::PaletteIncrease, "Switch to next palette", "" }, + { Event::PreviousPaletteAttribute,"Select previous palette attribute", "" }, + { Event::NextPaletteAttribute, "Select next palette attribute", "" }, + { Event::PaletteAttributeDecrease,"Decrease selected palette attribute", "" }, + { Event::PaletteAttributeIncrease,"Increase selected palette attribute", "" }, { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, - // TV effects: + // Blargg TV effects: { Event::VidmodeStd, "Disable TV effects", "" }, { Event::VidmodeRGB, "Select 'RGB' preset", "" }, { Event::VidmodeSVideo, "Select 'S-Video' preset", "" }, { Event::VidModeComposite, "Select 'Composite' preset", "" }, { Event::VidModeBad, "Select 'Badly adjusted' preset", "" }, { Event::VidModeCustom, "Select 'Custom' preset", "" }, + { Event::PreviousVideoMode, "Select previous TV effect mode preset", "" }, + { Event::NextVideoMode, "Select next TV effect mode preset", "" }, { Event::PreviousAttribute, "Select previous 'Custom' attribute", "" }, { Event::NextAttribute, "Select next 'Custom' attribute", "" }, { Event::DecreaseAttribute, "Decrease selected 'Custom' attribute", "" }, { Event::IncreaseAttribute, "Increase selected 'Custom' attribute", "" }, + // Other TV effects { Event::TogglePhosphor, "Toggle 'phosphor' effect", "" }, { Event::PhosphorDecrease, "Decrease 'phosphor' blend", "" }, { Event::PhosphorIncrease, "Increase 'phosphor' blend", "" }, @@ -2066,6 +2098,9 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, Event::ColorShiftDecrease, Event::ColorShiftIncrease, + Event::PreviousVideoMode, Event::NextVideoMode, + Event::PreviousPaletteAttribute, Event::NextPaletteAttribute, + Event::PaletteAttributeDecrease, Event::PaletteAttributeIncrease, Event::ToggleInter }; diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 10259780a..fd8522e5f 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -25,6 +25,7 @@ class OSystem; class MouseControl; class DialogContainer; class PhysicalJoystick; +class Variant; namespace GUI { class Font; @@ -36,7 +37,6 @@ namespace GUI { #include "StellaKeys.hxx" #include "PKeyboardHandler.hxx" #include "PJoystickHandler.hxx" -#include "Variant.hxx" #include "bspf.hxx" /** @@ -468,7 +468,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 150 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 154 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index ccf6838cb..8d60f6fb1 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -49,6 +49,7 @@ #include "CartDetector.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" +#include "PaletteHandler.hxx" #include "TIAConstants.hxx" #include "Settings.hxx" #include "PropsSet.hxx" @@ -243,6 +244,8 @@ void OSystem::saveConfig() Logger::debug("Saving TV effects options ..."); myFrameBuffer->tiaSurface().ntsc().saveConfig(settings()); + Logger::debug("Saving palette settings..."); + myFrameBuffer->tiaSurface().paletteHandler().saveConfig(settings()); } Logger::debug("Saving config options ..."); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index a8100d99d..a959cc255 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -46,8 +46,6 @@ 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 @@ -64,6 +62,8 @@ Settings::Settings() setPermanent("tv.phosphor", "byrom"); setPermanent("tv.phosblend", "50"); setPermanent("tv.scanlines", "25"); + setPermanent("tv.phase_ntsc", "26.2"); + setPermanent("tv.phase_pal", "31.3"); setPermanent("tv.contrast", "0.0"); setPermanent("tv.brightness", "0.0"); setPermanent("tv.hue", "0.0"); diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index a13a9fd83..19e817b0d 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -23,6 +23,7 @@ #include "Console.hxx" #include "TIA.hxx" #include "PNGLibrary.hxx" +#include "PaletteHandler.hxx" #include "TIASurface.hxx" namespace { @@ -76,6 +77,9 @@ TIASurface::TIASurface(OSystem& system) // Enable/disable threading in the NTSC TV effects renderer myNTSCFilter.enableThreading(myOSystem.settings().getBool("threads")); + + myPaletteHandler = make_unique(myOSystem); + myPaletteHandler->loadConfig(myOSystem.settings()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -89,6 +93,8 @@ void TIASurface::initialize(const Console& console, mySLineSurface->setDstPos(mode.image.x(), mode.image.y()); mySLineSurface->setDstSize(mode.image.w(), mode.image.h()); + myPaletteHandler->setPalette(); + // Phosphor mode can be enabled either globally or per-ROM int p_blend = 0; bool enable = false; @@ -188,6 +194,32 @@ void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) if(show) myFB.showMessage(buf.str()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::changeNTSC(bool next, bool show) +{ + constexpr NTSCFilter::Preset PRESETS[] = { + NTSCFilter::Preset::OFF, NTSCFilter::Preset::RGB, NTSCFilter::Preset::SVIDEO, + NTSCFilter::Preset::COMPOSITE, NTSCFilter::Preset::BAD, NTSCFilter::Preset::CUSTOM + }; + int preset = myOSystem.settings().getInt("tv.filter"); + + if(next) + { + if(preset == int(NTSCFilter::Preset::CUSTOM)) + preset = int(NTSCFilter::Preset::OFF); + else + preset++; + } + else + { + if(preset == int(NTSCFilter::Preset::OFF)) + preset = int(NTSCFilter::Preset::CUSTOM); + else + preset--; + } + setNTSC(PRESETS[preset], show); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::setScanlineIntensity(int amount) { diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index c87ddc881..9dbda5b14 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -22,6 +22,7 @@ class TIA; class Console; class OSystem; class FBSurface; +class PaletteHandler; #include @@ -49,6 +50,8 @@ class TIASurface */ explicit TIASurface(OSystem& system); + virtual ~TIASurface() = default; + /** Set the TIA object, which is needed for actually rendering the TIA image. */ @@ -87,6 +90,16 @@ class TIASurface */ void setNTSC(NTSCFilter::Preset preset, bool show = true); + /** + Switch to next/previous NTSC filtering effect. + */ + void changeNTSC(bool next, bool show = true); + + /** + Retrieve palette handler. + */ + PaletteHandler& paletteHandler() const { return *myPaletteHandler; } + /** Increase/decrease current scanline intensity by given relative amount. */ @@ -100,7 +113,6 @@ class TIASurface @return New current intensity */ uInt32 enableScanlines(int relative, int absolute = 50); - void enableScanlineInterpolation(bool enable); /** Enable/disable/query phosphor effect. @@ -183,6 +195,9 @@ class TIASurface // Flag for saving a snapshot bool mySaveSnapFlag{false}; + // The palette handler + unique_ptrmyPaletteHandler; + private: // Following constructors and assignment operators not supported TIASurface() = delete; diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 9efa56a7b..0d8729635 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -204,7 +204,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, break; case kPaletteCmd: - instance().console().paletteHandler().changePalette(); + instance().frameBuffer().tiaSurface().paletteHandler().changePalette(); updatePalette(); break; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 606553562..610ba18ff 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -367,8 +367,8 @@ void VideoDialog::loadConfig() instance().settings().getString("palette"), "standard"); // Custom Palette - myPhaseShiftNtsc->setValue(instance().settings().getFloat("phase_ntsc") * 10); - myPhaseShiftPal->setValue(instance().settings().getFloat("phase_pal") * 10); + myPhaseShiftNtsc->setValue(instance().settings().getFloat("tv.phase_ntsc") * 10); + myPhaseShiftPal->setValue(instance().settings().getFloat("tv.phase_pal") * 10); handlePaletteChange(); // TIA interpolation @@ -413,6 +413,15 @@ 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); @@ -444,8 +453,8 @@ void VideoDialog::saveConfig() myTIAPalette->getSelectedTag().toString()); // Custom Palette - instance().settings().setValue("phase_ntsc", myPhaseShiftNtsc->getValue() / 10.0); - instance().settings().setValue("phase_pal", myPhaseShiftPal->getValue() / 10.0); + 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()); @@ -490,19 +499,23 @@ void VideoDialog::saveConfig() 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 adj; - adj.hue = myTVHue->getValue(); - adj.saturation = myTVSatur->getValue(); - adj.contrast = myTVContrast->getValue(); - adj.brightness = myTVBright->getValue(); - adj.sharpness = myTVSharp->getValue(); - adj.gamma = myTVGamma->getValue(); - adj.resolution = myTVRes->getValue(); - adj.artifacts = myTVArtifacts->getValue(); - adj.fringing = myTVFringe->getValue(); - adj.bleed = myTVBleed->getValue(); - instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(adj); + NTSCFilter::Adjustable ntscAdj; + ntscAdj.sharpness = myTVSharp->getValue(); + ntscAdj.resolution = myTVRes->getValue(); + ntscAdj.artifacts = myTVArtifacts->getValue(); + ntscAdj.fringing = myTVFringe->getValue(); + ntscAdj.bleed = myTVBleed->getValue(); + instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(ntscAdj); // TV phosphor mode instance().settings().setValue("tv.phosphor", @@ -520,8 +533,8 @@ void VideoDialog::saveConfig() if(instance().settings().getString("palette") == "custom") { - instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); - instance().console().paletteHandler().generateCustomPalette(ConsoleTiming::pal); + instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); + instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::pal); } if(vsizeChanged) @@ -595,15 +608,10 @@ void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) bool enable = preset == NTSCFilter::Preset::CUSTOM; myTVSharp->setEnabled(enable); - myTVHue->setEnabled(enable); myTVRes->setEnabled(enable); myTVArtifacts->setEnabled(enable); myTVFringe->setEnabled(enable); myTVBleed->setEnabled(enable); - myTVBright->setEnabled(enable); - myTVContrast->setEnabled(enable); - myTVSatur->setEnabled(enable); - myTVGamma->setEnabled(enable); myCloneComposite->setEnabled(enable); myCloneSvideo->setEnabled(enable); myCloneRGB->setEnabled(enable); @@ -618,15 +626,10 @@ void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) instance().frameBuffer().tiaSurface().ntsc().getAdjustables( adj, NTSCFilter::Preset(preset)); myTVSharp->setValue(adj.sharpness); - myTVHue->setValue(adj.hue); myTVRes->setValue(adj.resolution); myTVArtifacts->setValue(adj.artifacts); myTVFringe->setValue(adj.fringing); myTVBleed->setValue(adj.bleed); - myTVBright->setValue(adj.brightness); - myTVContrast->setValue(adj.contrast); - myTVSatur->setValue(adj.saturation); - myTVGamma->setValue(adj.gamma); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/Widget.hxx b/src/gui/Widget.hxx index eb31f7cd4..c2a0b6b65 100644 --- a/src/gui/Widget.hxx +++ b/src/gui/Widget.hxx @@ -31,6 +31,7 @@ namespace GUI { #include "bspf.hxx" #include "Event.hxx" +#include "StellaKeys.hxx" #include "GuiObject.hxx" #include "Font.hxx" From fd02fb6e8658ea8b77b0ce41baaba037f39fbb63 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 9 May 2020 23:00:16 +0200 Subject: [PATCH 06/42] started refactoring VideoDialog fixed selecting adjustable in NTSCFilter --- src/common/PaletteHandler.cxx | 29 +-- src/common/PaletteHandler.hxx | 10 +- src/common/tv_filters/NTSCFilter.cxx | 9 + src/gui/VideoDialog.cxx | 286 ++++++++++++++++----------- src/gui/VideoDialog.hxx | 3 + 5 files changed, 206 insertions(+), 131 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 4e61199d0..b260842b1 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -98,20 +98,22 @@ void PaletteHandler::changePalette(bool increase) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::selectAdjustable(bool next) { - if(next) - { - if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) - myCurrentAdjustable = 0; - else + bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); + + do { + if(next) + { myCurrentAdjustable++; - } - else - { - if(myCurrentAdjustable == 0) - myCurrentAdjustable = NUM_ADJUSTABLES - 1; + myCurrentAdjustable %= NUM_ADJUSTABLES; + } else - myCurrentAdjustable--; - } + { + if(myCurrentAdjustable == 0) + myCurrentAdjustable = NUM_ADJUSTABLES - 1; + else + myCurrentAdjustable--; + } + } while(!isCustomPalette && myAdjustables[myCurrentAdjustable].value == nullptr); ostringstream buf; buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].type @@ -123,8 +125,7 @@ void PaletteHandler::selectAdjustable(bool next) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::changeAdjustable(bool increase) { - - if(myCurrentAdjustable == NUM_ADJUSTABLES - 1) + if(myAdjustables[myCurrentAdjustable].value == nullptr) changeColorPhaseShift(increase); else { diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index d8e5518c0..995018e1e 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -96,8 +96,8 @@ class PaletteHandler MaxType = Custom }; - float scaleFrom100(float x) const { return (x / 100.F) - 1.F; } - uInt32 scaleTo100(float x) const { return uInt32(100 * (x + 1.F)); } + float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } + uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } PaletteType toPaletteType(const string& name) const; string toPaletteName(PaletteType type) const; @@ -125,12 +125,12 @@ class PaletteHandler }; const std::array myAdjustables = { { - { "contrast", &myContrast }, - { "brightness", &myBrightness }, + { "phase shift", nullptr }, { "hue", &myHue }, { "saturation", &mySaturation }, + { "contrast", &myContrast }, + { "brightness", &myBrightness }, { "gamma", &myGamma }, - { "phase shift", nullptr }, } }; // range -1.0 to +1.0 (as in AtariNTSC) diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 9e46b6426..8a40ddd2c 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -77,7 +77,12 @@ string NTSCFilter::setNextAdjustable() if(myPreset != Preset::CUSTOM) return "'Custom' TV mode not selected"; +#ifdef BLARGG_PALETTE myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; +#else + myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; +#endif + ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type << "' selected"; @@ -91,7 +96,11 @@ string NTSCFilter::setPreviousAdjustable() if(myPreset != Preset::CUSTOM) return "'Custom' TV mode not selected"; +#ifdef BLARGG_PALETTE if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; +#else + if(myCurrentAdjustable == 0) myCurrentAdjustable = 4; +#endif else --myCurrentAdjustable; ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 610ba18ff..bc890ede1 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -79,21 +79,14 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent, font, "Video settings") { - const int lineHeight = font.getLineHeight(), - fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(), - buttonHeight = font.getLineHeight() * 1.25; + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - - int xpos, ypos, tabID; - int lwidth = font.getStringWidth("V-Size adjust "), - pwidth = font.getStringWidth("XXXXxXXXX"); - - WidgetArray wid; - VariantList items; + int xpos, ypos; // Set real dimensions setSize(57 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, @@ -107,65 +100,69 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); - xpos = HBORDER; ypos = VBORDER; - ////////////////////////////////////////////////////////// - // 1) General options + addGeneralTab(); + addPaletteTab(); + addTVEffectsTab(); + + // Add Defaults, OK and Cancel buttons + WidgetArray wid; + addDefaultsOKCancelBGroup(wid, _font); + addBGroupToFocusList(wid); + + // Activate the first tab + myTab->setActiveTab(0); + + // Disable certain functions when we know they aren't present +#ifndef WINDOWED_SUPPORT + myFullscreen->clearFlags(Widget::FLAG_ENABLED); + myCenter->clearFlags(Widget::FLAG_ENABLED); +#endif +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::addGeneralTab() +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VGAP = fontHeight / 4; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + + int xpos, ypos, tabID; + int lwidth = _font.getStringWidth("V-Size adjust "), + pwidth = _font.getStringWidth("XXXXxXXXX"), + swidth = fontWidth * 8 - fontWidth / 2; + WidgetArray wid; + VariantList items; + tabID = myTab->addTab(" General "); + xpos = HBORDER; ypos = VBORDER; // Video renderer - myRenderer = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, + myRenderer = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, instance().frameBuffer().supportedRenderers(), "Renderer ", lwidth); wid.push_back(myRenderer); ypos += lineHeight + VGAP; - // TIA Palette - items.clear(); - VarList::push_back(items, "Standard", "standard"); - 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, 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 "); + myTIAInterpolate = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Interpolation "); wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP; // TIA zoom levels (will be dynamically filled later) - myTIAZoom = new SliderWidget(myTab, font, xpos, ypos - 1, swidth, lineHeight, - "Zoom ", lwidth, 0, fontWidth * 4, "%"); + myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, + "Zoom ", lwidth, 0, fontWidth * 4, "%"); myTIAZoom->setMinValue(200); myTIAZoom->setStepValue(FrameBuffer::ZOOM_STEPS * 100); wid.push_back(myTIAZoom); ypos += lineHeight + VGAP; // Aspect ratio (NTSC mode) myVSizeAdjust = - new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "V-Size adjust", lwidth, kVSizeChanged, fontWidth * 7, "%", 0, true); myVSizeAdjust->setMinValue(-5); myVSizeAdjust->setMaxValue(5); myVSizeAdjust->setTickmarkIntervals(2); @@ -174,7 +171,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Speed mySpeed = - new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "Emul. speed ", lwidth, kSpeedupChanged, fontWidth * 5, "%"); mySpeed->setMinValue(MIN_SPEED); mySpeed->setMaxValue(MAX_SPEED); mySpeed->setStepValue(SPEED_STEP); @@ -183,7 +180,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, ypos += lineHeight + VGAP; // Use sync to vblank - myUseVSync = new CheckboxWidget(myTab, font, xpos, ypos + 1, "VSync"); + myUseVSync = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "VSync"); wid.push_back(myUseVSync); // Move over to the next column @@ -191,7 +188,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, ypos = VBORDER; // Fullscreen - myFullscreen = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); + myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); wid.push_back(myFullscreen); ypos += lineHeight + VGAP; @@ -202,13 +199,13 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, ypos += lineHeight + VGAP;*/ // FS stretch - myUseStretch = new CheckboxWidget(myTab, font, xpos + INDENT, ypos + 1, "Stretch"); + myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); wid.push_back(myUseStretch); ypos += lineHeight + VGAP; // FS overscan - myTVOverscan = new SliderWidget(myTab, font, xpos + INDENT, ypos - 1, swidth, lineHeight, - "Overscan", font.getStringWidth("Overscan "), kOverscanChanged, fontWidth * 3, "%"); + myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, + "Overscan", _font.getStringWidth("Overscan "), kOverscanChanged, fontWidth * 3, "%"); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); myTVOverscan->setTickmarkIntervals(2); wid.push_back(myTVOverscan); @@ -216,36 +213,120 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Skip progress load bars for SuperCharger ROMs // Doesn't really belong here, but I couldn't find a better place for it - myFastSCBios = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Fast SuperCharger load"); + myFastSCBios = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fast SuperCharger load"); wid.push_back(myFastSCBios); ypos += lineHeight + VGAP; // Show UI messages onscreen - myUIMessages = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Show UI messages"); + myUIMessages = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Show UI messages"); wid.push_back(myUIMessages); ypos += lineHeight + VGAP; // Center window (in windowed mode) - myCenter = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Center window"); + myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center window"); wid.push_back(myCenter); ypos += (lineHeight + VGAP) * 2; // Use multi-threading - myUseThreads = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Multi-threading"); + myUseThreads = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Multi-threading"); wid.push_back(myUseThreads); // Add items for tab 0 addToFocusList(wid, myTab, tabID); +} - ////////////////////////////////////////////////////////// - // 2) TV effects options - wid.clear(); - tabID = myTab->addTab(" TV Effects "); - xpos = HBORDER; - ypos = VBORDER; - swidth = fontWidth * 8 - fontWidth / 2; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::addPaletteTab() +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos = HBORDER, + ypos = VBORDER; + int swidth = fontWidth * 8 - fontWidth / 2; + int lwidth = _font.getStringWidth("Saturation "); + int pwidth = _font.getStringWidth("Standard"); + WidgetArray wid; + VariantList items; + + int tabID = myTab->addTab(" Palettes "); + + // TIA Palette + items.clear(); + VarList::push_back(items, "Standard", "standard"); + 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, kPaletteChanged); + wid.push_back(myTIAPalette); + ypos += lineHeight + VGAP; + + 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; + +#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ + myTV ## obj = \ + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ + desc, lwidth, cmd, fontWidth*4, "%"); \ + myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ + myTV ## obj->setTickmarkIntervals(2); \ + 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) + + // Add items for tab 2 + addToFocusList(wid, myTab, tabID); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoDialog::addTVEffectsTab() +{ + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(), + buttonHeight = _font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + int xpos = HBORDER, + ypos = VBORDER; + int swidth = fontWidth * 8 - fontWidth / 2; + int lwidth = _font.getStringWidth("TV Mode "); + int pwidth = _font.getStringWidth("Bad adjust"); + WidgetArray wid; + VariantList items; + int tabID = myTab->addTab(" TV Effects "); - // TV Mode items.clear(); VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); VarList::push_back(items, "RGB", static_cast(NTSCFilter::Preset::RGB)); @@ -253,32 +334,25 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, VarList::push_back(items, "Composite", static_cast(NTSCFilter::Preset::COMPOSITE)); VarList::push_back(items, "Bad adjust", static_cast(NTSCFilter::Preset::BAD)); VarList::push_back(items, "Custom", static_cast(NTSCFilter::Preset::CUSTOM)); - lwidth = font.getStringWidth("TV Mode "); - pwidth = font.getStringWidth("Bad adjust"); myTVMode = - new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, + new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, items, "TV mode ", lwidth, kTVModeChanged); wid.push_back(myTVMode); ypos += lineHeight + VGAP; // Custom adjustables (using macro voodoo) xpos += INDENT - 2; ypos += 0; - lwidth = font.getStringWidth("Saturation "); + lwidth = _font.getStringWidth("Saturation "); #define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ myTV ## obj = \ - new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, \ + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ desc, lwidth, cmd, fontWidth*4, "%"); \ myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ myTV ## obj->setTickmarkIntervals(2); \ wid.push_back(myTV ## obj); \ ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", 0) - CREATE_CUSTOM_SLIDERS(Bright, "Brightness ", 0) - CREATE_CUSTOM_SLIDERS(Hue, "Hue ", 0) - CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", 0) - CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", 0) CREATE_CUSTOM_SLIDERS(Sharp, "Sharpness ", 0) CREATE_CUSTOM_SLIDERS(Res, "Resolution ", 0) CREATE_CUSTOM_SLIDERS(Artifacts, "Artifacts ", 0) @@ -288,22 +362,22 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, xpos += myTVContrast->getWidth() + fontWidth * 6; ypos = VBORDER; - lwidth = font.getStringWidth("Intensity "); + lwidth = _font.getStringWidth("Intensity "); // TV Phosphor effect - myTVPhosphor = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Phosphor for all ROMs", kPhosphorChanged); + myTVPhosphor = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Phosphor for all ROMs", kPhosphorChanged); wid.push_back(myTVPhosphor); ypos += lineHeight + VGAP / 2; // TV Phosphor blend level xpos += INDENT; - swidth = font.getMaxCharWidth() * 10; + swidth = _font.getMaxCharWidth() * 10; CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend ", kPhosBlendChanged) - ypos += VGAP * 2; + ypos += VGAP * 2; // Scanline intensity and interpolation xpos -= INDENT; - myTVScanLabel = new StaticTextWidget(myTab, font, xpos, ypos, "Scanlines:"); + myTVScanLabel = new StaticTextWidget(myTab, _font, xpos, ypos, "Scanlines:"); ypos += lineHeight + VGAP / 2; xpos += INDENT; @@ -312,10 +386,10 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Adjustable presets xpos -= INDENT; - int cloneWidth = font.getStringWidth("Clone Bad Adjust") + 20; + int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + 20; #define CREATE_CLONE_BUTTON(obj, desc) \ myClone ## obj = \ - new ButtonWidget(myTab, font, xpos, ypos, cloneWidth, buttonHeight,\ + new ButtonWidget(myTab, _font, xpos, ypos, cloneWidth, buttonHeight,\ desc, kClone ## obj ##Cmd); \ wid.push_back(myClone ## obj); \ ypos += buttonHeight + VGAP; @@ -327,22 +401,8 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, CREATE_CLONE_BUTTON(Bad, "Clone Bad adjust") CREATE_CLONE_BUTTON(Custom, "Revert") - // Add items for tab 2 + // Add items for tab 3 addToFocusList(wid, myTab, tabID); - - // Activate the first tab - myTab->setActiveTab(0); - - // Add Defaults, OK and Cancel buttons - wid.clear(); - addDefaultsOKCancelBGroup(wid, font); - addBGroupToFocusList(wid); - - // Disable certain functions when we know they aren't present -#ifndef WINDOWED_SUPPORT - myFullscreen->clearFlags(Widget::FLAG_ENABLED); - myCenter->clearFlags(Widget::FLAG_ENABLED); -#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -531,12 +591,6 @@ void VideoDialog::saveConfig() { instance().console().setTIAProperties(); - if(instance().settings().getString("palette") == "custom") - { - instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::ntsc); - instance().frameBuffer().tiaSurface().paletteHandler().generateCustomPalette(ConsoleTiming::pal); - } - if(vsizeChanged) { instance().console().tia().clearFrameBuffer(); @@ -560,9 +614,6 @@ 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); @@ -580,7 +631,18 @@ void VideoDialog::setDefaults() break; } - case 1: // TV effects + case 1: // Palettes + myTIAPalette->setSelected("standard", ""); + myPhaseShiftNtsc->setValue(262); + myPhaseShiftPal->setValue(313); + myTVHue->setValue(50); + myTVSatur->setValue(50); + myTVContrast->setValue(50); + myTVBright->setValue(50); + myTVGamma->setValue(50); + break; + + case 2: // TV effects { myTVMode->setSelected("0", "0"); diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index 429290082..459990e13 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -43,6 +43,9 @@ class VideoDialog : public Dialog void saveConfig() override; void setDefaults() override; + void addGeneralTab(); + void addPaletteTab(); + void addTVEffectsTab(); void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handlePaletteChange(); From b21efb62696425ef47106bd37b449165399b15cb Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 12:46:54 +0200 Subject: [PATCH 07/42] improved VideoDialog alignment moved "Center Windows" to UIDialog --- src/gui/UIDialog.cxx | 45 ++++++++----- src/gui/UIDialog.hxx | 3 +- src/gui/VideoDialog.cxx | 136 +++++++++++++++++----------------------- src/gui/VideoDialog.hxx | 4 +- 4 files changed, 95 insertions(+), 93 deletions(-) diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 099886b9b..94032a4ce 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -105,12 +105,13 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, wid.push_back(myDialogFontPopup); // Enable HiDPI mode - myHidpiWidget = new CheckboxWidget(myTab, font, myDialogFontPopup->getRight() + fontWidth * 5, + xpos = myDialogFontPopup->getRight() + fontWidth * 5; + myHidpiWidget = new CheckboxWidget(myTab, font, xpos, ypos + 1, "HiDPI mode (*)"); wid.push_back(myHidpiWidget); - ypos += lineHeight + VGAP; // Dialog position + xpos = HBORDER; ypos += lineHeight + VGAP; items.clear(); VarList::push_back(items, "Centered", 0); VarList::push_back(items, "Left top", 1); @@ -120,9 +121,14 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myPositionPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Dialogs position", lwidth); wid.push_back(myPositionPopup); - ypos += lineHeight + VGAP * 2; + + // Center window (in windowed mode) + xpos = myHidpiWidget->getLeft(); + myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center windows"); + wid.push_back(myCenter); // Confirm dialog when exiting emulation + xpos = HBORDER; ypos += lineHeight + VGAP * 2; myConfirmExitWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Confirm exiting emulation"); wid.push_back(myConfirmExitWidget); ypos += lineHeight + VGAP * 3; @@ -303,6 +309,10 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, wid.clear(); addDefaultsOKCancelBGroup(wid, font); addBGroupToFocusList(wid); + +#ifndef WINDOWED_SUPPORT + myCenter->clearFlags(Widget::FLAG_ENABLED); +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -353,6 +363,10 @@ void UIDialog::loadConfig() const string& pal = settings.getString("uipalette"); myPalettePopup->setSelected(pal, "standard"); + // Dialog font + const string& dialogFont = settings.getString("dialogfont"); + myDialogFontPopup->setSelected(dialogFont, "medium"); + // Enable HiDPI mode if (!instance().frameBuffer().hidpiAllowed()) { @@ -364,16 +378,15 @@ void UIDialog::loadConfig() myHidpiWidget->setState(settings.getBool("hidpi")); } - // Confirm dialog when exiting emulation - myConfirmExitWidget->setState(settings.getBool("confirmexit")); - - // Dialog font - const string& dialogFont = settings.getString("dialogfont"); - myDialogFontPopup->setSelected(dialogFont, "medium"); - // Dialog position myPositionPopup->setSelected(settings.getString("dialogpos"), "0"); + // Center window + myCenter->setState(settings.getBool("center")); + + // Confirm dialog when exiting emulation + myConfirmExitWidget->setState(settings.getBool("confirmexit")); + // Listwidget quick delay int delay = settings.getInt("listdelay"); myListDelaySlider->setValue(delay); @@ -436,16 +449,19 @@ void UIDialog::saveConfig() myPalettePopup->getSelectedTag().toString()); instance().frameBuffer().setUIPalette(); - // Enable HiDPI mode - settings.setValue("hidpi", myHidpiWidget->getState()); - // Dialog font settings.setValue("dialogfont", myDialogFontPopup->getSelectedTag().toString()); + // Enable HiDPI mode + settings.setValue("hidpi", myHidpiWidget->getState()); + // Dialog position settings.setValue("dialogpos", myPositionPopup->getSelectedTag().toString()); + // Center window + settings.setValue("center", myCenter->getState()); + // Confirm dialog when exiting emulation settings.setValue("confirmexit", myConfirmExitWidget->getState()); @@ -481,9 +497,10 @@ void UIDialog::setDefaults() { case 0: // Misc. options myPalettePopup->setSelected("standard"); - myHidpiWidget->setState(false); myDialogFontPopup->setSelected("medium", ""); + myHidpiWidget->setState(false); myPositionPopup->setSelected("0"); + myCenter->setState(false); myConfirmExitWidget->setState(false); myListDelaySlider->setValue(300); myWheelLinesSlider->setValue(4); diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index 83851e971..91bc7ff82 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -66,9 +66,10 @@ class UIDialog : public Dialog, public CommandSender // Misc options PopUpWidget* myPalettePopup{nullptr}; - CheckboxWidget* myHidpiWidget{nullptr}; PopUpWidget* myDialogFontPopup{nullptr}; + CheckboxWidget* myHidpiWidget{nullptr}; PopUpWidget* myPositionPopup{nullptr}; + CheckboxWidget* myCenter{nullptr}; CheckboxWidget* myConfirmExitWidget{nullptr}; SliderWidget* myListDelaySlider{nullptr}; SliderWidget* myWheelLinesSlider{nullptr}; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index bc890ede1..26ed93a33 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -115,7 +115,8 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, // Disable certain functions when we know they aren't present #ifndef WINDOWED_SUPPORT myFullscreen->clearFlags(Widget::FLAG_ENABLED); - myCenter->clearFlags(Widget::FLAG_ENABLED); + myUseStretch->clearFlags(Widget::FLAG_ENABLED); + myTVOverscan->clearFlags(Widget::FLAG_ENABLED); #endif } @@ -129,17 +130,14 @@ void VideoDialog::addGeneralTab() const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - - int xpos, ypos, tabID; - int lwidth = _font.getStringWidth("V-Size adjust "), - pwidth = _font.getStringWidth("XXXXxXXXX"), - swidth = fontWidth * 8 - fontWidth / 2; + const int INDENT = CheckboxWidget::prefixSize(_font); + const int lwidth = _font.getStringWidth("V-Size adjust "), + pwidth = _font.getStringWidth("XXXXxXXXX"); + int xpos = HBORDER, + ypos = VBORDER; WidgetArray wid; VariantList items; - - tabID = myTab->addTab(" General "); - xpos = HBORDER; ypos = VBORDER; + const int tabID = myTab->addTab(" General "); // Video renderer myRenderer = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, @@ -150,8 +148,32 @@ void VideoDialog::addGeneralTab() // TIA interpolation myTIAInterpolate = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Interpolation "); - wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP; + wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP * 4; + // Fullscreen + myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); + wid.push_back(myFullscreen); + ypos += lineHeight + VGAP; + + /*pwidth = font.getStringWidth("0: 3840x2860@120Hz"); + myFullScreenMode = new PopUpWidget(myTab, font, xpos + INDENT + 2, ypos, pwidth, lineHeight, + instance().frameBuffer().supportedScreenModes(), "Mode "); + wid.push_back(myFullScreenMode); + ypos += lineHeight + VGAP;*/ + + // FS stretch + myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); + wid.push_back(myUseStretch); + ypos += lineHeight + VGAP; + + // FS overscan + const int swidth = myRenderer->getWidth() - lwidth; + myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, + "Overscan", lwidth - INDENT, kOverscanChanged, fontWidth * 3, "%"); + myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); + myTVOverscan->setTickmarkIntervals(2); + wid.push_back(myTVOverscan); + ypos += lineHeight + VGAP; // TIA zoom levels (will be dynamically filled later) myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, @@ -160,14 +182,14 @@ void VideoDialog::addGeneralTab() wid.push_back(myTIAZoom); ypos += lineHeight + VGAP; - // Aspect ratio (NTSC mode) + // Vertical size myVSizeAdjust = new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, "V-Size adjust", lwidth, kVSizeChanged, fontWidth * 7, "%", 0, true); myVSizeAdjust->setMinValue(-5); myVSizeAdjust->setMaxValue(5); myVSizeAdjust->setTickmarkIntervals(2); wid.push_back(myVSizeAdjust); - ypos += lineHeight + VGAP; + ypos += lineHeight + VGAP * 4; // Speed mySpeed = @@ -187,30 +209,6 @@ void VideoDialog::addGeneralTab() xpos = myVSizeAdjust->getRight() + fontWidth * 3; ypos = VBORDER; - // Fullscreen - myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); - wid.push_back(myFullscreen); - ypos += lineHeight + VGAP; - - /*pwidth = font.getStringWidth("0: 3840x2860@120Hz"); - myFullScreenMode = new PopUpWidget(myTab, font, xpos + INDENT + 2, ypos, pwidth, lineHeight, - instance().frameBuffer().supportedScreenModes(), "Mode "); - wid.push_back(myFullScreenMode); - ypos += lineHeight + VGAP;*/ - - // FS stretch - myUseStretch = new CheckboxWidget(myTab, _font, xpos + INDENT, ypos + 1, "Stretch"); - wid.push_back(myUseStretch); - ypos += lineHeight + VGAP; - - // FS overscan - myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, - "Overscan", _font.getStringWidth("Overscan "), kOverscanChanged, fontWidth * 3, "%"); - myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); - myTVOverscan->setTickmarkIntervals(2); - wid.push_back(myTVOverscan); - ypos += (lineHeight + VGAP) * 2; - // Skip progress load bars for SuperCharger ROMs // Doesn't really belong here, but I couldn't find a better place for it myFastSCBios = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fast SuperCharger load"); @@ -222,11 +220,6 @@ void VideoDialog::addGeneralTab() wid.push_back(myUIMessages); ypos += lineHeight + VGAP; - // Center window (in windowed mode) - myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center window"); - wid.push_back(myCenter); - ypos += (lineHeight + VGAP) * 2; - // Use multi-threading myUseThreads = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Multi-threading"); wid.push_back(myUseThreads); @@ -246,15 +239,13 @@ void VideoDialog::addPaletteTab() const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; const int VGAP = fontHeight / 4; + const int lwidth = _font.getStringWidth(" NTSC phase "); + const int pwidth = _font.getStringWidth("Standard"); int xpos = HBORDER, ypos = VBORDER; - int swidth = fontWidth * 8 - fontWidth / 2; - int lwidth = _font.getStringWidth("Saturation "); - int pwidth = _font.getStringWidth("Standard"); WidgetArray wid; VariantList items; - - int tabID = myTab->addTab(" Palettes "); + const int tabID = myTab->addTab(" Palettes "); // TIA Palette items.clear(); @@ -268,9 +259,9 @@ void VideoDialog::addPaletteTab() wid.push_back(myTIAPalette); ypos += lineHeight + VGAP; - swidth = myTIAPalette->getWidth() - lwidth; - int plWidth = _font.getStringWidth("NTSC phase "); - int pswidth = swidth - INDENT + lwidth - plWidth; + const int swidth = myTIAPalette->getWidth() - lwidth; + const int plWidth = _font.getStringWidth("NTSC phase "); + const int pswidth = swidth - INDENT + lwidth - plWidth; myPhaseShiftNtsc = new SliderWidget(myTab, _font, xpos + INDENT, ypos-1, pswidth, lineHeight, @@ -316,16 +307,15 @@ void VideoDialog::addTVEffectsTab() buttonHeight = _font.getLineHeight() * 1.25; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; + const int INDENT = CheckboxWidget::prefixSize(_font);// fontWidth * 2; const int VGAP = fontHeight / 4; int xpos = HBORDER, ypos = VBORDER; - int swidth = fontWidth * 8 - fontWidth / 2; - int lwidth = _font.getStringWidth("TV Mode "); - int pwidth = _font.getStringWidth("Bad adjust"); + const int lwidth = _font.getStringWidth("Saturation "); + const int pwidth = _font.getStringWidth("Bad adjust "); WidgetArray wid; VariantList items; - int tabID = myTab->addTab(" TV Effects "); + const int tabID = myTab->addTab(" TV Effects "); items.clear(); VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); @@ -334,15 +324,14 @@ void VideoDialog::addTVEffectsTab() VarList::push_back(items, "Composite", static_cast(NTSCFilter::Preset::COMPOSITE)); VarList::push_back(items, "Bad adjust", static_cast(NTSCFilter::Preset::BAD)); VarList::push_back(items, "Custom", static_cast(NTSCFilter::Preset::CUSTOM)); - myTVMode = - new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, - items, "TV mode ", lwidth, kTVModeChanged); + myTVMode = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, + items, "TV mode ", 0, kTVModeChanged); wid.push_back(myTVMode); ypos += lineHeight + VGAP; // Custom adjustables (using macro voodoo) - xpos += INDENT - 2; ypos += 0; - lwidth = _font.getStringWidth("Saturation "); + const int swidth = myTVMode->getWidth() - INDENT - lwidth; + xpos += INDENT; #define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ myTV ## obj = \ @@ -359,10 +348,9 @@ void VideoDialog::addTVEffectsTab() CREATE_CUSTOM_SLIDERS(Fringe, "Fringing ", 0) CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding ", 0) - xpos += myTVContrast->getWidth() + fontWidth * 6; - ypos = VBORDER; + ypos += VGAP * 3; - lwidth = _font.getStringWidth("Intensity "); + xpos = HBORDER; // TV Phosphor effect myTVPhosphor = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Phosphor for all ROMs", kPhosphorChanged); @@ -371,9 +359,8 @@ void VideoDialog::addTVEffectsTab() // TV Phosphor blend level xpos += INDENT; - swidth = _font.getMaxCharWidth() * 10; - CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend ", kPhosBlendChanged) - ypos += VGAP * 2; + CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend", kPhosBlendChanged) + ypos += VGAP; // Scanline intensity and interpolation xpos -= INDENT; @@ -381,12 +368,14 @@ void VideoDialog::addTVEffectsTab() ypos += lineHeight + VGAP / 2; xpos += INDENT; - CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity ", kScanlinesChanged) - ypos += VGAP * 3; + CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity", kScanlinesChanged) + + // Create buttons in 2nd column + xpos = myTVSharp->getRight() + fontWidth * 2; + ypos = VBORDER - VGAP / 2; // Adjustable presets - xpos -= INDENT; - int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + 20; + int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + fontWidth * 2.5; #define CREATE_CLONE_BUTTON(obj, desc) \ myClone ## obj = \ new ButtonWidget(myTab, _font, xpos, ypos, cloneWidth, buttonHeight,\ @@ -458,9 +447,6 @@ void VideoDialog::loadConfig() // Show UI messages myUIMessages->setState(instance().settings().getBool("uimessages")); - // Center window - myCenter->setState(instance().settings().getBool("center")); - // Fast loading of Supercharger BIOS myFastSCBios->setState(instance().settings().getBool("fastscbios")); @@ -544,9 +530,6 @@ void VideoDialog::saveConfig() // Show UI messages instance().settings().setValue("uimessages", myUIMessages->getState()); - // Center window - instance().settings().setValue("center", myCenter->getState()); - // Fast loading of Supercharger BIOS instance().settings().setValue("fastscbios", myFastSCBios->getState()); @@ -623,7 +606,6 @@ void VideoDialog::setDefaults() myUseStretch->setState(false); myUseVSync->setState(true); myUIMessages->setState(true); - myCenter->setState(false); myFastSCBios->setState(true); myUseThreads->setState(false); diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoDialog.hxx index 459990e13..d780a508f 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoDialog.hxx @@ -22,6 +22,7 @@ class CommandSender; class CheckboxWidget; class DialogContainer; class PopUpWidget; +class RadioButtonGroup; class SliderWidget; class StaticTextWidget; class TabWidget; @@ -67,13 +68,13 @@ class VideoDialog : public Dialog SliderWidget* myVSizeAdjust{nullptr}; SliderWidget* mySpeed{nullptr}; + RadioButtonGroup* myZoomGroup{nullptr}; CheckboxWidget* myFullscreen{nullptr}; //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; CheckboxWidget* myUseVSync{nullptr}; CheckboxWidget* myUIMessages{nullptr}; - CheckboxWidget* myCenter{nullptr}; CheckboxWidget* myFastSCBios{nullptr}; CheckboxWidget* myUseThreads{nullptr}; @@ -112,6 +113,7 @@ class VideoDialog : public Dialog kSpeedupChanged = 'VDSp', kVSizeChanged = 'VDVs', kFullScreenChanged = 'VDFs', + kZoomChanged = 'VDZo', kOverscanChanged = 'VDOv', kTVModeChanged = 'VDtv', From 85f438f6930f04e61deaad46178e531782a461b9 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 19:53:59 +0200 Subject: [PATCH 08/42] 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', From 5686c37a5752c8b164f69932311455d2e73da4de Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 21:53:02 +0200 Subject: [PATCH 09/42] add hue adjustment code to PaletteHandler --- src/common/PaletteHandler.cxx | 26 +++++++++++++++++++++++--- src/common/PaletteHandler.hxx | 3 ++- src/gui/VideoDialog.cxx | 28 ++++++++++------------------ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index e6bce1494..f6fed70cf 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -294,6 +294,7 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) constexpr int ADJUST_SIZE = 256; constexpr int RGB_UNIT = 1 << 8; constexpr float RGB_OFFSET = 0.5F; + const float hue = myHue; 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; @@ -313,10 +314,11 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) int g = (pixel >> 8) & 0xff; int b = (pixel >> 0) & 0xff; - // TOOD: adjust hue (different for NTSC and PAL?) + // adjust hue (different for NTSC and PAL?) + adjustHue(r, g, b, hue); // adjust saturation - changeSaturation(r, g, b, saturation); + adustSaturation(r, g, b, saturation); // adjust contrast, brightness, gamma r = adjust[r]; @@ -496,7 +498,25 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeSaturation(int& R, int& G, int& B, float change) +void PaletteHandler::adjustHue(int& R, int& G, int& B, float change) +{ + const float U = cos(-change * BSPF::PI_f); + const float W = sin(-change * BSPF::PI_f); + const float R_out = (.299 + .701 * U + .168 * W) * R + + (.587 - .587 * U + .330 * W) * G + + (.114 - .114 * U - .497 * W) * B; + const float G_out = (.299 - .299 * U - .328 * W) * R + + (.587 + .413 * U + .035 * W) * G + + (.114 - .114 * U + .292 * W) * B; + const float B_out = (.299 - .3 * U + 1.25 * W) * R + + (.587 - .588 * U - 1.05 * W) * G + + (.114 + .886 * U - .203 * W) * B; + + R = R_out; G = G_out; B = B_out; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::adustSaturation(int& R, int& G, int& B, float change) { // public-domain function by Darel Rex Finley // diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 7c0f69dfc..ddb4bfaa1 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -110,7 +110,8 @@ class PaletteHandler PaletteArray adjustPalette(const PaletteArray& source); - void changeSaturation(int& R, int& G, int& B, float change); + void adjustHue(int& R, int& G, int& B, float change); + void adustSaturation(int& R, int& G, int& B, float change); /** Loads a user-defined palette file (from OSystem::paletteFile), filling the diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 41460d9ba..a90657892 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -76,6 +76,16 @@ namespace { } } +#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ + myTV ## obj = \ + new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ + desc, lwidth, cmd, fontWidth*4, "%"); \ + myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ + myTV ## obj->setStepValue(2); \ + myTV ## obj->setTickmarkIntervals(2); \ + wid.push_back(myTV ## obj); \ + ypos += lineHeight + VGAP; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) @@ -291,15 +301,6 @@ void VideoDialog::addPaletteTab() wid.push_back(myPhaseShiftPal); ypos += lineHeight + VGAP; -#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ - myTV ## obj = \ - new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ - desc, lwidth, cmd, fontWidth*4, "%"); \ - myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ - myTV ## obj->setTickmarkIntervals(2); \ - wid.push_back(myTV ## obj); \ - ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Hue, "Hue ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Satur, "Saturation ", kPaletteUpdated) CREATE_CUSTOM_SLIDERS(Contrast, "Contrast ", kPaletteUpdated) @@ -349,15 +350,6 @@ void VideoDialog::addTVEffectsTab() const int swidth = myTVMode->getWidth() - INDENT - lwidth; xpos += INDENT; -#define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ - myTV ## obj = \ - new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, \ - desc, lwidth, cmd, fontWidth*4, "%"); \ - myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ - myTV ## obj->setTickmarkIntervals(2); \ - wid.push_back(myTV ## obj); \ - ypos += lineHeight + VGAP; - CREATE_CUSTOM_SLIDERS(Sharp, "Sharpness ", 0) CREATE_CUSTOM_SLIDERS(Res, "Resolution ", 0) CREATE_CUSTOM_SLIDERS(Artifacts, "Artifacts ", 0) From 5aa57decb5012a98e4c50289921e3d97e72aa997 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sun, 10 May 2020 22:53:58 +0200 Subject: [PATCH 10/42] some transformation code cleanup --- src/common/PaletteHandler.cxx | 68 +++++++++++------------------------ src/common/PaletteHandler.hxx | 3 +- 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index f6fed70cf..dbca46ff2 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -314,11 +314,8 @@ PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) int g = (pixel >> 8) & 0xff; int b = (pixel >> 0) & 0xff; - // adjust hue (different for NTSC and PAL?) - adjustHue(r, g, b, hue); - - // adjust saturation - adustSaturation(r, g, b, saturation); + // adjust hue (different for NTSC and PAL?) and saturation + adjustHueSaturation(r, g, b, hue, saturation); // adjust contrast, brightness, gamma r = adjust[r]; @@ -498,51 +495,26 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::adjustHue(int& R, int& G, int& B, float change) +void PaletteHandler::adjustHueSaturation(int& R, int& G, int& B, float H, float S) { - const float U = cos(-change * BSPF::PI_f); - const float W = sin(-change * BSPF::PI_f); - const float R_out = (.299 + .701 * U + .168 * W) * R - + (.587 - .587 * U + .330 * W) * G - + (.114 - .114 * U - .497 * W) * B; - const float G_out = (.299 - .299 * U - .328 * W) * R - + (.587 + .413 * U + .035 * W) * G - + (.114 - .114 * U + .292 * W) * B; - const float B_out = (.299 - .3 * U + 1.25 * W) * R - + (.587 - .588 * U - 1.05 * W) * G - + (.114 + .886 * U - .203 * W) * B; + // Adapted from http://beesbuzz.biz/code/16-hsv-color-transforms + // (C) J. “Fluffy” Shagam + // License: CC BY-SA 4.0 + const float su = S * cos(-H * BSPF::PI_f); + const float sw = S * sin(-H * BSPF::PI_f); + const float r = (.299 + .701 * su + .168 * sw) * R + + (.587 - .587 * su + .330 * sw) * G + + (.114 - .114 * su - .497 * sw) * B; + const float g = (.299 - .299 * su - .328 * sw) * R + + (.587 + .413 * su + .035 * sw) * G + + (.114 - .114 * su + .292 * sw) * B; + const float b = (.299 - .300 * su + 1.25 * sw) * R + + (.587 - .588 * su - 1.05 * sw) * G + + (.114 + .886 * su - .203 * sw) * B; - R = R_out; G = G_out; B = B_out; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::adustSaturation(int& R, int& G, int& B, float change) -{ - // public-domain function by Darel Rex Finley - // - // The passed-in RGB values can be on any desired scale, such as 0 to - // to 1, or 0 to 255. (But use the same scale for all three!) - // - // The "change" parameter works like this: - // 0.0 creates a black-and-white image. - // 0.5 reduces the color saturation by half. - // 1.0 causes no change. - // 2.0 doubles the color saturation. - // Note: A "change" value greater than 1.0 may project your RGB values - // beyond their normal range, in which case you probably should truncate - // them to the desired range before trying to use them in an image. - constexpr float PR = .2989F; - constexpr float PG = .5870F; - constexpr float PB = .1140F; - const float P = sqrt(R * R * PR + G * G * PG + B * B * PB) ; - - R = P + (R - P) * change; - G = P + (G - P) * change; - B = P + (B - P) * change; - - R = BSPF::clamp(R, 0, 255); - G = BSPF::clamp(G, 0, 255); - B = BSPF::clamp(B, 0, 255); + R = BSPF::clamp(r, 0.F, 255.F); + G = BSPF::clamp(g, 0.F, 255.F); + B = BSPF::clamp(b, 0.F, 255.F); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index ddb4bfaa1..cffdc2ad4 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -110,8 +110,7 @@ class PaletteHandler PaletteArray adjustPalette(const PaletteArray& source); - void adjustHue(int& R, int& G, int& B, float change); - void adustSaturation(int& R, int& G, int& B, float change); + void adjustHueSaturation(int& R, int& G, int& B, float H, float S); /** Loads a user-defined palette file (from OSystem::paletteFile), filling the From 614e28375de435f4d6a236dd9b7142feaf70b215 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 10:47:43 +0200 Subject: [PATCH 11/42] code cleanup and bug fixing --- src/common/PKeyboardHandler.cxx | 2 - src/common/PaletteHandler.cxx | 150 ++++++++++++--------------- src/common/PaletteHandler.hxx | 122 ++++++++++++++++------ src/common/tv_filters/NTSCFilter.cxx | 26 ++--- src/emucore/Event.hxx | 1 - src/emucore/EventHandler.cxx | 19 +--- src/emucore/EventHandler.hxx | 2 +- src/emucore/Settings.cxx | 10 +- src/gui/CommandDialog.cxx | 8 +- src/gui/VideoDialog.cxx | 12 +-- 10 files changed, 193 insertions(+), 159 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 1a0fe6499..3edd7698d 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -491,8 +491,6 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, 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/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index dbca46ff2..3f1066724 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -54,19 +54,14 @@ string PaletteHandler::toPaletteName(PaletteType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changePalette(bool increase) +void PaletteHandler::cyclePalette(bool next) { const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" }; - - string palette, message; - palette = myOSystem.settings().getString("palette"); - - int type = toPaletteType(myOSystem.settings().getString("palette")); - if(increase) + if(next) { if(type == PaletteType::MaxType) type = PaletteType::Standard; @@ -87,8 +82,8 @@ void PaletteHandler::changePalette(bool increase) type--; } - palette = toPaletteName(PaletteType(type)); - message = MESSAGES[type] + " palette"; + const string palette = toPaletteName(PaletteType(type)); + const string message = MESSAGES[type] + " palette"; myOSystem.frameBuffer().showMessage(message); @@ -96,9 +91,10 @@ void PaletteHandler::changePalette(bool increase) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::selectAdjustable(bool next) +void PaletteHandler::cycleAdjustable(bool next) { - const bool isCustomPalette = "custom" == myOSystem.settings().getString("palette"); + const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); + bool isPhaseShift; do { if(next) @@ -113,11 +109,19 @@ void PaletteHandler::selectAdjustable(bool next) else myCurrentAdjustable--; } - } while(!isCustomPalette && myAdjustables[myCurrentAdjustable].value == nullptr); + isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; + + // skip phase shift when 'Custom' palette is not selected + } while(isPhaseShift && !isCustomPalette); ostringstream buf; - buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].type - << "' selected"; + buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].name + << "' selected ("; + if(isPhaseShift) + buf << (myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC) + << DEGREE << ")"; + else + buf << scaleTo100(*myAdjustables[myCurrentAdjustable].value) << "%)"; myOSystem.frameBuffer().showMessage(buf.str()); } @@ -129,25 +133,19 @@ void PaletteHandler::changeAdjustable(bool increase) changeColorPhaseShift(increase); else { - float newVal = (*myAdjustables[myCurrentAdjustable].value); + int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value); if(increase) - { - newVal += 0.05F; - if(newVal > 1.0F) - newVal = 1.0F; - } + newVal += 2; // += 2% else - { - newVal -= 0.05F; - if(newVal < -1.0F) - newVal = -1.0F; - } - *myAdjustables[myCurrentAdjustable].value = newVal; + newVal -= 2; // -= 2% + newVal = BSPF::clamp(newVal, 0, 100); + + *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); ostringstream buf; - buf << "Custom '" << myAdjustables[myCurrentAdjustable].type - << "' set to " << int((newVal + 1.0F) * 100.0F + 0.5F) << "%"; + buf << "Custom '" << myAdjustables[myCurrentAdjustable].name + << "' set to " << newVal << "%"; myOSystem.frameBuffer().showMessage(buf.str()); setPalette(); @@ -162,32 +160,27 @@ void PaletteHandler::changeColorPhaseShift(bool increase) // 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; + float newPhase = isNTSC ? myPhaseNTSC : myPhasePAL; if(increase) // increase color phase shift - { - phase += 0.3F; - phase = std::min(phase, shift + MAX_SHIFT); - } + newPhase += 0.3F; else // decrease color phase shift - { - phase -= 0.3F; - phase = std::max(phase, shift - MAX_SHIFT); - } + newPhase -= 0.3F; + newPhase = BSPF::clamp(newPhase, shift - MAX_SHIFT, shift + MAX_SHIFT); + if(isNTSC) - myPhaseNTSC = phase; + myPhaseNTSC = newPhase; else - myPhasePAL = phase; + myPhasePAL = newPhase; generateCustomPalette(timing); - setPalette("custom"); + setPalette(SETTING_CUSTOM); ostringstream ss; ss << "Color phase shift at " - << std::fixed << std::setprecision(1) << phase << DEGREE; + << std::fixed << std::setprecision(1) << newPhase << DEGREE; myOSystem.frameBuffer().showMessage(ss.str()); } @@ -260,30 +253,33 @@ void PaletteHandler::setPalette(const string& name) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::setPalette() { - const string& name = myOSystem.settings().getString("palette"); + if(myOSystem.hasConsole()) + { + const string& name = myOSystem.settings().getString("palette"); - // 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 }, - { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } - }}; - // See which format we should be using - const ConsoleTiming timing = myOSystem.console().timing(); - const PaletteType paletteType = toPaletteType(name); - // Now consider the current display format - const PaletteArray* palette = palettes[paletteType][int(timing)]; + // 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 }, + { &ourCustomNTSCPalette, &ourCustomPALPalette, &ourSECAMPalette } + }}; + // See which format we should be using + const ConsoleTiming timing = myOSystem.console().timing(); + const PaletteType paletteType = toPaletteType(name); + // Now consider the current display format + const PaletteArray* palette = palettes[paletteType][int(timing)]; - if(paletteType == PaletteType::Custom) - generateCustomPalette(timing); + if(paletteType == PaletteType::Custom) + generateCustomPalette(timing); - myOSystem.frameBuffer().setTIAPalette(adjustPalette(*palette)); + myOSystem.frameBuffer().setTIAPalette(adjustedPalette(*palette)); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PaletteArray PaletteHandler::adjustPalette(const PaletteArray& palette) +PaletteArray PaletteHandler::adjustedPalette(const PaletteArray& palette) { PaletteArray destPalette; // Constants for saturation and gray scale calculation @@ -387,15 +383,15 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) { constexpr int NUM_CHROMA = 16; constexpr int NUM_LUMA = 8; - constexpr float SATURATION = 0.25F; + constexpr float SATURATION = 0.25F; // default saturation float color[NUM_CHROMA][2] = {{0.0F}}; if(timing == ConsoleTiming::ntsc) { // YIQ is YUV shifted by 33° - constexpr float offset = 33 * (2 * BSPF::PI_f / 360); - const float shift = myPhaseNTSC * (2 * BSPF::PI_f / 360); + constexpr float offset = 33 * BSPF::PI_f / 180; + const float shift = myPhaseNTSC * BSPF::PI_f / 180; // color 0 is grayscale for(int chroma = 1; chroma < NUM_CHROMA; chroma++) @@ -425,13 +421,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) G = powf(G, 0.9F); B = powf(B, 0.9F); - 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; + int r = BSPF::clamp(R * 255.F, 0.F, 255.F); + int g = BSPF::clamp(G * 255.F, 0.F, 255.F); + int b = BSPF::clamp(B * 255.F, 0.F, 255.F); ourCustomNTSCPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; } @@ -439,9 +431,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) } else if(timing == ConsoleTiming::pal) { - constexpr float offset = 180 * (2 * BSPF::PI_f / 360); - const float shift = myPhasePAL * (2 * BSPF::PI_f / 360); - constexpr float fixedShift = 22.5F * (2 * BSPF::PI_f / 360); + constexpr float offset = BSPF::PI_f; + const float shift = myPhasePAL * BSPF::PI_f / 180; + constexpr float fixedShift = 22.5F * BSPF::PI_f / 180; // colors 0, 1, 14 and 15 are grayscale for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++) @@ -470,7 +462,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) // German Wikipedia, huh??? //float B = Y + 1 / 0.493 * U; //float R = Y + 1 / 0.877 * V; - //float G = 1.704 * Y - 0.590 * R - 0.194 * B; + //float G = 1.704 * Y - 0.590 * R - 0.194 * B; if(R < 0) R = 0.0; if(G < 0) G = 0.0; @@ -480,13 +472,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) G = powf(G, 1.2F); B = powf(B, 1.2F); - 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; + int r = BSPF::clamp(R * 255.F, 0.F, 255.F); + int g = BSPF::clamp(G * 255.F, 0.F, 255.F); + int b = BSPF::clamp(B * 255.F, 0.F, 255.F); ourCustomPALPalette[(chroma * NUM_LUMA + luma) << 1] = (r << 16) + (g << 8) + b; } diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index cffdc2ad4..237d9b878 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -25,22 +25,18 @@ class PaletteHandler { public: + // Setting names of palette types static constexpr const char* SETTING_STANDARD = "standard"; static constexpr const char* SETTING_Z26 = "z26"; static constexpr const char* SETTING_USER = "user"; static constexpr const char* SETTING_CUSTOM = "custom"; + // Phase shift default and limits static constexpr float DEF_NTSC_SHIFT = 26.2F; - static constexpr float DEF_PAL_SHIFT = 31.3F; // 360 / 11.5 + static constexpr float DEF_PAL_SHIFT = 31.3F; // ~= 360 / 11.5 static constexpr float MAX_SHIFT = 4.5F; - enum DisplayType { - NTSC, - PAL, - SECAM, - NumDisplayTypes - }; - + // Externally used adjustment parameters struct Adjustable { float phaseNtsc, phasePal; uInt32 hue, saturation, contrast, brightness, gamma; @@ -51,28 +47,38 @@ class PaletteHandler virtual ~PaletteHandler() = default; /** - Switch between the available palettes. - */ - void changePalette(bool increase = true); + Cycle through available palettes. - void selectAdjustable(bool next = true); + @param next Select next palette, else previous one + */ + void cyclePalette(bool next = true); + + /* + Cycle through each palette adjustable + + @param next Select next adjustable, else previous one + */ + void cycleAdjustable(bool next = true); + + /* + Increase or decrease current palette adjustable + + @param increase Increase adjustable if true, else decrease + */ void changeAdjustable(bool increase = true); - + // Load adjustables from settings void loadConfig(const Settings& settings); + + // Save adjustables to settings void saveConfig(Settings& settings) const; + + // Set adjustables void setAdjustables(const Adjustable& adjustable); + + // Retrieve current adjustables void getAdjustables(Adjustable& adjustable) const; - /** - 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 increase increase if true, else decrease. - */ - void changeColorPhaseShift(bool increase = true); - /** Sets the palette according to the given palette name. @@ -80,18 +86,14 @@ class PaletteHandler */ void setPalette(const string& name); - /** Sets the palette from current settings. */ void setPalette(); - /** - Generates a custom palette, based on user defined phase shifts. - */ - void generateCustomPalette(ConsoleTiming timing); - private: + static constexpr char DEGREE = 0x1c; + enum PaletteType { Standard, Z26, @@ -102,14 +104,64 @@ class PaletteHandler MaxType = Custom }; + /** + Convert adjustables from/to 100% scale + */ float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } + /** + Convert palette settings name to enumeration + + @param name The given palette's settings name + + @return The palette type + */ PaletteType toPaletteType(const string& name) const; + + /** + Convert enumeration to palette settings name + + @param type The given palette type + + @return The palette's settings name + */ string toPaletteName(PaletteType type) const; - PaletteArray adjustPalette(const PaletteArray& source); + /** + 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 increase Increase if true, else decrease. + */ + void changeColorPhaseShift(bool increase = true); + + /** + Generates a custom palette, based on user defined phase shifts. + + @param timing Use NTSC or PAL phase shift and generate according palette + */ + void generateCustomPalette(ConsoleTiming timing); + + /** + Create new palette by applying palette adjustments on given palette + + @param type The palette which should be adjusted + + @return An adjusted palette + */ + PaletteArray adjustedPalette(const PaletteArray& source); + + /** + Adjust hue and saturation for given RGB values + + @param R The red value to adjust + @param G The green value to adjust + @param B The blue value to adjust + @param H The hue adjustment value + @param S The saturation + */ void adjustHueSaturation(int& R, int& G, int& B, float H, float S); /** @@ -118,15 +170,16 @@ class PaletteHandler */ void loadUserPalette(); - private: static constexpr int NUM_ADJUSTABLES = 6; OSystem& myOSystem; + // The currently selected adjustable uInt32 myCurrentAdjustable{0}; + struct AdjustableTag { - const char* const type{nullptr}; + const char* const name{nullptr}; float* value{nullptr}; }; const std::array myAdjustables = @@ -139,8 +192,9 @@ class PaletteHandler { "gamma", &myGamma }, } }; - float myPhaseNTSC{0.0F}; - float myPhasePAL{0.0F}; + // NTSC and PAL color phase shifts + float myPhaseNTSC{DEF_NTSC_SHIFT}; + float myPhasePAL{DEF_PAL_SHIFT}; // range -1.0 to +1.0 (as in AtariNTSC) // Basic parameters float myHue{0.0F}; // -1 = -180 degrees +1 = +180 degrees @@ -169,7 +223,7 @@ class PaletteHandler static PaletteArray ourUserPALPalette; static PaletteArray ourUserSECAMPalette; - // Table of RGB values for NTSC, PAL - custom-defined + // Table of RGB values for NTSC, PAL - custom-defined and generated static PaletteArray ourCustomNTSCPalette; static PaletteArray ourCustomPALPalette; diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 8a40ddd2c..64f26da2b 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -74,8 +74,8 @@ string NTSCFilter::getPreset() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setNextAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; #ifdef BLARGG_PALETTE myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; @@ -85,7 +85,8 @@ string NTSCFilter::setNextAdjustable() ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected"; + << "' selected (" + << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; return buf.str(); } @@ -93,8 +94,8 @@ string NTSCFilter::setNextAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setPreviousAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; #ifdef BLARGG_PALETTE if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; @@ -104,7 +105,8 @@ string NTSCFilter::setPreviousAdjustable() else --myCurrentAdjustable; ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected"; + << "' selected (" + << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; return buf.str(); } @@ -112,8 +114,8 @@ string NTSCFilter::setPreviousAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::increaseAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); newval += 2; if(newval > 100) newval = 100; @@ -121,7 +123,7 @@ string NTSCFilter::increaseAdjustable() ostringstream buf; buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval; + << "' set to " << newval << "%"; setPreset(myPreset); return buf.str(); @@ -130,8 +132,8 @@ string NTSCFilter::increaseAdjustable() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::decreaseAdjustable() { - if(myPreset != Preset::CUSTOM) - return "'Custom' TV mode not selected"; + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); if(newval < 2) newval = 0; @@ -140,7 +142,7 @@ string NTSCFilter::decreaseAdjustable() ostringstream buf; buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval; + << "' set to " << newval << "%"; setPreset(myPreset); return buf.str(); diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index ae82ef810..fba15b6fb 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -101,7 +101,6 @@ class Event RewindPause, UnwindPause, FormatDecrease, FormatIncrease, PaletteDecrease, PaletteIncrease, ToggleColorLoss, - ColorShiftDecrease, ColorShiftIncrease, PreviousPaletteAttribute, NextPaletteAttribute, PaletteAttributeDecrease, PaletteAttributeIncrease, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 325438765..362625909 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -437,11 +437,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PreviousPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(false); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); return; case Event::NextPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().selectAdjustable(true); + if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); return; case Event::PaletteAttributeDecrease: @@ -452,14 +452,6 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); return; - case Event::ColorShiftDecrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(false); - return; - - case Event::ColorShiftIncrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeColorPhaseShift(true); - return; - case Event::ToggleFullScreen: if (pressed && !repeated) myOSystem.frameBuffer().toggleFullscreen(); return; @@ -565,11 +557,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(false); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); return; case Event::PaletteIncrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().changePalette(true); + if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); return; case Event::ToggleInter: @@ -1965,8 +1957,6 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::NextPaletteAttribute, "Select next palette attribute", "" }, { Event::PaletteAttributeDecrease,"Decrease selected palette attribute", "" }, { Event::PaletteAttributeIncrease,"Increase selected palette attribute", "" }, - { Event::ColorShiftDecrease, "Decrease custom palette phase shift", "" }, - { Event::ColorShiftIncrease, "Increase custom palette phase shift", "" }, { Event::ToggleInter, "Toggle display interpolation", "" }, // Blargg TV effects: { Event::VidmodeStd, "Disable TV effects", "" }, @@ -2097,7 +2087,6 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, - Event::ColorShiftDecrease, Event::ColorShiftIncrease, Event::PreviousVideoMode, Event::NextVideoMode, Event::PreviousPaletteAttribute, Event::NextPaletteAttribute, Event::PaletteAttributeDecrease, Event::PaletteAttributeIncrease, diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index fd8522e5f..6d19b685b 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 = 154 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 152 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index a959cc255..07c41e0f3 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -21,6 +21,7 @@ #include "Version.hxx" #include "Logger.hxx" #include "AudioSettings.hxx" +#include "PaletteHandler.hxx" #include "Paddles.hxx" #ifdef DEBUGGER_SUPPORT @@ -45,7 +46,7 @@ Settings::Settings() setPermanent("center", "true"); setPermanent("windowedpos", Common::Point(50, 50)); setPermanent("display", 0); - setPermanent("palette", "standard"); + setPermanent("palette", PaletteHandler::SETTING_STANDARD); setPermanent("uimessages", "true"); // TIA specific options @@ -358,8 +359,11 @@ void Settings::validate() else if(i > 10) setValue("ssinterval", "10"); s = getString("palette"); - if(s != "standard" && s != "z26" && s != "user" && s != "custom") - setValue("palette", "standard"); + if(s != PaletteHandler::SETTING_STANDARD + && s != PaletteHandler::SETTING_Z26 + && s != PaletteHandler::SETTING_USER + && s != PaletteHandler::SETTING_CUSTOM) + setValue("palette", PaletteHandler::SETTING_STANDARD); s = getString("launcherfont"); if(s != "small" && s != "low_medium" && s != "medium" && s != "large" diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 0d8729635..5790f7193 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -204,7 +204,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, break; case kPaletteCmd: - instance().frameBuffer().tiaSurface().paletteHandler().changePalette(); + instance().frameBuffer().tiaSurface().paletteHandler().cyclePalette(); updatePalette(); break; @@ -270,11 +270,11 @@ void CommandDialog::updatePalette() string palette, label; palette = instance().settings().getString("palette"); - if(BSPF::equalsIgnoreCase(palette, "standard")) + if(BSPF::equalsIgnoreCase(palette, PaletteHandler::SETTING_STANDARD)) label = "Stella Palette"; - else if(BSPF::equalsIgnoreCase(palette, "z26")) + else if(BSPF::equalsIgnoreCase(palette, PaletteHandler::SETTING_Z26)) label = "Z26 Palette"; - else if(BSPF::equalsIgnoreCase(palette, "user")) + else if(BSPF::equalsIgnoreCase(palette, PaletteHandler::SETTING_USER)) label = "User Palette"; else label = "Custom Palette"; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index a90657892..bc1fdfa36 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -269,11 +269,11 @@ void VideoDialog::addPaletteTab() // TIA Palette items.clear(); - VarList::push_back(items, "Standard", "standard"); - VarList::push_back(items, "z26", "z26"); + VarList::push_back(items, "Standard", PaletteHandler::SETTING_STANDARD); + VarList::push_back(items, "z26", PaletteHandler::SETTING_Z26); if (instance().checkUserPalette()) - VarList::push_back(items, "User", "user"); - VarList::push_back(items, "Custom", "custom"); + VarList::push_back(items, "User", PaletteHandler::SETTING_USER); + VarList::push_back(items, "Custom", PaletteHandler::SETTING_CUSTOM); myTIAPalette = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, items, "Palette ", lwidth, kPaletteChanged); wid.push_back(myTIAPalette); @@ -421,7 +421,7 @@ void VideoDialog::loadConfig() // TIA Palette myPalette = instance().settings().getString("palette"); - myTIAPalette->setSelected(myPalette, "standard"); + myTIAPalette->setSelected(myPalette, PaletteHandler::SETTING_STANDARD); // Palette adjustables instance().frameBuffer().tiaSurface().paletteHandler().getAdjustables(myPaletteAdj); @@ -610,7 +610,7 @@ void VideoDialog::setDefaults() } case 1: // Palettes - myTIAPalette->setSelected("standard", ""); + myTIAPalette->setSelected(PaletteHandler::SETTING_STANDARD); myPhaseShiftNtsc->setValue(PaletteHandler::DEF_NTSC_SHIFT * 10); myPhaseShiftPal->setValue(PaletteHandler::DEF_PAL_SHIFT * 10); myTVHue->setValue(50); From 259c0bf48fe0d0539d56ccc220a14e31bb123f1c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 16:15:12 +0200 Subject: [PATCH 12/42] refactored Video and Audio dialogs into common dialog created new EmulationDialog (re)moved some includes to reduce compile time --- src/debugger/gui/CartDebugWidget.hxx | 3 - src/debugger/gui/CartEnhancedWidget.cxx | 2 + src/debugger/gui/DebuggerDialog.hxx | 2 +- src/emucore/OSystem.hxx | 2 +- src/gui/AudioDialog.cxx | 353 ------------ src/gui/AudioDialog.hxx | 77 --- src/gui/DeveloperDialog.cxx | 42 -- src/gui/DeveloperDialog.hxx | 2 - src/gui/EmulationDialog.cxx | 283 ++++++++++ src/gui/EmulationDialog.hxx | 63 +++ src/gui/InputDialog.cxx | 2 +- src/gui/OptionsDialog.cxx | 26 +- src/gui/OptionsDialog.hxx | 10 +- src/gui/UIDialog.cxx | 14 +- src/gui/UIDialog.hxx | 1 - .../{VideoDialog.cxx => VideoAudioDialog.cxx} | 528 ++++++++++++------ .../{VideoDialog.hxx => VideoAudioDialog.hxx} | 89 +-- src/gui/module.mk | 4 +- src/libpng/pngconf.h | 6 +- src/windows/Stella.vcxproj | 8 +- src/windows/Stella.vcxproj.filters | 24 +- 21 files changed, 795 insertions(+), 746 deletions(-) delete mode 100644 src/gui/AudioDialog.cxx delete mode 100644 src/gui/AudioDialog.hxx create mode 100644 src/gui/EmulationDialog.cxx create mode 100644 src/gui/EmulationDialog.hxx rename src/gui/{VideoDialog.cxx => VideoAudioDialog.cxx} (66%) rename src/gui/{VideoDialog.hxx => VideoAudioDialog.hxx} (75%) diff --git a/src/debugger/gui/CartDebugWidget.hxx b/src/debugger/gui/CartDebugWidget.hxx index 7bdcbf472..27c3befa5 100644 --- a/src/debugger/gui/CartDebugWidget.hxx +++ b/src/debugger/gui/CartDebugWidget.hxx @@ -19,7 +19,6 @@ #define CART_DEBUG_WIDGET_HXX class GuiObject; -class ButtonWidget; class StringListWidget; namespace GUI { @@ -29,8 +28,6 @@ namespace GUI { #include "Base.hxx" // not needed here, but all child classes need it #include "Command.hxx" #include "Widget.hxx" -#include "Debugger.hxx" -#include "CartDebug.hxx" class CartDebugWidget : public Widget, public CommandSender { diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index f864a21c0..d955a803a 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -17,6 +17,8 @@ #include "PopUpWidget.hxx" +#include "Debugger.hxx" +#include "CartDebug.hxx" #include "CartEnhanced.hxx" #include "CartEnhancedWidget.hxx" diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index b66ae37a6..bfd7c332b 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -33,6 +33,7 @@ class TiaOutputWidget; class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; +class OptionsDialog; namespace Common { struct Rect; @@ -40,7 +41,6 @@ namespace Common { #include "Dialog.hxx" #include "MessageBox.hxx" -#include "OptionsDialog.hxx" class DebuggerDialog : public Dialog { diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index b23cbdb83..2bc5368c6 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -41,7 +41,7 @@ class AudioSettings; class Menu; class MessageMenu; class TimeMachine; - class VideoDialog; + class VideoAudioDialog; #endif #ifdef PNG_SUPPORT class PNGLibrary; diff --git a/src/gui/AudioDialog.cxx b/src/gui/AudioDialog.cxx deleted file mode 100644 index 1f97c2f8b..000000000 --- a/src/gui/AudioDialog.cxx +++ /dev/null @@ -1,353 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -//============================================================================ - -#include - -#include "bspf.hxx" - -#include "Console.hxx" -#include "Cart.hxx" -#include "CartDPC.hxx" -#include "Control.hxx" -#include "Dialog.hxx" -#include "Font.hxx" -#include "Menu.hxx" -#include "OSystem.hxx" -#include "PopUpWidget.hxx" -#include "Settings.hxx" -#include "Sound.hxx" -#include "Widget.hxx" -#include "AudioSettings.hxx" - -#include "AudioDialog.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AudioDialog::AudioDialog(OSystem& osystem, DialogContainer& parent, - const GUI::Font& font) - : Dialog(osystem, parent, font, "Audio settings") -{ - const int lineHeight = font.getLineHeight(), - fontHeight = font.getFontHeight(), - fontWidth = font.getMaxCharWidth(); - const int VBORDER = fontHeight / 2; - const int HBORDER = fontWidth * 1.25; - const int INDENT = fontWidth * 2; - const int VGAP = fontHeight / 4; - - int xpos, ypos; - int lwidth = font.getStringWidth("Volume "), - pwidth; - - WidgetArray wid; - VariantList items; - - // Set real dimensions - _w = 48 * fontWidth + HBORDER * 2; - _h = 12 * (lineHeight + VGAP) + VBORDER + _th; - - xpos = HBORDER; ypos = VBORDER + _th; - - // Enable sound - mySoundEnableCheckbox = new CheckboxWidget(this, font, xpos, ypos, - "Enable sound", kSoundEnableChanged); - wid.push_back(mySoundEnableCheckbox); - ypos += lineHeight + VGAP; - xpos += CheckboxWidget::prefixSize(font); - - // Volume - myVolumeSlider = new SliderWidget(this, font, xpos, ypos, - "Volume", lwidth, 0, 4 * fontWidth, "%"); - myVolumeSlider->setMinValue(1); myVolumeSlider->setMaxValue(100); - myVolumeSlider->setTickmarkIntervals(4); - wid.push_back(myVolumeSlider); - ypos += lineHeight + VGAP; - - // Mode - items.clear(); - VarList::push_back(items, "Low quality, medium lag", static_cast(AudioSettings::Preset::lowQualityMediumLag)); - VarList::push_back(items, "High quality, medium lag", static_cast(AudioSettings::Preset::highQualityMediumLag)); - VarList::push_back(items, "High quality, low lag", static_cast(AudioSettings::Preset::highQualityLowLag)); - VarList::push_back(items, "Ultra quality, minimal lag", static_cast(AudioSettings::Preset::ultraQualityMinimalLag)); - VarList::push_back(items, "Custom", static_cast(AudioSettings::Preset::custom)); - myModePopup = new PopUpWidget(this, font, xpos, ypos, - font.getStringWidth("Ultry quality, minimal lag"), lineHeight, - items, "Mode", lwidth, kModeChanged); - wid.push_back(myModePopup); - ypos += lineHeight + VGAP; - xpos += INDENT; - - // Fragment size - pwidth = font.getStringWidth("512 samples") + 7; - lwidth = font.getStringWidth("Resampling quality "); - items.clear(); - VarList::push_back(items, "128 samples", 128); - VarList::push_back(items, "256 samples", 256); - VarList::push_back(items, "512 samples", 512); - VarList::push_back(items, "1k samples", 1024); - VarList::push_back(items, "2k samples", 2048); - VarList::push_back(items, "4K samples", 4096); - myFragsizePopup = new PopUpWidget(this, font, xpos, ypos, - pwidth, lineHeight, - items, "Fragment size", lwidth); - wid.push_back(myFragsizePopup); - ypos += lineHeight + VGAP; - - // Output frequency - items.clear(); - VarList::push_back(items, "44100 Hz", 44100); - VarList::push_back(items, "48000 Hz", 48000); - VarList::push_back(items, "96000 Hz", 96000); - myFreqPopup = new PopUpWidget(this, font, xpos, ypos, - pwidth, lineHeight, - items, "Sample rate", lwidth); - wid.push_back(myFreqPopup); - ypos += lineHeight + VGAP; - - // Resampling quality - items.clear(); - VarList::push_back(items, "Low", static_cast(AudioSettings::ResamplingQuality::nearestNeightbour)); - VarList::push_back(items, "High", static_cast(AudioSettings::ResamplingQuality::lanczos_2)); - VarList::push_back(items, "Ultra", static_cast(AudioSettings::ResamplingQuality::lanczos_3)); - myResamplingPopup = new PopUpWidget(this, font, xpos, ypos, - pwidth, lineHeight, - items, "Resampling quality ", lwidth); - wid.push_back(myResamplingPopup); - ypos += lineHeight + VGAP; - - // Param 1 - int swidth = pwidth+23; - myHeadroomSlider = new SliderWidget(this, font, xpos, ypos, swidth, lineHeight, - "Headroom ", 0, kHeadroomChanged, 10 * fontWidth); - myHeadroomSlider->setMinValue(0); myHeadroomSlider->setMaxValue(AudioSettings::MAX_HEADROOM); - myHeadroomSlider->setTickmarkIntervals(5); - wid.push_back(myHeadroomSlider); - ypos += lineHeight + VGAP; - - // Param 2 - myBufferSizeSlider = new SliderWidget(this, font, xpos, ypos, swidth, lineHeight, - "Buffer size ", 0, kBufferSizeChanged, 10 * fontWidth); - myBufferSizeSlider->setMinValue(0); myBufferSizeSlider->setMaxValue(AudioSettings::MAX_BUFFER_SIZE); - myBufferSizeSlider->setTickmarkIntervals(5); - wid.push_back(myBufferSizeSlider); - ypos += lineHeight + VGAP; - - // Stereo sound - xpos -= INDENT; - myStereoSoundCheckbox = new CheckboxWidget(this, font, xpos, ypos, - "Stereo for all ROMs"); - wid.push_back(myStereoSoundCheckbox); - ypos += lineHeight + VGAP; - - myDpcPitch = new SliderWidget(this, font, xpos, ypos, swidth - 16, lineHeight, - "Pitfall II music pitch ", 0, 0, 5 * fontWidth); - myDpcPitch->setMinValue(10000); myDpcPitch->setMaxValue(30000); - myDpcPitch->setStepValue(100); - myDpcPitch->setTickmarkIntervals(2); - wid.push_back(myDpcPitch); - - // Add Defaults, OK and Cancel buttons - addDefaultsOKCancelBGroup(wid, font); - - addToFocusList(wid); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::loadConfig() -{ - AudioSettings& audioSettings = instance().audioSettings(); - - // Enable sound - mySoundEnableCheckbox->setState(audioSettings.enabled()); - - // Volume - myVolumeSlider->setValue(audioSettings.volume()); - - // Stereo - myStereoSoundCheckbox->setState(audioSettings.stereo()); - - // DPC Pitch - myDpcPitch->setValue(audioSettings.dpcPitch()); - - // Preset / mode - myModePopup->setSelected(static_cast(audioSettings.preset())); - - updateSettingsWithPreset(instance().audioSettings()); - - updateEnabledState(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::updateSettingsWithPreset(AudioSettings& audioSettings) -{ - // Fragsize - myFragsizePopup->setSelected(audioSettings.fragmentSize()); - - // Output frequency - myFreqPopup->setSelected(audioSettings.sampleRate()); - - // Headroom - myHeadroomSlider->setValue(audioSettings.headroom()); - - // Buffer size - myBufferSizeSlider->setValue(audioSettings.bufferSize()); - - // Resampling quality - myResamplingPopup->setSelected(static_cast(audioSettings.resamplingQuality())); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::saveConfig() -{ - AudioSettings& audioSettings = instance().audioSettings(); - - // Enabled - audioSettings.setEnabled(mySoundEnableCheckbox->getState()); - instance().sound().setEnabled(mySoundEnableCheckbox->getState()); - - // Volume - audioSettings.setVolume(myVolumeSlider->getValue()); - instance().sound().setVolume(myVolumeSlider->getValue()); - - // Stereo - audioSettings.setStereo(myStereoSoundCheckbox->getState()); - - // DPC Pitch - audioSettings.setDpcPitch(myDpcPitch->getValue()); - // update if current cart is Pitfall II - if (instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC") - { - CartridgeDPC& cart = static_cast(instance().console().cartridge()); - cart.setDpcPitch(myDpcPitch->getValue()); - } - - AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); - audioSettings.setPreset(preset); - - if (preset == AudioSettings::Preset::custom) { - // Fragsize - audioSettings.setFragmentSize(myFragsizePopup->getSelectedTag().toInt()); - audioSettings.setSampleRate(myFreqPopup->getSelectedTag().toInt()); - audioSettings.setHeadroom(myHeadroomSlider->getValue()); - audioSettings.setBufferSize(myBufferSizeSlider->getValue()); - audioSettings.setResamplingQuality(static_cast(myResamplingPopup->getSelectedTag().toInt())); - } - - // Only force a re-initialization when necessary, since it can - // be a time-consuming operation - if(instance().hasConsole()) - instance().console().initializeAudio(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::setDefaults() -{ - mySoundEnableCheckbox->setState(AudioSettings::DEFAULT_ENABLED); - myVolumeSlider->setValue(AudioSettings::DEFAULT_VOLUME); - myStereoSoundCheckbox->setState(AudioSettings::DEFAULT_STEREO); - myDpcPitch->setValue(AudioSettings::DEFAULT_DPC_PITCH); - myModePopup->setSelected(static_cast(AudioSettings::DEFAULT_PRESET)); - - if (AudioSettings::DEFAULT_PRESET == AudioSettings::Preset::custom) { - myResamplingPopup->setSelected(static_cast(AudioSettings::DEFAULT_RESAMPLING_QUALITY)); - myFragsizePopup->setSelected(AudioSettings::DEFAULT_FRAGMENT_SIZE); - myFreqPopup->setSelected(AudioSettings::DEFAULT_SAMPLE_RATE); - myHeadroomSlider->setValue(AudioSettings::DEFAULT_HEADROOM); - myBufferSizeSlider->setValue(AudioSettings::DEFAULT_BUFFER_SIZE); - } - else updatePreset(); - - updateEnabledState(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::updateEnabledState() -{ - bool active = mySoundEnableCheckbox->getState(); - AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); - bool userMode = preset == AudioSettings::Preset::custom; - - myVolumeSlider->setEnabled(active); - myStereoSoundCheckbox->setEnabled(active); - myModePopup->setEnabled(active); - // enable only for Pitfall II cart - myDpcPitch->setEnabled(active && instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC"); - - myFragsizePopup->setEnabled(active && userMode); - myFreqPopup->setEnabled(active && userMode); - myResamplingPopup->setEnabled(active && userMode); - myHeadroomSlider->setEnabled(active && userMode); - myBufferSizeSlider->setEnabled(active && userMode); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::updatePreset() -{ - AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); - - // Make a copy that does not affect the actual settings... - AudioSettings audioSettings = instance().audioSettings(); - audioSettings.setPersistent(false); - // ... and set the requested preset - audioSettings.setPreset(preset); - - updateSettingsWithPreset(audioSettings); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void AudioDialog::handleCommand(CommandSender* sender, int cmd, - int data, int id) -{ - switch(cmd) - { - case GuiObject::kOKCmd: - saveConfig(); - close(); - break; - - case GuiObject::kDefaultsCmd: - setDefaults(); - break; - - case kSoundEnableChanged: - updateEnabledState(); - break; - - case kModeChanged: - updatePreset(); - updateEnabledState(); - break; - - case kHeadroomChanged: - { - std::ostringstream ss; - ss << std::fixed << std::setprecision(1) << (0.5 * myHeadroomSlider->getValue()) << " frames"; - myHeadroomSlider->setValueLabel(ss.str()); - break; - } - case kBufferSizeChanged: - { - std::ostringstream ss; - ss << std::fixed << std::setprecision(1) << (0.5 * myBufferSizeSlider->getValue()) << " frames"; - myBufferSizeSlider->setValueLabel(ss.str()); - break; - } - - default: - Dialog::handleCommand(sender, cmd, data, 0); - break; - } -} diff --git a/src/gui/AudioDialog.hxx b/src/gui/AudioDialog.hxx deleted file mode 100644 index b7aa35c65..000000000 --- a/src/gui/AudioDialog.hxx +++ /dev/null @@ -1,77 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -//============================================================================ - -#ifndef AUDIO_DIALOG_HXX -#define AUDIO_DIALOG_HXX - -class CommandSender; -class Dialog; -class DialogContainer; -class PopUpWidget; -class SliderWidget; -class StaticTextWidget; -class CheckboxWidget; -class OSystem; -class AudioSettings; - -#include "bspf.hxx" - -class AudioDialog : public Dialog -{ - public: - AudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); - virtual ~AudioDialog() = default; - - private: - void loadConfig() override; - void saveConfig() override; - void setDefaults() override; - - void updatePreset(); - void updateEnabledState(); - void updateSettingsWithPreset(AudioSettings&); - void handleCommand(CommandSender* sender, int cmd, int data, int id) override; - - private: - enum { - kSoundEnableChanged = 'ADse', - kModeChanged = 'ADmc', - kHeadroomChanged = 'ADhc', - kBufferSizeChanged = 'ADbc' - }; - - CheckboxWidget* mySoundEnableCheckbox{nullptr}; - SliderWidget* myVolumeSlider{nullptr}; - CheckboxWidget* myStereoSoundCheckbox{nullptr}; - PopUpWidget* myModePopup{nullptr}; - PopUpWidget* myFragsizePopup{nullptr}; - PopUpWidget* myFreqPopup{nullptr}; - PopUpWidget* myResamplingPopup{nullptr}; - SliderWidget* myHeadroomSlider{nullptr}; - SliderWidget* myBufferSizeSlider{nullptr}; - SliderWidget* myDpcPitch{nullptr}; - - private: - // Following constructors and assignment operators not supported - AudioDialog() = delete; - AudioDialog(const AudioDialog&) = delete; - AudioDialog(AudioDialog&&) = delete; - AudioDialog& operator=(const AudioDialog&) = delete; - AudioDialog& operator=(AudioDialog&&) = delete; -}; - -#endif diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx index 5badbc513..288fb6a40 100644 --- a/src/gui/DeveloperDialog.cxx +++ b/src/gui/DeveloperDialog.cxx @@ -499,31 +499,6 @@ void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) lineHeight, items, "Horizon ~ ", 0, kHorizonChanged); wid.push_back(myStateHorizonWidget); - xpos = HBORDER + INDENT; - ypos += lineHeight + VGAP * 2; - new StaticTextWidget(myTab, font, HBORDER, ypos + 1, - "When entering/exiting emulation:"); - ypos += lineHeight + VGAP; - mySaveOnExitGroup = new RadioButtonGroup(); - r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, - "Do nothing", mySaveOnExitGroup); - wid.push_back(r); - ypos += lineHeight + VGAP; - r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, - "Save current state in current slot", mySaveOnExitGroup); - wid.push_back(r); - ypos += lineHeight + VGAP; - r = new RadioButtonWidget(myTab, font, xpos, ypos + 1, - "Load/save all Time Machine states", mySaveOnExitGroup); - wid.push_back(r); - ypos += lineHeight + VGAP; - xpos = HBORDER; - - - myAutoSlotWidget = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Automatically change save state slots"); - wid.push_back(myAutoSlotWidget); - ypos += lineHeight + VGAP; - // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); ypos = myTab->getHeight() - fontHeight - infofont.getFontHeight() - VGAP - VBORDER; @@ -678,8 +653,6 @@ void DeveloperDialog::loadSettings(SettingsSet set) myUncompressed[set] = instance().settings().getInt(prefix + "tm.uncompressed"); myStateInterval[set] = instance().settings().getString(prefix + "tm.interval"); myStateHorizon[set] = instance().settings().getString(prefix + "tm.horizon"); - - } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -871,12 +844,6 @@ void DeveloperDialog::loadConfig() // Debug colours handleDebugColours(instance().settings().getString("tia.dbgcolors")); - // Save on exit - string saveOnExit = instance().settings().getString("saveonexit"); - mySaveOnExitGroup->setSelected(saveOnExit == "all" ? 2 : saveOnExit == "current" ? 1 : 0); - // Automatically change save state slots - myAutoSlotWidget->setState(instance().settings().getBool("autoslot")); - #ifdef DEBUGGER_SUPPORT uInt32 w, h; @@ -953,13 +920,6 @@ void DeveloperDialog::saveConfig() instance().state().setRewindMode(myTimeMachineWidget->getState() ? StateManager::Mode::TimeMachine : StateManager::Mode::Off); - // Save on exit - int saveOnExit = mySaveOnExitGroup->getSelected(); - instance().settings().setValue("saveonexit", - saveOnExit == 0 ? "none" : saveOnExit == 1 ? "current" : "all"); - // Automatically change save state slots - instance().settings().setValue("autoslot", myAutoSlotWidget->getState()); - #ifdef DEBUGGER_SUPPORT // Debugger font style instance().settings().setValue("dbg.fontstyle", @@ -1050,8 +1010,6 @@ void DeveloperDialog::setDefaults() myStateHorizon[set] = devSettings ? "30s" : "10m"; setWidgetStates(set); - mySaveOnExitGroup->setSelected(0); - myAutoSlotWidget->setState(false); break; case 4: // Debugger options diff --git a/src/gui/DeveloperDialog.hxx b/src/gui/DeveloperDialog.hxx index ddee5468d..8bd84ab91 100644 --- a/src/gui/DeveloperDialog.hxx +++ b/src/gui/DeveloperDialog.hxx @@ -135,8 +135,6 @@ class DeveloperDialog : public Dialog SliderWidget* myUncompressedWidget{nullptr}; PopUpWidget* myStateIntervalWidget{nullptr}; PopUpWidget* myStateHorizonWidget{nullptr}; - RadioButtonGroup* mySaveOnExitGroup{nullptr}; - CheckboxWidget* myAutoSlotWidget{nullptr}; #ifdef DEBUGGER_SUPPORT // Debugger UI widgets diff --git a/src/gui/EmulationDialog.cxx b/src/gui/EmulationDialog.cxx new file mode 100644 index 000000000..111fa12f9 --- /dev/null +++ b/src/gui/EmulationDialog.cxx @@ -0,0 +1,283 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "Console.hxx" +#include "FrameBuffer.hxx" +#include "RadioButtonWidget.hxx" +#include "TIASurface.hxx" + +#include "EmulationDialog.hxx" + +namespace { + // Emulation speed is a positive float that multiplies the framerate. However, the UI controls + // adjust speed in terms of a speedup factor (1/10, 1/9 .. 1/2, 1, 2, 3, .., 10). The following + // mapping and formatting functions implement this conversion. The speedup factor is represented + // by an integer value between -900 and 900 (0 means no speedup). + + constexpr int MAX_SPEED = 900; + constexpr int MIN_SPEED = -900; + constexpr int SPEED_STEP = 10; + + int mapSpeed(float speed) + { + speed = std::abs(speed); + + return BSPF::clamp( + static_cast(round(100 * (speed >= 1 ? speed - 1 : -1 / speed + 1))), + MIN_SPEED, MAX_SPEED + ); + } + + float unmapSpeed(int speed) + { + float f_speed = static_cast(speed) / 100; + + return speed < 0 ? -1 / (f_speed - 1) : 1 + f_speed; + } + + string formatSpeed(int speed) { + stringstream ss; + + ss + << std::setw(3) << std::fixed << std::setprecision(0) + << (unmapSpeed(speed) * 100); + + return ss.str(); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +EmulationDialog::EmulationDialog(OSystem& osystem, DialogContainer& parent, + const GUI::Font& font, int max_w, int max_h) + : Dialog(osystem, parent, font, "Emulation settings") +{ + const int lineHeight = font.getLineHeight(), + fontHeight = font.getFontHeight(), + fontWidth = font.getMaxCharWidth(), + buttonHeight = font.getLineHeight() * 1.25; + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = fontWidth * 2; + const int VGAP = fontHeight / 4; + + int xpos, ypos; + int lwidth = font.getStringWidth("Emulation speed "); + WidgetArray wid; + VariantList items; + const int swidth = fontWidth * 10; + + // Set real dimensions + _w = 37 * fontWidth + HBORDER * 2 + CheckboxWidget::prefixSize(_font); + _h = 12 * (lineHeight + VGAP) + VGAP * 7 + VBORDER * 3 + _th + buttonHeight; + + xpos = HBORDER; ypos = VBORDER + _th; + + // Speed + mySpeed = + new SliderWidget(this, _font, xpos, ypos-1, swidth, lineHeight, + "Emulation speed ", lwidth, kSpeedupChanged, fontWidth * 5, "%"); + mySpeed->setMinValue(MIN_SPEED); mySpeed->setMaxValue(MAX_SPEED); + mySpeed->setStepValue(SPEED_STEP); + mySpeed->setTickmarkIntervals(2); + wid.push_back(mySpeed); + ypos += lineHeight + VGAP; + + // Use sync to vblank + myUseVSync = new CheckboxWidget(this, _font, xpos, ypos + 1, "VSync"); + wid.push_back(myUseVSync); + ypos += lineHeight + VGAP; + + + myTurbo = new CheckboxWidget(this, _font, xpos, ypos + 1, "Turbo mode"); + wid.push_back(myTurbo); + ypos += lineHeight + VGAP * 3; + + // Use multi-threading + myUseThreads = new CheckboxWidget(this, _font, xpos, ypos + 1, "Multi-threading"); + wid.push_back(myUseThreads); + ypos += lineHeight + VGAP; + + // Skip progress load bars for SuperCharger ROMs + // Doesn't really belong here, but I couldn't find a better place for it + myFastSCBios = new CheckboxWidget(this, _font, xpos, ypos + 1, "Fast SuperCharger load"); + wid.push_back(myFastSCBios); + ypos += lineHeight + VGAP; + + // Show UI messages onscreen + myUIMessages = new CheckboxWidget(this, _font, xpos, ypos + 1, "Show UI messages"); + wid.push_back(myUIMessages); + ypos += lineHeight + VGAP; + + // Confirm dialog when exiting emulation + xpos = HBORDER; ypos += VGAP * 3; + myConfirmExitWidget = new CheckboxWidget(this, _font, xpos, ypos, "Confirm exiting emulation"); + wid.push_back(myConfirmExitWidget); + + xpos = HBORDER + INDENT; + ypos += lineHeight + VGAP * 3; + new StaticTextWidget(this, font, HBORDER, ypos + 1, + "When entering/exiting emulation:"); + ypos += lineHeight + VGAP; + mySaveOnExitGroup = new RadioButtonGroup(); + RadioButtonWidget* r; + r = new RadioButtonWidget(this, font, xpos, ypos + 1, + "Do nothing", mySaveOnExitGroup); + wid.push_back(r); + ypos += lineHeight + VGAP; + r = new RadioButtonWidget(this, font, xpos, ypos + 1, + "Save current state in current slot", mySaveOnExitGroup); + wid.push_back(r); + ypos += lineHeight + VGAP; + r = new RadioButtonWidget(this, font, xpos, ypos + 1, + "Load/save all Time Machine states", mySaveOnExitGroup); + wid.push_back(r); + ypos += lineHeight + VGAP; + xpos = HBORDER; + + + myAutoSlotWidget = new CheckboxWidget(this, font, xpos, ypos + 1, "Automatically change save state slots"); + wid.push_back(myAutoSlotWidget); + ypos += lineHeight + VGAP; + + // Add Defaults, OK and Cancel buttons + addDefaultsOKCancelBGroup(wid, font); + + addToFocusList(wid); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::loadConfig() +{ + Settings& settings = instance().settings(); + + // Emulation speed + int speed = mapSpeed(settings.getFloat("speed")); + mySpeed->setValue(speed); + mySpeed->setValueLabel(formatSpeed(speed)); + + // Use sync to vertical blank + myUseVSync->setState(settings.getBool("vsync")); + + // Enable 'Turbo' mode + myTurbo->setState(settings.getBool("turbo")); + + // Show UI messages + myUIMessages->setState(settings.getBool("uimessages")); + + // Fast loading of Supercharger BIOS + myFastSCBios->setState(settings.getBool("fastscbios")); + + // Multi-threaded rendering + myUseThreads->setState(settings.getBool("threads")); + + // Confirm dialog when exiting emulation + myConfirmExitWidget->setState(settings.getBool("confirmexit")); + + // Save on exit + string saveOnExit = settings.getString("saveonexit"); + mySaveOnExitGroup->setSelected(saveOnExit == "all" ? 2 : saveOnExit == "current" ? 1 : 0); + // Automatically change save state slots + myAutoSlotWidget->setState(settings.getBool("autoslot")); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::saveConfig() +{ + Settings& settings = instance().settings(); + + // Speed + const int speedup = mySpeed->getValue(); + settings.setValue("speed", unmapSpeed(speedup)); + if(instance().hasConsole()) + instance().console().initializeAudio(); + + // Use sync to vertical blank + settings.setValue("vsync", myUseVSync->getState()); + + // Enable 'Turbo' mode + settings.setValue("turbo", myTurbo->getState()); + + // Show UI messages + settings.setValue("uimessages", myUIMessages->getState()); + + // Fast loading of Supercharger BIOS + settings.setValue("fastscbios", myFastSCBios->getState()); + + // Multi-threaded rendering + settings.setValue("threads", myUseThreads->getState()); + + // Confirm dialog when exiting emulation + settings.setValue("confirmexit", myConfirmExitWidget->getState()); + + // Save on exit + int saveOnExit = mySaveOnExitGroup->getSelected(); + settings.setValue("saveonexit", + saveOnExit == 0 ? "none" : saveOnExit == 1 ? "current" : "all"); + // Automatically change save state slots + settings.setValue("autoslot", myAutoSlotWidget->getState()); + + if(instance().hasConsole()) + { + // update speed + instance().console().initializeAudio(); + // update VSync + instance().console().initializeVideo(); + + instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState()); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::setDefaults() +{ + // speed + mySpeed->setValue(0); + myUseVSync->setState(true); + // misc + myUIMessages->setState(true); + myFastSCBios->setState(true); + myUseThreads->setState(false); + myConfirmExitWidget->setState(false); + + mySaveOnExitGroup->setSelected(0); + myAutoSlotWidget->setState(false); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EmulationDialog::handleCommand(CommandSender* sender, int cmd, + int data, int id) +{ + switch(cmd) + { + case GuiObject::kOKCmd: + saveConfig(); + close(); + break; + + case GuiObject::kDefaultsCmd: + setDefaults(); + break; + + case kSpeedupChanged: + mySpeed->setValueLabel(formatSpeed(mySpeed->getValue())); + break; + + default: + Dialog::handleCommand(sender, cmd, data, 0); + break; + } +} \ No newline at end of file diff --git a/src/gui/EmulationDialog.hxx b/src/gui/EmulationDialog.hxx new file mode 100644 index 000000000..f1470d7bb --- /dev/null +++ b/src/gui/EmulationDialog.hxx @@ -0,0 +1,63 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef EMULATION_DIALOG_HXX +#define EMULATION_DIALOG_HXX + +class RadioButtonGroup; + +#include "Dialog.hxx" + +class EmulationDialog : public Dialog +{ +public: + EmulationDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, + int max_w, int max_h); + virtual ~EmulationDialog() = default; + +private: + void loadConfig() override; + void saveConfig() override; + void setDefaults() override; + + void handleCommand(CommandSender* sender, int cmd, int data, int id) override; + +private: + SliderWidget* mySpeed{nullptr}; + CheckboxWidget* myUseVSync{nullptr}; + CheckboxWidget* myTurbo{nullptr}; + CheckboxWidget* myUIMessages{nullptr}; + CheckboxWidget* myFastSCBios{nullptr}; + CheckboxWidget* myUseThreads{nullptr}; + CheckboxWidget* myConfirmExitWidget{nullptr}; + RadioButtonGroup* mySaveOnExitGroup{nullptr}; + CheckboxWidget* myAutoSlotWidget{nullptr}; + + enum { + kSpeedupChanged = 'EDSp', + }; + +private: + // Following constructors and assignment operators not supported + EmulationDialog() = delete; + EmulationDialog(const EmulationDialog&) = delete; + EmulationDialog(EmulationDialog&&) = delete; + EmulationDialog& operator=(const EmulationDialog&) = delete; + EmulationDialog& operator=(EmulationDialog&&) = delete; +}; + +#endif diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 03cedb644..c3959c742 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -53,7 +53,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, int xpos, ypos, tabID; // Set real dimensions - setSize(50 * fontWidth + HBORDER * 2, + setSize(48 * fontWidth + PopUpWidget::dropDownWidth(_font) + HBORDER * 2, _th + VGAP * 3 + lineHeight + 13 * (lineHeight + VGAP) + VGAP * 8 + buttonHeight + VBORDER * 3, max_w, max_h); diff --git a/src/gui/OptionsDialog.cxx b/src/gui/OptionsDialog.cxx index 84ea9f605..865103822 100644 --- a/src/gui/OptionsDialog.cxx +++ b/src/gui/OptionsDialog.cxx @@ -23,8 +23,8 @@ #include "Widget.hxx" #include "Font.hxx" #include "Control.hxx" -#include "VideoDialog.hxx" -#include "AudioDialog.hxx" +#include "EmulationDialog.hxx" +#include "VideoAudioDialog.hxx" #include "InputDialog.hxx" #include "UIDialog.hxx" #include "SnapshotDialog.hxx" @@ -89,13 +89,10 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, return bw; }; - b = ADD_OD_BUTTON("Video" + ELLIPSIS, kVidCmd); + b = ADD_OD_BUTTON("Video & Audio" + ELLIPSIS, kVidCmd); wid.push_back(b); - b = ADD_OD_BUTTON("Audio" + ELLIPSIS, kAudCmd); -#ifndef SOUND_SUPPORT - b->clearFlags(Widget::FLAG_ENABLED); -#endif + b = ADD_OD_BUTTON("Emulation" + ELLIPSIS, kEmuCmd); wid.push_back(b); b = ADD_OD_BUTTON("Input" + ELLIPSIS, kInptCmd); @@ -143,8 +140,8 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, addCancelWidget(b); // Now create all the dialogs attached to each menu button - myVideoDialog = make_unique(osystem, parent, _font, max_w, max_h); - myAudioDialog = make_unique(osystem, parent, _font); + myVideoDialog = make_unique(osystem, parent, _font, max_w, max_h); + myEmulationDialog= make_unique(osystem, parent, _font, max_w, max_h); myInputDialog = make_unique(osystem, parent, _font, max_w, max_h); myUIDialog = make_unique(osystem, parent, _font, boss, max_w, max_h); mySnapshotDialog = make_unique(osystem, parent, _font, max_w, max_h); @@ -212,6 +209,10 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd, instance().eventHandler().leaveMenuMode(); break; + case kEmuCmd: + myEmulationDialog->open(); + break; + case kVidCmd: { // This dialog is resizable under certain conditions, so we need @@ -220,17 +221,12 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd, if(myVideoDialog == nullptr || myVideoDialog->shouldResize(w, h)) { - myVideoDialog = make_unique(instance(), parent(), + myVideoDialog = make_unique(instance(), parent(), instance().frameBuffer().font(), w, h); } myVideoDialog->open(); break; } - - case kAudCmd: - myAudioDialog->open(); - break; - case kInptCmd: { // This dialog is resizable under certain conditions, so we need diff --git a/src/gui/OptionsDialog.hxx b/src/gui/OptionsDialog.hxx index 3b5598693..001fad73b 100644 --- a/src/gui/OptionsDialog.hxx +++ b/src/gui/OptionsDialog.hxx @@ -22,8 +22,8 @@ class CommandSender; class DialogContainer; class GuiObject; class OSystem; -class VideoDialog; -class AudioDialog; +class EmulationDialog; +class VideoAudioDialog; class InputDialog; class UIDialog; class SnapshotDialog; @@ -52,8 +52,8 @@ class OptionsDialog : public Dialog void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: - unique_ptr myVideoDialog; - unique_ptr myAudioDialog; + unique_ptr myVideoDialog; + unique_ptr myEmulationDialog; unique_ptr myInputDialog; unique_ptr myUIDialog; unique_ptr mySnapshotDialog; @@ -78,7 +78,7 @@ class OptionsDialog : public Dialog enum { kBasSetCmd = 'BAST', kVidCmd = 'VIDO', - kAudCmd = 'AUDO', + kEmuCmd = 'EMUO', kInptCmd = 'INPT', kUsrIfaceCmd = 'URIF', kSnapCmd = 'SNAP', diff --git a/src/gui/UIDialog.cxx b/src/gui/UIDialog.cxx index 94032a4ce..eafc2e00b 100644 --- a/src/gui/UIDialog.cxx +++ b/src/gui/UIDialog.cxx @@ -127,13 +127,8 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, myCenter = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Center windows"); wid.push_back(myCenter); - // Confirm dialog when exiting emulation - xpos = HBORDER; ypos += lineHeight + VGAP * 2; - myConfirmExitWidget = new CheckboxWidget(myTab, font, xpos, ypos, "Confirm exiting emulation"); - wid.push_back(myConfirmExitWidget); - ypos += lineHeight + VGAP * 3; - // Delay between quick-selecting characters in ListWidget + xpos = HBORDER; ypos += lineHeight + VGAP * 4; int swidth = myPalettePopup->getWidth() - lwidth; myListDelaySlider = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight, "List input delay ", 0, kListDelay, @@ -384,9 +379,6 @@ void UIDialog::loadConfig() // Center window myCenter->setState(settings.getBool("center")); - // Confirm dialog when exiting emulation - myConfirmExitWidget->setState(settings.getBool("confirmexit")); - // Listwidget quick delay int delay = settings.getInt("listdelay"); myListDelaySlider->setValue(delay); @@ -462,9 +454,6 @@ void UIDialog::saveConfig() // Center window settings.setValue("center", myCenter->getState()); - // Confirm dialog when exiting emulation - settings.setValue("confirmexit", myConfirmExitWidget->getState()); - // Listwidget quick delay settings.setValue("listdelay", myListDelaySlider->getValue()); FileListWidget::setQuickSelectDelay(myListDelaySlider->getValue()); @@ -501,7 +490,6 @@ void UIDialog::setDefaults() myHidpiWidget->setState(false); myPositionPopup->setSelected("0"); myCenter->setState(false); - myConfirmExitWidget->setState(false); myListDelaySlider->setValue(300); myWheelLinesSlider->setValue(4); myDoubleClickSlider->setValue(500); diff --git a/src/gui/UIDialog.hxx b/src/gui/UIDialog.hxx index 91bc7ff82..6ed1c655f 100644 --- a/src/gui/UIDialog.hxx +++ b/src/gui/UIDialog.hxx @@ -70,7 +70,6 @@ class UIDialog : public Dialog, public CommandSender CheckboxWidget* myHidpiWidget{nullptr}; PopUpWidget* myPositionPopup{nullptr}; CheckboxWidget* myCenter{nullptr}; - CheckboxWidget* myConfirmExitWidget{nullptr}; SliderWidget* myListDelaySlider{nullptr}; SliderWidget* myWheelLinesSlider{nullptr}; SliderWidget* myControllerRateSlider{nullptr}; diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoAudioDialog.cxx similarity index 66% rename from src/gui/VideoDialog.cxx rename to src/gui/VideoAudioDialog.cxx index bc1fdfa36..dbab74acf 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -20,6 +20,8 @@ #include "bspf.hxx" #include "Base.hxx" #include "Control.hxx" +#include "Cart.hxx" +#include "CartDPC.hxx" #include "Dialog.hxx" #include "Menu.hxx" #include "OSystem.hxx" @@ -30,51 +32,15 @@ #include "PaletteHandler.hxx" #include "TIA.hxx" #include "Settings.hxx" +#include "Sound.hxx" +#include "AudioSettings.hxx" #include "Widget.hxx" #include "Font.hxx" #include "TabWidget.hxx" #include "NTSCFilter.hxx" #include "TIASurface.hxx" -#include "VideoDialog.hxx" - -namespace { - // Emulation speed is a positive float that multiplies the framerate. However, the UI controls - // adjust speed in terms of a speedup factor (1/10, 1/9 .. 1/2, 1, 2, 3, .., 10). The following - // mapping and formatting functions implement this conversion. The speedup factor is represented - // by an integer value between -900 and 900 (0 means no speedup). - - constexpr int MAX_SPEED = 900; - constexpr int MIN_SPEED = -900; - constexpr int SPEED_STEP = 10; - - int mapSpeed(float speed) - { - speed = std::abs(speed); - - return BSPF::clamp( - static_cast(round(100 * (speed >= 1 ? speed - 1 : -1 / speed + 1))), - MIN_SPEED, MAX_SPEED - ); - } - - float unmapSpeed(int speed) - { - float f_speed = static_cast(speed) / 100; - - return speed < 0 ? -1 / (f_speed - 1) : 1 + f_speed; - } - - string formatSpeed(int speed) { - stringstream ss; - - ss - << std::setw(3) << std::fixed << std::setprecision(0) - << (unmapSpeed(speed) * 100); - - return ss.str(); - } -} +#include "VideoAudioDialog.hxx" #define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ myTV ## obj = \ @@ -87,9 +53,9 @@ namespace { ypos += lineHeight + VGAP; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, +VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) - : Dialog(osystem, parent, font, "Video settings") + : Dialog(osystem, parent, font, "Video & Audio settings") { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -101,8 +67,8 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, int xpos, ypos; // Set real dimensions - setSize(57 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, - _th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, + setSize(44 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2, + _th + VGAP * 6 + lineHeight + 10 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3, max_w, max_h); // The tab widget @@ -112,9 +78,10 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, _h - _th - VGAP - buttonHeight - VBORDER * 2); addTabWidget(myTab); - addGeneralTab(); + addDisplayTab(); addPaletteTab(); addTVEffectsTab(); + addAudioTab(); //const int req_w = std::max(myFastSCBios->getRight(), myCloneBad->getRight()) + HBORDER + 1; //const int req_h = _th + VGAP * 3 @@ -141,7 +108,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addGeneralTab() +void VideoAudioDialog::addDisplayTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -152,24 +119,32 @@ void VideoDialog::addGeneralTab() const int HBORDER = fontWidth * 1.25; const int INDENT = CheckboxWidget::prefixSize(_font); const int lwidth = _font.getStringWidth("V-Size adjust "), - pwidth = _font.getStringWidth("XXXXxXXXX"); + pwidth = _font.getStringWidth("OpenGLES2"); int xpos = HBORDER, ypos = VBORDER; WidgetArray wid; VariantList items; - const int tabID = myTab->addTab(" General "); + const int tabID = myTab->addTab(" Display ", TabWidget::AUTO_WIDTH); // Video renderer myRenderer = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, instance().frameBuffer().supportedRenderers(), "Renderer ", lwidth); wid.push_back(myRenderer); + const int swidth = myRenderer->getWidth() - lwidth; ypos += lineHeight + VGAP; // TIA interpolation myTIAInterpolate = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Interpolation "); wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP * 4; + // TIA zoom levels (will be dynamically filled later) + myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, + "Zoom ", lwidth, 0, fontWidth * 4, "%"); + myTIAZoom->setMinValue(200); myTIAZoom->setStepValue(FrameBuffer::ZOOM_STEPS * 100); + wid.push_back(myTIAZoom); + ypos += lineHeight + VGAP; + // Fullscreen myFullscreen = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fullscreen", kFullScreenChanged); wid.push_back(myFullscreen); @@ -187,7 +162,6 @@ void VideoDialog::addGeneralTab() ypos += lineHeight + VGAP; // FS overscan - const int swidth = myRenderer->getWidth() - lwidth; myTVOverscan = new SliderWidget(myTab, _font, xpos + INDENT, ypos - 1, swidth, lineHeight, "Overscan", lwidth - INDENT, kOverscanChanged, fontWidth * 3, "%"); myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); @@ -195,13 +169,6 @@ void VideoDialog::addGeneralTab() wid.push_back(myTVOverscan); ypos += lineHeight + VGAP; - // TIA zoom levels (will be dynamically filled later) - myTIAZoom = new SliderWidget(myTab, _font, xpos, ypos - 1, swidth, lineHeight, - "Zoom ", lwidth, 0, fontWidth * 4, "%"); - myTIAZoom->setMinValue(200); myTIAZoom->setStepValue(FrameBuffer::ZOOM_STEPS * 100); - wid.push_back(myTIAZoom); - ypos += lineHeight + VGAP; - // Vertical size myVSizeAdjust = new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, @@ -209,47 +176,13 @@ void VideoDialog::addGeneralTab() myVSizeAdjust->setMinValue(-5); myVSizeAdjust->setMaxValue(5); myVSizeAdjust->setTickmarkIntervals(2); wid.push_back(myVSizeAdjust); - ypos += lineHeight + VGAP * 4; - - // Speed - mySpeed = - new SliderWidget(myTab, _font, xpos, ypos-1, swidth, lineHeight, - "Emul. speed ", lwidth, kSpeedupChanged, fontWidth * 5, "%"); - mySpeed->setMinValue(MIN_SPEED); mySpeed->setMaxValue(MAX_SPEED); - mySpeed->setStepValue(SPEED_STEP); - mySpeed->setTickmarkIntervals(2); - wid.push_back(mySpeed); - ypos += lineHeight + VGAP; - - // Use sync to vblank - myUseVSync = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "VSync"); - wid.push_back(myUseVSync); - - // Move over to the next column - xpos = myVSizeAdjust->getRight() + fontWidth * 3; - ypos = VBORDER; - - // Skip progress load bars for SuperCharger ROMs - // Doesn't really belong here, but I couldn't find a better place for it - myFastSCBios = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Fast SuperCharger load"); - wid.push_back(myFastSCBios); - ypos += lineHeight + VGAP; - - // Show UI messages onscreen - myUIMessages = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Show UI messages"); - wid.push_back(myUIMessages); - ypos += lineHeight + VGAP; - - // Use multi-threading - myUseThreads = new CheckboxWidget(myTab, _font, xpos, ypos + 1, "Multi-threading"); - wid.push_back(myUseThreads); // Add items for tab 0 addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addPaletteTab() +void VideoAudioDialog::addPaletteTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -265,7 +198,7 @@ void VideoDialog::addPaletteTab() ypos = VBORDER; WidgetArray wid; VariantList items; - const int tabID = myTab->addTab(" Palettes "); + const int tabID = myTab->addTab(" Palettes ", TabWidget::AUTO_WIDTH); // TIA Palette items.clear(); @@ -308,15 +241,16 @@ void VideoDialog::addPaletteTab() CREATE_CUSTOM_SLIDERS(Gamma, "Gamma ", kPaletteUpdated) // The resulting palette - addPalette(myPhaseShiftNtsc->getRight() + fontWidth * 2, VBORDER, - fontWidth * 2 * 8, myTVGamma->getBottom() - myTIAPalette->getTop()); + xpos = myPhaseShiftNtsc->getRight() + fontWidth * 2; + addPalette(xpos, VBORDER, _w - 2 * 2 - HBORDER - xpos, + myTVGamma->getBottom() - myTIAPalette->getTop()); // Add items for tab 2 addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addTVEffectsTab() +void VideoAudioDialog::addTVEffectsTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), @@ -332,7 +266,7 @@ void VideoDialog::addTVEffectsTab() const int pwidth = _font.getStringWidth("Bad adjust "); WidgetArray wid; VariantList items; - const int tabID = myTab->addTab(" TV Effects "); + const int tabID = myTab->addTab(" TV Effects ", TabWidget::AUTO_WIDTH); items.clear(); VarList::push_back(items, "Disabled", static_cast(NTSCFilter::Preset::OFF)); @@ -403,11 +337,138 @@ void VideoDialog::addTVEffectsTab() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::loadConfig() +void VideoAudioDialog::addAudioTab() { + const int lineHeight = _font.getLineHeight(), + fontHeight = _font.getFontHeight(), + fontWidth = _font.getMaxCharWidth(); + const int VBORDER = fontHeight / 2; + const int HBORDER = fontWidth * 1.25; + const int INDENT = CheckboxWidget::prefixSize(_font); + const int VGAP = fontHeight / 4; + + int xpos, ypos; + int lwidth = _font.getStringWidth("Volume "), + pwidth; + WidgetArray wid; + VariantList items; + const int tabID = myTab->addTab(" Audio ", TabWidget::AUTO_WIDTH); + + xpos = HBORDER; ypos = VBORDER; + + // Enable sound + mySoundEnableCheckbox = new CheckboxWidget(myTab, _font, xpos, ypos, + "Enable sound", kSoundEnableChanged); + wid.push_back(mySoundEnableCheckbox); + ypos += lineHeight + VGAP; + xpos += CheckboxWidget::prefixSize(_font); + + // Volume + myVolumeSlider = new SliderWidget(myTab, _font, xpos, ypos, + "Volume", lwidth, 0, 4 * fontWidth, "%"); + myVolumeSlider->setMinValue(1); myVolumeSlider->setMaxValue(100); + myVolumeSlider->setTickmarkIntervals(4); + wid.push_back(myVolumeSlider); + ypos += lineHeight + VGAP; + + // Mode + items.clear(); + VarList::push_back(items, "Low quality, medium lag", static_cast(AudioSettings::Preset::lowQualityMediumLag)); + VarList::push_back(items, "High quality, medium lag", static_cast(AudioSettings::Preset::highQualityMediumLag)); + VarList::push_back(items, "High quality, low lag", static_cast(AudioSettings::Preset::highQualityLowLag)); + VarList::push_back(items, "Ultra quality, minimal lag", static_cast(AudioSettings::Preset::ultraQualityMinimalLag)); + VarList::push_back(items, "Custom", static_cast(AudioSettings::Preset::custom)); + myModePopup = new PopUpWidget(myTab, _font, xpos, ypos, + _font.getStringWidth("Ultry quality, minimal lag"), lineHeight, + items, "Mode", lwidth, kModeChanged); + wid.push_back(myModePopup); + ypos += lineHeight + VGAP; + xpos += INDENT; + + // Fragment size + lwidth = _font.getStringWidth("Resampling quality "); + pwidth = myModePopup->getRight() - xpos - lwidth - PopUpWidget::dropDownWidth(_font); + items.clear(); + VarList::push_back(items, "128 samples", 128); + VarList::push_back(items, "256 samples", 256); + VarList::push_back(items, "512 samples", 512); + VarList::push_back(items, "1k samples", 1024); + VarList::push_back(items, "2k samples", 2048); + VarList::push_back(items, "4K samples", 4096); + myFragsizePopup = new PopUpWidget(myTab, _font, xpos, ypos, + pwidth, lineHeight, + items, "Fragment size", lwidth); + wid.push_back(myFragsizePopup); + ypos += lineHeight + VGAP; + + // Output frequency + items.clear(); + VarList::push_back(items, "44100 Hz", 44100); + VarList::push_back(items, "48000 Hz", 48000); + VarList::push_back(items, "96000 Hz", 96000); + myFreqPopup = new PopUpWidget(myTab, _font, xpos, ypos, + pwidth, lineHeight, + items, "Sample rate", lwidth); + wid.push_back(myFreqPopup); + ypos += lineHeight + VGAP; + + // Resampling quality + items.clear(); + VarList::push_back(items, "Low", static_cast(AudioSettings::ResamplingQuality::nearestNeightbour)); + VarList::push_back(items, "High", static_cast(AudioSettings::ResamplingQuality::lanczos_2)); + VarList::push_back(items, "Ultra", static_cast(AudioSettings::ResamplingQuality::lanczos_3)); + myResamplingPopup = new PopUpWidget(myTab, _font, xpos, ypos, + pwidth, lineHeight, + items, "Resampling quality ", lwidth); + wid.push_back(myResamplingPopup); + ypos += lineHeight + VGAP; + + // Param 1 + int swidth = pwidth + PopUpWidget::dropDownWidth(_font); + myHeadroomSlider = new SliderWidget(myTab, _font, xpos, ypos, swidth, lineHeight, + "Headroom ", 0, kHeadroomChanged, 10 * fontWidth); + myHeadroomSlider->setMinValue(0); myHeadroomSlider->setMaxValue(AudioSettings::MAX_HEADROOM); + myHeadroomSlider->setTickmarkIntervals(5); + wid.push_back(myHeadroomSlider); + ypos += lineHeight + VGAP; + + // Param 2 + myBufferSizeSlider = new SliderWidget(myTab, _font, xpos, ypos, swidth, lineHeight, + "Buffer size ", 0, kBufferSizeChanged, 10 * fontWidth); + myBufferSizeSlider->setMinValue(0); myBufferSizeSlider->setMaxValue(AudioSettings::MAX_BUFFER_SIZE); + myBufferSizeSlider->setTickmarkIntervals(5); + wid.push_back(myBufferSizeSlider); + ypos += lineHeight + VGAP; + + // Stereo sound + xpos -= INDENT; + myStereoSoundCheckbox = new CheckboxWidget(myTab, _font, xpos, ypos, + "Stereo for all ROMs"); + wid.push_back(myStereoSoundCheckbox); + ypos += lineHeight + VGAP; + + swidth += INDENT - fontWidth * 4; + myDpcPitch = new SliderWidget(myTab, _font, xpos, ypos, swidth, lineHeight, + "Pitfall II music pitch ", 0, 0, 5 * fontWidth); + myDpcPitch->setMinValue(10000); myDpcPitch->setMaxValue(30000); + myDpcPitch->setStepValue(100); + myDpcPitch->setTickmarkIntervals(2); + wid.push_back(myDpcPitch); + + // Add items for tab 4 + addToFocusList(wid, myTab, tabID); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::loadConfig() +{ + // Display tab // Renderer settings myRenderer->setSelected(instance().settings().getString("video"), "default"); + // TIA interpolation + myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); + // TIA zoom levels // These are dynamically loaded, since they depend on the size of // the desktop and which renderer we're using @@ -419,6 +480,21 @@ void VideoDialog::loadConfig() myTIAZoom->setTickmarkIntervals((maxZoom - minZoom) * 2); // every ~50% myTIAZoom->setValue(instance().settings().getFloat("tia.zoom") * 100); + // Fullscreen + myFullscreen->setState(instance().settings().getBool("fullscreen")); + /*string mode = instance().settings().getString("fullscreenmode"); + myFullScreenMode->setSelected(mode);*/ + // Fullscreen stretch setting + myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); + // Fullscreen overscan setting + myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); + handleFullScreenChange(); + + // Aspect ratio setting (NTSC and PAL) + myVSizeAdjust->setValue(instance().settings().getInt("tia.vsizeadjust")); + + ///////////////////////////////////////////////////////////////////////////// + // Palettes tab // TIA Palette myPalette = instance().settings().getString("palette"); myTIAPalette->setSelected(myPalette, PaletteHandler::SETTING_STANDARD); @@ -435,39 +511,8 @@ void VideoDialog::loadConfig() handlePaletteChange(); colorPalette(); - // TIA interpolation - myTIAInterpolate->setState(instance().settings().getBool("tia.inter")); - - // Aspect ratio setting (NTSC and PAL) - myVSizeAdjust->setValue(instance().settings().getInt("tia.vsizeadjust")); - - // Emulation speed - int speed = mapSpeed(instance().settings().getFloat("speed")); - mySpeed->setValue(speed); - mySpeed->setValueLabel(formatSpeed(speed)); - - // Fullscreen - myFullscreen->setState(instance().settings().getBool("fullscreen")); - /*string mode = instance().settings().getString("fullscreenmode"); - myFullScreenMode->setSelected(mode);*/ - // Fullscreen stretch setting - myUseStretch->setState(instance().settings().getBool("tia.fs_stretch")); - // Fullscreen overscan setting - myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan")); - handleFullScreenChange(); - - // Use sync to vertical blank - myUseVSync->setState(instance().settings().getBool("vsync")); - - // Show UI messages - myUIMessages->setState(instance().settings().getBool("uimessages")); - - // Fast loading of Supercharger BIOS - myFastSCBios->setState(instance().settings().getBool("fastscbios")); - - // Multi-threaded rendering - myUseThreads->setState(instance().settings().getBool("threads")); - + ///////////////////////////////////////////////////////////////////////////// + // TV Effects tab // TV Mode myTVMode->setSelected( instance().settings().getString("tv.filter"), "0"); @@ -487,12 +532,60 @@ void VideoDialog::loadConfig() // TV scanline intensity and interpolation myTVScanIntense->setValue(instance().settings().getInt("tv.scanlines")); + ///////////////////////////////////////////////////////////////////////////// + // Audio tab + AudioSettings& audioSettings = instance().audioSettings(); + + // Enable sound +#ifndef SOUND_SUPPORT + mySoundEnableCheckbox->setState(audioSettings.enabled()); +#else + mySoundEnableCheckbox->setState(false); +#endif + + // Volume + myVolumeSlider->setValue(audioSettings.volume()); + + // Stereo + myStereoSoundCheckbox->setState(audioSettings.stereo()); + + // DPC Pitch + myDpcPitch->setValue(audioSettings.dpcPitch()); + + // Preset / mode + myModePopup->setSelected(static_cast(audioSettings.preset())); + + updateSettingsWithPreset(instance().audioSettings()); + + updateEnabledState(); + myTab->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::saveConfig() +void VideoAudioDialog::updateSettingsWithPreset(AudioSettings& audioSettings) { + // Fragsize + myFragsizePopup->setSelected(audioSettings.fragmentSize()); + + // Output frequency + myFreqPopup->setSelected(audioSettings.sampleRate()); + + // Headroom + myHeadroomSlider->setValue(audioSettings.headroom()); + + // Buffer size + myBufferSizeSlider->setValue(audioSettings.bufferSize()); + + // Resampling quality + myResamplingPopup->setSelected(static_cast(audioSettings.resamplingQuality())); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::saveConfig() +{ + ///////////////////////////////////////////////////////////////////////////// + // Display tab // Renderer setting instance().settings().setValue("video", myRenderer->getSelectedTag().toString()); @@ -500,10 +593,6 @@ void VideoDialog::saveConfig() // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getState()); - - // Note: Palette values are saved directly when changed! - - // Fullscreen instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting @@ -521,26 +610,12 @@ void VideoDialog::saveConfig() 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()); + // Note: Palette values are saved directly when changed! - // Show UI messages - instance().settings().setValue("uimessages", myUIMessages->getState()); - - // Fast loading of Supercharger BIOS - instance().settings().setValue("fastscbios", myFastSCBios->getState()); - - // Multi-threaded rendering - instance().settings().setValue("threads", myUseThreads->getState()); - if (instance().hasConsole()) - instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState()); + ///////////////////////////////////////////////////////////////////////////// + // TV Effects tab // TV Mode instance().settings().setValue("tv.filter", myTVMode->getSelectedTag().toString()); @@ -579,10 +654,51 @@ void VideoDialog::saveConfig() // ... and apply potential setting changes to the TIA surface instance().frameBuffer().tiaSurface().updateSurfaceSettings(); + + ///////////////////////////////////////////////////////////////////////////// + // Audio tab + AudioSettings& audioSettings = instance().audioSettings(); + + // Enabled + audioSettings.setEnabled(mySoundEnableCheckbox->getState()); + instance().sound().setEnabled(mySoundEnableCheckbox->getState()); + + // Volume + audioSettings.setVolume(myVolumeSlider->getValue()); + instance().sound().setVolume(myVolumeSlider->getValue()); + + // Stereo + audioSettings.setStereo(myStereoSoundCheckbox->getState()); + + // DPC Pitch + audioSettings.setDpcPitch(myDpcPitch->getValue()); + // update if current cart is Pitfall II + if (instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC") + { + CartridgeDPC& cart = static_cast(instance().console().cartridge()); + cart.setDpcPitch(myDpcPitch->getValue()); + } + + AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); + audioSettings.setPreset(preset); + + if (preset == AudioSettings::Preset::custom) { + // Fragsize + audioSettings.setFragmentSize(myFragsizePopup->getSelectedTag().toInt()); + audioSettings.setSampleRate(myFreqPopup->getSelectedTag().toInt()); + audioSettings.setHeadroom(myHeadroomSlider->getValue()); + audioSettings.setBufferSize(myBufferSizeSlider->getValue()); + audioSettings.setResamplingQuality(static_cast(myResamplingPopup->getSelectedTag().toInt())); + } + + // Only force a re-initialization when necessary, since it can + // be a time-consuming operation + if(instance().hasConsole()) + instance().console().initializeAudio(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::setDefaults() +void VideoAudioDialog::setDefaults() { switch(myTab->getActiveTab()) { @@ -597,13 +713,6 @@ void VideoDialog::setDefaults() 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); handleFullScreenChange(); break; @@ -640,11 +749,29 @@ void VideoDialog::setDefaults() loadTVAdjustables(NTSCFilter::Preset::CUSTOM); break; } + case 3: // Audio + mySoundEnableCheckbox->setState(AudioSettings::DEFAULT_ENABLED); + myVolumeSlider->setValue(AudioSettings::DEFAULT_VOLUME); + myStereoSoundCheckbox->setState(AudioSettings::DEFAULT_STEREO); + myDpcPitch->setValue(AudioSettings::DEFAULT_DPC_PITCH); + myModePopup->setSelected(static_cast(AudioSettings::DEFAULT_PRESET)); + + if (AudioSettings::DEFAULT_PRESET == AudioSettings::Preset::custom) { + myResamplingPopup->setSelected(static_cast(AudioSettings::DEFAULT_RESAMPLING_QUALITY)); + myFragsizePopup->setSelected(AudioSettings::DEFAULT_FRAGMENT_SIZE); + myFreqPopup->setSelected(AudioSettings::DEFAULT_SAMPLE_RATE); + myHeadroomSlider->setValue(AudioSettings::DEFAULT_HEADROOM); + myBufferSizeSlider->setValue(AudioSettings::DEFAULT_BUFFER_SIZE); + } + else updatePreset(); + + updateEnabledState(); + break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) +void VideoAudioDialog::handleTVModeChange(NTSCFilter::Preset preset) { bool enable = preset == NTSCFilter::Preset::CUSTOM; @@ -661,7 +788,7 @@ void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) +void VideoAudioDialog::loadTVAdjustables(NTSCFilter::Preset preset) { NTSCFilter::Adjustable adj; instance().frameBuffer().tiaSurface().ntsc().getAdjustables( @@ -674,7 +801,7 @@ void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handlePaletteChange() +void VideoAudioDialog::handlePaletteChange() { bool enable = myTIAPalette->getSelectedTag().toString() == "custom"; @@ -683,7 +810,7 @@ void VideoDialog::handlePaletteChange() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handlePaletteUpdate() +void VideoAudioDialog::handlePaletteUpdate() { // TIA Palette instance().settings().setValue("palette", @@ -704,7 +831,7 @@ void VideoDialog::handlePaletteUpdate() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleFullScreenChange() +void VideoAudioDialog::handleFullScreenChange() { bool enable = myFullscreen->getState(); myUseStretch->setEnabled(enable); @@ -712,7 +839,7 @@ void VideoDialog::handleFullScreenChange() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleOverscanChange() +void VideoAudioDialog::handleOverscanChange() { if (myTVOverscan->getValue() == 0) { @@ -724,13 +851,13 @@ void VideoDialog::handleOverscanChange() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handlePhosphorChange() +void VideoAudioDialog::handlePhosphorChange() { myTVPhosLevel->setEnabled(myTVPhosphor->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::handleCommand(CommandSender* sender, int cmd, +void VideoAudioDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) @@ -793,11 +920,6 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, myVSizeAdjust->setValueUnit("%"); break; } - - case kSpeedupChanged: - mySpeed->setValueLabel(formatSpeed(mySpeed->getValue())); - break; - case kFullScreenChanged: handleFullScreenChange(); break; @@ -845,6 +967,30 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, myTVPhosLevel->setValueUnit("%"); break; + case kSoundEnableChanged: + updateEnabledState(); + break; + + case kModeChanged: + updatePreset(); + updateEnabledState(); + break; + + case kHeadroomChanged: + { + std::ostringstream ss; + ss << std::fixed << std::setprecision(1) << (0.5 * myHeadroomSlider->getValue()) << " frames"; + myHeadroomSlider->setValueLabel(ss.str()); + break; + } + case kBufferSizeChanged: + { + std::ostringstream ss; + ss << std::fixed << std::setprecision(1) << (0.5 * myBufferSizeSlider->getValue()) << " frames"; + myBufferSizeSlider->setValueLabel(ss.str()); + break; + } + default: Dialog::handleCommand(sender, cmd, data, 0); break; @@ -852,7 +998,7 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::addPalette(int x, int y, int w, int h) +void VideoAudioDialog::addPalette(int x, int y, int w, int h) { if(instance().hasConsole()) { @@ -877,7 +1023,7 @@ void VideoDialog::addPalette(int x, int y, int w, int h) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void VideoDialog::colorPalette() +void VideoAudioDialog::colorPalette() { if(instance().hasConsole()) { @@ -904,3 +1050,37 @@ void VideoDialog::colorPalette() } } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::updateEnabledState() +{ + bool active = mySoundEnableCheckbox->getState(); + AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); + bool userMode = preset == AudioSettings::Preset::custom; + + myVolumeSlider->setEnabled(active); + myStereoSoundCheckbox->setEnabled(active); + myModePopup->setEnabled(active); + // enable only for Pitfall II cart + myDpcPitch->setEnabled(active && instance().hasConsole() && instance().console().cartridge().name() == "CartridgeDPC"); + + myFragsizePopup->setEnabled(active && userMode); + myFreqPopup->setEnabled(active && userMode); + myResamplingPopup->setEnabled(active && userMode); + myHeadroomSlider->setEnabled(active && userMode); + myBufferSizeSlider->setEnabled(active && userMode); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VideoAudioDialog::updatePreset() +{ + AudioSettings::Preset preset = static_cast(myModePopup->getSelectedTag().toInt()); + + // Make a copy that does not affect the actual settings... + AudioSettings audioSettings = instance().audioSettings(); + audioSettings.setPersistent(false); + // ... and set the requested preset + audioSettings.setPreset(preset); + + updateSettingsWithPreset(audioSettings); +} diff --git a/src/gui/VideoDialog.hxx b/src/gui/VideoAudioDialog.hxx similarity index 75% rename from src/gui/VideoDialog.hxx rename to src/gui/VideoAudioDialog.hxx index 7d01b6808..6380ae352 100644 --- a/src/gui/VideoDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -15,8 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#ifndef VIDEO_DIALOG_HXX -#define VIDEO_DIALOG_HXX +#ifndef VIDEOAUDIO_DIALOG_HXX +#define VIDEOAUDIO_DIALOG_HXX class CommandSender; class CheckboxWidget; @@ -34,21 +34,22 @@ class OSystem; #include "NTSCFilter.hxx" #include "bspf.hxx" -class VideoDialog : public Dialog +class VideoAudioDialog : public Dialog { public: - VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, + VideoAudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h); - virtual ~VideoDialog() = default; + virtual ~VideoAudioDialog() = default; private: void loadConfig() override; void saveConfig() override; void setDefaults() override; - void addGeneralTab(); + void addDisplayTab(); void addPaletteTab(); void addTVEffectsTab(); + void addAudioTab(); void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handlePaletteChange(); @@ -59,45 +60,30 @@ class VideoDialog : public Dialog void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void addPalette(int x, int y, int h, int w); void colorPalette(); + void updatePreset(); + void updateEnabledState(); + void updateSettingsWithPreset(AudioSettings&); private: TabWidget* myTab; // General options PopUpWidget* myRenderer{nullptr}; - SliderWidget* myTIAZoom{nullptr}; - PopUpWidget* myTIAPalette{nullptr}; - SliderWidget* myPhaseShiftNtsc{nullptr}; - SliderWidget* myPhaseShiftPal{nullptr}; CheckboxWidget* myTIAInterpolate{nullptr}; - SliderWidget* myVSizeAdjust{nullptr}; - SliderWidget* mySpeed{nullptr}; - - RadioButtonGroup* myZoomGroup{nullptr}; CheckboxWidget* myFullscreen{nullptr}; //PopUpWidget* myFullScreenMode; CheckboxWidget* myUseStretch{nullptr}; SliderWidget* myTVOverscan{nullptr}; - CheckboxWidget* myUseVSync{nullptr}; - CheckboxWidget* myUIMessages{nullptr}; - CheckboxWidget* myFastSCBios{nullptr}; - CheckboxWidget* myUseThreads{nullptr}; - std::array myColorLbl{nullptr}; - //std::array myColor{nullptr}; - ColorWidget* myColor[16][8]{nullptr}; + SliderWidget* myTIAZoom{nullptr}; + SliderWidget* myVSizeAdjust{nullptr}; // TV effects adjustables (custom mode) PopUpWidget* myTVMode{nullptr}; SliderWidget* myTVSharp{nullptr}; - SliderWidget* myTVHue{nullptr}; SliderWidget* myTVRes{nullptr}; SliderWidget* myTVArtifacts{nullptr}; SliderWidget* myTVFringe{nullptr}; SliderWidget* myTVBleed{nullptr}; - SliderWidget* myTVBright{nullptr}; - SliderWidget* myTVContrast{nullptr}; - SliderWidget* myTVSatur{nullptr}; - SliderWidget* myTVGamma{nullptr}; // TV phosphor effect CheckboxWidget* myTVPhosphor{nullptr}; @@ -114,19 +100,43 @@ class VideoDialog : public Dialog ButtonWidget* myCloneBad{nullptr}; ButtonWidget* myCloneCustom{nullptr}; + // Palettes + PopUpWidget* myTIAPalette{nullptr}; + SliderWidget* myPhaseShiftNtsc{nullptr}; + SliderWidget* myPhaseShiftPal{nullptr}; + SliderWidget* myTVHue{nullptr}; + SliderWidget* myTVSatur{nullptr}; + SliderWidget* myTVBright{nullptr}; + SliderWidget* myTVContrast{nullptr}; + SliderWidget* myTVGamma{nullptr}; + std::array myColorLbl{nullptr}; + ColorWidget* myColor[16][8]{nullptr}; + + // Audio + CheckboxWidget* mySoundEnableCheckbox{nullptr}; + SliderWidget* myVolumeSlider{nullptr}; + CheckboxWidget* myStereoSoundCheckbox{nullptr}; + PopUpWidget* myModePopup{nullptr}; + PopUpWidget* myFragsizePopup{nullptr}; + PopUpWidget* myFreqPopup{nullptr}; + PopUpWidget* myResamplingPopup{nullptr}; + SliderWidget* myHeadroomSlider{nullptr}; + SliderWidget* myBufferSizeSlider{nullptr}; + SliderWidget* myDpcPitch{nullptr}; + string myPalette; PaletteHandler::Adjustable myPaletteAdj{0.0F}; enum { + kZoomChanged = 'VDZo', + kVSizeChanged = 'VDVs', + kFullScreenChanged = 'VDFs', + kOverscanChanged = 'VDOv', + kPaletteChanged = 'VDpl', kNtscShiftChanged = 'VDns', kPalShiftChanged = 'VDps', kPaletteUpdated = 'VDpu', - kSpeedupChanged = 'VDSp', - kVSizeChanged = 'VDVs', - kFullScreenChanged = 'VDFs', - kZoomChanged = 'VDZo', - kOverscanChanged = 'VDOv', kTVModeChanged = 'VDtv', kCloneCompositeCmd = 'CLcp', @@ -136,16 +146,21 @@ class VideoDialog : public Dialog kCloneCustomCmd = 'CLcu', kPhosphorChanged = 'VDph', kPhosBlendChanged = 'VDbl', - kScanlinesChanged = 'VDsc' + kScanlinesChanged = 'VDsc', + + kSoundEnableChanged = 'ADse', + kModeChanged = 'ADmc', + kHeadroomChanged = 'ADhc', + kBufferSizeChanged = 'ADbc' }; private: // Following constructors and assignment operators not supported - VideoDialog() = delete; - VideoDialog(const VideoDialog&) = delete; - VideoDialog(VideoDialog&&) = delete; - VideoDialog& operator=(const VideoDialog&) = delete; - VideoDialog& operator=(VideoDialog&&) = delete; + VideoAudioDialog() = delete; + VideoAudioDialog(const VideoAudioDialog&) = delete; + VideoAudioDialog(VideoAudioDialog&&) = delete; + VideoAudioDialog& operator=(const VideoAudioDialog&) = delete; + VideoAudioDialog& operator=(VideoAudioDialog&&) = delete; }; #endif diff --git a/src/gui/module.mk b/src/gui/module.mk index f550e167d..1447b8195 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -2,7 +2,6 @@ MODULE := src/gui MODULE_OBJS := \ src/gui/AboutDialog.o \ - src/gui/AudioDialog.o \ src/gui/BrowserDialog.o \ src/gui/CheckListWidget.o \ src/gui/ColorWidget.o \ @@ -15,6 +14,7 @@ MODULE_OBJS := \ src/gui/Dialog.o \ src/gui/EditableWidget.o \ src/gui/EditTextWidget.o \ + src/gui/EmulationDialog.o \ src/gui/EventMappingWidget.o \ src/gui/FileListWidget.o \ src/gui/Font.o \ @@ -49,7 +49,7 @@ MODULE_OBJS := \ src/gui/TimeMachineDialog.o \ src/gui/TimeMachine.o \ src/gui/UIDialog.o \ - src/gui/VideoDialog.o \ + src/gui/VideoAudioDialog.o \ src/gui/Widget.o MODULE_DIRS += \ diff --git a/src/libpng/pngconf.h b/src/libpng/pngconf.h index 927a769db..b5f468ae5 100644 --- a/src/libpng/pngconf.h +++ b/src/libpng/pngconf.h @@ -230,7 +230,7 @@ * the type. */ # ifndef PNG_EXPORT_TYPE -# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# define PNG_EXPORT_TYPE(name) name PNG_IMPEXP # endif # define PNG_DLL_EXPORT __export # else /* newer compiler */ @@ -450,7 +450,7 @@ # define PNG_FP_EXPORT(ordinal, type, name, args)\ PNG_EXPORT(ordinal, type, name, args); # else /* No floating point APIs */ -# define PNG_FP_EXPORT(ordinal, type, name, args) +# define PNG_FP_EXPORT(ordinal, name, name, args) # endif #endif #ifndef PNG_FIXED_EXPORT /* A fixed point API. */ @@ -458,7 +458,7 @@ # define PNG_FIXED_EXPORT(ordinal, type, name, args)\ PNG_EXPORT(ordinal, type, name, args); # else /* No fixed point APIs */ -# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# define PNG_FIXED_EXPORT(ordinal, name, name, args) # endif #endif diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index bc0724d09..6fef5d589 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -758,6 +758,7 @@ + @@ -907,7 +908,6 @@ true - @@ -939,7 +939,7 @@ - + CompileAsC @@ -1791,6 +1791,7 @@ + @@ -1967,7 +1968,6 @@ - @@ -2003,7 +2003,7 @@ - + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 62e324fa4..0e4f58929 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -342,9 +342,6 @@ Source Files\gui - - Source Files\gui - Source Files\gui @@ -438,9 +435,6 @@ Source Files\gui - - Source Files\gui - Source Files\gui @@ -1005,6 +999,12 @@ Source Files + + Source Files\gui + + + Source Files\gui + @@ -1316,9 +1316,6 @@ Header Files\gui - - Header Files\gui - Header Files\gui @@ -1424,9 +1421,6 @@ Header Files\gui - - Header Files\gui - Header Files\gui @@ -2063,6 +2057,12 @@ Header Files + + Header Files\gui + + + Header Files\gui + From c078bf135d2f7ad73440346c6ed9bc601cb71c1d Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 16:18:43 +0200 Subject: [PATCH 13/42] bugfix audio widgets enabling --- src/gui/VideoAudioDialog.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index dbab74acf..b5f155f40 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -537,7 +537,7 @@ void VideoAudioDialog::loadConfig() AudioSettings& audioSettings = instance().audioSettings(); // Enable sound -#ifndef SOUND_SUPPORT +#ifdef SOUND_SUPPORT mySoundEnableCheckbox->setState(audioSettings.enabled()); #else mySoundEnableCheckbox->setState(false); From 5ddaea992daaaaccf9880e614dc1a49ddcadc8d5 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 11 May 2020 14:57:01 -0230 Subject: [PATCH 14/42] Fixes for warnings in latest g++ and clang, and update libretro port to latest changes. --- src/common/PKeyboardHandler.cxx | 2 ++ src/common/PaletteHandler.cxx | 37 +++++++++++++++-------------- src/common/PaletteHandler.hxx | 26 ++++++++++---------- src/debugger/gui/CartARWidget.cxx | 2 ++ src/debugger/gui/CartE0Widget.cxx | 2 +- src/debugger/gui/DebuggerDialog.hxx | 2 +- src/emucore/PointingDevice.cxx | 2 ++ src/emucore/TIASurface.hxx | 2 +- src/emucore/Thumbulator.cxx | 1 + src/gui/ColorWidget.cxx | 4 ++-- src/gui/DialogContainer.cxx | 1 - src/gui/EmulationDialog.cxx | 2 +- src/gui/VideoAudioDialog.cxx | 6 ++--- src/gui/VideoAudioDialog.hxx | 4 ++-- src/libretro/Makefile.common | 1 + src/libretro/StellaLIBRETRO.cxx | 13 +++------- src/libretro/StellaLIBRETRO.hxx | 2 +- src/libretro/libretro.cxx | 18 ++++++-------- 18 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 3edd7698d..9384d3232 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -15,6 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" +#include "Console.hxx" #include "EventHandler.hxx" #include "PKeyboardHandler.hxx" diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 3f1066724..2aecc6abf 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include #include "Console.hxx" #include "FrameBuffer.hxx" @@ -303,7 +304,7 @@ PaletteArray PaletteHandler::adjustedPalette(const PaletteArray& palette) adjust[i] = powf(i * toFloat, gamma) * contrast + brightness; // Transform original palette into destination palette - for(int i = 0; i < destPalette.size(); i += 2) + for(size_t i = 0; i < destPalette.size(); i += 2) { const uInt32 pixel = palette[i]; int r = (pixel >> 16) & 0xff; @@ -396,8 +397,8 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) // 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 - BSPF::PI_f)); + color[chroma][0] = SATURATION * sinf(offset + shift * (chroma - 1)); + color[chroma][1] = SATURATION * sinf(offset + shift * (chroma - 1 - BSPF::PI_f)); } for(int chroma = 0; chroma < NUM_CHROMA; chroma++) @@ -488,17 +489,17 @@ void PaletteHandler::adjustHueSaturation(int& R, int& G, int& B, float H, float // Adapted from http://beesbuzz.biz/code/16-hsv-color-transforms // (C) J. “Fluffy” Shagam // License: CC BY-SA 4.0 - const float su = S * cos(-H * BSPF::PI_f); - const float sw = S * sin(-H * BSPF::PI_f); - const float r = (.299 + .701 * su + .168 * sw) * R - + (.587 - .587 * su + .330 * sw) * G - + (.114 - .114 * su - .497 * sw) * B; - const float g = (.299 - .299 * su - .328 * sw) * R - + (.587 + .413 * su + .035 * sw) * G - + (.114 - .114 * su + .292 * sw) * B; - const float b = (.299 - .300 * su + 1.25 * sw) * R - + (.587 - .588 * su - 1.05 * sw) * G - + (.114 + .886 * su - .203 * sw) * B; + const float su = S * cosf(-H * BSPF::PI_f); + const float sw = S * sinf(-H * BSPF::PI_f); + const float r = (.299F + .701F * su + .168F * sw) * R + + (.587F - .587F * su + .330F * sw) * G + + (.114F - .114F * su - .497F * sw) * B; + const float g = (.299F - .299F * su - .328F * sw) * R + + (.587F + .413F * su + .035F * sw) * G + + (.114F - .114F * su + .292F * sw) * B; + const float b = (.299F - .300F * su + 1.25F * sw) * R + + (.587F - .588F * su - 1.05F * sw) * G + + (.114F + .886F * su - .203F * sw) * B; R = BSPF::clamp(r, 0.F, 255.F); G = BSPF::clamp(g, 0.F, 255.F); @@ -724,14 +725,14 @@ const PaletteArray PaletteHandler::ourSECAMPaletteZ26 = { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourUserNTSCPalette = { 0 }; // filled from external file - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourUserPALPalette = { 0 }; // filled from external file - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourUserSECAMPalette = { 0 }; // filled from external file - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourCustomNTSCPalette = { 0 }; // filled by function - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaletteArray PaletteHandler::ourCustomPALPalette = { 0 }; // filled by function diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 237d9b878..3a8c5c9e3 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -38,8 +38,8 @@ class PaletteHandler // Externally used adjustment parameters struct Adjustable { - float phaseNtsc, phasePal; - uInt32 hue, saturation, contrast, brightness, gamma; + float phaseNtsc{0.F}, phasePal{0.F}; + uInt32 hue{0}, saturation{0}, contrast{0}, brightness{0}, gamma{0}; }; public: @@ -54,14 +54,14 @@ class PaletteHandler void cyclePalette(bool next = true); /* - Cycle through each palette adjustable + Cycle through each palette adjustable. @param next Select next adjustable, else previous one */ void cycleAdjustable(bool next = true); /* - Increase or decrease current palette adjustable + Increase or decrease current palette adjustable. @param increase Increase adjustable if true, else decrease */ @@ -82,7 +82,7 @@ class PaletteHandler /** Sets the palette according to the given palette name. - @param palette The palette to switch to. + @param name The palette to switch to */ void setPalette(const string& name); @@ -107,11 +107,11 @@ class PaletteHandler /** Convert adjustables from/to 100% scale */ - float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } - uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } + constexpr float scaleFrom100(float x) const { return (x / 50.F) - 1.F; } + constexpr uInt32 scaleTo100(float x) const { return uInt32(50 * (x + 1.F)); } /** - Convert palette settings name to enumeration + Convert palette settings name to enumeration. @param name The given palette's settings name @@ -120,7 +120,7 @@ class PaletteHandler PaletteType toPaletteType(const string& name) const; /** - Convert enumeration to palette settings name + Convert enumeration to palette settings name. @param type The given palette type @@ -133,7 +133,7 @@ class PaletteHandler Note that there are two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param increase Increase if true, else decrease. + @param increase Increase if true, else decrease */ void changeColorPhaseShift(bool increase = true); @@ -145,16 +145,16 @@ class PaletteHandler void generateCustomPalette(ConsoleTiming timing); /** - Create new palette by applying palette adjustments on given palette + Create new palette by applying palette adjustments on given palette. - @param type The palette which should be adjusted + @param source The palette which should be adjusted @return An adjusted palette */ PaletteArray adjustedPalette(const PaletteArray& source); /** - Adjust hue and saturation for given RGB values + Adjust hue and saturation for given RGB values. @param R The red value to adjust @param G The green value to adjust diff --git a/src/debugger/gui/CartARWidget.cxx b/src/debugger/gui/CartARWidget.cxx index 6037849f6..aa552d78e 100644 --- a/src/debugger/gui/CartARWidget.cxx +++ b/src/debugger/gui/CartARWidget.cxx @@ -16,6 +16,8 @@ //============================================================================ #include "CartAR.hxx" +#include "Debugger.hxx" +#include "CartDebug.hxx" #include "PopUpWidget.hxx" #include "CartARWidget.hxx" diff --git a/src/debugger/gui/CartE0Widget.cxx b/src/debugger/gui/CartE0Widget.cxx index 12205c463..08ccc802a 100644 --- a/src/debugger/gui/CartE0Widget.cxx +++ b/src/debugger/gui/CartE0Widget.cxx @@ -49,7 +49,7 @@ string CartridgeE0Widget::romDescription() info << "Segment #" << seg << " accessible @ $" << Common::Base::HEX4 << (ADDR_BASE | segmentOffset) - << " - $" << (ADDR_BASE | segmentOffset + /*myCart.myBankSize - 1*/ 0x3FF) << ",\n"; + << " - $" << (ADDR_BASE | (segmentOffset + /*myCart.myBankSize - 1*/ 0x3FF)) << ",\n"; if (seg < 3) info << " Hotspots " << hotspotStr(0, seg, true) << " - " << hotspotStr(7, seg, true) << "\n"; else diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index bfd7c332b..b66ae37a6 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -33,7 +33,6 @@ class TiaOutputWidget; class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; -class OptionsDialog; namespace Common { struct Rect; @@ -41,6 +40,7 @@ namespace Common { #include "Dialog.hxx" #include "MessageBox.hxx" +#include "OptionsDialog.hxx" class DebuggerDialog : public Dialog { diff --git a/src/emucore/PointingDevice.cxx b/src/emucore/PointingDevice.cxx index 1a2c781b4..4d91d010c 100644 --- a/src/emucore/PointingDevice.cxx +++ b/src/emucore/PointingDevice.cxx @@ -15,6 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include + #include "Control.hxx" #include "Event.hxx" #include "System.hxx" diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 9dbda5b14..6552c26ca 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -22,13 +22,13 @@ class TIA; class Console; class OSystem; class FBSurface; -class PaletteHandler; #include #include "Rect.hxx" #include "FrameBuffer.hxx" #include "NTSCFilter.hxx" +#include "PaletteHandler.hxx" #include "PhosphorHandler.hxx" #include "bspf.hxx" #include "TIAConstants.hxx" diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index c5bd3e637..2984159cd 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -108,6 +108,7 @@ void Thumbulator::setConsoleTiming(ConsoleTiming timing) case ConsoleTiming::ntsc: timing_factor = NTSC; break; case ConsoleTiming::secam: timing_factor = SECAM; break; case ConsoleTiming::pal: timing_factor = PAL; break; + default: break; // satisfy compiler } } diff --git a/src/gui/ColorWidget.cxx b/src/gui/ColorWidget.cxx index 8052bf029..27f4bc3cf 100644 --- a/src/gui/ColorWidget.cxx +++ b/src/gui/ColorWidget.cxx @@ -28,8 +28,8 @@ ColorWidget::ColorWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, int cmd, bool framed) : Widget(boss, font, x, y, w, h), CommandSender(boss), - _cmd(cmd), - _framed(framed) + _framed(framed), + _cmd(cmd) { _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS; } diff --git a/src/gui/DialogContainer.cxx b/src/gui/DialogContainer.cxx index b60faf6d4..950d71c06 100644 --- a/src/gui/DialogContainer.cxx +++ b/src/gui/DialogContainer.cxx @@ -384,4 +384,3 @@ void DialogContainer::reset() uInt64 DialogContainer::_DOUBLE_CLICK_DELAY = 500; uInt64 DialogContainer::_REPEAT_INITIAL_DELAY = 400; uInt64 DialogContainer::_REPEAT_SUSTAIN_DELAY = 50; - diff --git a/src/gui/EmulationDialog.cxx b/src/gui/EmulationDialog.cxx index 111fa12f9..ad86e2e60 100644 --- a/src/gui/EmulationDialog.cxx +++ b/src/gui/EmulationDialog.cxx @@ -280,4 +280,4 @@ void EmulationDialog::handleCommand(CommandSender* sender, int cmd, Dialog::handleCommand(sender, cmd, data, 0); break; } -} \ No newline at end of file +} diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index b5f155f40..5d569014a 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -112,8 +112,7 @@ void VideoAudioDialog::addDisplayTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), - fontWidth = _font.getMaxCharWidth(), - buttonHeight = _font.getLineHeight() * 1.25; + fontWidth = _font.getMaxCharWidth(); const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; @@ -186,8 +185,7 @@ void VideoAudioDialog::addPaletteTab() { const int lineHeight = _font.getLineHeight(), fontHeight = _font.getFontHeight(), - fontWidth = _font.getMaxCharWidth(), - buttonHeight = _font.getLineHeight() * 1.25; + fontWidth = _font.getMaxCharWidth(); const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; const int INDENT = fontWidth * 2; diff --git a/src/gui/VideoAudioDialog.hxx b/src/gui/VideoAudioDialog.hxx index 6380ae352..f46740ae6 100644 --- a/src/gui/VideoAudioDialog.hxx +++ b/src/gui/VideoAudioDialog.hxx @@ -110,7 +110,7 @@ class VideoAudioDialog : public Dialog SliderWidget* myTVContrast{nullptr}; SliderWidget* myTVGamma{nullptr}; std::array myColorLbl{nullptr}; - ColorWidget* myColor[16][8]{nullptr}; + ColorWidget* myColor[16][8]{{nullptr}}; // Audio CheckboxWidget* mySoundEnableCheckbox{nullptr}; @@ -125,7 +125,7 @@ class VideoAudioDialog : public Dialog SliderWidget* myDpcPitch{nullptr}; string myPalette; - PaletteHandler::Adjustable myPaletteAdj{0.0F}; + PaletteHandler::Adjustable myPaletteAdj; enum { kZoomChanged = 'VDZo', diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index 1893fa57b..5fafdd855 100644 --- a/src/libretro/Makefile.common +++ b/src/libretro/Makefile.common @@ -23,6 +23,7 @@ SOURCES_CXX := \ $(CORE_DIR)/common/KeyMap.cxx \ $(CORE_DIR)/common/Logger.cxx \ $(CORE_DIR)/common/MouseControl.cxx \ + $(CORE_DIR)/common/PaletteHandler.cxx \ $(CORE_DIR)/common/PhosphorHandler.cxx \ $(CORE_DIR)/common/PhysicalJoystick.cxx \ $(CORE_DIR)/common/PJoystickHandler.cxx \ diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index e3cb5073a..065917c15 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -40,7 +40,7 @@ StellaLIBRETRO::StellaLIBRETRO() video_aspect_ntsc = 0; video_aspect_pal = 0; - video_palette = "standard"; + video_palette = PaletteHandler::SETTING_STANDARD; video_filter = NTSCFilter::Preset::OFF; video_ready = false; @@ -374,19 +374,12 @@ void StellaLIBRETRO::setVideoFilter(NTSCFilter::Preset mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StellaLIBRETRO::setVideoPalette(uInt32 mode) +void StellaLIBRETRO::setVideoPalette(const string& mode) { - switch (mode) - { - case 0: video_palette = "standard"; break; - case 1: video_palette = "z26"; break; - case 2: video_palette = "user"; break; - } - if (system_ready) { myOSystem->settings().setValue("palette", video_palette); - myOSystem->console().setPalette(video_palette); + myOSystem->frameBuffer().tiaSurface().paletteHandler().setPalette(video_palette); } } diff --git a/src/libretro/StellaLIBRETRO.hxx b/src/libretro/StellaLIBRETRO.hxx index f48a13708..3078e8eb1 100644 --- a/src/libretro/StellaLIBRETRO.hxx +++ b/src/libretro/StellaLIBRETRO.hxx @@ -104,7 +104,7 @@ class StellaLIBRETRO void setVideoAspectPAL(uInt32 value) { video_aspect_pal = value; }; void setVideoFilter(NTSCFilter::Preset mode); - void setVideoPalette(uInt32 mode); + void setVideoPalette(const string& mode); void setVideoPhosphor(uInt32 mode, uInt32 blend); void setAudioStereo(int mode); diff --git a/src/libretro/libretro.cxx b/src/libretro/libretro.cxx index 6babbf07f..8caae3765 100644 --- a/src/libretro/libretro.cxx +++ b/src/libretro/libretro.cxx @@ -15,6 +15,7 @@ #include "StellaLIBRETRO.hxx" #include "Event.hxx" #include "NTSCFilter.hxx" +#include "PaletteHandler.hxx" #include "Version.hxx" @@ -30,11 +31,12 @@ static retro_audio_sample_batch_t audio_batch_cb; // libretro UI settings static int setting_ntsc, setting_pal; -static int setting_stereo, setting_palette; +static int setting_stereo; static int setting_phosphor, setting_console, setting_phosphor_blend; static int stella_paddle_joypad_sensitivity; static int setting_crop_hoverscan, crop_left; static NTSCFilter::Preset setting_filter; +static const char* setting_palette; static bool system_reset; @@ -275,17 +277,11 @@ static void update_variables(bool init = false) RETRO_GET("stella_palette") { - int value = 0; - - if(!strcmp(var.value, "standard")) value = 0; - else if(!strcmp(var.value, "z26")) value = 1; - else if(!strcmp(var.value, "user")) value = 2; - - if(setting_palette != value) + if(setting_palette != var.value) { - stella.setVideoPalette(value); + stella.setVideoPalette(var.value); - setting_palette = value; + setting_palette = var.value; } } @@ -494,7 +490,7 @@ void retro_set_environment(retro_environment_t cb) static struct retro_variable variables[] = { // Adding more variables and rearranging them is safe. { "stella_console", "Console display; auto|ntsc|pal|secam|ntsc50|pal60|secam60" }, - { "stella_palette", "Palette colors; standard|z26|user" }, + { "stella_palette", "Palette colors; standard|z26|user|custom" }, { "stella_filter", "TV effects; disabled|composite|s-video|rgb|badly adjusted" }, { "stella_ntsc_aspect", "NTSC aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|50|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" }, { "stella_pal_aspect", "PAL aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|50|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" }, From 9b933ec4d484cc3c96c4242a5f62c11fa5095c82 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 11 May 2020 15:33:42 -0230 Subject: [PATCH 15/42] Update Xcode project for class changes. --- src/debugger/DiStella.cxx | 2 +- src/macos/stella.xcodeproj/project.pbxproj | 96 +++++++++++----------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/debugger/DiStella.cxx b/src/debugger/DiStella.cxx index 8aff0b568..c77d1eabf 100644 --- a/src/debugger/DiStella.cxx +++ b/src/debugger/DiStella.cxx @@ -1179,7 +1179,7 @@ void DiStella::outputColors() color = SECAM_COLOR[(byte >> 1) & 0x7]; myDisasmBuf << "$" << Base::HEX1 << (byte >> 4) << "|" << color; } - myDisasmBuf << std::setw(16 - color.length()) << std::setfill(' '); + myDisasmBuf << std::setw(int(16 - color.length())) << std::setfill(' '); // output address myDisasmBuf << "; $" << Base::HEX4 << myPC + myOffset << " " diff --git a/src/macos/stella.xcodeproj/project.pbxproj b/src/macos/stella.xcodeproj/project.pbxproj index 33eccde69..d59aac510 100644 --- a/src/macos/stella.xcodeproj/project.pbxproj +++ b/src/macos/stella.xcodeproj/project.pbxproj @@ -44,7 +44,6 @@ 2D9173FA09BA90380026E9FF /* FrameBuffer.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D71062895B2006265D9 /* FrameBuffer.hxx */; }; 2D9173FB09BA90380026E9FF /* Settings.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D77062895F1006265D9 /* Settings.hxx */; }; 2D91740009BA90380026E9FF /* AboutDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */; }; - 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */; }; 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */; }; 2D91740309BA90380026E9FF /* Command.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAAA084578BF00812C11 /* Command.hxx */; }; 2D91740409BA90380026E9FF /* Dialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAAC084578BF00812C11 /* Dialog.hxx */; }; @@ -61,7 +60,6 @@ 2D91741209BA90380026E9FF /* ProgressDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */; }; 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */; }; 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */; }; - 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */; }; 2D91741809BA90380026E9FF /* Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD5084578BF00812C11 /* Widget.hxx */; }; 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEB7108457B7D00812C11 /* CartUA.hxx */; }; 2D91741A09BA90380026E9FF /* FSNode.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEB7308457B7D00812C11 /* FSNode.hxx */; }; @@ -142,7 +140,6 @@ 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D944848062904E800DD9879 /* Settings.cxx */; }; 2D9174A809BA90380026E9FF /* FSNodePOSIX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */; }; 2D9174AA09BA90380026E9FF /* AboutDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */; }; - 2D9174AB09BA90380026E9FF /* AudioDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */; }; 2D9174AC09BA90380026E9FF /* BrowserDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */; }; 2D9174AD09BA90380026E9FF /* Dialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAAB084578BF00812C11 /* Dialog.cxx */; }; 2D9174AE09BA90380026E9FF /* DialogContainer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAAD084578BF00812C11 /* DialogContainer.cxx */; }; @@ -157,7 +154,6 @@ 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */; }; 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */; }; 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */; }; - 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */; }; 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD4084578BF00812C11 /* Widget.cxx */; }; 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEB7008457B7D00812C11 /* CartUA.cxx */; }; 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEB7208457B7D00812C11 /* FSNode.cxx */; }; @@ -233,8 +229,6 @@ DC2410E32274BDA8007A4CBF /* MinUICommandDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2410E12274BDA7007A4CBF /* MinUICommandDialog.hxx */; }; DC2410E42274BDA8007A4CBF /* MinUICommandDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2410E22274BDA8007A4CBF /* MinUICommandDialog.cxx */; }; DC2874071F8F2278004BF21A /* TrapArray.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2874061F8F2278004BF21A /* TrapArray.hxx */; }; - DC2AADAE194F389C0026C7A4 /* CartDASH.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */; }; - DC2AADAF194F389C0026C7A4 /* CartDASH.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */; }; DC2AADB0194F389C0026C7A4 /* TIASurface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */; }; DC2AADB1194F389C0026C7A4 /* TIASurface.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */; }; DC2AADB4194F390F0026C7A4 /* CartRamWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */; }; @@ -250,6 +244,18 @@ DC368F5918A2FB710084199C /* SoundSDL2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC368F5318A2FB710084199C /* SoundSDL2.hxx */; }; DC36D2C814CAFAB0007DC821 /* CartFA2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */; }; DC36D2C914CAFAB0007DC821 /* CartFA2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */; }; + DC3C9BC52469C8F700CF2D47 /* PaletteHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BC32469C8F700CF2D47 /* PaletteHandler.cxx */; }; + DC3C9BC62469C8F700CF2D47 /* PaletteHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BC42469C8F700CF2D47 /* PaletteHandler.hxx */; }; + DC3C9BCB2469C93D00CF2D47 /* VideoAudioDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BC72469C93D00CF2D47 /* VideoAudioDialog.cxx */; }; + DC3C9BCC2469C93D00CF2D47 /* EmulationDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BC82469C93D00CF2D47 /* EmulationDialog.cxx */; }; + DC3C9BCD2469C93D00CF2D47 /* VideoAudioDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BC92469C93D00CF2D47 /* VideoAudioDialog.hxx */; }; + DC3C9BCE2469C93D00CF2D47 /* EmulationDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BCA2469C93D00CF2D47 /* EmulationDialog.hxx */; }; + DC3C9BD32469C9A200CF2D47 /* CartEnhanced.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BCF2469C9A200CF2D47 /* CartEnhanced.cxx */; }; + DC3C9BD42469C9A200CF2D47 /* Cart3EX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BD02469C9A200CF2D47 /* Cart3EX.hxx */; }; + DC3C9BD52469C9A200CF2D47 /* CartEnhanced.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BD12469C9A200CF2D47 /* CartEnhanced.hxx */; }; + DC3C9BD62469C9A200CF2D47 /* Cart3EX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BD22469C9A200CF2D47 /* Cart3EX.cxx */; }; + DC3C9BD92469C9C700CF2D47 /* CartEnhancedWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C9BD72469C9C700CF2D47 /* CartEnhancedWidget.cxx */; }; + DC3C9BDA2469C9C700CF2D47 /* CartEnhancedWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C9BD82469C9C700CF2D47 /* CartEnhancedWidget.hxx */; }; DC3DAFAC1F2E233B00A64410 /* PointingDevice.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */; }; DC3EE8561E2C0E6D00905161 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83C1E2C0E6D00905161 /* adler32.c */; settings = {COMPILER_FLAGS = "-w"; }; }; DC3EE8571E2C0E6D00905161 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83D1E2C0E6D00905161 /* compress.c */; settings = {COMPILER_FLAGS = "-w"; }; }; @@ -393,8 +399,6 @@ DC73BD891915E5E3003FAFAD /* FBSurface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC73BD871915E5E3003FAFAD /* FBSurface.cxx */; }; DC73BD8A1915E5E3003FAFAD /* FBSurface.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC73BD881915E5E3003FAFAD /* FBSurface.hxx */; }; DC74D6A2138D4D7E00F05C5C /* StringParser.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */; }; - DC74E5C6198AF12700F37E36 /* CartDASHWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */; }; - DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */; }; DC79F81217A88D9E00288B91 /* Base.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC79F81017A88D9E00288B91 /* Base.cxx */; }; DC79F81317A88D9E00288B91 /* Base.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC79F81117A88D9E00288B91 /* Base.hxx */; }; DC7A24D5173B1CF600B20FE9 /* Variant.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC7A24D4173B1CF600B20FE9 /* Variant.hxx */; }; @@ -494,10 +498,6 @@ DCAAE5F11715887B0080BB82 /* CartFAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */; }; DCAAE5F21715887B0080BB82 /* CartUAWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */; }; DCAAE5F31715887B0080BB82 /* CartUAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */; }; - DCACBAD01C54296300703A9B /* CartCVPlusWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */; }; - DCACBAD11C54296300703A9B /* CartCVPlusWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */; }; - DCACBAD41C54298300703A9B /* CartCVPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCACBAD21C54298300703A9B /* CartCVPlus.cxx */; }; - DCACBAD51C54298300703A9B /* CartCVPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCACBAD31C54298300703A9B /* CartCVPlus.hxx */; }; DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */; }; DCAD60A91152F8BD00BC4184 /* CartDPCPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */; }; DCB20EC71A0C506C0048F595 /* main.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB20EC61A0C506C0048F595 /* main.cxx */; }; @@ -828,8 +828,6 @@ 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FSNodePOSIX.cxx; sourceTree = ""; }; 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AboutDialog.cxx; sourceTree = ""; }; 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AboutDialog.hxx; sourceTree = ""; }; - 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AudioDialog.cxx; sourceTree = ""; }; - 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AudioDialog.hxx; sourceTree = ""; }; 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = BrowserDialog.cxx; sourceTree = ""; }; 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = BrowserDialog.hxx; sourceTree = ""; }; 2DDBEAAA084578BF00812C11 /* Command.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Command.hxx; sourceTree = ""; }; @@ -860,8 +858,6 @@ 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ScrollBarWidget.hxx; sourceTree = ""; }; 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TabWidget.cxx; sourceTree = ""; }; 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TabWidget.hxx; sourceTree = ""; }; - 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = VideoDialog.cxx; sourceTree = ""; }; - 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = VideoDialog.hxx; sourceTree = ""; }; 2DDBEAD4084578BF00812C11 /* Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Widget.cxx; sourceTree = ""; }; 2DDBEAD5084578BF00812C11 /* Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Widget.hxx; sourceTree = ""; }; 2DDBEB7008457B7D00812C11 /* CartUA.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartUA.cxx; sourceTree = ""; }; @@ -972,8 +968,6 @@ DC2410E12274BDA7007A4CBF /* MinUICommandDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MinUICommandDialog.hxx; sourceTree = ""; }; DC2410E22274BDA8007A4CBF /* MinUICommandDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MinUICommandDialog.cxx; sourceTree = ""; }; DC2874061F8F2278004BF21A /* TrapArray.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrapArray.hxx; sourceTree = ""; }; - DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDASH.cxx; sourceTree = ""; }; - DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDASH.hxx; sourceTree = ""; }; DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIASurface.cxx; sourceTree = ""; }; DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIASurface.hxx; sourceTree = ""; }; DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartRamWidget.cxx; sourceTree = ""; }; @@ -989,6 +983,18 @@ DC368F5318A2FB710084199C /* SoundSDL2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SoundSDL2.hxx; sourceTree = ""; }; DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFA2.cxx; sourceTree = ""; }; DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFA2.hxx; sourceTree = ""; }; + DC3C9BC32469C8F700CF2D47 /* PaletteHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PaletteHandler.cxx; sourceTree = ""; }; + DC3C9BC42469C8F700CF2D47 /* PaletteHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PaletteHandler.hxx; sourceTree = ""; }; + DC3C9BC72469C93D00CF2D47 /* VideoAudioDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VideoAudioDialog.cxx; sourceTree = ""; }; + DC3C9BC82469C93D00CF2D47 /* EmulationDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmulationDialog.cxx; sourceTree = ""; }; + DC3C9BC92469C93D00CF2D47 /* VideoAudioDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VideoAudioDialog.hxx; sourceTree = ""; }; + DC3C9BCA2469C93D00CF2D47 /* EmulationDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = EmulationDialog.hxx; sourceTree = ""; }; + DC3C9BCF2469C9A200CF2D47 /* CartEnhanced.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEnhanced.cxx; sourceTree = ""; }; + DC3C9BD02469C9A200CF2D47 /* Cart3EX.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart3EX.hxx; sourceTree = ""; }; + DC3C9BD12469C9A200CF2D47 /* CartEnhanced.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEnhanced.hxx; sourceTree = ""; }; + DC3C9BD22469C9A200CF2D47 /* Cart3EX.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3EX.cxx; sourceTree = ""; }; + DC3C9BD72469C9C700CF2D47 /* CartEnhancedWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEnhancedWidget.cxx; sourceTree = ""; }; + DC3C9BD82469C9C700CF2D47 /* CartEnhancedWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEnhancedWidget.hxx; sourceTree = ""; }; DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PointingDevice.hxx; sourceTree = ""; }; DC3EE83C1E2C0E6D00905161 /* adler32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adler32.c; sourceTree = ""; }; DC3EE83D1E2C0E6D00905161 /* compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compress.c; sourceTree = ""; }; @@ -1132,8 +1138,6 @@ DC73BD871915E5E3003FAFAD /* FBSurface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FBSurface.cxx; sourceTree = ""; }; DC73BD881915E5E3003FAFAD /* FBSurface.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FBSurface.hxx; sourceTree = ""; }; DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StringParser.hxx; sourceTree = ""; }; - DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDASHWidget.cxx; sourceTree = ""; }; - DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDASHWidget.hxx; sourceTree = ""; }; DC79F81017A88D9E00288B91 /* Base.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Base.cxx; sourceTree = ""; }; DC79F81117A88D9E00288B91 /* Base.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Base.hxx; sourceTree = ""; }; DC7A24D4173B1CF600B20FE9 /* Variant.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Variant.hxx; sourceTree = ""; }; @@ -1234,10 +1238,6 @@ DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFAWidget.hxx; sourceTree = ""; }; DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartUAWidget.cxx; sourceTree = ""; }; DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartUAWidget.hxx; sourceTree = ""; }; - DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCVPlusWidget.cxx; sourceTree = ""; }; - DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCVPlusWidget.hxx; sourceTree = ""; }; - DCACBAD21C54298300703A9B /* CartCVPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCVPlus.cxx; sourceTree = ""; }; - DCACBAD31C54298300703A9B /* CartCVPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCVPlus.hxx; sourceTree = ""; }; DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDPCPlus.cxx; sourceTree = ""; }; DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDPCPlus.hxx; sourceTree = ""; }; DCB20EC61A0C506C0048F595 /* main.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cxx; sourceTree = ""; }; @@ -1589,12 +1589,8 @@ DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */, DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */, DC676A2E1729A0B000E4E73D /* CartCTYWidget.hxx */, - DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */, - DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */, DCAAE5BA1715887B0080BB82 /* CartCVWidget.cxx */, DCAAE5BB1715887B0080BB82 /* CartCVWidget.hxx */, - DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */, - DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */, DC5ACB5D1FBFCEB800A213FD /* CartDebugWidget.cxx */, DCAAE5BC1715887B0080BB82 /* CartDebugWidget.hxx */, DCAACB0A188D636F00A4D282 /* CartDFSCWidget.cxx */, @@ -1615,6 +1611,8 @@ DCAAE5BE1715887B0080BB82 /* CartEFSCWidget.hxx */, DCAAE5BF1715887B0080BB82 /* CartEFWidget.cxx */, DCAAE5C01715887B0080BB82 /* CartEFWidget.hxx */, + DC3C9BD72469C9C700CF2D47 /* CartEnhancedWidget.cxx */, + DC3C9BD82469C9C700CF2D47 /* CartEnhancedWidget.hxx */, DCAAE5C11715887B0080BB82 /* CartF0Widget.cxx */, DCAAE5C21715887B0080BB82 /* CartF0Widget.hxx */, DCAAE5C31715887B0080BB82 /* CartF4SCWidget.cxx */, @@ -1744,6 +1742,8 @@ DCB87E571A104C1E00BF2A3B /* MediaFactory.hxx */, DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */, DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */, + DC3C9BC32469C8F700CF2D47 /* PaletteHandler.cxx */, + DC3C9BC42469C8F700CF2D47 /* PaletteHandler.hxx */, DCA233AE23B583FE0032ABF3 /* PhosphorHandler.cxx */, DCA233AF23B583FE0032ABF3 /* PhosphorHandler.hxx */, DC6DC91A205DB879004A5FC3 /* PhysicalJoystick.cxx */, @@ -1824,6 +1824,8 @@ 2D9555DA0880E78000466554 /* Cart3E.hxx */, DCBDDE9C1D6A5F2F009DF1E9 /* Cart3EPlus.cxx */, DCBDDE9D1D6A5F2F009DF1E9 /* Cart3EPlus.hxx */, + DC3C9BD22469C9A200CF2D47 /* Cart3EX.cxx */, + DC3C9BD02469C9A200CF2D47 /* Cart3EX.hxx */, 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */, 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */, DCD56D360B247D920092F9F8 /* Cart4A50.cxx */, @@ -1850,10 +1852,6 @@ DC6727091556F4860023653B /* CartCTY.hxx */, 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */, 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */, - DCACBAD21C54298300703A9B /* CartCVPlus.cxx */, - DCACBAD31C54298300703A9B /* CartCVPlus.hxx */, - DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */, - DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */, DCB2ECAC1F0AECA3009738A6 /* CartDetector.cxx */, DCB2ECAD1F0AECA3009738A6 /* CartDetector.hxx */, DCAACAF2188D631500A4D282 /* CartDF.cxx */, @@ -1874,6 +1872,8 @@ DCF467BF0F939A1400B25D7A /* CartEF.hxx */, DCF467C00F939A1400B25D7A /* CartEFSC.cxx */, DCF467C10F939A1400B25D7A /* CartEFSC.hxx */, + DC3C9BCF2469C9A200CF2D47 /* CartEnhanced.cxx */, + DC3C9BD12469C9A200CF2D47 /* CartEnhanced.hxx */, DCF7B0D910A762FC007A2870 /* CartF0.cxx */, DCF7B0DA10A762FC007A2870 /* CartF0.hxx */, 2DE2DF240627AE07006BEC99 /* CartF4.cxx */, @@ -2003,8 +2003,6 @@ children = ( 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */, 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */, - 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */, - 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */, 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */, 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */, 2DEF21F808BC033500B246B4 /* CheckListWidget.cxx */, @@ -2034,6 +2032,8 @@ 2D403BA1086116D1001E31A1 /* EditableWidget.hxx */, 2D403BA4086116D1001E31A1 /* EditTextWidget.cxx */, 2D403BA5086116D1001E31A1 /* EditTextWidget.hxx */, + DC3C9BC82469C93D00CF2D47 /* EmulationDialog.cxx */, + DC3C9BCA2469C93D00CF2D47 /* EmulationDialog.hxx */, 2D05FF5E096E269100A518FE /* EventMappingWidget.cxx */, 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */, DC7A24DD173B1DBC00B20FE9 /* FileListWidget.cxx */, @@ -2107,8 +2107,8 @@ DCA82C701FEB4E780059340F /* TimeMachineDialog.hxx */, DC8078E60B4BD697005E9305 /* UIDialog.cxx */, DC8078E70B4BD697005E9305 /* UIDialog.hxx */, - 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */, - 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */, + DC3C9BC72469C93D00CF2D47 /* VideoAudioDialog.cxx */, + DC3C9BC92469C93D00CF2D47 /* VideoAudioDialog.hxx */, 2DDBEAD4084578BF00812C11 /* Widget.cxx */, 2DDBEAD5084578BF00812C11 /* Widget.hxx */, ); @@ -2391,10 +2391,9 @@ DC5AAC2D1FCB24DF00C420A6 /* RadioButtonWidget.hxx in Headers */, 2D9173E309BA90380026E9FF /* Driving.hxx in Headers */, 2D9173E409BA90380026E9FF /* Event.hxx in Headers */, + DC3C9BCD2469C93D00CF2D47 /* VideoAudioDialog.hxx in Headers */, 2D9173E509BA90380026E9FF /* Joystick.hxx in Headers */, 2D9173E609BA90380026E9FF /* Keyboard.hxx in Headers */, - DCACBAD51C54298300703A9B /* CartCVPlus.hxx in Headers */, - DCACBAD11C54296300703A9B /* CartCVPlusWidget.hxx in Headers */, DC1B2EC81E50036100F62837 /* TrakBall.hxx in Headers */, 2D9173E709BA90380026E9FF /* M6532.hxx in Headers */, E0893AF3211B9842008B170D /* HighPass.hxx in Headers */, @@ -2417,7 +2416,7 @@ DCF3A6EE1DFC75E3008A8AF3 /* DelayQueueMember.hxx in Headers */, DC96162F1F817830008A2206 /* AtariMouseWidget.hxx in Headers */, DCF4907A1A0ECE5B00A67AA9 /* Vec.hxx in Headers */, - 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */, + DC3C9BCE2469C93D00CF2D47 /* EmulationDialog.hxx in Headers */, DC71EA9E1FDA06D2008827CB /* CartE78K.hxx in Headers */, 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */, 2D91740309BA90380026E9FF /* Command.hxx in Headers */, @@ -2446,7 +2445,6 @@ 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */, 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */, DCB2ECB01F0AECA3009738A6 /* CartDetector.hxx in Headers */, - 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */, 2D91741809BA90380026E9FF /* Widget.hxx in Headers */, 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */, DCE8B1871E7E03B300189864 /* FrameLayout.hxx in Headers */, @@ -2476,6 +2474,7 @@ DC3EE86C1E2C0E6D00905161 /* zconf.h in Headers */, 2D91743609BA90380026E9FF /* DebuggerSystem.hxx in Headers */, 2D91743A09BA90380026E9FF /* Expression.hxx in Headers */, + DC3C9BDA2469C9C700CF2D47 /* CartEnhancedWidget.hxx in Headers */, 2D91744F09BA90380026E9FF /* InputTextDialog.hxx in Headers */, DC1B2EC61E50036100F62837 /* AtariMouse.hxx in Headers */, DC9616331F817830008A2206 /* PointingDeviceWidget.hxx in Headers */, @@ -2502,7 +2501,7 @@ DCA078351F8C1B04008EFEE5 /* SDL_lib.hxx in Headers */, DCDA03B11A2009BB00711920 /* CartWD.hxx in Headers */, 2D91745909BA90380026E9FF /* PromptWidget.hxx in Headers */, - DC2AADAF194F389C0026C7A4 /* CartDASH.hxx in Headers */, + DC3C9BC62469C8F700CF2D47 /* PaletteHandler.hxx in Headers */, 2D91745A09BA90380026E9FF /* RamWidget.hxx in Headers */, 2D91745B09BA90380026E9FF /* RomListWidget.hxx in Headers */, 2D91745C09BA90380026E9FF /* RomWidget.hxx in Headers */, @@ -2513,6 +2512,7 @@ 2D91746109BA90380026E9FF /* TogglePixelWidget.hxx in Headers */, 2D91746209BA90380026E9FF /* ToggleWidget.hxx in Headers */, 2D91746409BA90380026E9FF /* TiaZoomWidget.hxx in Headers */, + DC3C9BD52469C9A200CF2D47 /* CartEnhanced.hxx in Headers */, DC1BC6672066B4390076F74A /* PKeyboardHandler.hxx in Headers */, 2D91746609BA90380026E9FF /* AudioWidget.hxx in Headers */, DC70065E241EC97900A459AB /* Stella14x28tFont.hxx in Headers */, @@ -2593,7 +2593,6 @@ DCD6FC7111C281ED005DA767 /* png.h in Headers */, DCD6FC7211C281ED005DA767 /* pngconf.h in Headers */, DCF3A6F41DFC75E3008A8AF3 /* LatchedInput.hxx in Headers */, - DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */, DCD6FC7711C281ED005DA767 /* pngpriv.h in Headers */, CFE3F60C1E84A9A200A8204E /* CartBUSWidget.hxx in Headers */, DCD6FC9411C28C6F005DA767 /* PNGLibrary.hxx in Headers */, @@ -2637,6 +2636,7 @@ DCE395EF16CB0B5F008DB1E5 /* FSNodeFactory.hxx in Headers */, DCE395F116CB0B5F008DB1E5 /* FSNodeZIP.hxx in Headers */, DCE395F316CB0B5F008DB1E5 /* ZipHandler.hxx in Headers */, + DC3C9BD42469C9A200CF2D47 /* Cart3EX.hxx in Headers */, DCAAE5D41715887B0080BB82 /* Cart2KWidget.hxx in Headers */, DCF7F129223D796000701A47 /* ProfilingRunner.hxx in Headers */, DCAAE5D61715887B0080BB82 /* Cart3FWidget.hxx in Headers */, @@ -2816,7 +2816,9 @@ E0A755792244294600101889 /* CartCDFInfoWidget.cxx in Sources */, E0406FB81F81A85400A82AE0 /* FrameManager.cxx in Sources */, 2D91747409BA90380026E9FF /* SDLMain.m in Sources */, + DC3C9BC52469C8F700CF2D47 /* PaletteHandler.cxx in Sources */, 2D91747509BA90380026E9FF /* Booster.cxx in Sources */, + DC3C9BD62469C9A200CF2D47 /* Cart3EX.cxx in Sources */, DC3EE8671E2C0E6D00905161 /* inftrees.c in Sources */, 2D91747609BA90380026E9FF /* Cart.cxx in Sources */, 2D91747709BA90380026E9FF /* Cart2K.cxx in Sources */, @@ -2844,6 +2846,7 @@ DCF3A6FA1DFC75E3008A8AF3 /* Player.cxx in Sources */, 2D91748609BA90380026E9FF /* CartFE.cxx in Sources */, 2D91748909BA90380026E9FF /* Console.cxx in Sources */, + DC3C9BD32469C9A200CF2D47 /* CartEnhanced.cxx in Sources */, DC6DC91E205DB879004A5FC3 /* PhysicalJoystick.cxx in Sources */, E08FCD5323A037EB0051F59B /* QisBlitter.cxx in Sources */, DCCE0355225104BF008C246F /* StellaSettingsDialog.cxx in Sources */, @@ -2867,7 +2870,6 @@ 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */, 2D9174A809BA90380026E9FF /* FSNodePOSIX.cxx in Sources */, 2D9174AA09BA90380026E9FF /* AboutDialog.cxx in Sources */, - 2D9174AB09BA90380026E9FF /* AudioDialog.cxx in Sources */, 2D9174AC09BA90380026E9FF /* BrowserDialog.cxx in Sources */, 2D9174AD09BA90380026E9FF /* Dialog.cxx in Sources */, 2D9174AE09BA90380026E9FF /* DialogContainer.cxx in Sources */, @@ -2877,6 +2879,7 @@ 2D9174B309BA90380026E9FF /* LauncherDialog.cxx in Sources */, 2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */, 2D9174B609BA90380026E9FF /* Menu.cxx in Sources */, + DC3C9BD92469C9C700CF2D47 /* CartEnhancedWidget.cxx in Sources */, CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */, 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */, 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */, @@ -2886,7 +2889,6 @@ 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */, 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */, 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */, - 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */, DC6A18FC19B3E67A00DEB242 /* CartMDM.cxx in Sources */, 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */, 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */, @@ -2914,7 +2916,6 @@ 2D9174F109BA90380026E9FF /* InputTextDialog.cxx in Sources */, DC6DC920205DB879004A5FC3 /* PJoystickHandler.cxx in Sources */, DC2410E42274BDA8007A4CBF /* MinUICommandDialog.cxx in Sources */, - DC74E5C6198AF12700F37E36 /* CartDASHWidget.cxx in Sources */, 2D9174F209BA90380026E9FF /* CheckListWidget.cxx in Sources */, 2D9174F309BA90380026E9FF /* StringListWidget.cxx in Sources */, 2D9174F409BA90380026E9FF /* CommandDialog.cxx in Sources */, @@ -2931,7 +2932,6 @@ DC5963132139FA14002736F2 /* Bankswitch.cxx in Sources */, DCDFF08120B781B0001227C0 /* DispatchResult.cxx in Sources */, 2D9174FC09BA90380026E9FF /* RamWidget.cxx in Sources */, - DC2AADAE194F389C0026C7A4 /* CartDASH.cxx in Sources */, DC21E5C121CA903E007D0E1A /* SerialPortMACOS.cxx in Sources */, E007231F210FBF5E002CF343 /* FpsMeter.cxx in Sources */, 2D9174FD09BA90380026E9FF /* RomListWidget.cxx in Sources */, @@ -2960,7 +2960,6 @@ DC47455A09C34BFA00EDDA3A /* CheatManager.cxx in Sources */, DC47455C09C34BFA00EDDA3A /* CheetahCheat.cxx in Sources */, DC62E6471960E87B007AEF05 /* AtariVoxWidget.cxx in Sources */, - DCACBAD41C54298300703A9B /* CartCVPlus.cxx in Sources */, DC47455E09C34BFA00EDDA3A /* RamCheat.cxx in Sources */, E0FABEEC20E9948200EB8E28 /* AudioSettings.cxx in Sources */, DCD56D380B247D920092F9F8 /* Cart4A50.cxx in Sources */, @@ -3003,6 +3002,7 @@ DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */, DCB20EC71A0C506C0048F595 /* main.cxx in Sources */, DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */, + DC3C9BCB2469C93D00CF2D47 /* VideoAudioDialog.cxx in Sources */, CFE3F6151E84A9CE00A8204E /* CartCDF.cxx in Sources */, E08D2F3E23089B9B000BD709 /* JoyMap.cxx in Sources */, DCA82C711FEB4E780059340F /* TimeMachine.cxx in Sources */, @@ -3103,6 +3103,7 @@ DC676A531729A0B000E4E73D /* CartFA2Widget.cxx in Sources */, DC676A551729A0B000E4E73D /* CartFEWidget.cxx in Sources */, DC676A591729A0B000E4E73D /* CartSBWidget.cxx in Sources */, + DC3C9BCC2469C93D00CF2D47 /* EmulationDialog.cxx in Sources */, DC676A5B1729A0B000E4E73D /* CartX07Widget.cxx in Sources */, DC7A24DF173B1DBC00B20FE9 /* FileListWidget.cxx in Sources */, DC13B53F176FF2F500B8B4BB /* RomListSettings.cxx in Sources */, @@ -3116,7 +3117,6 @@ DCAACAFC188D631500A4D282 /* CartDF.cxx in Sources */, DCAACAFE188D631500A4D282 /* CartDFSC.cxx in Sources */, DCAACB0E188D636F00A4D282 /* Cart4KSCWidget.cxx in Sources */, - DCACBAD01C54296300703A9B /* CartCVPlusWidget.cxx in Sources */, DCAACB10188D636F00A4D282 /* CartBFSCWidget.cxx in Sources */, DCAACB12188D636F00A4D282 /* CartBFWidget.cxx in Sources */, DCAACB14188D636F00A4D282 /* CartDFSCWidget.cxx in Sources */, From 08c48c5f82646feef69ef87a20ac43f8cfbda109 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 11 May 2020 16:15:34 -0230 Subject: [PATCH 16/42] Don't include some header files when we don't need to. --- src/debugger/gui/DebuggerDialog.cxx | 5 +++++ src/debugger/gui/DebuggerDialog.hxx | 8 +++++--- src/emucore/TIASurface.cxx | 5 +++++ src/emucore/TIASurface.hxx | 5 ++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index 5d8404d06..f62df7724 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -68,6 +68,11 @@ DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent, Menu::AppMode::debugger); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +DebuggerDialog::~DebuggerDialog() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::loadConfig() { diff --git a/src/debugger/gui/DebuggerDialog.hxx b/src/debugger/gui/DebuggerDialog.hxx index b66ae37a6..f38e8b2dc 100644 --- a/src/debugger/gui/DebuggerDialog.hxx +++ b/src/debugger/gui/DebuggerDialog.hxx @@ -33,14 +33,16 @@ class TiaOutputWidget; class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; +class OptionsDialog; +namespace GUI { + class MessageBox; +} namespace Common { struct Rect; } #include "Dialog.hxx" -#include "MessageBox.hxx" -#include "OptionsDialog.hxx" class DebuggerDialog : public Dialog { @@ -55,7 +57,7 @@ class DebuggerDialog : public Dialog DebuggerDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h); - virtual ~DebuggerDialog() = default; + virtual ~DebuggerDialog(); const GUI::Font& lfont() const { return *myLFont; } const GUI::Font& nfont() const { return *myNFont; } diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 19e817b0d..8ff9f3e17 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -82,6 +82,11 @@ TIASurface::TIASurface(OSystem& system) myPaletteHandler->loadConfig(myOSystem.settings()); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +TIASurface::~TIASurface() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::initialize(const Console& console, const FrameBuffer::VideoMode& mode) diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 6552c26ca..b2c00f912 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -22,13 +22,13 @@ class TIA; class Console; class OSystem; class FBSurface; +class PaletteHandler; #include #include "Rect.hxx" #include "FrameBuffer.hxx" #include "NTSCFilter.hxx" -#include "PaletteHandler.hxx" #include "PhosphorHandler.hxx" #include "bspf.hxx" #include "TIAConstants.hxx" @@ -49,8 +49,7 @@ class TIASurface Creates a new TIASurface object */ explicit TIASurface(OSystem& system); - - virtual ~TIASurface() = default; + virtual ~TIASurface(); /** Set the TIA object, which is needed for actually rendering the TIA image. From 36c18c2e281d6fa5386cd4b871b357889638768f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 11 May 2020 21:18:49 +0200 Subject: [PATCH 17/42] Fixed minimal zoom and message area width --- Changes.txt | 2 ++ src/emucore/FrameBuffer.cxx | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Changes.txt b/Changes.txt index f0c1b4acc..222b1e8a3 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 interactive palette to Video & Audio settings + * Added 'Custom' palette, generated from user controlled phase shifts. * Added 'Turbo' mode, runs the game as fast as the computer allows. diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index ce2d4cf46..14f620373 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -171,10 +171,9 @@ void FrameBuffer::setupFonts() // However, we have to make sure all Dialogs are sized using the fontsize. int zoom_h = (fd.height * 4 * 2) / GUI::stellaMediumDesc.height; int zoom_w = (fd.maxwidth * 4 * 2) / GUI::stellaMediumDesc.maxwidth; - myTIAMinZoom = std::max(zoom_w, zoom_h) / 4.F; // round to 25% steps + myTIAMinZoom = std::max(std::max(zoom_w, zoom_h) / 4.F, 2.F); // round to 25% steps, >= 200% } - // The font used by the ROM launcher const string& lf = myOSystem.settings().getString("launcherfont"); @@ -310,7 +309,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type, } if(!myMsg.surface) - myMsg.surface = allocateSurface(FBMinimum::Width, font().getFontHeight() * 1.5); + myMsg.surface = allocateSurface(font().getMaxCharWidth() * 56, font().getFontHeight() * 1.5); #endif // Print initial usage message, but only print it later if the status has changed From 838cba2d164ef531c6ccac419772fe2b9fae45ab Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 15:21:15 +0200 Subject: [PATCH 18/42] Moved two more mouse settings to Mouse tab --- src/gui/InputDialog.cxx | 81 +++++++++++++++++++++++------------------ src/gui/InputDialog.hxx | 16 ++++---- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index c3959c742..3cced561b 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -127,10 +127,9 @@ void InputDialog::addDevicePortTab() "Joystick deadzone size", lwidth, kDeadzoneChanged, 5 * fontWidth); myDeadzone->setMinValue(0); myDeadzone->setMaxValue(29); myDeadzone->setTickmarkIntervals(4); - xpos = HBORDER + myDeadzone->getWidth() + 5; wid.push_back(myDeadzone); - xpos = HBORDER; ypos += lineHeight + VGAP * 2; + xpos = HBORDER; ypos += lineHeight + VGAP * 4; new StaticTextWidget(myTab, _font, xpos, ypos+1, "Analog paddle:"); xpos += fontWidth * 2; @@ -165,7 +164,7 @@ void InputDialog::addDevicePortTab() wid.push_back(myDejitterDiff); // Add paddle speed (digital emulation) - ypos += lineHeight + VGAP * 3; + ypos += lineHeight + VGAP * 4; myDPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, "Digital paddle sensitivity", lwidth, kDPSpeedChanged, 4 * fontWidth, "%"); @@ -173,26 +172,8 @@ void InputDialog::addDevicePortTab() myDPaddleSpeed->setTickmarkIntervals(4); wid.push_back(myDPaddleSpeed); - // Add trackball speed - ypos += lineHeight + VGAP; - myTrackBallSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Trackball sensitivity", - lwidth, kTBSpeedChanged, 4 * fontWidth, "%"); - myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20); - myTrackBallSpeed->setTickmarkIntervals(4); - wid.push_back(myTrackBallSpeed); - - // Add driving controller speed - ypos += lineHeight + VGAP; - myDrivingSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Driving contr. sensitivity", - lwidth, kDCSpeedChanged, 4 * fontWidth, "%"); - myDrivingSpeed->setMinValue(1); myDrivingSpeed->setMaxValue(20); - myDrivingSpeed->setTickmarkIntervals(4); - wid.push_back(myDrivingSpeed); - // Add 'allow all 4 directions' for joystick - ypos += lineHeight + VGAP * 3; + ypos += lineHeight + VGAP * 4; myAllowAll4 = new CheckboxWidget(myTab, _font, HBORDER, ypos, "Allow all 4 directions on joystick"); wid.push_back(myAllowAll4); @@ -231,7 +212,7 @@ void InputDialog::addDevicePortTab() wid.push_back(myEraseEEPROMButton); // Add AtariVox serial port - ypos += lineHeight + VGAP * 2; + ypos += lineHeight + VGAP * 3; lwidth = _font.getStringWidth("AVox serial port "); fwidth = _w - HBORDER * 2 - 2 - lwidth; new StaticTextWidget(myTab, _font, HBORDER, ypos + 2, "AVox serial port "); @@ -252,7 +233,8 @@ void InputDialog::addMouseTab() const int VGAP = fontHeight / 4; const int VBORDER = fontHeight / 2; const int HBORDER = fontWidth * 1.25; - int ypos, lwidth, pwidth, tabID; + const int INDENT = fontWidth * 2; + int xpos = HBORDER, ypos, lwidth, pwidth, tabID; WidgetArray wid; VariantList items; @@ -267,21 +249,43 @@ void InputDialog::addMouseTab() VarList::push_back(items, "Always", "always"); VarList::push_back(items, "Analog devices", "analog"); VarList::push_back(items, "Never", "never"); - myMouseControl = new PopUpWidget(myTab, _font, HBORDER, ypos, pwidth, lineHeight, items, + myMouseControl = new PopUpWidget(myTab, _font, xpos, ypos, pwidth, lineHeight, items, "Use mouse as a controller ", lwidth, kMouseCtrlChanged); wid.push_back(myMouseControl); - // Add paddle speed (mouse emulation) ypos += lineHeight + VGAP; - myMPaddleSpeed = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight, - "Mouse paddle sensitivity ", + myMouseSensitivity = new StaticTextWidget(myTab, _font, xpos, ypos + 1, "Sensitivity:"); + + // Add paddle speed (mouse emulation) + xpos += INDENT; ypos += lineHeight + VGAP; + lwidth -= INDENT; + myMPaddleSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Paddle", lwidth, kMPSpeedChanged, 4 * fontWidth, "%"); myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20); myMPaddleSpeed->setTickmarkIntervals(4); wid.push_back(myMPaddleSpeed); + // Add trackball speed + ypos += lineHeight + VGAP; + myTrackBallSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Trackball", + lwidth, kTBSpeedChanged, 4 * fontWidth, "%"); + myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20); + myTrackBallSpeed->setTickmarkIntervals(4); + wid.push_back(myTrackBallSpeed); + + // Add driving controller speed + ypos += lineHeight + VGAP; + myDrivingSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, + "Driving controller", + lwidth, kDCSpeedChanged, 4 * fontWidth, "%"); + myDrivingSpeed->setMinValue(1); myDrivingSpeed->setMaxValue(20); + myDrivingSpeed->setTickmarkIntervals(4); + wid.push_back(myDrivingSpeed); // Mouse cursor state + lwidth += INDENT; ypos += lineHeight + VGAP * 4; items.clear(); VarList::push_back(items, "-UI, -Emulation", "0"); @@ -473,9 +477,6 @@ void InputDialog::setDefaults() myDejitterBase->setValue(0); myDejitterDiff->setValue(0); #endif - myDrivingSpeed->setValue(10); - myTrackBallSpeed->setValue(10); - // AtariVox serial port myAVoxPort->setText(""); @@ -491,15 +492,17 @@ void InputDialog::setDefaults() // Use mouse as a controller myMouseControl->setSelected("analog"); + // Paddle speed (mouse) + myMPaddleSpeed->setValue(10); + myTrackBallSpeed->setValue(10); + myDrivingSpeed->setValue(10); + // Mouse cursor state myCursorState->setSelected("2"); // Grab mouse myGrabMouse->setState(true); - // Paddle speed (mouse) - myMPaddleSpeed->setValue(10); - handleMouseControlState(); handleCursorState(); break; @@ -691,6 +694,7 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd, case kMouseCtrlChanged: handleMouseControlState(); + handleCursorState(); break; case kCursorStateChanged: @@ -725,14 +729,19 @@ void InputDialog::updateDejitterReaction() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleMouseControlState() { - myMPaddleSpeed->setEnabled(myMouseControl->getSelected() != 2); + bool enable = myMouseControl->getSelected() != 2; + + myMouseSensitivity->setEnabled(enable); + myMPaddleSpeed->setEnabled(enable); + myTrackBallSpeed->setEnabled(enable); + myDrivingSpeed->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleCursorState() { int state = myCursorState->getSelected(); - bool enableGrab = state != 1 && state != 3; + bool enableGrab = state != 1 && state != 3 && myMouseControl->getSelected() != 2; myGrabMouse->setEnabled(enableGrab); } diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index 54fde4a91..1c8c04367 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -91,9 +91,7 @@ class InputDialog : public Dialog EventMappingWidget* myEmulEventMapper{nullptr}; EventMappingWidget* myMenuEventMapper{nullptr}; - CheckboxWidget* mySAPort{nullptr}; - PopUpWidget* myMouseControl{nullptr}; - PopUpWidget* myCursorState{nullptr}; + CheckboxWidget* mySAPort{nullptr}; EditTextWidget* myAVoxPort{nullptr}; @@ -102,16 +100,20 @@ class InputDialog : public Dialog SliderWidget* myDejitterBase{nullptr}; SliderWidget* myDejitterDiff{nullptr}; SliderWidget* myDPaddleSpeed{nullptr}; - SliderWidget* myMPaddleSpeed{nullptr}; - SliderWidget* myTrackBallSpeed{nullptr}; - SliderWidget* myDrivingSpeed{nullptr}; CheckboxWidget* myAllowAll4{nullptr}; - CheckboxWidget* myGrabMouse{nullptr}; CheckboxWidget* myModCombo{nullptr}; ButtonWidget* myJoyDlgButton{nullptr}; ButtonWidget* myEraseEEPROMButton{nullptr}; + PopUpWidget* myMouseControl{nullptr}; + StaticTextWidget* myMouseSensitivity{nullptr}; + SliderWidget* myMPaddleSpeed{nullptr}; + SliderWidget* myTrackBallSpeed{nullptr}; + SliderWidget* myDrivingSpeed{nullptr}; + PopUpWidget* myCursorState{nullptr}; + CheckboxWidget* myGrabMouse{nullptr}; + // Show the list of joysticks that the eventhandler knows about unique_ptr myJoyDialog; From 43da84eb088f7c8c06ddbdb70e91e6092bed2329 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:09:39 +0200 Subject: [PATCH 19/42] renamed palette settings prefix --- src/common/PaletteHandler.cxx | 28 ++++++++++----------- src/common/tv_filters/NTSCFilter.cxx | 10 ++++---- src/emucore/Settings.cxx | 37 ++++++++++++++-------------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 2aecc6abf..70867d116 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -191,30 +191,30 @@ void PaletteHandler::changeColorPhaseShift(bool increase) void PaletteHandler::loadConfig(const Settings& settings) { // Load adjustables - myPhaseNTSC = BSPF::clamp(settings.getFloat("tv.phase_ntsc"), + myPhaseNTSC = BSPF::clamp(settings.getFloat("pal.phase_ntsc"), DEF_NTSC_SHIFT - MAX_SHIFT, DEF_NTSC_SHIFT + MAX_SHIFT); - myPhasePAL = BSPF::clamp(settings.getFloat("tv.phase_pal"), + myPhasePAL = BSPF::clamp(settings.getFloat("pal.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); - myBrightness = BSPF::clamp(settings.getFloat("tv.brightness"), -1.0F, 1.0F); - myGamma = BSPF::clamp(settings.getFloat("tv.gamma"), -1.0F, 1.0F); + myHue = BSPF::clamp(settings.getFloat("pal.hue"), -1.0F, 1.0F); + mySaturation = BSPF::clamp(settings.getFloat("pal.saturation"), -1.0F, 1.0F); + myContrast = BSPF::clamp(settings.getFloat("pal.contrast"), -1.0F, 1.0F); + myBrightness = BSPF::clamp(settings.getFloat("pal.brightness"), -1.0F, 1.0F); + myGamma = BSPF::clamp(settings.getFloat("pal.gamma"), -1.0F, 1.0F); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::saveConfig(Settings& settings) const { // Save adjustables - settings.setValue("tv.phase_ntsc", myPhaseNTSC); - settings.setValue("tv.phase_pal", myPhasePAL); + settings.setValue("pal.phase_ntsc", myPhaseNTSC); + settings.setValue("pal.phase_pal", myPhasePAL); - settings.setValue("tv.hue", myHue); - settings.setValue("tv.saturation", mySaturation); - settings.setValue("tv.contrast", myContrast); - settings.setValue("tv.brightness", myBrightness); - settings.setValue("tv.gamma", myGamma); + settings.setValue("pal.hue", myHue); + settings.setValue("pal.saturation", mySaturation); + settings.setValue("pal.contrast", myContrast); + settings.setValue("pal.brightness", myBrightness); + settings.setValue("pal.gamma", myGamma); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 64f26da2b..5a275fbf2 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -172,11 +172,11 @@ void NTSCFilter::saveConfig(Settings& settings) const { // Save adjustables for custom mode #ifdef BLARGG_PALETTE - //settings.setValue("tv.hue", myCustomSetup.hue); - //settings.setValue("tv.saturation", myCustomSetup.saturation); - //settings.setValue("tv.contrast", myCustomSetup.contrast); - //settings.setValue("tv.brightness", myCustomSetup.brightness); - //settings.setValue("tv.gamma", myCustomSetup.gamma); + settings.setValue("tv.hue", myCustomSetup.hue); + settings.setValue("tv.saturation", myCustomSetup.saturation); + settings.setValue("tv.contrast", myCustomSetup.contrast); + settings.setValue("tv.brightness", myCustomSetup.brightness); + settings.setValue("tv.gamma", myCustomSetup.gamma); #endif settings.setValue("tv.sharpness", myCustomSetup.sharpness); settings.setValue("tv.resolution", myCustomSetup.resolution); diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 07c41e0f3..f5e120408 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -46,30 +46,29 @@ Settings::Settings() setPermanent("center", "true"); setPermanent("windowedpos", Common::Point(50, 50)); setPermanent("display", 0); - setPermanent("palette", PaletteHandler::SETTING_STANDARD); setPermanent("uimessages", "true"); - // TIA specific options - setPermanent("tia.zoom", "3"); setPermanent("tia.inter", "false"); - setPermanent("tia.vsizeadjust", 0); + setPermanent("tia.zoom", "3"); setPermanent("fullscreen", "false"); setPermanent("tia.fs_stretch", "false"); setPermanent("tia.fs_overscan", "0"); + setPermanent("tia.vsizeadjust", 0); setPermanent("tia.dbgcolors", "roygpb"); - + // Palette options + setPermanent("palette", PaletteHandler::SETTING_STANDARD); + setPermanent("pal.phase_ntsc", "26.2"); + setPermanent("pal.phase_pal", "31.3"); + setPermanent("pal.contrast", "0.0"); + setPermanent("pal.brightness", "0.0"); + setPermanent("pal.hue", "0.0"); + setPermanent("pal.saturation", "0.0"); + setPermanent("pal.gamma", "0.0"); // TV filtering options setPermanent("tv.filter", "0"); setPermanent("tv.phosphor", "byrom"); setPermanent("tv.phosblend", "50"); setPermanent("tv.scanlines", "25"); - setPermanent("tv.phase_ntsc", "26.2"); - setPermanent("tv.phase_pal", "31.3"); - setPermanent("tv.contrast", "0.0"); - setPermanent("tv.brightness", "0.0"); - setPermanent("tv.hue", "0.0"); - setPermanent("tv.saturation", "0.0"); - setPermanent("tv.gamma", "0.0"); // TV options when using 'custom' mode setPermanent("tv.sharpness", "0.0"); setPermanent("tv.resolution", "0.0"); @@ -411,8 +410,13 @@ void Settings::usage() const << " -palette \n" - << " -phase_ntsc Phase shift for NTSC custom color palette\n" - << " -phase_pal Phase shift for PAL custom color palette\n" + << " -pal.phase_ntsc Phase shift for NTSC 'custom' palette\n" + << " -pal.phase_pal Phase shift for PAL 'custom' palette\n" + << " -pal.hue <-1.0 - 1.0> Adjust hue for current palette\n" + << " -pal.saturation <-1.0 - 1.0> Adjust saturation of current palette\n" + << " -pal.contrast <-1.0 - 1.0> Adjust contrast of current palette\n" + << " -pal.brightness <-1.0 - 1.0> Adjust brightness of current palette\n" + << " -pal.gamma <-1.0 - 1.0> Adjust gamma of current 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" @@ -447,11 +451,6 @@ void Settings::usage() const << " -tv.phosblend <0-100> Set default blend level in phosphor mode\n" << " -tv.scanlines <0-100> Set scanline intensity to percentage\n" << " (0 disables completely)\n" - << " -tv.contrast <-1.0 - 1.0> Set TV effects custom contrast\n" - << " -tv.brightness <-1.0 - 1.0> Set TV effects custom brightness\n" - << " -tv.hue <-1.0 - 1.0> Set TV effects custom hue\n" - << " -tv.saturation <-1.0 - 1.0> Set TV effects custom saturation\n" - << " -tv.gamma <-1.0 - 1.0> Set TV effects custom gamma\n" << " -tv.sharpness <-1.0 - 1.0> Set TV effects custom sharpness\n" << " -tv.resolution <-1.0 - 1.0> Set TV effects custom resolution\n" << " -tv.artifacts <-1.0 - 1.0> Set TV effects custom artifacts\n" From 4a7676215c9e2905b900590884d8a038f1b643d6 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:10:22 +0200 Subject: [PATCH 20/42] updated doc --- Changes.txt | 13 +- docs/debugger.html | 1 + docs/graphics/eventmapping.png | Bin 4538 -> 4210 bytes docs/graphics/eventmapping_devsports.png | Bin 8669 -> 7375 bytes docs/graphics/eventmapping_remap.png | Bin 4583 -> 4494 bytes docs/graphics/options.png | Bin 3613 -> 2066 bytes docs/graphics/options_audio.png | Bin 5815 -> 3879 bytes .../options_developer_timemachine.png | Bin 4782 -> 3527 bytes docs/graphics/options_gameinfo_controller.png | Bin 6882 -> 4057 bytes docs/graphics/options_misc.png | Bin 4416 -> 4318 bytes docs/graphics/options_video.png | Bin 3927 -> 2744 bytes docs/graphics/options_video_tv.png | Bin 7899 -> 3847 bytes docs/index.html | 249 +++++++++++------- 13 files changed, 170 insertions(+), 93 deletions(-) diff --git a/Changes.txt b/Changes.txt index 222b1e8a3..83f2abc26 100644 --- a/Changes.txt +++ b/Changes.txt @@ -14,26 +14,29 @@ 6.1.2 to 6.2: (??? ??, 2020) - * Added that paddle centering and sensitivity can be adjusted (TODO: Doc) - - * Added that Driving controller sensitivity can be adjusted (TODO: Doc) - * Added high scores: Score addresses, game variation etc. can be defined for 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 interactive palette to Video & Audio settings + * Added interactive palette to Video & Audio settings. * Added 'Custom' palette, generated from user controlled phase shifts. * Added 'Turbo' mode, runs the game as fast as the computer allows. + * Added that paddle centering (per ROM) and sensitivity can be adjusted + + * Added that mouse sensitivity for Driving controller can be adjusted + * Added selectable dialog fonts * Added separate positioning of launcher, emulator and debugger * Added option which lets default ROM path follow launcher navigation + * Added debugger 'saveaccess' function, which saves memory access counts to + a CSV file. + * Added displaying last write address in the debugger. * Added detection of color and audio data in DiStella. diff --git a/docs/debugger.html b/docs/debugger.html index 91e71bd47..423a20aa1 100644 --- a/docs/debugger.html +++ b/docs/debugger.html @@ -978,6 +978,7 @@ clearsavestateifs - Clear all savestate points runtopc - Run until PC is set to value xx s - Set Stack Pointer to value xx save - Save breaks, watches, traps and functions to file xx + saveaccess - Save access counters to CSV file saveconfig - Save Distella config file (with default name) savedis - Save Distella disassembly (with default name) saverom - Save (possibly patched) ROM (with default name) diff --git a/docs/graphics/eventmapping.png b/docs/graphics/eventmapping.png index 86deacd4aa8ced58e82776d4f402bd2c67778325..f9b089b6d70f6058d740a30112d8b58777a19515 100644 GIT binary patch delta 4138 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 bBhZBe`c(CT@Z0I1&+d$~HO=xofAW6-B`-Rj delta 4468 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 literal 8669 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 P2knNsH+2YFc2WNYVT?VX diff --git a/docs/graphics/eventmapping_remap.png b/docs/graphics/eventmapping_remap.png index a2e3ce94954fe294c4fc56445d34237b1e5c0981..34df629373d86aa9e469d82bdc8506dc982d522e 100644 GIT binary patch delta 4424 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

FHR#LhXmbjUoS{PuDpAZo0ie_x;)-sJ4S< z>;s1Mz}c-h1{&2f2nad~TcZsNr8YG)l!Pv9wc9c5r{fL-b!fO)P`1`aag|$6t}tvA zcnMoun8tm0^TPWi@tbh=^-iMd4P_k{yc<~<@_$%^hQ+I6D{U$UIT`r8lZPi((zV7~ zbsMp(2|?lg*Bo8C{iU%;MN7M7>|TAUKOb1QPTkgEaa!br=qgNyVIAYc3(ojIivOiM z?%t*Zt{1l4prB#Ww2SSg6UUyuLFK%Gl^b53CoY?1H8Qi^D)b>xRYqLT!H)8q(Is=g za~BI`0P59aqIeAfR=8p$U3`>Ui0-Sl>?+_1AKs7;-XNW;I8B=b!iiG1^e{H(B(N`h z@Y#d!t|eVMI{#Rca+z8@-{x5AhLSViZ;EmIK20HTz?AmvI&ngUwi10|Eb}Ntl~Q$) z)w_Bx(l}S0y(M$C>2uV&P{RiAADI~Lsh_bdvaEA8yR?9?W*1FUT;ucl zAx~HbB}QfyZyPW0dTJTa?p@4(ceidaZx&?yEpj^LBF~fCLGLU}i@YCWxq&P)Ft%WN zuSerHpfUbbQ z1^idPTy$dZ`}PsSzH4as&+hysilr}n`{w>$kM%h;No*+0IKV!J24?>G_44BH3$)9P zW^f9WhO(k`JZh=SlQQ^Vwbh3RzZ}2gt zyr1;VK2;&a-a~8k0q2_}cs)K8#DUu#N_ZL5yP%3IgvR>7nGkLK|N(Qs{{AgKAOey4~Ksc71@6mU@MkK8XQfy52 zo^c%-3AfE2RGdCa^S)6a^^bRltp3J>GEyU<`4BKuY@ZC?v|NAp|EQA-9N0~5IiG$# b=9h7doC`W9N7i@$bA-bhdc~Y%>Jj%pJoUsU delta 4513 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 literal 3613 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 SH*;@$<*~G|K3{9*5%+&xM}~?3 literal 5815 zcmeHLcTiK^whsu>>!J4=kPb$=Admn7Lhk|s8VS8)RHU~9d{pV7gA@TnQ&c(uD^(E$ zlo(JDMT!L!kQ?;+y}2{@zIlJYxo2k2nZ5R!HG8e!{;jq41})8vnCSWFArJ@?(imc(UAP32(>oShqR0dyeChny!23d5J+n#!@dVK1ab^wX=aNc%P|;C z6O8pC1TyWUSDo(h=vL&ycSL%JYir%(uldFW_RJP546 zKo;_ZAsoYO0xyPL@(4jgf;_wf!W06~VInXEWd+p(bGlUs1Q0;N^=z?j>!oQ`^Qz47 z&}aU+hleD|n1Of>Nz;xCXJO{(Ac&=+`SJ(1y8C@mQBrCvQmAfSZxU4v2xLLc&lIau zG=tH~hCf5BNJCdy-IVyw-Y&W}D zVb!!#RhG|{d23a(3mgsU%0##8t??RASOnD`=Q&Y{_zvh}0}s(AJi(D7Kf&IWVes9m zDgPt&sHYiBUpk=WR&StbeG>a7dba7jb>{RzCA(H!a z=1x%|&XDZcZ#ON?_7(4H{EN%~VFKH#qa0rT++en>IImZX74`wPrVR(o_9aDb;@9R9 z#I>UnHqgl+tEs*$DpHDU(k$$a`Qm*wylJN+Sa<=f8Sa)1X2Bw0VfnSXGd_SRf zqTayt)MW#S^DgdU9mG8L#v1V)C;(v=AIMH@)Cl9jNSs_5{W0^cdQ&nfGUmQ$<8x-w9) z?A;1vK5nMnX1q!CCc2!-IM)JKI37pS5XrWqI;mhz9f*qrGNYl7r&0#j92H{onN9-` zA#Elc!^5rbA5}~y1|5R?;pfWLjqOx#^8B&^k;3b0^EEz;rrSfgwB*|RwWm_B`22MD zTP>)iU!e?%#Hp33m;E%w`guBWp2PW+c6gq>th|7pjm`gTwrukVG#FV@3%(651d%1O zsAXLP+%>j6R84I#I^GuDo;twXf%B>=n?V$J#VOD&)Py%)hdNg>;*ZHo6&p*X$LU|A zUhEeF7R`Uo`InI66X4<5hWh)6keSdw3?=o2@4MldXF@u`-HnXCq-ftMg4VWTRHZ}> zct_%QD0QB}_d+TzuBcHD6VCNL?g>5Pv76t^v^bUB>-z%&41K9p zPyN{CwG&^r>j=O2Sf_oftHXqLV1f@KyHbqr}W26FA4XuaY=I$UMzR% z@m}SW0=tQeAu;ZTwG!J(aI4{spgJxDaygEwrTQW!K%Q$H}~M@YMaPbo-lG$Gs-ocxP*lm+Xg6Y$cTPW!PdnrTp78ngh%@m7-wlslPdgL> zq@XAqWWSRU%?$JjHVt*U_<3&AlbKPt0Pk+-VR3oT`7}UGC$O6_vchVL0APE--2w(t zly>|dmO0$r&YiiNj0U0!CX6(d{D})grDh2{=q1QXNxedP5jLm~wiWsK$9(k{86cYI z&Kv0A$%Y2uhyk>afoY?TWEH1xP;4#87WFXB-Sa%HuokUQSCzP_pq0vG>@S#i%fZIS zX_AuDrm9hTn55NNT;tnmOYP%ar89RJN9RI)PQ8C}QL$m(9nHaw2baYjThcxdz@C<_p1%Aj&i!fa|Ce!&CD^Aze&Sic825z-A<`+R&8K+zB6liXD&E>j@pjX zcIn<1G6xZYXG%5v#L9-|i+SkVkhSb{;cNChjV~b041!WkE^+?frkr#hAXtvTef?$K zHbK=B0W{kDWi-6fG3acNC9Z#IYciH~??T4%Yb!gDS&1#O4dm~qK)xQIbJo2uT}x8~ zuH-_Q2R2SkY)Fy$=m8iZf$^2E&=)nJRDa;74XT-7`P`CS!K309ST_^*p(}siJyc=$ zOf^{{>o8UMpCus++S0xhKl4PV*q;(uSF2O1HSqI}d76wnu`xp~yd%d_#kOPk zyqyM}qiDbxM}=c1v?drf>jjD;X@#kv@^TRI@(3mf6UOUi%9+RUon^_c^>S}&Gvf2C zIChykt;2770FMwE!v11xu6R_V0PA@~Lz_`CZGtR*mxFI4%^v_iluKuDT@>BK?(i09PTl^6qT2G5yh73)s_Xq zV$j!bHcIo+3WZr;3x*38v>J_h@tCFM1ZQ%D z{l=(;G1p;RRNLp2p?}vfyAd61;Ap#;}P%Mw8wOSvn|SOi))LdjZ!gUPcx_Xa~oq%B|T?TO@@j=J1PZ?3^foe z#9f3D8_mvp_r4zIC-Dm^2B0AB#GvX`q$^(gOY;d^^oQR`wbk9c)lSK5|CzvWuKN*E zcXr*+iz*0s-A1Mzt77nd|D?hBH85GDM^1robiofqyn~fC-4R@qAC}7DPBN;wwHeYL z^m$!RDJBy;zr3}TXNtUlI?Ar%GWVY=@^z<@kYu9uTC$h_jCky8C+}!?dsK$Y6>GY# z+|&T znvj4+%%b`tUCWX)RBcP^-!~y?+y_@*x7UDYpZbX{&W|ufjrA<;K$nO!UPHU#XXrvU z5lm~+-XzscPoAFiizrRmj>2~G3F5~pGq&i*PdQau^SR!ULM`*>S#u!rxMfuJEzdpw zN_1K3PxA;8OkB&*y0ei6caTq|X0el`y*L3ENMN~ObW;|lcT&jip-An`Y=&!;N5-lx zUnvRm^EsNAX6-_!O=!nYgI@>MQuF1lJmwjQ!)u$0Ba$c@H`WhH0giut=zrz#oKv$% zhPNnZ7AgpgwL?{KAU;2#upYlo{SYmG`7YQq-|U-Dt!JsgPyhUdmHHc`#9C_dul3E* z2y7?#>V9)tegmaL)!@Clw>`fcNpY;_NEg`a?G;#^l%iS8qdL1b5yw}neFop>R(gwCUJRt zZp-|y?VmAl>GR#bcvIlg$s%wcVccHM$yF-f;>OcE@vMKw)F{Paz}fqAJcENWrs{b0 z1#6|&v|~2O#9=Kao=_?mqsrdtw<_|o_b<1D4)N2vbiagNcQtD#6R(cJfvBG%^x8Ss z`8K)uT-?1$0=q$V6z4NyK1g#@iW0v`vcY7}Yvf6DY1`(B6s|-;RbwsL&W@HV2M*tJ zFxYZhHW{ZJ5g532%w%<;4h>V2=tXw24*|-l5jnZK2uwH!kSFy2zREClg~KYM7*d;m!wg*$_=QR{7;Z{u_r=cyQ%Y$cJ>ZL~;cwHLwvtV)mBC)W z+~zc#xVb>X?+`%{safJQIIC?xxT8s<UpMLaaFr@30is?RrchTY;@4`!z#;s%p; z=|{{YE`WH;Ud+9ad|SI4KLPwle(O#*Eihy0s!jdyOi(d69XDcP#~EqPDHFCc;VYG= z{j|cpit6J56Yjf&N@LUD;2!)`-8036#;wDdr;$~0Bc4_#Xs@RcO#A6g9t>4=B z6cA~VW(6r}7wwJn(w)sBRK$rf*oLJp-L-fl+JC>GF++jzx`wf@(|7ujMf2RuH;`z)sL5VCc@xCxK4$if;Zb8#R`RzR+*2UTbSO z#L|v*^znhq>lr&KLm!o_+_LhdtEc-tGukKT+{c%v#T6rxBp<{|C1*d&|Bz++Qaq#m z3E|snam1MK<@s5^(&4pfY5cPK=CV?xeJ>;ZRRUxWC1-IT7nfkHRcGf(H|XfQHRh70 zC#&fso5a~Pz$u$eRQ^P5nsLm6IsP-(s%DT?iD!)0qPZZFD-_phk3{DhO2S6yDoSxft+ zP<-ntrH9%j#PQuLTx#kxktu<(25BSxX?HIK-p(BopvV`XDHAxpGK`r0O4c@4&Nljc z2T9=wk+8&+gbwbDF}-PK5g!tK&nLeExyTQ%cg$HW=E3Mv6x?Bebc`Eb~Z2A+f?9PB`Ex4 zQ=TQOPpc;dHc74<#9k=$e{S*rH^~3IX$%meTlQCkaT0f9b|pxGFI_3kx2%ZKho9Ml zQVVd^SJ)5tH&lK`l5%(B`)saI1c=ddPn_E7lSL6u=%n(Zo=RJU)du-x=kVw%!O@H^QCP(4kynY%MN%$o1@P4r=<$;AgeKx4}F)56$(75Tu%6mEdjqv zls%X?`;7ugcXvLqU^Cl-lt|>bbts!w@H5xNC{ha*VDg9Pe^CFO4=l~h0>;M24=JY3 Wy*Rj9bF$;;2@#1fhqvgv$NdA>S|xM< diff --git a/docs/graphics/options_developer_timemachine.png b/docs/graphics/options_developer_timemachine.png index ddb58f28e654942d25b01309383ff6b3317efe2e..498f83c0f7cce460505db2f3e21f4fb749a66426 100644 GIT binary patch literal 3527 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 literal 4782 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 diff --git a/docs/graphics/options_gameinfo_controller.png b/docs/graphics/options_gameinfo_controller.png index 9b9413ab25b29a0e3d563a1e074f196bfefc41b8..04cc025db75520f97063cec392956647b1f79a04 100644 GIT binary patch literal 4057 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 DZ8%y~ literal 6882 zcmeHscT^MIw>DLp^d=xpr3yhp4+w$?NJlyZkP?c77P=HAQdAUa66uNvD7_O1UFsn9 zHS}U2^j@V1U%bEfzUBMp{(skm z#CXDKO-V}7Oo5zD2^V7D2byX`CH+@d2m+als-7wlQTZF1GkbC(B2pqlU6XqRy{oHh zku*a$5z)t2_C2McQv;v2w+9IN|2zHVZc+wvEvQYalKvG4lp$!<)7-dHD%(RSVGmoDZbhb z`Ow;n^}b79Oj)SMB2+mC9uf`de*Vm1nhi!v{tYDkFnXC}p6_L4YTbIRG4tVEK3Rw2 zM2&;!jazwq@O7P+NtQpMc}M+%>k%6J5j6DWlxnrOmUqbK?l;(7q_!%kL$riix#`Qh zk*P)u%KQk^jJt@`5=lE}+QYIqM;kA>)(H)phiQo<;#}#%{elfspbFc^;YZ2TsBBJR zuOQw`dE~B)#n&Xvgt`wn6QHn=%*E7m{Aah@^+1QOFiP`1lqUiaOqK>*n4dxZGekh8 zWvi}lmb{te>T*OpaADgoMCWt+V$P5qc|B7Pjmbs?XCi`yxKuMe^IcNCm1)O_EG1AEKC=q$IvlxSq6ewb&lX=^ zBq3naWs?<VVmkjEaxB^uBGGR5VH3X=G|~9#jrY^Vqk@p& zB=b$YUsJ8G!kJk5&M0)Rz1#FOcHZ+GQWqY9+JwP@F}AZx(m`I>Bp$1FG{}*4f>^Ni zL_IG}tK4*yv$4d~XOC>cnr`GnQ6Ck9qXESCrlpGWZGFIN3Rtp9{1{^8H$G!i)$zLO zXz;145zCulT&>m-Sd$vT@MxvG+_D$rdQINfg$-c|&)eT@gpZdRck3_TsS8c7Z zTL1^-N2~;DRqtDw{CJ7895i*;Xknp!t_+61rh4uEF?bACkvdP64NQ{{r^sB{sw&87 zsLOb7KJI6!|7zuk9s5<=+n*#m$AU+v}M5^LxyOYHZ{mp$}v`ud%tXcqWDTJ&txzHv}hk4zz|`2^>oh4GbO z-l!jYChCCL;l%DF44B%l>6vZ8ob{=o#LA4RsBtP^&Cm!%!ffXHcx-CiqCLt- zC_7YQ@1AzsJC5TiQ>@O_Gw5NCYLqk_=j)!?RsmSuzdKYyW9`JvESshY#gqnz3=lf#W2!tynnxSgdhL_ztgxO*|WA)6+27pcmpbJP(B6(lpRZ zTT?*jo&Lw4>e^ZJ?<^Nk-W;TkHCurye=Q-+xLf~-H!qMQzp57l0J;+R&+JDWAYcpC z{8i@&LGq2Y7lv~?+BNcA-(3otY7CXi`mr0hh3~swV%}xEiRUsp+PxQfz}SS9D;dvbB6)=^G4<8xcb?dK?jUr~wKr(gahP$14II6%e5XgI!j<~zMExM= z2iukWUrH~98XYwkdMm|bgTDab1FVxuSUisCuf*{?oznYos3-^1cxxNrL_qT{ADfB8 z>8wRi67!=M^l7moC^-?7O2-JaQ&axVUPv;Kj#&VMeHBqF4ef_6;EY$L;gc3n+w)Tr zXUpSL@;L7-Kxk^L=Jt!}hV;53`)~NW(Y#g|vWBVfUpufsY}k6<%~4cdiN=dAJBgZM;r@8*nT7mKtf!JtHOUSi5WWeF@0*bSnq~ zo&uIgqwJqbje@eJi)79rZfVW7%P7uBcC?v&yjO15UfjK?C@Zj)mtgNM{Kfm;j$Sw3 znM`-+>GJhYaRE z`LR0@@S})T5LNPiBQ+>+EkS{C8i#rgs=ZT2`fpDZ3O&GwYsK8uC*CT%rofoi{)qWS zKVAer6m1|hR!1BLdJ?+_wRK+Ydu2`t@m{-$0F|`)&l=!c+ogR1O=}39##?W%f$VhA z7^-k4ErL;z@_N@2}UyR%8{|L4H@U6D-`OOrwfrHwkP+y)U@C^E3MaC==U32Bp9+9t8@#u-0%A19R zY(Os_D>N#m<`H!#5o^IKMHmR5%iq0%qCzjg<#fc+d7@Yo@7N)$CCCUTK6EzP0PhBx zG>s{Kbmyv@vs?sSG5LpsN59oZ*?_oVXJdi*R!o|wh6tHk2U@8bTVzm-UcmJzZTgN+ zwSUr_wW^Q1H8i*ZCqw{km5rqYrB&`zA{+yNbFn!Lsr+e=iv63t{z+wj``(R^KYi~a zjH?$92%~0mpvv0lPy+KKgeOe`Xdj{Bu`%_pE>>8++rkUQLY-b#M)!HuVde+c)(0kS z1|p6Zd5JwY@+JK_a11r3Oi&9-oJ#oNStPL7(+lfzZRh5dD7AORlrLzb6#A&5%>>RK z_lRtr`mW!0x6M&GS&y(qaBRQC!?+yti^r{MmJ!TlZAz)s9bd$R`=}@6inYfM5{(zx zdmi!hh4xI~%$JYkYA*y()-PX5ITuuuM^$r5e{daimem-HE7^^^bn6sd)Z56{dXFjE zgH;`h67_O%hT4+u6~jtLwt_dc8i9>r+-hg+tHKf~?hXwh>1we~$=teCG7*;GT(M?H zA>KZ2@w|E4chiP!nBL`sVc!&W38X<-fQ%lrqLTf=B5IY;OC75UO%h+A9_cW4 zx9baV19RP@E%_Ymem|LdpI&Ykxl*2;^_B3aJkjJVUr}PjsCe z9{DLWaxtiE?Ji{9?p-~UYebz&orj?$@FiPg+<%!Z>3^FxKZxDS=${PmUxnQND2&6- zoS5%a1}S9%XDUAtX8M1W0F1Iuj#;=WbUe0CdRAlo?ktN<~__QWVoG9?H-wj{{SvZefg>; zOt-brA>}rRdBwq*|4wvzFC-%a8z1v34_T(K0g;a`PA$2~BvId&3lt7p8`{4fI>PD8!N_&1dVP z&uB{mk7u>eXRN(=gFiopB6P7-?^ME2$htU`yg~XA=z>3A0ji3=Z0i?%GMR`t?pzP< z@&p}dWbURL1Xva~As2UfEv67?O#f6Sz#Ye8^;#fzcom;ecSZq9!YxqaVBN6t)CXvc zYI9zyKzOPam6auDIRJO|jbwFkbHC@=NZp_->nnzmGfcl?Ix$~#c#r+4&H?fS(!GNhs`=2e|zKJydbQAQ2px<=y>S0sQXk@trt5!GD4X z4%g2O=iz#kn(8I|zC8gc!T;7w;>}n5N$~pG_`!Gcn&KhOVW|YBstRcb)Og<_<<0(K z?8~XgtO2R;MGFEzvXWn_y2eMnwZ&fd^)IiOVCV?Uq_KUKQ0RYFIoKO}gA+iZQ=A)+ z$-8NuzlMcFAU9{85!eG1M)220;Mk&*sByfPyjT3F-N@lcc%2`5iq}?0;L+zq0wWhO?tt zhGsniza)4qeZb7N-NxA|*qbQi+abNesmewua1-(T1+c%BJi8^+nn)A>i^9uZgiL5f z>D_0bHq@wWfh6eYFipY8u$3N^)wj=W9Zs91zWY#|@~&bCTkRJve{Q$?W)FMF2WO7S ze#*-Su@&)t!!1=bL1>H;=@ z(bK?xfmn-3o#EoW*bLI##3OuY|AqDcFZ9)AG7UOkwMKNPpW;{tDep?wfGg#S=dL%lO@9GP@ zpUnaUwLa#_+vNLI7nK)XaE$zVSm597(-3RvovJUGo%f!6plI7_a{mu2lBb)eH7ZKM z>gd9eB*xZq@^6<`2A3X49WYe4vRY{r98^5C(b>IqYat~@SRrYFJ1iQt1tY`2i_xDv z7^Qs-5!BZU8_=*xUKzFMZ8R-eGGvL#QiDm{K6B{%V^RbZk(%fsM4Pl6Gb9wWw|_9?)dz z__JgHg{T2KxJCZz5B}}1gk~Y38#B+{QTpI$m*MYn_diC%VAI*06i6liwXy|mM?$xg z8k+^}wDSufruXM?c|yDi=43YnZ4vmW271Z}G#iaLzC!5zphLOBr(owtiyz*)QS=pM zZUdl^wS1a6dx|yC7CQGKY^4TB+VjBUHsNJ;xEPzoQC-#S1`Ge=!K@VXO&|1Ry=iPi zWh?HbD%3Xg7c&+*)6DMda~zIZp^Z3lI313o$lM{LrG#BZ?YY~+vVq6k)-Cub^>4!?^@O0qMaz@AS zh>2>NHuc2R+n~Kpo9FkIS6`{ik$kMnusfi32Tjhv-`pguNk|6MEpIns6-^2TU-2gv zyM&LyLdtmp%2vT!52QZVJ@KrY>&v9F24(k4G@LQ5fwJ$SF|mJv*o${e1_*q~d2e>mK~r>|b3_7M61 E04+ZjRR910 diff --git a/docs/graphics/options_misc.png b/docs/graphics/options_misc.png index b1930b45d7a246f7cc729bb5c0ef6e4cc70e0431..1faa756b5ce1fd194c32b74aef1dd9dfe606b887 100644 GIT binary patch literal 4318 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 Q|9(sDtkG6Ar?83t0!3{^{Qv*} literal 7899 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 diff --git a/docs/index.html b/docs/index.html index 82b8c4a38..b2da54d33 100644 --- a/docs/index.html +++ b/docs/index.html @@ -19,7 +19,7 @@

A multi-platform Atari 2600 VCS emulator

-

Release 6.1

+

Release 6.2



User's Guide

@@ -70,7 +70,7 @@


-
February 1999 - March 2020
+
February 1999 - ??? 2020
The Stella Team
Stella Homepage
@@ -2008,11 +2008,11 @@
-center <1|0>
- Centers game window (if possible). + Centers all windows (if possible). -
-windowedpos <WxH>
+
-windowedpos <XxY>
Sets the window position in windowed emulator mode. @@ -2029,13 +2029,38 @@ -
-phase_ntsc <number>
- Set phase shift for custom NTSC palette. +
-pal.phase_ntsc <number>
+ Adjust phase shift of 'custom' NTSC palette. -
-phase_pal <number>
- Set phase shift for custom PAL palette. +
-pal.phase_pal <number>
+ Adjust phase shift of 'custom' PAL palette. + + + +
-pal.hue <number>
+ Adjust hue of current palette (range -1.0 to 1.0). + + + +
-pal.saturation <number>
+ Adjust saturation of current palette (range -1.0 to 1.0). + + + +
-pal.contrast <number>
+ Adjust contrast of current palette (range -1.0 to 1.0). + + + +
-pal.brightness <number>
+ Adjust brightness of current palette (range -1.0 to 1.0). + + + +
-pal.gamma <number>
+ Adjust gamma of current palette (range -1.0 to 1.0). @@ -2152,36 +2177,6 @@ and 'Custom' modes. - -
-tv.contrast <number>
- Blargg TV effects 'contrast' (only available in custom mode, - range -1.0 to 1.0). - - - -
-tv.brightness <number>
- Blargg TV effects 'brightness' (only available in custom mode, - range -1.0 to 1.0). - - - -
-tv.hue <number>
- Blargg TV effects 'hue' (only available in custom mode, - range -1.0 to 1.0). - - - -
-tv.saturation <number>
- Blargg TV effects 'saturation' (only available in custom mode, - range -1.0 to 1.0). - - - -
-tv.gamma <number>
- Blargg TV effects 'gamma' (only available in custom mode, - range -1.0 to 1.0). - -
-tv.sharpness <number>
Blargg TV effects 'sharpness' (only available in custom mode, @@ -2319,6 +2314,13 @@ faster movement. + +
-dcsense <number>
+ Sensitivity for emulation of driving controllers when using a mouse. + Valid range of values is from 1 to 20, with larger numbers causing + faster movement. + +
-saport <lr|rl>
Determines how to enumerate the Stelladaptor/2600-daptor devices in the @@ -2410,7 +2412,7 @@ -
-launcherpos <WxH>
+
-launcherpos <XxY>
Sets the window position in windowed ROM launcher mode. @@ -2566,7 +2568,7 @@ -
-dbg.pos <WxH>
+
-dbg.pos <XxY>
Sets the window position in windowed debugger mode. @@ -2703,6 +2705,16 @@ Set "Controller.SwapPaddles" property. + +
-pxcenter <-10..30>
+ Set "Controller.PaddlesXCenter" property. + + + +
-pycenter <-10..30>
+ Set "Controller.PaddlesYCenter" property. + +
-ma <Auto|XY>
Set "Controller.MouseAxis" property. @@ -2860,7 +2872,7 @@

Options Menu dialog:



-

Video Settings dialog:

+

Video & Audio Settings dialog (Display):

@@ -2869,29 +2881,42 @@
- - - - - - - - + + - - - - +
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
Emul. speedEmulation speed-speed
VSyncEnable vertical synced updates-vsync
InterpolationInterpolation of TIA image-tia.inter
ZoomZoom level of TIA image-tia.zoom
FullscreenSelf-explanatory - Note that colors may slightly change. This depends on the OS and renderer used.-fullscreen
StretchIn fullscreen mode, completely fill screen with TIA image-tia.fs_stretch
OverscanIn fullscreen mode, add overscan to the TIA image-tia.fs_overscan
Fast SuperCharger loadSkip progress loading bars for SuperCharger ROMs-fastscbios
Show UI messagesOverlay UI messages onscreen-uimessages
Center windowAttempt to center application windows, else position at last position-center
Multi-threadingEnable multi-threaded rendering-threads
V-Size adjustAdjust height of TIA image-tia.vsizeadjust

-

Video Settings dialog (TV Effects):

+

Video & Audio Settings dialog (Palettes):

+ + + + + + +
     + + + + + + + + + + +
ItemBrief descriptionFor more information,
see CommandLine
PalettePalette used for emulation mode-palette
NTSC phaseAdjust phase shift for 'Custom' NTSC palette-pal.phase_ntsc
PAL phaseAdjust phase shift for 'Custom' PAL palette-pal.phase_pal
HueAdjust hue of currently selected palette-pal.hue
SaturationAdjust saturation of currently selected palette-pal.saturation
ContrastAdjust contrast of currently selected palette-pal.contrast
BrightnessAdjust brightness of currently selected palette-pal.brightness
GammaAdjust gamma of currently selected palette-pal.gamma
+
+
+ +

Video & Audio Settings dialog (TV Effects):

@@ -2900,24 +2925,24 @@
- + - - - - - + + + + +
ItemBrief descriptionFor more information,
see CommandLine
TV modeDisable TV effects, or select TV preset-tv.filter
Adjustable slidersSet specific attribute in 'Custom' TV mode-tv.contrast, -tv.hue, etc.
Adjustable slidersSet specific attribute in 'Custom' TV mode-tv.sharpness, -tv.resolution, etc.
Phosphor for all ROMsEnable phosphor mode for all ROMs-tv.phosphor
Blend (phosphor)Blend level to use in phosphor mode for all ROMs (needs to be manually adjusted for your particular hardware)-tv.phosblend
Scanline intensitySets scanline black-level intensity.
Note: No scanlines in 1x mode snapshots.
-tv.scanlines
Clone CompositeCopy 'Composite' attributes to 'Custom' sliders 
Clone S-VideoCopy 'S-Video' attributes to 'Custom' sliders 
Clone RGBCopy 'RGB' attributes to 'Custom' sliders 
Clone Bad adjustCopy 'Bad Adjust' attributes to 'Custom' sliders 
RevertRevert attribute sliders to saved 'Custom' settings 
Clone RGBCopy 'RGB' attributes to 'Custom' TV mode sliders 
Clone S-VideoCopy 'S-Video' attributes to 'Custom' TV mode sliders 
Clone CompositeCopy 'Composite' attributes to 'Custom' TV mode sliders 
Clone Bad adjustCopy 'Bad Adjust' attributes to 'Custom' TV mode sliders 
RevertRevert attribute sliders to saved 'Custom' TV mode settings 

-

Audio Settings dialog:

+

Video & Audio Settings dialog (Audio):

@@ -2941,7 +2966,7 @@ - +
-audio.resampling_quality
HeadroomNumber of frames to buffer before playback starts. Higher values increase latency, but reduce the potential for dropouts.-audio.headroom
Buffer sizeMaximum size of the audio buffer. Higher values increase maximum latency, but reduce the potential for dropouts-audio.buffer_size
Stereo for all ROMsEnables stereo mode for all ROMs.-audio.stereo
Stereo for all ROMsEnable stereo mode for all ROMs.-audio.stereo
Pitfall II music pitchDefines the pitch of Pitfall II music (which may vary between carts).-audio.dpc_pitch

@@ -2960,6 +2985,44 @@
+ +

Emulation dialog:

+ + + + + + +
     + + + + + + + + + + + + + + + + + + +
ItemBrief descriptionFor more information,
see CommandLine
Emulation speedEmulation speed-speed
VSyncEnable vertical synced updates-vsync
TurboEnable 'Turbo' mode for maximum emulation speed. This overwrites 'Emulation speed' setting and disables 'VSync'.-turbo
Multi-threadingEnable multi-threaded rendering-threads
Fast SuperCharger loadSkip progress loading bars for SuperCharger ROMs-fastscbios
Show UI messagesOverlay UI messages onscreen-uimessages
Confirm exiting...Display a popup when emulation is exited-confirmexit
When entering/exiting emulation: + Automatically save no, current or all Time Machine states when exiting emulation.
+ The latter also loads all states when entering emulation. When this is enabled, you + can always continue your game session from where you exited it. Even including the + Time Machine buffer! +
-saveonexit
Automatically change... + Automatically change to the next available save state slot after saving a ROM state file. + -autoslot
+
+
+

Input Settings dialog:

@@ -2980,9 +3043,9 @@ - + - + @@ -3129,16 +3192,12 @@
ItemBrief descriptionFor more information,
see CommandLine
ThemeTheme to use for UI elements (see examples)-uipalette
Dialogs fontThe font used in the dialogs-dialogfont
HiDPI modeScales the UI by a factor of two when enabled-hidpi
HiDPI modeScale the UI by a factor of two when enabled-hidpi
Dialogs positionPosition of dialogs with Stella window-dialogpos
Confirm exiting...Display a popup when emulation is exited-confirmexit
Center windowsAttempt to center application windows, else position at last position-center
List input delayMaximum delay between keypresses in filelist-widgets before a search string resets. -listdelay
Mouse wheel scrollNumber of lines a mouse scroll will move in list-widgets-mwheel
Double-click speedSpeed of mouse double-clicks-mdouble
- - - + + + - - - @@ -3148,6 +3207,27 @@
ItemBrief descriptionFor more information,
see CommandLine
Use mouse as ...Allow the mouse to emulate various controllers-usemouse
Mouse cursor visibilityShow/hide cursor depending on current state-cursor
Joystick deadzone sizeDeadzone area for axes on joysticks/gamepads-joydeadzone
Paddle dejitter strengthStrenght of paddle input averaging (base) and reaction to fast paddle movements (diff)-dejitter.base, -dejitter.diff
(Analog paddle) SensitivitySensitivity of an analog paddle-psense
Analog paddle) Dejitter averagingStrength of paddle input averaging, suppresses mouse jitter-dejitter.base
(Analog paddle) Dejitter reactionStrength of paddle reaction to fast paddle movements, suppresses mouse jitter-dejitter.diff
Digital paddle sensitivitySensitivity used when emulating a paddle using a digital device-dsense
Mouse paddle sensitivitySensitivity used when emulating a paddle using a mouse-msense
Trackball sensitivitySensitivity used when emulating a trackball device using a mouse-tsense
Allow all 4 directions ...Allow all 4 joystick directions to be pressed simultaneously-joyallow4
Grab mouse ...Keep mouse in window in emulation mode
(only when used as controller)
- Note: The sensitivity may greatly vary when the mouse is not grabbed.
-grabmouse
Use modifier key combosEnable using modifier keys in keyboard actions-modcombo
Swap Stelladaptor portsSwap the order of the detected Stelladaptors/2600-daptors (see Advanced Configuration - Stelladaptor/2600-daptor Support)-saport
Joystick databaseShow all joysticks that Stella knows about, with the option to remove them 
+ +

Mouse settings can be configured under the 'Mouse' tab, shown below:

+ + + + + + +
     + + + + + + + + +
ItemBrief descriptionFor more information,
see CommandLine
Use mouse as ...Allow the mouse to emulate various controllers-usemouse
(Sensitivity) PaddleSensitivity used when emulating a paddle using a mouse-msense
(Sensitivity) TrackballSensitivity used when emulating a trackball device using a mouse-tsense
(Sensitivity) Driving controllerSensitivity used when emulating a driving controller device using a mouse-dcsense
Mouse cursor visibilityShow/hide cursor depending on current state-cursor
Grab mouse ...Keep mouse in window in emulation mode
(only when used as controller)
+ Note: The sensitivity may greatly vary when the mouse is not grabbed.
-grabmouse
+
+

ROM Launcher

@@ -3233,8 +3313,6 @@
- -
  • Show only ROM files: Selecting this reloads the current listing, showing only files that have a valid ROM extension.
  • @@ -3518,21 +3596,6 @@ 'Buffer size'. -plr.tm.horizon
    -dev.tm.horizon - - When entering/exiting emulation: - - Automatically save no, current or all Time Machine states when exiting emulation.
    - The latter also loads all states when entering emulation. When this is enabled, you - can always continue your game session from where you exited it. Even including the - Time Machine buffer! - - -saveonexit - - Automatically change... - - Automatically change to the next available save state slot after saving a ROM state file. - - -autoslot @@ -4032,6 +4095,16 @@ Ms Pac-Man (Stella extended codes): 'Console.SwapPorts'. The value must be Yes or No. + + Controller.PaddlesXCenter: + Defines the horizontal center of the paddles (range -10..30). + + + + Controller.PaddlesYCenter: + Defines the vertical center of the paddles (range -10..30). + + Controller.MouseAxis: Indicates how the mouse should emulate virtual controllers. From 1d45fbb5fa6007c7787fe65d9453cfcc3540e5d2 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:11:02 +0200 Subject: [PATCH 21/42] added missing screen shots --- docs/graphics/eventmapping_mouse.png | Bin 0 -> 3359 bytes docs/graphics/options_emulation.png | Bin 0 -> 3431 bytes docs/graphics/options_video_palettes.png | Bin 0 -> 7989 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/graphics/eventmapping_mouse.png create mode 100644 docs/graphics/options_emulation.png create mode 100644 docs/graphics/options_video_palettes.png diff --git a/docs/graphics/eventmapping_mouse.png b/docs/graphics/eventmapping_mouse.png new file mode 100644 index 0000000000000000000000000000000000000000..daac75b09f09c09507673d50da49878caa05717a GIT binary patch literal 3359 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 h1jX87X3m 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 I*`HVb2mfmGH2?qr literal 0 HcmV?d00001 From e4ac8df6f9f4b30ac448fc145ffe5cf8b0ae0b05 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 12 May 2020 16:12:03 +0200 Subject: [PATCH 22/42] removed audio dialog screenshot --- docs/graphics/options_audio.png | Bin 3879 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/graphics/options_audio.png diff --git a/docs/graphics/options_audio.png b/docs/graphics/options_audio.png deleted file mode 100644 index f37f07c6f33333eb2756b43a5e6fddaf2e48ad85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3879 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 From f0cee245f73086a1392b462166d45951b6524258 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 12 May 2020 11:51:55 -0230 Subject: [PATCH 23/42] libretro: Fixed #634. --- src/libretro/StellaLIBRETRO.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index 065917c15..e86709490 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -21,6 +21,7 @@ #include "FrameBufferLIBRETRO.hxx" #include "AtariNTSC.hxx" +#include "PaletteHandler.hxx" #include "AudioSettings.hxx" #include "Serializer.hxx" #include "StateManager.hxx" From 7ae0aff0626618e9d4230e587decbc46f86917a3 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 12 May 2020 13:52:33 -0230 Subject: [PATCH 24/42] Some more header file cleanups, hopefully resulting in faster compile times. --- src/common/JoyMap.hxx | 1 + src/common/RewindManager.cxx | 1 + src/common/SoundNull.hxx | 7 ++- src/common/SoundSDL2.hxx | 2 +- src/common/sdl_blitter/BilinearBlitter.cxx | 4 +- src/common/sdl_blitter/BilinearBlitter.hxx | 3 +- src/common/sdl_blitter/QisBlitter.cxx | 4 +- src/common/sdl_blitter/QisBlitter.hxx | 3 +- src/debugger/DebuggerParser.cxx | 1 + src/debugger/gui/CartARWidget.cxx | 1 + src/debugger/gui/CartCMWidget.cxx | 1 + src/debugger/gui/CartCTYWidget.cxx | 1 + src/debugger/gui/CartEnhancedWidget.cxx | 2 +- src/debugger/gui/CartEnhancedWidget.hxx | 1 + src/debugger/gui/ControllerWidget.hxx | 1 + src/debugger/gui/DataGridWidget.cxx | 1 + src/debugger/gui/DebuggerDialog.cxx | 2 + src/debugger/gui/PromptWidget.cxx | 1 + src/debugger/gui/RiotRamWidget.cxx | 1 + src/debugger/gui/RomListWidget.cxx | 1 + src/debugger/gui/RomWidget.cxx | 1 + src/emucore/AtariVox.cxx | 5 ++ src/emucore/AtariVox.hxx | 4 +- src/emucore/Cart.hxx | 9 ++- src/emucore/Cart3EPlus.hxx | 1 - src/emucore/Cart3EX.hxx | 57 ++++++++++--------- src/emucore/CartAR.cxx | 1 + src/emucore/CartDPC.cxx | 1 + src/emucore/CartDetector.cxx | 1 + src/emucore/CartDetector.hxx | 2 +- src/emucore/CompuMate.cxx | 3 + src/emucore/CompuMate.hxx | 7 ++- src/emucore/Console.cxx | 1 + src/emucore/ConsoleIO.hxx | 6 +- src/emucore/Control.hxx | 2 +- src/emucore/ControllerDetector.hxx | 2 + src/emucore/Device.hxx | 4 +- src/emucore/Joystick.hxx | 2 +- src/emucore/Keyboard.hxx | 2 +- src/emucore/Lightgun.hxx | 5 ++ src/emucore/PointingDevice.hxx | 1 - src/emucore/ProfilingRunner.cxx | 1 - src/emucore/ProfilingRunner.hxx | 17 +++--- src/emucore/Switches.hxx | 2 +- src/emucore/System.hxx | 3 +- src/emucore/tia/Audio.hxx | 4 +- src/emucore/tia/Background.hxx | 4 +- src/emucore/tia/Ball.hxx | 6 +- src/emucore/tia/DelayQueueIterator.hxx | 2 - src/emucore/tia/DelayQueueIteratorImpl.hxx | 1 - src/emucore/tia/DelayQueueMember.hxx | 2 +- src/emucore/tia/Missile.hxx | 6 +- src/emucore/tia/PaddleReader.hxx | 2 +- src/emucore/tia/Player.hxx | 4 +- src/emucore/tia/Playfield.hxx | 6 +- .../tia/frame-manager/FrameLayoutDetector.hxx | 2 +- src/gui/CommandMenu.cxx | 2 + src/gui/EditTextWidget.hxx | 1 - src/gui/EmulationDialog.cxx | 1 + src/gui/GuiObject.hxx | 1 - src/gui/InputDialog.hxx | 1 - src/gui/LauncherDialog.hxx | 4 +- src/gui/Menu.cxx | 1 + src/gui/MessageDialog.cxx | 1 + src/gui/MessageMenu.cxx | 1 + src/gui/RomAuditDialog.cxx | 1 + src/gui/SnapshotDialog.cxx | 1 + src/gui/StellaSettingsDialog.cxx | 6 ++ src/gui/StellaSettingsDialog.hxx | 4 +- src/gui/Widget.hxx | 6 +- src/libretro/SoundLIBRETRO.hxx | 1 - src/libretro/StellaLIBRETRO.cxx | 1 + 72 files changed, 148 insertions(+), 103 deletions(-) diff --git a/src/common/JoyMap.hxx b/src/common/JoyMap.hxx index 6448de1ff..e3cc7ff7a 100644 --- a/src/common/JoyMap.hxx +++ b/src/common/JoyMap.hxx @@ -19,6 +19,7 @@ #define CONTROLLERMAP_HXX #include + #include "Event.hxx" #include "EventHandlerConstants.hxx" diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx index d16bbd6c3..6bafbeeaa 100644 --- a/src/common/RewindManager.cxx +++ b/src/common/RewindManager.cxx @@ -18,6 +18,7 @@ #include #include "OSystem.hxx" +#include "Console.hxx" #include "Serializer.hxx" #include "StateManager.hxx" #include "TIA.hxx" diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index 87ba7736a..f2aafbff8 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -18,12 +18,13 @@ #ifndef SOUND_NULL_HXX #define SOUND_NULL_HXX +class OSystem; +class AudioQueue; +class EmulationTiming; + #include "bspf.hxx" #include "Logger.hxx" #include "Sound.hxx" -#include "OSystem.hxx" -#include "AudioQueue.hxx" -#include "EmulationTiming.hxx" /** This class implements a Null sound object, where-by sound generation diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index 85fb86031..613e6980d 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -24,12 +24,12 @@ class OSystem; class AudioQueue; class EmulationTiming; class AudioSettings; +class Resampler; #include "SDL_lib.hxx" #include "bspf.hxx" #include "Sound.hxx" -#include "audio/Resampler.hxx" /** This class implements the sound API for SDL. diff --git a/src/common/sdl_blitter/BilinearBlitter.cxx b/src/common/sdl_blitter/BilinearBlitter.cxx index bae05207c..295d8e8e2 100644 --- a/src/common/sdl_blitter/BilinearBlitter.cxx +++ b/src/common/sdl_blitter/BilinearBlitter.cxx @@ -15,9 +15,9 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "BilinearBlitter.hxx" - +#include "FrameBufferSDL2.hxx" #include "ThreadDebugging.hxx" +#include "BilinearBlitter.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BilinearBlitter::BilinearBlitter(FrameBufferSDL2& fb, bool interpolate) diff --git a/src/common/sdl_blitter/BilinearBlitter.hxx b/src/common/sdl_blitter/BilinearBlitter.hxx index e18cba6bf..84c550ad1 100644 --- a/src/common/sdl_blitter/BilinearBlitter.hxx +++ b/src/common/sdl_blitter/BilinearBlitter.hxx @@ -18,8 +18,9 @@ #ifndef BILINEAR_BLITTER_HXX #define BILINEAR_BLITTER_HXX +class FrameBufferSDL2; + #include "Blitter.hxx" -#include "FrameBufferSDL2.hxx" #include "SDL_lib.hxx" class BilinearBlitter : public Blitter { diff --git a/src/common/sdl_blitter/QisBlitter.cxx b/src/common/sdl_blitter/QisBlitter.cxx index 95d958565..c68c4bff9 100644 --- a/src/common/sdl_blitter/QisBlitter.cxx +++ b/src/common/sdl_blitter/QisBlitter.cxx @@ -15,9 +15,9 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "QisBlitter.hxx" - +#include "FrameBufferSDL2.hxx" #include "ThreadDebugging.hxx" +#include "QisBlitter.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - QisBlitter::QisBlitter(FrameBufferSDL2& fb) diff --git a/src/common/sdl_blitter/QisBlitter.hxx b/src/common/sdl_blitter/QisBlitter.hxx index 77ab2b51d..14ee84fcc 100644 --- a/src/common/sdl_blitter/QisBlitter.hxx +++ b/src/common/sdl_blitter/QisBlitter.hxx @@ -18,8 +18,9 @@ #ifndef QIS_BLITTER_HXX #define QIS_BLITTER_HXX +class FrameBufferSDL2; + #include "Blitter.hxx" -#include "FrameBufferSDL2.hxx" #include "SDL_lib.hxx" class QisBlitter : public Blitter { diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index da3b0bc5f..d6be07b68 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -30,6 +30,7 @@ #include "M6502.hxx" #include "Expression.hxx" #include "FSNode.hxx" +#include "OSystem.hxx" #include "Settings.hxx" #include "PromptWidget.hxx" #include "RomWidget.hxx" diff --git a/src/debugger/gui/CartARWidget.cxx b/src/debugger/gui/CartARWidget.cxx index aa552d78e..ec4c4037a 100644 --- a/src/debugger/gui/CartARWidget.cxx +++ b/src/debugger/gui/CartARWidget.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "CartAR.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "PopUpWidget.hxx" diff --git a/src/debugger/gui/CartCMWidget.cxx b/src/debugger/gui/CartCMWidget.cxx index 8fa72f0bb..e4d11ba55 100644 --- a/src/debugger/gui/CartCMWidget.cxx +++ b/src/debugger/gui/CartCMWidget.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "CartCM.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "RiotDebug.hxx" diff --git a/src/debugger/gui/CartCTYWidget.cxx b/src/debugger/gui/CartCTYWidget.cxx index 76230fa21..659fb9bea 100644 --- a/src/debugger/gui/CartCTYWidget.cxx +++ b/src/debugger/gui/CartCTYWidget.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartCTY.hxx" diff --git a/src/debugger/gui/CartEnhancedWidget.cxx b/src/debugger/gui/CartEnhancedWidget.cxx index d955a803a..0bf38f529 100644 --- a/src/debugger/gui/CartEnhancedWidget.cxx +++ b/src/debugger/gui/CartEnhancedWidget.cxx @@ -15,8 +15,8 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ - #include "PopUpWidget.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartEnhanced.hxx" diff --git a/src/debugger/gui/CartEnhancedWidget.hxx b/src/debugger/gui/CartEnhancedWidget.hxx index 968a4bbf0..a367e8def 100644 --- a/src/debugger/gui/CartEnhancedWidget.hxx +++ b/src/debugger/gui/CartEnhancedWidget.hxx @@ -25,6 +25,7 @@ namespace GUI { class Font; } +#include "Variant.hxx" #include "CartDebugWidget.hxx" class CartridgeEnhancedWidget : public CartDebugWidget diff --git a/src/debugger/gui/ControllerWidget.hxx b/src/debugger/gui/ControllerWidget.hxx index e552be284..d14c1ba69 100644 --- a/src/debugger/gui/ControllerWidget.hxx +++ b/src/debugger/gui/ControllerWidget.hxx @@ -23,6 +23,7 @@ class ButtonWidget; #include "Font.hxx" #include "Widget.hxx" +#include "OSystem.hxx" #include "Console.hxx" #include "Command.hxx" #include "ControlLowLevel.hxx" diff --git a/src/debugger/gui/DataGridWidget.cxx b/src/debugger/gui/DataGridWidget.cxx index 6b663609c..719eebef2 100644 --- a/src/debugger/gui/DataGridWidget.cxx +++ b/src/debugger/gui/DataGridWidget.cxx @@ -18,6 +18,7 @@ #include "Widget.hxx" #include "Dialog.hxx" #include "Font.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" diff --git a/src/debugger/gui/DebuggerDialog.cxx b/src/debugger/gui/DebuggerDialog.cxx index f62df7724..6674311f6 100644 --- a/src/debugger/gui/DebuggerDialog.cxx +++ b/src/debugger/gui/DebuggerDialog.cxx @@ -47,6 +47,8 @@ #include "OptionsDialog.hxx" #include "StateManager.hxx" #include "FrameManager.hxx" +#include "OSystem.hxx" +#include "Console.hxx" #include "DebuggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/PromptWidget.cxx b/src/debugger/gui/PromptWidget.cxx index b803adc17..eb27f5258 100644 --- a/src/debugger/gui/PromptWidget.cxx +++ b/src/debugger/gui/PromptWidget.cxx @@ -20,6 +20,7 @@ #include "Font.hxx" #include "StellaKeys.hxx" #include "Version.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "DebuggerDialog.hxx" #include "DebuggerParser.hxx" diff --git a/src/debugger/gui/RiotRamWidget.cxx b/src/debugger/gui/RiotRamWidget.cxx index 2666182ec..5f3d5c0ab 100644 --- a/src/debugger/gui/RiotRamWidget.cxx +++ b/src/debugger/gui/RiotRamWidget.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" diff --git a/src/debugger/gui/RomListWidget.cxx b/src/debugger/gui/RomListWidget.cxx index 64ca2df9d..6e450e334 100644 --- a/src/debugger/gui/RomListWidget.cxx +++ b/src/debugger/gui/RomListWidget.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "bspf.hxx" +#include "OSystem.hxx" #include "Debugger.hxx" #include "DiStella.hxx" #include "Widget.hxx" diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index 3279ca5d9..bf459d8f7 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Settings.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" diff --git a/src/emucore/AtariVox.cxx b/src/emucore/AtariVox.cxx index 3314ac08c..700789352 100644 --- a/src/emucore/AtariVox.cxx +++ b/src/emucore/AtariVox.cxx @@ -36,6 +36,11 @@ AtariVox::AtariVox(Jack jack, const Event& event, const System& system, setPin(DigitalPin::Four, true); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AtariVox::~AtariVox() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AtariVox::read(DigitalPin pin) { diff --git a/src/emucore/AtariVox.hxx b/src/emucore/AtariVox.hxx index b21ec38b0..e0c2e72c7 100644 --- a/src/emucore/AtariVox.hxx +++ b/src/emucore/AtariVox.hxx @@ -19,10 +19,10 @@ #define ATARIVOX_HXX class OSystem; +class SerialPort; #include "Control.hxx" #include "SaveKey.hxx" -#include "SerialPort.hxx" /** Richard Hutchinson's AtariVox "controller": A speech synthesizer and @@ -49,7 +49,7 @@ class AtariVox : public SaveKey AtariVox(Jack jack, const Event& event, const System& system, const string& portname, const string& eepromfile, const onMessageCallback& callback); - virtual ~AtariVox() = default; + virtual ~AtariVox(); public: using Controller::read; diff --git a/src/emucore/Cart.hxx b/src/emucore/Cart.hxx index 6fbf1a68d..b04a95f10 100644 --- a/src/emucore/Cart.hxx +++ b/src/emucore/Cart.hxx @@ -23,15 +23,18 @@ class Properties; class CartDebugWidget; class CartRamWidget; class GuiObject; +class Settings; + +#include #include "bspf.hxx" #include "Device.hxx" -#include "Settings.hxx" #ifdef DEBUGGER_SUPPORT - #include "Font.hxx" + namespace GUI { + class Font; + } #endif - /** A cartridge is a device which contains the machine code for a game and handles any bankswitching performed by the cartridge. diff --git a/src/emucore/Cart3EPlus.hxx b/src/emucore/Cart3EPlus.hxx index c2ce64cd8..fe6a0a263 100644 --- a/src/emucore/Cart3EPlus.hxx +++ b/src/emucore/Cart3EPlus.hxx @@ -24,7 +24,6 @@ class System; #include "Cart3E.hxx" #ifdef DEBUGGER_SUPPORT -class Cartridge3EPlusWidget; #include "Cart3EPlusWidget.hxx" #endif diff --git a/src/emucore/Cart3EX.hxx b/src/emucore/Cart3EX.hxx index 7df53593e..c949a0c9c 100644 --- a/src/emucore/Cart3EX.hxx +++ b/src/emucore/Cart3EX.hxx @@ -19,7 +19,9 @@ #define CARTRIDGE3EX_HXX class System; +class Settings; +#include "bspf.hxx" #include "Cart3E.hxx" /** @@ -30,39 +32,38 @@ class System; class Cartridge3EX : public Cartridge3E { + public: + /** + Create a new cartridge using the specified image and size -public: - /** - Create a new cartridge using the specified image and size + @param image Pointer to the ROM image + @param size The size of the ROM image + @param md5 The md5sum of the ROM image + @param settings A reference to the various settings (read-only) + */ + Cartridge3EX(const ByteBuffer& image, size_t size, const string& md5, + const Settings& settings); + virtual ~Cartridge3EX() = default; - @param image Pointer to the ROM image - @param size The size of the ROM image - @param md5 The md5sum of the ROM image - @param settings A reference to the various settings (read-only) - */ - Cartridge3EX(const ByteBuffer& image, size_t size, const string& md5, - const Settings& settings); - virtual ~Cartridge3EX() = default; + public: + /** + Get a descriptor for the device name (used in error checking). -public: - /** - Get a descriptor for the device name (used in error checking). + @return The name of the object + */ + string name() const override { return "Cartridge3EX"; } - @return The name of the object - */ - string name() const override { return "Cartridge3EX"; } + private: + // RAM size + static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 256K = 0x40000; -private: - // RAM size - static constexpr size_t RAM_SIZE = RAM_BANKS << (BANK_SHIFT - 1); // = 256K = 0x40000; - -private: - // Following constructors and assignment operators not supported - Cartridge3EX() = delete; - Cartridge3EX(const Cartridge3EX&) = delete; - Cartridge3EX(Cartridge3EX&&) = delete; - Cartridge3EX& operator=(const Cartridge3EX&) = delete; - Cartridge3EX& operator=(Cartridge3EX&&) = delete; + private: + // Following constructors and assignment operators not supported + Cartridge3EX() = delete; + Cartridge3EX(const Cartridge3EX&) = delete; + Cartridge3EX(Cartridge3EX&&) = delete; + Cartridge3EX& operator=(const Cartridge3EX&) = delete; + Cartridge3EX& operator=(Cartridge3EX&&) = delete; }; #endif diff --git a/src/emucore/CartAR.cxx b/src/emucore/CartAR.cxx index 2d8b204b6..a0eea7486 100644 --- a/src/emucore/CartAR.cxx +++ b/src/emucore/CartAR.cxx @@ -17,6 +17,7 @@ #include "M6502.hxx" #include "System.hxx" +#include "Settings.hxx" #include "CartAR.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDPC.cxx b/src/emucore/CartDPC.cxx index 481e385be..bc8962b1b 100644 --- a/src/emucore/CartDPC.cxx +++ b/src/emucore/CartDPC.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "Settings.hxx" #include "System.hxx" #include "AudioSettings.hxx" #include "CartDPC.hxx" diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 6c68bf6e4..976d56579 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -62,6 +62,7 @@ #include "MD5.hxx" #include "Props.hxx" #include "Logger.hxx" +#include "OSystem.hxx" #include "CartDetector.hxx" diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index 706731b0f..9ff193c87 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -20,10 +20,10 @@ class Cartridge; class Properties; +class Settings; #include "Bankswitch.hxx" #include "bspf.hxx" -#include "Settings.hxx" /** Auto-detect cart type based on various attributes (file size, signatures, diff --git a/src/emucore/CompuMate.cxx b/src/emucore/CompuMate.cxx index b39e46ab4..a3a0367cc 100644 --- a/src/emucore/CompuMate.cxx +++ b/src/emucore/CompuMate.cxx @@ -15,6 +15,9 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "Console.hxx" +#include "Event.hxx" +#include "System.hxx" #include "CompuMate.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CompuMate.hxx b/src/emucore/CompuMate.hxx index ff0e0f781..8b8d772e8 100644 --- a/src/emucore/CompuMate.hxx +++ b/src/emucore/CompuMate.hxx @@ -18,11 +18,12 @@ #ifndef COMPUMATE_HXX #define COMPUMATE_HXX +class Console; +class Event; +class System; + #include "bspf.hxx" -#include "CartCM.hxx" #include "Control.hxx" -#include "Event.hxx" -#include "Console.hxx" /** Handler for SpectraVideo CompuMate bankswitched games. diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index bf7d20abf..dda0c9fdd 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -24,6 +24,7 @@ #include "Cart.hxx" #include "Control.hxx" #include "Cart.hxx" +#include "CartCM.hxx" #include "Driving.hxx" #include "Event.hxx" #include "EventHandler.hxx" diff --git a/src/emucore/ConsoleIO.hxx b/src/emucore/ConsoleIO.hxx index d8ae106a6..2fde50ed8 100644 --- a/src/emucore/ConsoleIO.hxx +++ b/src/emucore/ConsoleIO.hxx @@ -15,12 +15,12 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ -#include "Control.hxx" -#include "Switches.hxx" - #ifndef CONSOLE_IO_HXX #define CONSOLE_IO_HXX +class Controller; +class Switches; + class ConsoleIO { public: diff --git a/src/emucore/Control.hxx b/src/emucore/Control.hxx index 3647d1bc0..a670f39f6 100644 --- a/src/emucore/Control.hxx +++ b/src/emucore/Control.hxx @@ -25,8 +25,8 @@ class System; #include -#include "Serializable.hxx" #include "bspf.hxx" +#include "Serializable.hxx" /** A controller is a device that plugs into either the left or right diff --git a/src/emucore/ControllerDetector.hxx b/src/emucore/ControllerDetector.hxx index 737ea36f2..d37076eb1 100644 --- a/src/emucore/ControllerDetector.hxx +++ b/src/emucore/ControllerDetector.hxx @@ -18,6 +18,8 @@ #ifndef CONTROLLER_DETECTOR_HXX #define CONTROLLER_DETECTOR_HXX +class Settings; + #include "Control.hxx" /** diff --git a/src/emucore/Device.hxx b/src/emucore/Device.hxx index 7c175852b..fb2423a35 100644 --- a/src/emucore/Device.hxx +++ b/src/emucore/Device.hxx @@ -20,9 +20,9 @@ class System; -#include "Console.hxx" -#include "Serializable.hxx" #include "bspf.hxx" +#include "ConsoleTiming.hxx" +#include "Serializable.hxx" /** Abstract base class for devices which can be attached to a 6502 diff --git a/src/emucore/Joystick.hxx b/src/emucore/Joystick.hxx index 7acd631bc..505294456 100644 --- a/src/emucore/Joystick.hxx +++ b/src/emucore/Joystick.hxx @@ -19,8 +19,8 @@ #define JOYSTICK_HXX #include "bspf.hxx" -#include "Control.hxx" #include "Event.hxx" +#include "Control.hxx" /** The standard Atari 2600 joystick controller. diff --git a/src/emucore/Keyboard.hxx b/src/emucore/Keyboard.hxx index a241cbc37..9ec176d71 100644 --- a/src/emucore/Keyboard.hxx +++ b/src/emucore/Keyboard.hxx @@ -19,8 +19,8 @@ #define KEYBOARD_HXX #include "bspf.hxx" -#include "Control.hxx" #include "Event.hxx" +#include "Control.hxx" /** The standard Atari 2600 keyboard controller diff --git a/src/emucore/Lightgun.hxx b/src/emucore/Lightgun.hxx index 7bec4f4e2..facdffe1e 100644 --- a/src/emucore/Lightgun.hxx +++ b/src/emucore/Lightgun.hxx @@ -18,6 +18,11 @@ #ifndef LIGHTGUN_HXX #define LIGHTGUN_HXX +class FrameBuffer; + +#include "bspf.hxx" +#include "Control.hxx" + /** This class handles the lightgun controller diff --git a/src/emucore/PointingDevice.hxx b/src/emucore/PointingDevice.hxx index 4f0a007b5..11b9fcd2d 100644 --- a/src/emucore/PointingDevice.hxx +++ b/src/emucore/PointingDevice.hxx @@ -18,7 +18,6 @@ #ifndef POINTING_DEVICE_HXX #define POINTING_DEVICE_HXX -class Controller; class Event; #include "Control.hxx" diff --git a/src/emucore/ProfilingRunner.cxx b/src/emucore/ProfilingRunner.cxx index f561dc7a1..e7d81b997 100644 --- a/src/emucore/ProfilingRunner.cxx +++ b/src/emucore/ProfilingRunner.cxx @@ -54,7 +54,6 @@ namespace { } } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ProfilingRunner::ProfilingRunner(int argc, char* argv[]) : profilingRuns(std::max(argc - 2, 0)) diff --git a/src/emucore/ProfilingRunner.hxx b/src/emucore/ProfilingRunner.hxx index 1194cfdda..a3523b98f 100644 --- a/src/emucore/ProfilingRunner.hxx +++ b/src/emucore/ProfilingRunner.hxx @@ -18,10 +18,9 @@ #ifndef PROFILING_RUNNER #define PROFILING_RUNNER -class Control; -class Switches; - #include "bspf.hxx" +#include "Control.hxx" +#include "Switches.hxx" #include "Settings.hxx" #include "ConsoleIO.hxx" #include "Props.hxx" @@ -41,13 +40,13 @@ class ProfilingRunner { }; struct IO: public ConsoleIO { - Controller& leftController() const override { return *myLeftControl; } - Controller& rightController() const override { return *myRightControl; } - Switches& switches() const override { return *mySwitches; } + Controller& leftController() const override { return *myLeftControl; } + Controller& rightController() const override { return *myRightControl; } + Switches& switches() const override { return *mySwitches; } - unique_ptr myLeftControl; - unique_ptr myRightControl; - unique_ptr mySwitches; + unique_ptr myLeftControl; + unique_ptr myRightControl; + unique_ptr mySwitches; }; private: diff --git a/src/emucore/Switches.hxx b/src/emucore/Switches.hxx index fb7ae4539..16c4dba74 100644 --- a/src/emucore/Switches.hxx +++ b/src/emucore/Switches.hxx @@ -22,8 +22,8 @@ class Event; class Properties; class Settings; -#include "Serializable.hxx" #include "bspf.hxx" +#include "Serializable.hxx" /** This class represents the console switches of the game console. diff --git a/src/emucore/System.hxx b/src/emucore/System.hxx index 1c36acf53..dab87b28a 100644 --- a/src/emucore/System.hxx +++ b/src/emucore/System.hxx @@ -18,11 +18,10 @@ #ifndef SYSTEM_HXX #define SYSTEM_HXX -class Device; class M6502; class M6532; class TIA; -class NullDevice; +class Cartridge; #include "bspf.hxx" #include "Device.hxx" diff --git a/src/emucore/tia/Audio.hxx b/src/emucore/tia/Audio.hxx index 92e854a0d..5ab53ecae 100644 --- a/src/emucore/tia/Audio.hxx +++ b/src/emucore/tia/Audio.hxx @@ -18,12 +18,12 @@ #ifndef TIA_AUDIO_HXX #define TIA_AUDIO_HXX +class AudioQueue; + #include "bspf.hxx" #include "AudioChannel.hxx" #include "Serializable.hxx" -class AudioQueue; - class Audio : public Serializable { public: diff --git a/src/emucore/tia/Background.hxx b/src/emucore/tia/Background.hxx index 3004c7978..ea84aed96 100644 --- a/src/emucore/tia/Background.hxx +++ b/src/emucore/tia/Background.hxx @@ -18,11 +18,11 @@ #ifndef TIA_BACKGROUND #define TIA_BACKGROUND +class TIA; + #include "Serializable.hxx" #include "bspf.hxx" -class TIA; - class Background : public Serializable { public: diff --git a/src/emucore/tia/Ball.hxx b/src/emucore/tia/Ball.hxx index 5b9b3a604..0a40250e2 100644 --- a/src/emucore/tia/Ball.hxx +++ b/src/emucore/tia/Ball.hxx @@ -18,11 +18,11 @@ #ifndef TIA_BALL #define TIA_BALL -#include "Serializable.hxx" +class TIA; + #include "bspf.hxx" #include "TIAConstants.hxx" - -class TIA; +#include "Serializable.hxx" class Ball : public Serializable { diff --git a/src/emucore/tia/DelayQueueIterator.hxx b/src/emucore/tia/DelayQueueIterator.hxx index 31e5251e8..3b615e3d4 100644 --- a/src/emucore/tia/DelayQueueIterator.hxx +++ b/src/emucore/tia/DelayQueueIterator.hxx @@ -19,8 +19,6 @@ #define TIA_DELAY_QUEUE_ITERATOR #include "bspf.hxx" -#include "DelayQueue.hxx" -#include "DelayQueueMember.hxx" class DelayQueueIterator { diff --git a/src/emucore/tia/DelayQueueIteratorImpl.hxx b/src/emucore/tia/DelayQueueIteratorImpl.hxx index b556cb279..9f9e4d4c7 100644 --- a/src/emucore/tia/DelayQueueIteratorImpl.hxx +++ b/src/emucore/tia/DelayQueueIteratorImpl.hxx @@ -20,7 +20,6 @@ #include "bspf.hxx" #include "DelayQueue.hxx" -#include "DelayQueueMember.hxx" #include "DelayQueueIterator.hxx" template diff --git a/src/emucore/tia/DelayQueueMember.hxx b/src/emucore/tia/DelayQueueMember.hxx index f87c9b459..653167b6f 100644 --- a/src/emucore/tia/DelayQueueMember.hxx +++ b/src/emucore/tia/DelayQueueMember.hxx @@ -18,8 +18,8 @@ #ifndef TIA_DELAY_QUEUE_MEMBER #define TIA_DELAY_QUEUE_MEMBER -#include "Serializable.hxx" #include "bspf.hxx" +#include "Serializable.hxx" template class DelayQueueMember : public Serializable { diff --git a/src/emucore/tia/Missile.hxx b/src/emucore/tia/Missile.hxx index dda9b493c..cd5cce582 100644 --- a/src/emucore/tia/Missile.hxx +++ b/src/emucore/tia/Missile.hxx @@ -18,13 +18,13 @@ #ifndef TIA_MISSILE #define TIA_MISSILE +class TIA; +class Player; + #include "Serializable.hxx" #include "bspf.hxx" -#include "Player.hxx" #include "TIAConstants.hxx" -class TIA; - class Missile : public Serializable { public: diff --git a/src/emucore/tia/PaddleReader.hxx b/src/emucore/tia/PaddleReader.hxx index abbc013c6..8071617c6 100644 --- a/src/emucore/tia/PaddleReader.hxx +++ b/src/emucore/tia/PaddleReader.hxx @@ -20,7 +20,7 @@ #include "bspf.hxx" #include "Serializable.hxx" -#include "Console.hxx" +#include "ConsoleTiming.hxx" class PaddleReader : public Serializable { diff --git a/src/emucore/tia/Player.hxx b/src/emucore/tia/Player.hxx index 454bfcd9f..60dfbe3c5 100644 --- a/src/emucore/tia/Player.hxx +++ b/src/emucore/tia/Player.hxx @@ -18,12 +18,12 @@ #ifndef TIA_PLAYER #define TIA_PLAYER +class TIA; + #include "bspf.hxx" #include "Serializable.hxx" #include "TIAConstants.hxx" -class TIA; - class Player : public Serializable { public: diff --git a/src/emucore/tia/Playfield.hxx b/src/emucore/tia/Playfield.hxx index fe811d53a..4a1376991 100644 --- a/src/emucore/tia/Playfield.hxx +++ b/src/emucore/tia/Playfield.hxx @@ -18,11 +18,11 @@ #ifndef TIA_PLAYFIELD #define TIA_PLAYFIELD -#include "Serializable.hxx" +class TIA; + #include "bspf.hxx" #include "TIAConstants.hxx" - -class TIA; +#include "Serializable.hxx" class Playfield : public Serializable { diff --git a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx index fa7e50308..443b9c20c 100644 --- a/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx +++ b/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx @@ -18,8 +18,8 @@ #ifndef TIA_FRAME_LAYOUT_DETECTOR #define TIA_FRAME_LAYOUT_DETECTOR -#include "AbstractFrameManager.hxx" #include "FrameLayout.hxx" +#include "AbstractFrameManager.hxx" /** * This frame manager performs frame layout autodetection. It counts the scanlines diff --git a/src/gui/CommandMenu.cxx b/src/gui/CommandMenu.cxx index 68e9a0fef..1a6708f71 100644 --- a/src/gui/CommandMenu.cxx +++ b/src/gui/CommandMenu.cxx @@ -16,6 +16,8 @@ //============================================================================ #include "Dialog.hxx" +#include "OSystem.hxx" +#include "Settings.hxx" #include "CommandDialog.hxx" #include "MinUICommandDialog.hxx" #include "CommandMenu.hxx" diff --git a/src/gui/EditTextWidget.hxx b/src/gui/EditTextWidget.hxx index f752ae385..c7a346804 100644 --- a/src/gui/EditTextWidget.hxx +++ b/src/gui/EditTextWidget.hxx @@ -21,7 +21,6 @@ #include "Rect.hxx" #include "EditableWidget.hxx" - /* EditTextWidget */ class EditTextWidget : public EditableWidget { diff --git a/src/gui/EmulationDialog.cxx b/src/gui/EmulationDialog.cxx index ad86e2e60..e9bb3804a 100644 --- a/src/gui/EmulationDialog.cxx +++ b/src/gui/EmulationDialog.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Console.hxx" #include "FrameBuffer.hxx" #include "RadioButtonWidget.hxx" diff --git a/src/gui/GuiObject.hxx b/src/gui/GuiObject.hxx index 3f473867b..fc8f77285 100644 --- a/src/gui/GuiObject.hxx +++ b/src/gui/GuiObject.hxx @@ -27,7 +27,6 @@ class Widget; class OSystem; #include "Command.hxx" -#include "OSystem.hxx" #include "Vec.hxx" using WidgetArray = vector; diff --git a/src/gui/InputDialog.hxx b/src/gui/InputDialog.hxx index 1c8c04367..48e1629a3 100644 --- a/src/gui/InputDialog.hxx +++ b/src/gui/InputDialog.hxx @@ -62,7 +62,6 @@ class InputDialog : public Dialog void addDevicePortTab(); void addMouseTab(); - void handleMouseControlState(); void handleCursorState(); void updateDejitterAveraging(); diff --git a/src/gui/LauncherDialog.hxx b/src/gui/LauncherDialog.hxx index bfa0cecba..faeea2598 100644 --- a/src/gui/LauncherDialog.hxx +++ b/src/gui/LauncherDialog.hxx @@ -32,6 +32,9 @@ class EditTextWidget; class FileListWidget; class RomInfoWidget; class StaticTextWidget; +namespace Common { + struct Size; +} namespace GUI { class MessageBox; } @@ -41,7 +44,6 @@ namespace GUI { #include "bspf.hxx" #include "Dialog.hxx" #include "FSNode.hxx" -#include "Stack.hxx" class LauncherDialog : public Dialog { diff --git a/src/gui/Menu.cxx b/src/gui/Menu.cxx index c2976857f..547f8e2ac 100644 --- a/src/gui/Menu.cxx +++ b/src/gui/Menu.cxx @@ -19,6 +19,7 @@ #include "FrameBufferConstants.hxx" #include "OptionsDialog.hxx" #include "StellaSettingsDialog.hxx" +#include "OSystem.hxx" #include "FrameBuffer.hxx" #include "bspf.hxx" #include "Menu.hxx" diff --git a/src/gui/MessageDialog.cxx b/src/gui/MessageDialog.cxx index d00acc5a5..ca52c99e6 100644 --- a/src/gui/MessageDialog.cxx +++ b/src/gui/MessageDialog.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Console.hxx" #include "EventHandler.hxx" #include "Font.hxx" diff --git a/src/gui/MessageMenu.cxx b/src/gui/MessageMenu.cxx index f7c7f0faa..19b700ae7 100644 --- a/src/gui/MessageMenu.cxx +++ b/src/gui/MessageMenu.cxx @@ -16,6 +16,7 @@ //============================================================================ #include "Dialog.hxx" +#include "OSystem.hxx" #include "FrameBuffer.hxx" #include "MessageDialog.hxx" #include "MessageMenu.hxx" diff --git a/src/gui/RomAuditDialog.cxx b/src/gui/RomAuditDialog.cxx index 890da7e95..58b9acaba 100644 --- a/src/gui/RomAuditDialog.cxx +++ b/src/gui/RomAuditDialog.cxx @@ -25,6 +25,7 @@ #include "FSNode.hxx" #include "Font.hxx" #include "MessageBox.hxx" +#include "OSystem.hxx" #include "FrameBuffer.hxx" #include "MD5.hxx" #include "Props.hxx" diff --git a/src/gui/SnapshotDialog.cxx b/src/gui/SnapshotDialog.cxx index 2c0534ffa..870a82b54 100644 --- a/src/gui/SnapshotDialog.cxx +++ b/src/gui/SnapshotDialog.cxx @@ -21,6 +21,7 @@ #include "FSNode.hxx" #include "Font.hxx" #include "LauncherDialog.hxx" +#include "OSystem.hxx" #include "Settings.hxx" #include "SnapshotDialog.hxx" diff --git a/src/gui/StellaSettingsDialog.cxx b/src/gui/StellaSettingsDialog.cxx index fbd93dc7d..b5c1e5106 100644 --- a/src/gui/StellaSettingsDialog.cxx +++ b/src/gui/StellaSettingsDialog.cxx @@ -15,6 +15,7 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ +#include "OSystem.hxx" #include "Console.hxx" #include "EventHandler.hxx" #include "Launcher.hxx" @@ -88,6 +89,11 @@ StellaSettingsDialog::StellaSettingsDialog(OSystem& osystem, DialogContainer& pa addToFocusList(wid); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +StellaSettingsDialog::~StellaSettingsDialog() +{ +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StellaSettingsDialog::addUIOptions(WidgetArray& wid, int& xpos, int& ypos) { diff --git a/src/gui/StellaSettingsDialog.hxx b/src/gui/StellaSettingsDialog.hxx index 791db381c..6f7cfe8a8 100644 --- a/src/gui/StellaSettingsDialog.hxx +++ b/src/gui/StellaSettingsDialog.hxx @@ -23,7 +23,6 @@ class PopUpWidget; #include "Props.hxx" #include "Menu.hxx" #include "Dialog.hxx" -#include "MessageBox.hxx" #if defined(RETRON77) #include "R77HelpDialog.hxx" @@ -33,6 +32,7 @@ class PopUpWidget; namespace GUI { class Font; + class MessageBox; } class StellaSettingsDialog : public Dialog @@ -40,7 +40,7 @@ class StellaSettingsDialog : public Dialog public: StellaSettingsDialog(OSystem& osystem, DialogContainer& parent, int max_w, int max_h, Menu::AppMode mode); - virtual ~StellaSettingsDialog() = default; + virtual ~StellaSettingsDialog(); private: void loadConfig() override; diff --git a/src/gui/Widget.hxx b/src/gui/Widget.hxx index c2a0b6b65..b20b8b159 100644 --- a/src/gui/Widget.hxx +++ b/src/gui/Widget.hxx @@ -23,14 +23,12 @@ class Dialog; -namespace GUI { - class Font; -} - #include #include "bspf.hxx" #include "Event.hxx" +#include "EventHandlerConstants.hxx" +#include "FrameBufferConstants.hxx" #include "StellaKeys.hxx" #include "GuiObject.hxx" #include "Font.hxx" diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index 9709e4b3d..aa98780e1 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -27,7 +27,6 @@ class AudioSettings; #include "bspf.hxx" #include "Sound.hxx" -#include "AudioQueue.hxx" /** This class implements the sound API for LIBRTRO. diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index e86709490..0759f9349 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -23,6 +23,7 @@ #include "AtariNTSC.hxx" #include "PaletteHandler.hxx" #include "AudioSettings.hxx" +#include "PaletteHandler.hxx" #include "Serializer.hxx" #include "StateManager.hxx" #include "Switches.hxx" From 1fbd774323396f10da5ae6e09eb52e1d4ad5673f Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Tue, 12 May 2020 14:00:08 -0230 Subject: [PATCH 25/42] libretro: Remove redundant code. --- src/libretro/StellaLIBRETRO.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libretro/StellaLIBRETRO.cxx b/src/libretro/StellaLIBRETRO.cxx index 0759f9349..d670c45a9 100644 --- a/src/libretro/StellaLIBRETRO.cxx +++ b/src/libretro/StellaLIBRETRO.cxx @@ -23,14 +23,12 @@ #include "AtariNTSC.hxx" #include "PaletteHandler.hxx" #include "AudioSettings.hxx" -#include "PaletteHandler.hxx" #include "Serializer.hxx" #include "StateManager.hxx" #include "Switches.hxx" #include "TIA.hxx" #include "TIASurface.hxx" - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StellaLIBRETRO::StellaLIBRETRO() { From e7b99f7cecc8f942ddb32fd8b167e40a7fdec68a Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 09:25:22 +0200 Subject: [PATCH 26/42] update default keys and doc for palette adjustments --- docs/index.html | 132 +++++++++++++++++--------------- src/common/PKeyboardHandler.cxx | 16 ++-- 2 files changed, 78 insertions(+), 70 deletions(-) diff --git a/docs/index.html b/docs/index.html index b2da54d33..246b84390 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1336,6 +1336,52 @@ +

    Palettes (can be remapped, only active in TIA mode)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FunctionKey (Standard)Key (macOS)
    Select previous palette (Standard/Z26/User/Custom)Shift-Control + pShift-Control + p
    Select next palette (Standard/Z26/User/Custom)Control + pControl + p
    Select previous palette attributeShift-Alt + 9Shift-Cmd + 9
    Select next palette attributeAlt + 9Cmd + 9
    Decrease selected palette attributeShift-Alt + 0Shift-Cmd + 0
    Increase selected palette attributeAlt + 0Cmd + 0
    +

    TV effects (can be remapped, only active in TIA mode)

    @@ -1345,54 +1391,34 @@ - + + + + + + - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + @@ -1403,25 +1429,25 @@ - - + + - - + + - - + + - - + + @@ -1614,24 +1640,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 9384d3232..e30bff52f 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -481,15 +481,15 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::NextAttribute, KBDK_2, MOD3}, {Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3}, {Event::IncreaseAttribute, KBDK_3, MOD3}, - {Event::PreviousPaletteAttribute, KBDK_4, KBDM_SHIFT | MOD3}, - {Event::NextPaletteAttribute, KBDK_4, MOD3}, - {Event::PaletteAttributeDecrease, KBDK_5, KBDM_SHIFT | MOD3}, - {Event::PaletteAttributeIncrease, KBDK_5, MOD3}, - {Event::PhosphorDecrease, KBDK_9, KBDM_SHIFT | MOD3}, - {Event::PhosphorIncrease, KBDK_9, MOD3}, + {Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3}, + {Event::PhosphorIncrease, KBDK_4, MOD3}, {Event::TogglePhosphor, KBDK_P, MOD3}, - {Event::ScanlinesDecrease, KBDK_0, KBDM_SHIFT | MOD3}, - {Event::ScanlinesIncrease, KBDK_0, MOD3}, + {Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3}, + {Event::ScanlinesIncrease, KBDK_5, MOD3}, + {Event::PreviousPaletteAttribute, KBDK_9, KBDM_SHIFT | MOD3}, + {Event::NextPaletteAttribute, KBDK_9, MOD3}, + {Event::PaletteAttributeDecrease, KBDK_0, KBDM_SHIFT | MOD3}, + {Event::PaletteAttributeIncrease, KBDK_0, MOD3}, {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, From 020dea9cc801cd45fcdd141610789aa436dc9cb5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 09:32:11 +0200 Subject: [PATCH 27/42] added UI messages with gauge bars for variable values (partially addresses #631) --- src/common/PaletteHandler.cxx | 19 ++-- src/common/SoundSDL2.cxx | 12 +-- src/common/tv_filters/NTSCFilter.cxx | 34 ++----- src/common/tv_filters/NTSCFilter.hxx | 3 +- src/emucore/Console.cxx | 109 ++++++---------------- src/emucore/Console.hxx | 16 ++-- src/emucore/EventHandler.cxx | 38 ++++---- src/emucore/FrameBuffer.cxx | 130 ++++++++++++++++++++++----- src/emucore/FrameBuffer.hxx | 29 ++++-- src/emucore/TIASurface.cxx | 14 +-- src/gui/CommandDialog.cxx | 2 +- src/gui/MinUICommandDialog.cxx | 2 +- 12 files changed, 211 insertions(+), 197 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 70867d116..b0e4eea2d 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -144,11 +144,10 @@ void PaletteHandler::changeAdjustable(bool increase) *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); - ostringstream buf; - buf << "Custom '" << myAdjustables[myCurrentAdjustable].name - << "' set to " << newVal << "%"; - - myOSystem.frameBuffer().showMessage(buf.str()); + ostringstream msg, val; + msg << "Palette " << myAdjustables[myCurrentAdjustable].name; + val << newVal << "%"; + myOSystem.frameBuffer().showMessage(msg.str(), val.str(), newVal); setPalette(); } } @@ -179,11 +178,11 @@ void PaletteHandler::changeColorPhaseShift(bool increase) generateCustomPalette(timing); setPalette(SETTING_CUSTOM); - ostringstream ss; - ss << "Color phase shift at " - << std::fixed << std::setprecision(1) << newPhase << DEGREE; - - myOSystem.frameBuffer().showMessage(ss.str()); + ostringstream val; + val << std::fixed << std::setprecision(1) << newPhase << DEGREE; + myOSystem.frameBuffer().showMessage("Palette phase shift", val.str(), newPhase, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); } } diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 671e5f83c..c32189e95 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -217,7 +217,6 @@ void SoundSDL2::setVolume(uInt32 percent) void SoundSDL2::adjustVolume(Int8 direction) { ostringstream strval; - string message; Int32 percent = myVolume; @@ -225,9 +224,7 @@ void SoundSDL2::adjustVolume(Int8 direction) percent -= 2; else if(direction == 1) percent += 2; - - if((percent < 0) || (percent > 100)) - return; + percent = BSPF::clamp(percent, 0, 100); setVolume(percent); @@ -241,11 +238,8 @@ void SoundSDL2::adjustVolume(Int8 direction) } // Now show an onscreen message - strval << percent; - message = "Volume set to "; - message += strval.str(); - - myOSystem.frameBuffer().showMessage(message); + strval << percent << "%"; + myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 5a275fbf2..d742cc674 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -112,40 +112,24 @@ string NTSCFilter::setPreviousAdjustable() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::increaseAdjustable() +void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& value) { //if(myPreset != Preset::CUSTOM) // return "'Custom' TV mode not selected"; - uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - newval += 2; if(newval > 100) newval = 100; - *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newval); + value = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); + value = BSPF::clamp(value + (increase ? 2 : -2), 0, 100); - ostringstream buf; - buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval << "%"; + *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(value); setPreset(myPreset); - return buf.str(); -} -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::decreaseAdjustable() -{ - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; + ostringstream msg, val; + msg << "Custom " << ourCustomAdjustables[myCurrentAdjustable].type; + val << value << "%"; - uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - if(newval < 2) newval = 0; - else newval -= 2; - *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newval); - - ostringstream buf; - buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' set to " << newval << "%"; - - setPreset(myPreset); - return buf.str(); + text = msg.str(); + valueText = val.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index f7e897916..c4fe30f15 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -92,8 +92,7 @@ class NTSCFilter // only 4 combinations are necessary string setNextAdjustable(); string setPreviousAdjustable(); - string increaseAdjustable(); - string decreaseAdjustable(); + void changeAdjustable(bool increase, string& text, string& valueText, Int32& value); // Load and save NTSC-related settings void loadConfig(const Settings& settings); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index dda0c9fdd..33b7520be 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -349,14 +349,14 @@ bool Console::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleFormat(int direction) +void Console::selectFormat(bool next) { string saveformat, message; uInt32 format = myCurrentFormat; - if(direction == 1) + if(next) format = (myCurrentFormat + 1) % 7; - else if(direction == -1) + else format = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; setFormat(format); @@ -521,39 +521,20 @@ void Console::togglePhosphor() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changePhosphor(int direction) +void Console::changePhosphor(bool increase) { int blend = BSPF::stringToInt(myProperties.get(PropType::Display_PPBlend)); - if(direction == +1) // increase blend - { - if(blend >= 100) - { - myOSystem.frameBuffer().showMessage("Phosphor blend at maximum"); - myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, 100); - return; - } - else - blend = std::min(blend+2, 100); - } - else if(direction == -1) // decrease blend - { - if(blend <= 2) - { - myOSystem.frameBuffer().showMessage("Phosphor blend at minimum"); - myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, 0); - return; - } - else - blend = std::max(blend-2, 0); - } - else - return; + if(increase) // increase blend + blend += 2; + else // decrease blend + blend -= 2; + blend = BSPF::clamp(blend, 0, 100); ostringstream val; val << blend; myProperties.set(PropType::Display_PPBlend, val.str()); - myOSystem.frameBuffer().showMessage("Phosphor blend " + val.str()); + myOSystem.frameBuffer().showMessage("Phosphor blend", val.str() + "%", blend); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); } @@ -631,45 +612,25 @@ void Console::fry() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeVerticalCenter(int direction) +void Console::changeVerticalCenter(bool increase) { Int32 vcenter = myTIA->vcenter(); - if(direction == +1) // increase vcenter - { - if(vcenter >= myTIA->maxVcenter()) - { - myOSystem.frameBuffer().showMessage("V-Center at maximum"); - return; - } + if(increase) // increase vcenter ++vcenter; - } - else if(direction == -1) // decrease vcenter - { - if (vcenter <= myTIA->minVcenter()) - { - myOSystem.frameBuffer().showMessage("V-Center at minimum"); - return; - } + else // decrease vcenter --vcenter; - } - else - return; + vcenter = BSPF::clamp(vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); - ostringstream ss; + ostringstream ss, val; ss << vcenter; myProperties.set(PropType::Display_VCenter, ss.str()); if (vcenter != myTIA->vcenter()) myTIA->setVcenter(vcenter); - ss.str(""); - ss << "V-Center "; - if (!vcenter) - ss << "default"; - else - ss << (vcenter > 0 ? "+" : "") << vcenter << "px"; - - myOSystem.frameBuffer().showMessage(ss.str()); + val << (vcenter ? vcenter > 0 ? "+" : "" : " ") << vcenter << "px"; + myOSystem.frameBuffer().showMessage("V-Center", val.str(), vcenter, + myTIA->minVcenter(), myTIA->maxVcenter()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -682,30 +643,15 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeScanlineAdjust(int direction) +void Console::changeScanlineAdjust(bool increase) { Int32 newAdjustVSize = myTIA->adjustVSize(); - if (direction != -1 && direction != +1) return; - - if(direction == +1) // increase scanline adjustment - { - if (newAdjustVSize >= 5) - { - myOSystem.frameBuffer().showMessage("V-Size at maximum"); - return; - } + if(increase) // increase scanline adjustment newAdjustVSize++; - } - else if(direction == -1) // decrease scanline adjustment - { - if (newAdjustVSize <= -5) - { - myOSystem.frameBuffer().showMessage("V-Size at minimum"); - return; - } + else // decrease scanline adjustment newAdjustVSize--; - } + newAdjustVSize = BSPF::clamp(newAdjustVSize, -5, 5); if (newAdjustVSize != myTIA->adjustVSize()) { myTIA->setAdjustVSize(newAdjustVSize); @@ -713,15 +659,10 @@ void Console::changeScanlineAdjust(int direction) initializeVideo(); } - ostringstream ss; + ostringstream val; - ss << "V-Size "; - if (!newAdjustVSize) - ss << "default"; - else - ss << (newAdjustVSize > 0 ? "+" : "") << newAdjustVSize << "%"; - - myOSystem.frameBuffer().showMessage(ss.str()); + val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ") << newAdjustVSize << "%"; + myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index ac26415d7..685297b55 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -189,9 +189,9 @@ class Console : public Serializable, public ConsoleIO /** Toggle between NTSC/PAL/SECAM (and variants) display format. - @param direction +1 indicates increase, -1 indicates decrease. + @param next Select next if true, else previous */ - void toggleFormat(int direction = 1); + void selectFormat(bool next = true); /** Set NTSC/PAL/SECAM (and variants) display format. @@ -222,9 +222,9 @@ class Console : public Serializable, public ConsoleIO /** Change the "Display.PPBlend" variable. - @param direction +1 indicates increase, -1 indicates decrease. + @param increase Increase if true, else decrease */ - void changePhosphor(int direction); + void changePhosphor(bool increase = true); /** Toggles the PAL color-loss effect. @@ -257,18 +257,18 @@ class Console : public Serializable, public ConsoleIO /** Change the "Display.VCenter" variable. - @param direction +1 indicates increase, -1 indicates decrease. + @param increase Increase if true, else decrease */ - void changeVerticalCenter(int direction); + void changeVerticalCenter(bool increase = true); /** Change the "TIA scanline adjust" variable. Note that there are currently two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param direction +1 indicates increase, -1 indicates decrease. + @param increase Increase if true, else decrease */ - void changeScanlineAdjust(int direction); + void changeScanlineAdjust(bool increase = true); /** Returns the current framerate. diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 362625909..82fd4280c 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -413,27 +413,27 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::VidmodeDecrease: - if(pressed) myOSystem.frameBuffer().changeVidMode(-1); + if(pressed) myOSystem.frameBuffer().selectVidMode(false); return; case Event::VidmodeIncrease: - if(pressed) myOSystem.frameBuffer().changeVidMode(+1); + if(pressed) myOSystem.frameBuffer().selectVidMode(true); return; case Event::VCenterDecrease: - if (pressed) myOSystem.console().changeVerticalCenter(-1); + if (pressed) myOSystem.console().changeVerticalCenter(false); return; case Event::VCenterIncrease: - if (pressed) myOSystem.console().changeVerticalCenter(+1); + if (pressed) myOSystem.console().changeVerticalCenter(true); return; case Event::ScanlineAdjustDecrease: - if (pressed) myOSystem.console().changeScanlineAdjust(-1); + if (pressed) myOSystem.console().changeScanlineAdjust(false); return; case Event::ScanlineAdjustIncrease: - if (pressed) myOSystem.console().changeScanlineAdjust(+1); + if (pressed) myOSystem.console().changeScanlineAdjust(true); return; case Event::PreviousPaletteAttribute: @@ -457,11 +457,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::OverscanDecrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(-1); + if (pressed) myOSystem.frameBuffer().changeOverscan(false); return; case Event::OverscanIncrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(1); + if (pressed) myOSystem.frameBuffer().changeOverscan(true); return; case Event::PreviousVideoMode: @@ -525,27 +525,33 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::DecreaseAttribute: if (pressed) { + string text, valueText; + Int32 newVal; + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable()); + myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(false, text, valueText, newVal); + myOSystem.frameBuffer().showMessage(text, valueText, newVal); } return; case Event::IncreaseAttribute: if (pressed) { + string text, valueText; + Int32 newVal; + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable()); + myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(true, text, valueText, newVal); + myOSystem.frameBuffer().showMessage(text, valueText, newVal); } return; case Event::PhosphorDecrease: - if (pressed) myOSystem.console().changePhosphor(-1); + if (pressed) myOSystem.console().changePhosphor(false); return; case Event::PhosphorIncrease: - if (pressed) myOSystem.console().changePhosphor(1); + if (pressed) myOSystem.console().changePhosphor(true); return; case Event::TogglePhosphor: @@ -603,11 +609,11 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::FormatDecrease: - if (pressed) myOSystem.console().toggleFormat(-1); + if (pressed) myOSystem.console().selectFormat(false); return; case Event::FormatIncrease: - if (pressed) myOSystem.console().toggleFormat(1); + if (pressed) myOSystem.console().selectFormat(true); return; case Event::ToggleGrabMouse: diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 14f620373..254060054 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -309,7 +309,12 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, BufferType type, } if(!myMsg.surface) - myMsg.surface = allocateSurface(font().getMaxCharWidth() * 56, font().getFontHeight() * 1.5); + { + const int fontWidth = font().getMaxCharWidth(), + HBORDER = fontWidth * 1.25 / 2.0; + myMsg.surface = allocateSurface(fontWidth * MESSAGE_WIDTH + HBORDER * 2, + font().getFontHeight() * 1.5); + } #endif // Print initial usage message, but only print it later if the status has changed @@ -500,19 +505,62 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; - // Precompute the message coordinates - myMsg.text = message; - myMsg.counter = uInt32(myOSystem.frameRate()) << 1; // Show message for 2 seconds - if(myMsg.counter == 0) myMsg.counter = 60; - myMsg.color = kBtnTextColor; + myMsg.counter = uInt32(myOSystem.frameRate()) * 2; // Show message for 2 seconds + if(myMsg.counter == 0) + myMsg.counter = 120; - myMsg.w = font().getStringWidth(myMsg.text) + HBORDER * 2; - myMsg.h = fontHeight + VBORDER * 2; + // Precompute the message coordinates + myMsg.text = message; + myMsg.color = kBtnTextColor; + myMsg.showGauge = false; + myMsg.w = font().getStringWidth(myMsg.text) + HBORDER * 2; + myMsg.h = fontHeight + VBORDER * 2; + myMsg.position = position; + myMsg.enabled = true; + + myMsg.surface->setSrcSize(myMsg.w, myMsg.h); + myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor()); +#endif +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::showMessage(const string& message, const string& valueText, + float value, float minValue, float maxValue) +{ +#ifdef GUI_SUPPORT + // Only show messages if they've been enabled + if(myMsg.surface == nullptr || !myOSystem.settings().getBool("uimessages")) + return; + + const int fontWidth = font().getMaxCharWidth(), + fontHeight = font().getFontHeight(); + const int VBORDER = fontHeight / 4; + const int HBORDER = fontWidth * 1.25 / 2.0; + + myMsg.counter = uInt32(myOSystem.frameRate()) * 5; // Show message for 5 seconds + if(myMsg.counter == 0) + myMsg.counter = 120; + + // Precompute the message coordinates + myMsg.text = message; + myMsg.color = kBtnTextColor; + myMsg.showGauge = true; + if(maxValue - minValue != 0) + myMsg.value = (value - minValue) / (maxValue - minValue) * 100.F; + else + myMsg.value = 100.F; + myMsg.valueText = valueText; + myMsg.w = std::min(fontWidth * MESSAGE_WIDTH, + font().getStringWidth(myMsg.text) + + fontWidth * (GAUGEBAR_WIDTH + 2) + + font().getStringWidth(myMsg.valueText)) + + HBORDER * 2; + myMsg.h = fontHeight + VBORDER * 2; + myMsg.position = MessagePosition::BottomCenter; + myMsg.enabled = true; myMsg.surface->setSrcSize(myMsg.w, myMsg.h); myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor()); - myMsg.position = position; - myMsg.enabled = true; #endif } @@ -631,6 +679,7 @@ inline bool FrameBuffer::drawMessage() fontHeight = font().getFontHeight(); const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; + constexpr int BORDER = 1; switch(myMsg.position) { @@ -681,10 +730,44 @@ inline bool FrameBuffer::drawMessage() } myMsg.surface->setDstPos(myMsg.x + myImageRect.x(), myMsg.y + myImageRect.y()); - myMsg.surface->fillRect(1, 1, myMsg.w - 2, myMsg.h - 2, kBtnColor); - myMsg.surface->frameRect(0, 0, myMsg.w, myMsg.h, kColor); + myMsg.surface->fillRect(0, 0, myMsg.w, myMsg.h, kColor); + myMsg.surface->fillRect(BORDER, BORDER, myMsg.w - BORDER * 2, myMsg.h - BORDER * 2, kBtnColor); myMsg.surface->drawString(font(), myMsg.text, HBORDER, VBORDER, myMsg.w, myMsg.color); + + if(myMsg.showGauge) + { + constexpr int NUM_TICKMARKS = 4; + // limit gauge bar width if texts are too long + const int swidth = std::min(fontWidth * GAUGEBAR_WIDTH, + fontWidth * (MESSAGE_WIDTH - 2) + - font().getStringWidth(myMsg.text) + - font().getStringWidth(myMsg.valueText)); + const int bwidth = swidth * myMsg.value / 100.F; + const int bheight = fontHeight >> 1; + const int x = HBORDER + font().getStringWidth(myMsg.text) + fontWidth; + // align bar with bottom of text + const int y = VBORDER + font().desc().ascent - bheight; + + // draw bar gauge + myMsg.surface->fillRect(x - BORDER, y, swidth + BORDER * 2, bheight, kSliderBGColor); + myMsg.surface->fillRect(x, y + BORDER, bwidth, bheight - BORDER * 2, kSliderColor); + // draw tickmark in the middle of the bar + for(int i = 1; i < NUM_TICKMARKS; ++i) + { + ColorId color; + int xt = x + swidth * i / NUM_TICKMARKS; + if(bwidth < xt - x) + color = kCheckColor; // kSliderColor; + else + color = kSliderBGColor; + myMsg.surface->vLine(xt, y + bheight / 2, y + bheight - 1, color); + } + // draw value text + myMsg.surface->drawString(font(), myMsg.valueText, + x + swidth + fontWidth, VBORDER, + myMsg.w, myMsg.color); + } myMsg.surface->render(); myMsg.counter--; #endif @@ -900,12 +983,12 @@ void FrameBuffer::toggleFullscreen() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::changeOverscan(int direction) +void FrameBuffer::changeOverscan(bool increase) { if (fullScreen()) { int oldOverscan = myOSystem.settings().getInt("tia.fs_overscan"); - int overscan = BSPF::clamp(oldOverscan + direction, 0, 10); + int overscan = BSPF::clamp(oldOverscan + (increase ? 1 : -1), 0, 10); if (overscan != oldOverscan) { @@ -914,14 +997,15 @@ void FrameBuffer::changeOverscan(int direction) // issue a complete framebuffer re-initialization myOSystem.createFrameBuffer(); } - ostringstream msg; - msg << "Overscan at " << overscan << "%"; - showMessage(msg.str()); + + ostringstream val; + val << (overscan ? overscan > 0 ? "+" : "" : " ") << overscan << "%"; + myOSystem.frameBuffer().showMessage("Overscan", val.str(), overscan, 0, 10); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBuffer::changeVidMode(int direction) +bool FrameBuffer::selectVidMode(bool next) { EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && @@ -931,12 +1015,10 @@ bool FrameBuffer::changeVidMode(int direction) if(!tiaMode) return false; - if(direction == +1) + if(next) myCurrentModeList->next(); - else if(direction == -1) - myCurrentModeList->previous(); else - return false; + myCurrentModeList->previous(); saveCurrentWindowPosition(); @@ -956,7 +1038,7 @@ bool FrameBuffer::changeVidMode(int direction) myTIASurface->initialize(myOSystem.console(), mode); resetSurfaces(); - showMessage(mode.description); + showMessage("Zoom", mode.description, mode.zoom, supportedTIAMinZoom(), myTIAMaxZoom); myOSystem.sound().mute(oldMuteState); if(fullScreen()) @@ -1077,7 +1159,7 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) for(float zoom = minZoom; zoom <= myTIAMaxZoom; zoom += ZOOM_STEPS) { ostringstream desc; - desc << "Zoom " << zoom << "x"; + desc << (zoom * 100) << "%"; VideoMode mode(baseWidth*zoom, baseHeight*zoom, baseWidth*zoom, baseHeight*zoom, VideoMode::Stretch::Fill, 1.0, desc.str(), zoom); diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index a73b01ffb..7a73b3d90 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -147,6 +147,17 @@ class FrameBuffer void showMessage(const string& message, MessagePosition position = MessagePosition::BottomCenter, bool force = false); + /** + Shows a message with a bar gauge onscreen. + + @param message The message to be shown + @param valueText The value of the bar gauge as text + @param value The bar gauge percentage + @param minValue The minimal value of the bar gauge + @param maxValue The maximal value of the bar gauge + */ + void showMessage(const string& message, const string& valueText, + float value, float minValue = 0.F, float maxValue = 100.F); /** Toggles showing or hiding framerate statistics. @@ -251,10 +262,10 @@ class FrameBuffer /** Changes the fullscreen overscan. - direction = -1 means less overscan - direction = +1 means more overscan + + @param increase Increase if true, else decrease */ - void changeOverscan(int direction); + void changeOverscan(bool increase = true); /** This method is called when the user wants to switch to the next @@ -264,9 +275,9 @@ class FrameBuffer direction = -1 means go to the next lower video mode direction = +1 means go to the next higher video mode - @param direction Described above + @param next Select next if true, else previous */ - bool changeVidMode(int direction); + bool selectVidMode(bool next = true); /** Sets the state of the cursor (hidden or grabbed) based on the @@ -502,6 +513,11 @@ class FrameBuffer OSystem& myOSystem; private: + // Maximum message width [chars] + static constexpr int MESSAGE_WIDTH = 56; + // Maximum gauge bar width [chars] + static constexpr int GAUGEBAR_WIDTH = 30; + /** Draw pending messages. @@ -648,6 +664,9 @@ class FrameBuffer ColorId color{kNone}; shared_ptr surface; bool enabled{false}; + bool showGauge{false}; + float value{0.0F}; + string valueText; }; Message myMsg; Message myStatsMsg; diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 8ff9f3e17..53060a97e 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -231,21 +231,11 @@ void TIASurface::setScanlineIntensity(int amount) ostringstream buf; uInt32 intensity = enableScanlines(amount); - if(intensity == 0) - buf << "Scanlines disabled"; - else - { - buf << "Scanline intensity at "; - if(intensity < 100) - buf << intensity << "%"; - else - buf << "maximum"; - } myOSystem.settings().setValue("tv.scanlines", intensity); - enableNTSC(ntscEnabled()); - myFB.showMessage(buf.str()); + buf << intensity << "%"; + myFB.showMessage("Scanline intensity", buf.str(), intensity); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/CommandDialog.cxx b/src/gui/CommandDialog.cxx index 5790f7193..e4c5f610a 100644 --- a/src/gui/CommandDialog.cxx +++ b/src/gui/CommandDialog.cxx @@ -199,7 +199,7 @@ void CommandDialog::handleCommand(CommandSender* sender, int cmd, // Column 3 case kFormatCmd: - instance().console().toggleFormat(); + instance().console().selectFormat(); updateTVFormat(); break; diff --git a/src/gui/MinUICommandDialog.cxx b/src/gui/MinUICommandDialog.cxx index b93b95890..080316005 100644 --- a/src/gui/MinUICommandDialog.cxx +++ b/src/gui/MinUICommandDialog.cxx @@ -217,7 +217,7 @@ void MinUICommandDialog::handleCommand(CommandSender* sender, int cmd, // Column 3 case kFormatCmd: - instance().console().toggleFormat(); + instance().console().selectFormat(); updateTVFormat(); break; From 35a113b628e009c1620a74f8c4310ca539011110 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 10:56:34 +0200 Subject: [PATCH 28/42] fix #635 (<=2K ROMs rewind broken) --- src/emucore/CartEnhanced.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 0bd964890..496a4d051 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -40,7 +40,10 @@ void CartridgeEnhanced::install(System& system) // calculate bank switching and RAM sizes and masks myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 myBankMask = myBankSize - 1; // e.g. = 0x0FFF - myBankSegs = 1 << (MAX_BANK_SHIFT - myBankShift); // e.g. = 1 + // Either the bankswitching supports multiple segments + // or the ROM is < 4K (-> 1 segment) + myBankSegs = std::min(1 << (MAX_BANK_SHIFT - myBankShift), + int(mySize) / myBankSize); // e.g. = 1 myRomOffset = myRamBankCount > 0 ? 0 : uInt32(myRamSize) * 2; myRamMask = ramSize - 1; // e.g. = 0xFFFF (doesn't matter for RAM size 0) myWriteOffset = myRamWpHigh ? ramSize : 0; // e.g. = 0x0000 From ac41d126644ecb1bc57575107caed1a80b65c26b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 13:33:17 +0200 Subject: [PATCH 29/42] increase maximum iterations and performance of RunToPC command --- src/debugger/Debugger.cxx | 8 +++++--- src/debugger/Debugger.hxx | 2 +- src/debugger/DebuggerParser.cxx | 24 +++++++++++++++++------- src/debugger/gui/RomWidget.cxx | 3 ++- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/debugger/Debugger.cxx b/src/debugger/Debugger.cxx index b46570a6a..cdb039491 100644 --- a/src/debugger/Debugger.cxx +++ b/src/debugger/Debugger.cxx @@ -293,9 +293,10 @@ void Debugger::loadAllStates() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Debugger::step() +int Debugger::step(bool save) { - saveOldState(); + if(save) + saveOldState(); uInt64 startCycle = mySystem.cycles(); @@ -303,7 +304,8 @@ int Debugger::step() myOSystem.console().tia().updateScanlineByStep().flushLineCache(); lockSystem(); - addState("step"); + if(save) + addState("step"); return int(mySystem.cycles() - startCycle); } diff --git a/src/debugger/Debugger.hxx b/src/debugger/Debugger.hxx index d063f2e90..6083d556a 100644 --- a/src/debugger/Debugger.hxx +++ b/src/debugger/Debugger.hxx @@ -306,7 +306,7 @@ class Debugger : public DialogContainer */ void setQuitState(); - int step(); + int step(bool save = true); int trace(); void nextScanline(int lines); void nextFrame(int frames); diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index d6be07b68..37632be39 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -1744,7 +1744,7 @@ void DebuggerParser::executeRunTo() bool done = false; do { - debugger.step(); + debugger.step(false); // Update romlist to point to current PC int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc()); @@ -1778,22 +1778,32 @@ void DebuggerParser::executeRunToPc() uInt32 count = 0; bool done = false; + constexpr uInt32 max_iterations = 1000000; + // Create a progress dialog box to show the progress searching through the + // disassembly, since this may be a time-consuming operation + ostringstream buf; + buf << "RunTo PC searching through " << max_iterations << " instructions"; + ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str()); + progress.setRange(0, max_iterations, 5); + do { - debugger.step(); + debugger.step(false); // Update romlist to point to current PC int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc()); done = (pcline >= 0) && (list[pcline].address == args[0]); - } while(!done && ++count < list.size()); + progress.setProgress(count); + } while(!done && ++count < max_iterations/*list.size()*/); + progress.close(); if(done) commandResult - << "set PC to " << Base::HEX4 << args[0] << " in " - << dec << count << " disassembled instructions"; + << "Set PC to $" << Base::HEX4 << args[0] << " in " + << dec << count << " instructions"; else commandResult - << "PC " << Base::HEX4 << args[0] << " not reached or found in " - << dec << count << " disassembled instructions"; + << "PC $" << Base::HEX4 << args[0] << " not reached or found in " + << dec << count << " instructions"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/gui/RomWidget.cxx b/src/debugger/gui/RomWidget.cxx index bf459d8f7..010ae5f0b 100644 --- a/src/debugger/gui/RomWidget.cxx +++ b/src/debugger/gui/RomWidget.cxx @@ -200,7 +200,8 @@ void RomWidget::runtoPC(int disasm_line) { ostringstream command; command << "runtopc #" << list[disasm_line].address; - instance().debugger().run(command.str()); + string msg = instance().debugger().run(command.str()); + instance().frameBuffer().showMessage(msg); } } From aa5367f152d782819937a46f2b68e5473cbc5861 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 16:00:20 +0200 Subject: [PATCH 30/42] make sure that debugger command 'stepwhile' doesn't run forever. --- src/debugger/DebuggerParser.cxx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/debugger/DebuggerParser.cxx b/src/debugger/DebuggerParser.cxx index 37632be39..49692ef8a 100644 --- a/src/debugger/DebuggerParser.cxx +++ b/src/debugger/DebuggerParser.cxx @@ -1941,9 +1941,23 @@ void DebuggerParser::executeStepwhile() } Expression* expr = YaccParser::getResult(); int ncycles = 0; + uInt32 count = 0; + constexpr uInt32 max_iterations = 1000000; + + // Create a progress dialog box to show the progress searching through the + // disassembly, since this may be a time-consuming operation + ostringstream buf; + buf << "stepwhile running through " << max_iterations << " disassembled instructions"; + ProgressDialog progress(debugger.baseDialog(), debugger.lfont(), buf.str()); + progress.setRange(0, max_iterations, 5); + do { - ncycles += debugger.step(); - } while (expr->evaluate()); + ncycles += debugger.step(false); + + progress.setProgress(count); + } while (expr->evaluate() && ++count < max_iterations); + + progress.close(); commandResult << "executed " << ncycles << " cycles"; } From ea98b7a8d010c509ef373c1a283c60d56f76c32b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Wed, 13 May 2020 20:26:19 +0200 Subject: [PATCH 31/42] added gauge bars display when selecting settings too --- src/common/PaletteHandler.cxx | 47 +++++++++------- src/common/PaletteHandler.hxx | 5 ++ src/common/tv_filters/NTSCFilter.cxx | 82 +++++++++++++--------------- src/common/tv_filters/NTSCFilter.hxx | 5 +- src/emucore/EventHandler.cxx | 58 ++++++-------------- src/emucore/TIASurface.cxx | 23 ++++++++ src/emucore/TIASurface.hxx | 10 ++++ 7 files changed, 121 insertions(+), 109 deletions(-) diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index b0e4eea2d..f040fe8e5 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -91,6 +91,31 @@ void PaletteHandler::cyclePalette(bool next) setPalette(palette); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::showAdjustableMessage() +{ + const bool isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; + ostringstream msg, buf; + + msg << "Palette " << myAdjustables[myCurrentAdjustable].name; + if(isPhaseShift) + { + const ConsoleTiming timing = myOSystem.console().timing(); + const bool isNTSC = timing == ConsoleTiming::ntsc; + const float value = myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC; + buf << std::fixed << std::setprecision(1) << value << DEGREE; + myOSystem.frameBuffer().showMessage("Palette phase shift", buf.str(), value, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, + (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); + } + else + { + const int value = scaleTo100(*myAdjustables[myCurrentAdjustable].value); + buf << value << "%"; + myOSystem.frameBuffer().showMessage(msg.str(), buf.str(), value); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaletteHandler::cycleAdjustable(bool next) { @@ -115,16 +140,7 @@ void PaletteHandler::cycleAdjustable(bool next) // skip phase shift when 'Custom' palette is not selected } while(isPhaseShift && !isCustomPalette); - ostringstream buf; - buf << "Palette adjustable '" << myAdjustables[myCurrentAdjustable].name - << "' selected ("; - if(isPhaseShift) - buf << (myOSystem.console().timing() == ConsoleTiming::pal ? myPhasePAL : myPhaseNTSC) - << DEGREE << ")"; - else - buf << scaleTo100(*myAdjustables[myCurrentAdjustable].value) << "%)"; - - myOSystem.frameBuffer().showMessage(buf.str()); + showAdjustableMessage(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -144,10 +160,7 @@ void PaletteHandler::changeAdjustable(bool increase) *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); - ostringstream msg, val; - msg << "Palette " << myAdjustables[myCurrentAdjustable].name; - val << newVal << "%"; - myOSystem.frameBuffer().showMessage(msg.str(), val.str(), newVal); + showAdjustableMessage(); setPalette(); } } @@ -178,11 +191,7 @@ void PaletteHandler::changeColorPhaseShift(bool increase) generateCustomPalette(timing); setPalette(SETTING_CUSTOM); - ostringstream val; - val << std::fixed << std::setprecision(1) << newPhase << DEGREE; - myOSystem.frameBuffer().showMessage("Palette phase shift", val.str(), newPhase, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT, - (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT); + showAdjustableMessage(); } } diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 3a8c5c9e3..e8e083a8a 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -128,6 +128,11 @@ class PaletteHandler */ string toPaletteName(PaletteType type) const; + /** + Display current adjustable with bar gauge message + */ + void showAdjustableMessage(); + /** Change the "phase shift" variable. Note that there are two of these (NTSC and PAL). The currently diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index d742cc674..2d0ffaa6e 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -72,61 +72,53 @@ string NTSCFilter::getPreset() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::setNextAdjustable() +void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, Int32& value) { - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; + if(next) + { + #ifdef BLARGG_PALETTE + myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; + #else + myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; + #endif + } + else + { + #ifdef BLARGG_PALETTE + if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; + #else + if(myCurrentAdjustable == 0) myCurrentAdjustable = 4; + #endif + else --myCurrentAdjustable; + } -#ifdef BLARGG_PALETTE - myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; -#else - myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; -#endif - - ostringstream buf; - buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected (" - << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string NTSCFilter::setPreviousAdjustable() -{ - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; - -#ifdef BLARGG_PALETTE - if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; -#else - if(myCurrentAdjustable == 0) myCurrentAdjustable = 4; -#endif - else --myCurrentAdjustable; - ostringstream buf; - buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type - << "' selected (" - << scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value) << "%)"; - - return buf.str(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& value) -{ - //if(myPreset != Preset::CUSTOM) - // return "'Custom' TV mode not selected"; + ostringstream msg, val; value = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - value = BSPF::clamp(value + (increase ? 2 : -2), 0, 100); + msg << "Custom " << ourCustomAdjustables[myCurrentAdjustable].type; + val << value << "%"; - *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(value); + text = msg.str(); + valueText = val.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue) +{ + //if(myPreset != Preset::CUSTOM) + // return "'Custom' TV mode not selected"; + + newValue = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); + newValue = BSPF::clamp(newValue + (increase ? 2 : -2), 0, 100); + + *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newValue); setPreset(myPreset); ostringstream msg, val; + msg << "Custom " << ourCustomAdjustables[myCurrentAdjustable].type; - val << value << "%"; + val << newValue << "%"; text = msg.str(); valueText = val.str(); diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index c4fe30f15..6ccdcd155 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -90,9 +90,8 @@ class NTSCFilter // Changes are made this way since otherwise 20 key-combinations // would be needed to dynamically change each setting, and now // only 4 combinations are necessary - string setNextAdjustable(); - string setPreviousAdjustable(); - void changeAdjustable(bool increase, string& text, string& valueText, Int32& value); + void selectAdjustable(bool next, string& text, string& valueText, Int32& value); + void changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue); // Load and save NTSC-related settings void loadConfig(const Settings& settings); diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 82fd4280c..d83a44aa0 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -496,6 +496,22 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); return; + case Event::PreviousAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); + return; + + case Event::NextAttribute: + if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); + return; + + case Event::DecreaseAttribute: + if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); + return; + + case Event::IncreaseAttribute: + if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); + return; + case Event::ScanlinesDecrease: if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-2); return; @@ -504,48 +520,6 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+2); return; - case Event::PreviousAttribute: - if (pressed) - { - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable()); - } - return; - - case Event::NextAttribute: - if (pressed) - { - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().showMessage( - myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable()); - } - return; - - case Event::DecreaseAttribute: - if (pressed) - { - string text, valueText; - Int32 newVal; - - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(false, text, valueText, newVal); - myOSystem.frameBuffer().showMessage(text, valueText, newVal); - } - return; - - case Event::IncreaseAttribute: - if (pressed) - { - string text, valueText; - Int32 newVal; - - myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::Preset::CUSTOM); - myOSystem.frameBuffer().tiaSurface().ntsc().changeAdjustable(true, text, valueText, newVal); - myOSystem.frameBuffer().showMessage(text, valueText, newVal); - } - return; - case Event::PhosphorDecrease: if (pressed) myOSystem.console().changePhosphor(false); return; diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 53060a97e..307863e8e 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -225,6 +225,29 @@ void TIASurface::changeNTSC(bool next, bool show) setNTSC(PRESETS[preset], show); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::setNTSCAdjustable(bool next) +{ + string text, valueText; + Int32 value; + + setNTSC(NTSCFilter::Preset::CUSTOM); + ntsc().selectAdjustable(next, text, valueText, value); + myOSystem.frameBuffer().showMessage(text, valueText, value); + +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::changeNTSCAdjustable(bool increase) +{ + string text, valueText; + Int32 newValue; + + setNTSC(NTSCFilter::Preset::CUSTOM); + ntsc().changeAdjustable(increase, text, valueText, newValue); + myOSystem.frameBuffer().showMessage(text, valueText, newValue); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::setScanlineIntensity(int amount) { diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index b2c00f912..90aeacb14 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -94,6 +94,16 @@ class TIASurface */ void changeNTSC(bool next, bool show = true); + /** + Switch to next/previous NTSC filtering adjustable. + */ + void setNTSCAdjustable(bool next = true); + + /** + Increase/decrease current NTSC filtering adjustable. + */ + void changeNTSCAdjustable(bool increase = true); + /** Retrieve palette handler. */ From a6df70db891aa6adf72f173e4c4971760fc05c6c Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 14 May 2020 11:12:56 +0200 Subject: [PATCH 32/42] a little bit of polishing --- src/common/PKeyboardHandler.cxx | 4 +-- src/common/SoundSDL2.cxx | 5 ++- src/emucore/CartEnhanced.cxx | 32 +++++++++---------- src/emucore/Console.cxx | 11 +++++-- src/emucore/Console.hxx | 2 +- src/emucore/Event.hxx | 2 +- src/emucore/EventHandler.cxx | 55 ++++++++++++++------------------- src/emucore/FrameBuffer.cxx | 5 +++ src/emucore/TIASurface.cxx | 5 ++- 9 files changed, 66 insertions(+), 55 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index e30bff52f..fc2c78722 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -460,8 +460,8 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::VidmodeIncrease, KBDK_EQUALS, MOD3}, {Event::VCenterDecrease, KBDK_PAGEUP, MOD3}, {Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3}, - {Event::ScanlineAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3}, - {Event::ScanlineAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3}, + {Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3}, + {Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3}, {Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3}, {Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3}, {Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL}, diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index c32189e95..85489abb5 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -238,7 +238,10 @@ void SoundSDL2::adjustVolume(Int8 direction) } // Now show an onscreen message - strval << percent << "%"; + if(percent) + strval << percent << "%"; + else + strval << "Off"; myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); } diff --git a/src/emucore/CartEnhanced.cxx b/src/emucore/CartEnhanced.cxx index 496a4d051..27fa425b5 100644 --- a/src/emucore/CartEnhanced.cxx +++ b/src/emucore/CartEnhanced.cxx @@ -35,7 +35,7 @@ CartridgeEnhanced::CartridgeEnhanced(const ByteBuffer& image, size_t size, void CartridgeEnhanced::install(System& system) { // limit banked RAM size to the size of one RAM bank - uInt32 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : uInt32(myRamSize); + const uInt32 ramSize = myRamBankCount > 0 ? 1 << (myBankShift - 1) : uInt32(myRamSize); // calculate bank switching and RAM sizes and masks myBankSize = 1 << myBankShift; // e.g. = 2 ^ 12 = 4K = 0x1000 @@ -71,7 +71,7 @@ void CartridgeEnhanced::install(System& system) access.type = System::PageAccessType::WRITE; for(uInt16 addr = ROM_OFFSET + myWriteOffset; addr < ROM_OFFSET + myWriteOffset + myRamSize; addr += System::PAGE_SIZE) { - uInt16 offset = addr & myRamMask; + const uInt16 offset = addr & myRamMask; access.directPokeBase = &myRAM[offset]; access.romAccessBase = &myRomAccessBase[myWriteOffset + offset]; @@ -85,7 +85,7 @@ void CartridgeEnhanced::install(System& system) access.directPokeBase = nullptr; for(uInt16 addr = ROM_OFFSET + myReadOffset; addr < ROM_OFFSET + myReadOffset + myRamSize; addr += System::PAGE_SIZE) { - uInt16 offset = addr & myRamMask; + const uInt16 offset = addr & myRamMask; access.directPeekBase = &myRAM[offset]; access.romAccessBase = &myRomAccessBase[myReadOffset + offset]; @@ -117,7 +117,7 @@ void CartridgeEnhanced::reset() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeEnhanced::peek(uInt16 address) { - uInt16 peekAddress = address; + const uInt16 peekAddress = address; // hotspots in TIA range are reacting to pokes only if (hotspot() >= 0x80) @@ -157,7 +157,7 @@ bool CartridgeEnhanced::poke(uInt16 address, uInt8 value) if(myRamSize > 0) { // Code should never get here (System::PageAccess::directPoke() handles this) - uInt16 pokeAddress = address; + const uInt16 pokeAddress = address; if(isRamBank(address)) { @@ -193,20 +193,20 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) { if(bankLocked()) return false; - uInt16 segmentOffset = segment << myBankShift; + const uInt16 segmentOffset = segment << myBankShift; if(myRamBankCount == 0 || bank < romBankCount()) { // Setup ROM bank - uInt16 romBank = bank % romBankCount(); + const uInt16 romBank = bank % romBankCount(); // Remember what bank is in this segment - uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; - uInt16 hotspot = this->hotspot(); + const uInt32 bankOffset = myCurrentSegOffset[segment] = romBank << myBankShift; + const uInt16 hotspot = this->hotspot(); uInt16 hotSpotAddr; // Skip extra RAM; if existing it is only mapped into first segment - uInt16 fromAddr = (ROM_OFFSET + segmentOffset + (segment == 0 ? myRomOffset : 0)) & ~System::PAGE_MASK; + const uInt16 fromAddr = (ROM_OFFSET + segmentOffset + (segment == 0 ? myRomOffset : 0)) & ~System::PAGE_MASK; // for ROMs < 4_KB, the whole address space will be mapped. - uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; + const uInt16 toAddr = (ROM_OFFSET + segmentOffset + (mySize < 4_KB ? 4_KB : myBankSize)) & ~System::PAGE_MASK; if(hotspot & 0x1000) hotSpotAddr = (hotspot & ~System::PAGE_MASK); @@ -217,7 +217,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) // Setup the page access methods for the current bank for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myBankMask); + const uInt32 offset = bankOffset + (addr & myBankMask); if(myDirectPeek && addr != hotSpotAddr) access.directPeekBase = &myImage[offset]; @@ -232,9 +232,9 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) else { // Setup RAM bank - uInt16 ramBank = (bank - romBankCount()) % myRamBankCount; + const uInt16 ramBank = (bank - romBankCount()) % myRamBankCount; // The RAM banks follow the ROM banks and are half the size of a ROM bank - uInt32 bankOffset = uInt32(mySize) + (ramBank << (myBankShift - 1)); + const uInt32 bankOffset = uInt32(mySize) + (ramBank << (myBankShift - 1)); // Remember what bank is in this segment myCurrentSegOffset[segment] = uInt32(mySize) + (ramBank << myBankShift); @@ -246,7 +246,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myRamMask); + const uInt32 offset = bankOffset + (addr & myRamMask); access.directPokeBase = &myRAM[offset - mySize]; access.romAccessBase = &myRomAccessBase[offset]; @@ -263,7 +263,7 @@ bool CartridgeEnhanced::bank(uInt16 bank, uInt16 segment) for(uInt16 addr = fromAddr; addr < toAddr; addr += System::PAGE_SIZE) { - uInt32 offset = bankOffset + (addr & myRamMask); + const uInt32 offset = bankOffset + (addr & myRamMask); access.directPeekBase = &myRAM[offset - mySize]; access.romAccessBase = &myRomAccessBase[offset]; diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 33b7520be..5af3d1077 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -534,7 +534,14 @@ void Console::changePhosphor(bool increase) ostringstream val; val << blend; myProperties.set(PropType::Display_PPBlend, val.str()); - myOSystem.frameBuffer().showMessage("Phosphor blend", val.str() + "%", blend); + if(blend) + val << "%"; + else + { + val.str(""); + val << "Off"; + } + myOSystem.frameBuffer().showMessage("Phosphor blend", val.str(), blend); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); } @@ -643,7 +650,7 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeScanlineAdjust(bool increase) +void Console::changeVSizeAdjust(bool increase) { Int32 newAdjustVSize = myTIA->adjustVSize(); diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 685297b55..15173b48d 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -268,7 +268,7 @@ class Console : public Serializable, public ConsoleIO @param increase Increase if true, else decrease */ - void changeScanlineAdjust(bool increase = true); + void changeVSizeAdjust(bool increase = true); /** Returns the current framerate. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index fba15b6fb..0c84225ed 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -104,7 +104,7 @@ class Event PreviousPaletteAttribute, NextPaletteAttribute, PaletteAttributeDecrease, PaletteAttributeIncrease, ToggleFullScreen, VidmodeDecrease, VidmodeIncrease, - VCenterDecrease, VCenterIncrease, ScanlineAdjustDecrease, ScanlineAdjustIncrease, + VCenterDecrease, VCenterIncrease, VSizeAdjustDecrease, VSizeAdjustIncrease, OverscanDecrease, OverscanIncrease, VidmodeStd, VidmodeRGB, VidmodeSVideo, VidModeComposite, VidModeBad, VidModeCustom, diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index d83a44aa0..2dbc5e217 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -345,7 +345,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) { // Take care of special events that aren't part of the emulation core // or need to be preprocessed before passing them on - bool pressed = (value != 0); + const bool pressed = (value != 0); switch(event) { @@ -428,12 +428,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (pressed) myOSystem.console().changeVerticalCenter(true); return; - case Event::ScanlineAdjustDecrease: - if (pressed) myOSystem.console().changeScanlineAdjust(false); + case Event::VSizeAdjustDecrease: + if (pressed) myOSystem.console().changeVSizeAdjust(false); return; - case Event::ScanlineAdjustIncrease: - if (pressed) myOSystem.console().changeScanlineAdjust(true); + case Event::VSizeAdjustIncrease: + if (pressed) myOSystem.console().changeVSizeAdjust(true); return; case Event::PreviousPaletteAttribute: @@ -592,14 +592,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::ToggleGrabMouse: if (pressed && !repeated && !myOSystem.frameBuffer().fullScreen()) - { - bool oldState = myOSystem.frameBuffer().grabMouseEnabled(); myOSystem.frameBuffer().toggleGrabMouse(); - bool newState = myOSystem.frameBuffer().grabMouseEnabled(); - myOSystem.frameBuffer().showMessage(oldState != newState ? myOSystem.frameBuffer().grabMouseEnabled() - ? "Grab mouse enabled" : "Grab mouse disabled" - : "Grab mouse not allowed while cursor shown"); - } return; case Event::ToggleP0Collision: @@ -760,7 +753,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) if (myOSystem.settings().getBool("confirmexit")) { StringList msg; - string saveOnExit = myOSystem.settings().getString("saveonexit"); + const string saveOnExit = myOSystem.settings().getString("saveonexit"); bool activeTM = myOSystem.settings().getBool( myOSystem.settings().getBool("dev.settings") ? "dev.timemachine" : "plr.timemachine"); @@ -1085,12 +1078,12 @@ void EventHandler::setActionMappings(EventMode mode) // Fill the EmulActionList with the current key and joystick mappings for(auto& item: ourEmulActionList) { - Event::Type event = item.event; + const Event::Type event = item.event; item.key = "None"; string key = myPKeyHandler->getMappingDesc(event, mode); #ifdef JOYSTICK_SUPPORT - string joydesc = myPJoyHandler->getMappingDesc(event, mode); + const string joydesc = myPJoyHandler->getMappingDesc(event, mode); if(joydesc != "") { if(key != "") @@ -1107,12 +1100,12 @@ void EventHandler::setActionMappings(EventMode mode) // Fill the MenuActionList with the current key and joystick mappings for(auto& item: ourMenuActionList) { - Event::Type event = item.event; + const Event::Type event = item.event; item.key = "None"; string key = myPKeyHandler->getMappingDesc(event, mode); #ifdef JOYSTICK_SUPPORT - string joydesc = myPJoyHandler->getMappingDesc(event, mode); + const string joydesc = myPJoyHandler->getMappingDesc(event, mode); if(joydesc != "") { if(key != "") @@ -1138,7 +1131,7 @@ void EventHandler::setComboMap() string list = myOSystem.settings().getString("combomap"); replace(list.begin(), list.end(), ':', ' '); istringstream buf(list); - Int32 version = myOSystem.settings().getInt("event_ver"); + const Int32 version = myOSystem.settings().getInt("event_ver"); // Erase the 'combo' array auto ERASE_ALL = [&]() { @@ -1200,7 +1193,7 @@ void EventHandler::removePhysicalJoystickFromDatabase(const string& name) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key, StellaMod mod) { - bool mapped = myPKeyHandler->addMapping(event, mode, key, mod); + const bool mapped = myPKeyHandler->addMapping(event, mode, key, mod); if(mapped) setActionMappings(mode); @@ -1213,7 +1206,7 @@ bool EventHandler::addJoyMapping(Event::Type event, EventMode mode, bool updateMenus) { #ifdef JOYSTICK_SUPPORT - bool mapped = myPJoyHandler->addJoyMapping(event, mode, stick, button, axis, adir); + const bool mapped = myPJoyHandler->addJoyMapping(event, mode, stick, button, axis, adir); if (mapped && updateMenus) setActionMappings(mode); @@ -1411,7 +1404,7 @@ VariantList EventHandler::getComboList(EventMode /**/) const VarList::push_back(l, "None", "-1"); for(uInt32 i = 0; i < ourEmulActionList.size(); ++i) { - Event::Type event = EventHandler::ourEmulActionList[i].event; + const Event::Type event = EventHandler::ourEmulActionList[i].event; // exclude combos events if(!(event >= Event::Combo1 && event <= Event::Combo16)) { @@ -1433,7 +1426,7 @@ StringList EventHandler::getComboListForEvent(Event::Type event) const int combo = event - Event::Combo1; for(uInt32 i = 0; i < EVENTS_PER_COMBO; ++i) { - Event::Type e = myComboTable[combo][i]; + const Event::Type e = myComboTable[combo][i]; for(uInt32 j = 0; j < ourEmulActionList.size(); ++j) { if(EventHandler::ourEmulActionList[j].event == e) @@ -1457,7 +1450,7 @@ void EventHandler::setComboListForEvent(Event::Type event, const StringList& eve if(event >= Event::Combo1 && event <= Event::Combo16) { assert(events.size() == 8); - int combo = event - Event::Combo1; + const int combo = event - Event::Combo1; for(uInt32 i = 0; i < 8; ++i) { uInt32 idx = BSPF::stringToInt(events[i]); @@ -1544,7 +1537,7 @@ int EventHandler::getActionListIndex(int idx, Event::Group group) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Event::Type EventHandler::eventAtIndex(int idx, Event::Group group) const { - int index = getActionListIndex(idx, group); + const int index = getActionListIndex(idx, group); if(group == Event::Group::Menu) { @@ -1565,7 +1558,7 @@ Event::Type EventHandler::eventAtIndex(int idx, Event::Group group) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::actionAtIndex(int idx, Event::Group group) const { - int index = getActionListIndex(idx, group); + const int index = getActionListIndex(idx, group); if(group == Event::Group::Menu) { @@ -1586,7 +1579,7 @@ string EventHandler::actionAtIndex(int idx, Event::Group group) const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::keyAtIndex(int idx, Event::Group group) const { - int index = getActionListIndex(idx, group); + const int index = getActionListIndex(idx, group); if(group == Event::Group::Menu) { @@ -1797,8 +1790,8 @@ void EventHandler::setState(EventHandlerState state) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::exitEmulation(bool checkLauncher) { - string saveOnExit = myOSystem.settings().getString("saveonexit"); - bool activeTM = myOSystem.settings().getBool( + const string saveOnExit = myOSystem.settings().getString("saveonexit"); + const bool activeTM = myOSystem.settings().getBool( myOSystem.settings().getBool("dev.settings") ? "dev.timemachine" : "plr.timemachine"); @@ -1924,8 +1917,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::OverscanIncrease, "Increase overscan in fullscreen mode", "" }, { Event::VidmodeDecrease, "Previous zoom level", "" }, { Event::VidmodeIncrease, "Next zoom level", "" }, - { Event::ScanlineAdjustDecrease, "Decrease vertical display size", "" }, - { Event::ScanlineAdjustIncrease, "Increase vertical display size", "" }, + { Event::VSizeAdjustDecrease, "Decrease vertical display size", "" }, + { Event::VSizeAdjustIncrease, "Increase vertical display size", "" }, { Event::VCenterDecrease, "Move display up", "" }, { Event::VCenterIncrease, "Move display down", "" }, { Event::FormatDecrease, "Decrease display format", "" }, @@ -2064,7 +2057,7 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::PhosphorDecrease, Event::PhosphorIncrease, Event::TogglePhosphor, Event::FormatDecrease, Event::FormatIncrease, Event::VCenterDecrease, Event::VCenterIncrease, - Event::ScanlineAdjustDecrease, Event::ScanlineAdjustIncrease, + Event::VSizeAdjustDecrease, Event::VSizeAdjustIncrease, Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, Event::PreviousVideoMode, Event::NextVideoMode, diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 254060054..cd7e2e57c 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -1106,9 +1106,14 @@ void FrameBuffer::enableGrabMouse(bool enable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleGrabMouse() { + const bool oldState = myGrabMouse; + myGrabMouse = !myGrabMouse; setCursorState(); myOSystem.settings().setValue("grabmouse", myGrabMouse); + myOSystem.frameBuffer().showMessage(oldState != myGrabMouse ? myGrabMouse + ? "Grab mouse enabled" : "Grab mouse disabled" + : "Grab mouse not allowed while cursor shown"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 307863e8e..98adb4bd4 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -257,7 +257,10 @@ void TIASurface::setScanlineIntensity(int amount) myOSystem.settings().setValue("tv.scanlines", intensity); enableNTSC(ntscEnabled()); - buf << intensity << "%"; + if(intensity) + buf << intensity << "%"; + else + buf << "Off"; myFB.showMessage("Scanline intensity", buf.str(), intensity); } From c06a60d704e95c781607f0c6758f5c0e7cfa9586 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 14 May 2020 21:18:55 +0200 Subject: [PATCH 33/42] added global hotkeys (pageup/down) for current displayed setting (or volume) --- docs/index.html | 18 +++++ src/common/PKeyboardHandler.cxx | 3 + src/common/PaletteHandler.cxx | 12 ++- src/common/PaletteHandler.hxx | 9 ++- src/common/SoundNull.hxx | 6 +- src/common/SoundSDL2.cxx | 31 +++++--- src/common/SoundSDL2.hxx | 8 +- src/common/StateManager.cxx | 17 ++-- src/common/StateManager.hxx | 6 +- src/common/bspf.hxx | 3 + src/emucore/Console.cxx | 17 ++-- src/emucore/Console.hxx | 10 +-- src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 137 +++++++++++++++++++++++--------- src/emucore/EventHandler.hxx | 4 +- src/emucore/FrameBuffer.cxx | 36 ++++++--- src/emucore/FrameBuffer.hxx | 16 ++-- src/emucore/Sound.hxx | 6 +- src/emucore/TIASurface.cxx | 16 ++-- src/emucore/TIASurface.hxx | 8 +- src/libretro/SoundLIBRETRO.hxx | 6 +- 21 files changed, 252 insertions(+), 118 deletions(-) diff --git a/docs/index.html b/docs/index.html index 246b84390..5c5204863 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1767,6 +1767,24 @@ + + + + + + + + + + + + + + +
    Key (macOS)
    Disable TV effectsSelect previous TV effects presetShift-Alt + 1Shift-Cmd + 1
    Select next TV effects preset Alt + 1 Cmd + 1
    Select 'RGB' presetSelect previous 'Custom' mode attribute (*)Shift-Alt + 2Shift-Cmd + 2
    Select next 'Custom' mode attribute (*) Alt + 2 Cmd + 2
    Select 'S-Video' presetAlt + 3Cmd + 3
    Select 'Composite' presetAlt + 4Cmd + 4
    Select 'Badly adjusted' presetAlt + 5Cmd + 5
    Select 'Custom' presetAlt + 6Cmd + 6
    Select previous 'Custom' mode attribute (*)Shift-Alt + 7Shift-Cmd + 7
    Select next 'Custom' mode attribute (*)Alt + 7Cmd + 7
    Decrease 'Custom' selected attribute value (*)Shift-Alt + 8Shift-Cmd + 8Shift-Alt + 3Shift-Cmd + 3
    Increase 'Custom' selected attribute value (*)Alt + 8Cmd + 8Alt + 3Cmd + 3
    Decrease 'phosphor' blendShift-Alt + 9Shift-Cmd + 9Shift-Alt + 4Shift-Cmd + 4
    Increase 'phosphor' blendAlt + 9Cmd + 9Alt + 4Cmd + 4
    Decrease scanline intensityShift-Alt + 0Shift-Cmd + 0Shift-Alt + 5Shift-Cmd + 5
    Increase scanline intensityAlt + 0Cmd + 0Alt + 5Cmd + 5
    Control + f
    Switch palette (Standard/Z26/User/Custom)Control + pControl + p
    Decrease 'Custom' palette's phase shiftShift-Control + 9Shift-Control + 9
    Increase 'Custom' palette's phase shiftControl + 9Control + 9
    Toggle display interpolation Control + iAlt + Up arrow Cmd + Up arrow
    Decrease current setting (*)PageDownPageDown
    Increase current setting (*) + PageUpPageUp
    + (*) Note: These keys allow easy changing of the current displayed selection (e.g. volume (default), + phosphor, zoom...) without having to use the original keys.

    UI keys in Text Editing areas (cannot be remapped)

    diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index fc2c78722..95cef05e8 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -493,11 +493,14 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, + {Event::SettingDecrease, KBDK_PAGEDOWN}, + {Event::SettingIncrease, KBDK_PAGEUP}, {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, {Event::ToggleFrameStats, KBDK_L, MOD3}, {Event::ToggleTimeMachine, KBDK_T, MOD3}, + #ifdef PNG_SUPPORT {Event::ToggleContSnapshots, KBDK_S, MOD3}, {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index f040fe8e5..2c04ccd3b 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -55,7 +55,7 @@ string PaletteHandler::toPaletteName(PaletteType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::cyclePalette(bool next) +AdjustFunction PaletteHandler::cyclePalette(bool next) { const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" @@ -89,6 +89,7 @@ void PaletteHandler::cyclePalette(bool next) myOSystem.frameBuffer().showMessage(message); setPalette(palette); + return std::bind(&PaletteHandler::cyclePalette, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -112,12 +113,13 @@ void PaletteHandler::showAdjustableMessage() { const int value = scaleTo100(*myAdjustables[myCurrentAdjustable].value); buf << value << "%"; - myOSystem.frameBuffer().showMessage(msg.str(), buf.str(), value); + myOSystem.frameBuffer().showMessage( + msg.str(), buf.str(), value); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::cycleAdjustable(bool next) +AdjustFunction PaletteHandler::cycleAdjustable(bool next) { const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); bool isPhaseShift; @@ -141,10 +143,11 @@ void PaletteHandler::cycleAdjustable(bool next) } while(isPhaseShift && !isCustomPalette); showAdjustableMessage(); + return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeAdjustable(bool increase) +AdjustFunction PaletteHandler::changeAdjustable(bool increase) { if(myAdjustables[myCurrentAdjustable].value == nullptr) changeColorPhaseShift(increase); @@ -163,6 +166,7 @@ void PaletteHandler::changeAdjustable(bool increase) showAdjustableMessage(); setPalette(); } + return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index e8e083a8a..7a4b8676d 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -21,6 +21,7 @@ #include "bspf.hxx" #include "OSystem.hxx" #include "ConsoleTiming.hxx" +#include "EventHandlerConstants.hxx" class PaletteHandler { @@ -51,21 +52,21 @@ class PaletteHandler @param next Select next palette, else previous one */ - void cyclePalette(bool next = true); + AdjustFunction cyclePalette(bool next = true); /* Cycle through each palette adjustable. @param next Select next adjustable, else previous one */ - void cycleAdjustable(bool next = true); + AdjustFunction cycleAdjustable(bool next = true); /* Increase or decrease current palette adjustable. @param increase Increase adjustable if true, else decrease */ - void changeAdjustable(bool increase = true); + AdjustFunction changeAdjustable(bool increase = true); // Load adjustables from settings void loadConfig(const Settings& settings); @@ -129,7 +130,7 @@ class PaletteHandler string toPaletteName(PaletteType type) const; /** - Display current adjustable with bar gauge message + Display current adjustable with gauge bar message */ void showAdjustableMessage(); diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index f2aafbff8..ef07090a3 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -97,10 +97,10 @@ class SoundNull : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 =decrease) + @param increase Increase or decrease the current volume by a predefined + amount */ - void adjustVolume(Int8 direction) override { } + AdjustFunction adjustVolume(bool increase) override { return nullptr; } /** This method is called to provide information about the sound device. diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 85489abb5..234e4aae7 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -186,16 +186,31 @@ bool SoundSDL2::mute(bool state) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SoundSDL2::toggleMute() { - bool enabled = myAudioSettings.enabled(); + bool enabled = !myAudioSettings.enabled(); - setEnabled(!enabled); + setEnabled(enabled); myOSystem.console().initializeAudio(); string message = "Sound "; - message += !enabled ? "unmuted" : "muted"; + message += enabled ? "unmuted" : "muted"; myOSystem.frameBuffer().showMessage(message); + //ostringstream strval; + //uInt32 volume; + //// Now show an onscreen message + //if(enabled) + //{ + // volume = myVolume; + // strval << volume << "%"; + //} + //else + //{ + // volume = 0; + // strval << "Muted"; + //} + //myOSystem.frameBuffer().showMessage("Volume", strval.str(), volume); + return enabled; } @@ -214,17 +229,12 @@ void SoundSDL2::setVolume(uInt32 percent) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void SoundSDL2::adjustVolume(Int8 direction) +AdjustFunction SoundSDL2::adjustVolume(bool increase) { ostringstream strval; - Int32 percent = myVolume; - if(direction == -1) - percent -= 2; - else if(direction == 1) - percent += 2; - percent = BSPF::clamp(percent, 0, 100); + percent = BSPF::clamp(percent += increase ? 2 : -2, 0, 100); setVolume(percent); @@ -243,6 +253,7 @@ void SoundSDL2::adjustVolume(Int8 direction) else strval << "Off"; myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); + return std::bind(&SoundSDL2::adjustVolume, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index 613e6980d..bea035dd3 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -98,10 +98,10 @@ class SoundSDL2 : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 = decrease) - */ - void adjustVolume(Int8 direction) override; + @param increase Increase or decrease the current volume by a predefined + amount + */ + AdjustFunction adjustVolume(bool increase) override; /** This method is called to provide information about the sound device. diff --git a/src/common/StateManager.cxx b/src/common/StateManager.cxx index 667665054..016b7a97a 100644 --- a/src/common/StateManager.cxx +++ b/src/common/StateManager.cxx @@ -198,7 +198,7 @@ void StateManager::update() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StateManager::loadState(int slot) +AdjustFunction StateManager::loadState(int slot) { if(myOSystem.hasConsole()) { @@ -216,7 +216,7 @@ void StateManager::loadState(int slot) buf.str(""); buf << "Can't open/load from state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return; + return nullptr; } // First test if we have a valid header @@ -241,10 +241,11 @@ void StateManager::loadState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } + return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StateManager::saveState(int slot) +AdjustFunction StateManager::saveState(int slot) { if(myOSystem.hasConsole()) { @@ -262,7 +263,7 @@ void StateManager::saveState(int slot) buf.str(""); buf << "Can't open/save to state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return; + return nullptr; } try @@ -275,7 +276,7 @@ void StateManager::saveState(int slot) { buf << "Error saving state " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return; + return nullptr; } // Do a complete state save using the Console @@ -294,12 +295,13 @@ void StateManager::saveState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } + return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void StateManager::changeState(int direction) +AdjustFunction StateManager::changeState(bool next) { - myCurrentSlot += direction; + myCurrentSlot += next ? 1 : -1; if (myCurrentSlot < 0) myCurrentSlot = 9; else @@ -309,6 +311,7 @@ void StateManager::changeState(int direction) ostringstream buf; buf << "Changed to slot " << myCurrentSlot; myOSystem.frameBuffer().showMessage(buf.str()); + return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 09de785fb..3739b8c31 100644 --- a/src/common/StateManager.hxx +++ b/src/common/StateManager.hxx @@ -104,19 +104,19 @@ class StateManager @param slot The state 'slot' to load state from */ - void loadState(int slot = -1); + AdjustFunction loadState(int slot = -1); /** Save the current state from the system. @param slot The state 'slot' to save into */ - void saveState(int slot = -1); + AdjustFunction saveState(int slot = -1); /** Switches to the next higher or lower state slot (circular queue style). */ - void changeState(int direction); + AdjustFunction changeState(bool next); /** Toggles auto slot mode. diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index 1484b21ed..cfb801045 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -43,6 +43,7 @@ using uInt64 = uint64_t; #include #include #include +#include #include #include #include @@ -86,6 +87,8 @@ using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT using DWordBuffer = std::unique_ptr; // NOLINT +using AdjustFunction = std::function; + // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) { diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 5af3d1077..be5643e81 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -349,7 +349,7 @@ bool Console::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::selectFormat(bool next) +AdjustFunction Console::selectFormat(bool next) { string saveformat, message; uInt32 format = myCurrentFormat; @@ -360,6 +360,7 @@ void Console::selectFormat(bool next) format = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; setFormat(format); + return std::bind(&Console::selectFormat, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -504,7 +505,7 @@ void Console::toggleTurbo() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::togglePhosphor() +AdjustFunction Console::togglePhosphor() { if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled()) { @@ -518,10 +519,11 @@ void Console::togglePhosphor() myOSystem.frameBuffer().tiaSurface().enablePhosphor(true); myOSystem.frameBuffer().showMessage("Phosphor effect enabled"); } + return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changePhosphor(bool increase) +AdjustFunction Console::changePhosphor(bool increase) { int blend = BSPF::stringToInt(myProperties.get(PropType::Display_PPBlend)); @@ -530,6 +532,7 @@ void Console::changePhosphor(bool increase) else // decrease blend blend -= 2; blend = BSPF::clamp(blend, 0, 100); + myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); ostringstream val; val << blend; @@ -542,7 +545,7 @@ void Console::changePhosphor(bool increase) val << "Off"; } myOSystem.frameBuffer().showMessage("Phosphor blend", val.str(), blend); - myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); + return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -619,7 +622,7 @@ void Console::fry() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeVerticalCenter(bool increase) +AdjustFunction Console::changeVerticalCenter(bool increase) { Int32 vcenter = myTIA->vcenter(); @@ -638,6 +641,7 @@ void Console::changeVerticalCenter(bool increase) val << (vcenter ? vcenter > 0 ? "+" : "" : " ") << vcenter << "px"; myOSystem.frameBuffer().showMessage("V-Center", val.str(), vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); + return std::bind(&Console::changeVerticalCenter, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -650,7 +654,7 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::changeVSizeAdjust(bool increase) +AdjustFunction Console::changeVSizeAdjust(bool increase) { Int32 newAdjustVSize = myTIA->adjustVSize(); @@ -670,6 +674,7 @@ void Console::changeVSizeAdjust(bool increase) val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ") << newAdjustVSize << "%"; myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5); + return std::bind(&Console::changeVSizeAdjust, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 15173b48d..8c48575ad 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -191,7 +191,7 @@ class Console : public Serializable, public ConsoleIO @param next Select next if true, else previous */ - void selectFormat(bool next = true); + AdjustFunction selectFormat(bool next = true); /** Set NTSC/PAL/SECAM (and variants) display format. @@ -217,14 +217,14 @@ class Console : public Serializable, public ConsoleIO /** Toggles phosphor effect. */ - void togglePhosphor(); + AdjustFunction togglePhosphor(); /** Change the "Display.PPBlend" variable. @param increase Increase if true, else decrease */ - void changePhosphor(bool increase = true); + AdjustFunction changePhosphor(bool increase = true); /** Toggles the PAL color-loss effect. @@ -259,7 +259,7 @@ class Console : public Serializable, public ConsoleIO @param increase Increase if true, else decrease */ - void changeVerticalCenter(bool increase = true); + AdjustFunction changeVerticalCenter(bool increase = true); /** Change the "TIA scanline adjust" variable. @@ -268,7 +268,7 @@ class Console : public Serializable, public ConsoleIO @param increase Increase if true, else decrease */ - void changeVSizeAdjust(bool increase = true); + AdjustFunction changeVSizeAdjust(bool increase = true); /** Returns the current framerate. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 0c84225ed..2102b57f6 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -122,6 +122,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten + SettingDecrease, SettingIncrease, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 2dbc5e217..883d2b744 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -63,6 +63,8 @@ #include "ScrollBarWidget.hxx" #endif +using namespace std::placeholders; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::EventHandler(OSystem& osystem) : myOSystem(osystem) @@ -347,8 +349,32 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) // or need to be preprocessed before passing them on const bool pressed = (value != 0); + // The global settings keys react as long as the setting message from the previous event is + // still displayed. When no message is displayed, volume adjustment will be the default event. + if(!myOSystem.frameBuffer().messageShown() || myAdjustFunction == nullptr) + myAdjustFunction = std::bind(&Sound::adjustVolume, &myOSystem.sound(), std::placeholders::_1); + + // Assume no adjust function will be pressed + const AdjustFunction oldAdjustFunction = myAdjustFunction; + if(pressed) + myAdjustFunction = nullptr; + switch(event) { + //////////////////////////////////////////////////////////////////////// + // Allow adjusting several (mostly repeated) settings using the same two hotkeys + case Event::SettingDecrease: + if(pressed && oldAdjustFunction != nullptr) + oldAdjustFunction(false); + myAdjustFunction = oldAdjustFunction; + return; + + case Event::SettingIncrease: + if(pressed && oldAdjustFunction != nullptr) + oldAdjustFunction(true); + myAdjustFunction = oldAdjustFunction; + return; + //////////////////////////////////////////////////////////////////////// // If enabled, make sure 'impossible' joystick directions aren't allowed case Event::JoystickZeroUp: @@ -401,55 +427,68 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::VolumeDecrease: - if(pressed) myOSystem.sound().adjustVolume(-1); + if(pressed) + myAdjustFunction = myOSystem.sound().adjustVolume(false); return; case Event::VolumeIncrease: - if(pressed) myOSystem.sound().adjustVolume(+1); + if(pressed) + myAdjustFunction = myOSystem.sound().adjustVolume(true); return; case Event::SoundToggle: - if(pressed && !repeated) myOSystem.sound().toggleMute(); + if(pressed && !repeated) + myOSystem.sound().toggleMute(); return; case Event::VidmodeDecrease: - if(pressed) myOSystem.frameBuffer().selectVidMode(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().selectVidMode(false); return; case Event::VidmodeIncrease: - if(pressed) myOSystem.frameBuffer().selectVidMode(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().selectVidMode(true); return; case Event::VCenterDecrease: - if (pressed) myOSystem.console().changeVerticalCenter(false); + if (pressed) + myAdjustFunction = myOSystem.console().changeVerticalCenter(false); return; case Event::VCenterIncrease: - if (pressed) myOSystem.console().changeVerticalCenter(true); + if (pressed) + myAdjustFunction = myOSystem.console().changeVerticalCenter(true); return; case Event::VSizeAdjustDecrease: - if (pressed) myOSystem.console().changeVSizeAdjust(false); + if (pressed) + myAdjustFunction = myOSystem.console().changeVSizeAdjust(false); return; case Event::VSizeAdjustIncrease: - if (pressed) myOSystem.console().changeVSizeAdjust(true); + if (pressed) + myAdjustFunction = myOSystem.console().changeVSizeAdjust(true); return; case Event::PreviousPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); return; case Event::NextPaletteAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); return; case Event::PaletteAttributeDecrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); return; case Event::PaletteAttributeIncrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); return; case Event::ToggleFullScreen: @@ -457,19 +496,23 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::OverscanDecrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(false); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().changeOverscan(false); return; case Event::OverscanIncrease: - if (pressed) myOSystem.frameBuffer().changeOverscan(true); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().changeOverscan(true); return; case Event::PreviousVideoMode: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(false); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(false); return; case Event::NextVideoMode: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().changeNTSC(true); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(true); return; case Event::VidmodeStd: @@ -497,39 +540,48 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PreviousAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); return; case Event::NextAttribute: - if (pressed) myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); return; case Event::DecreaseAttribute: - if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); return; case Event::IncreaseAttribute: - if(pressed) myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); + if(pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); return; case Event::ScanlinesDecrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-2); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(false); return; case Event::ScanlinesIncrease: - if (pressed) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+2); + if (pressed) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(true); return; case Event::PhosphorDecrease: - if (pressed) myOSystem.console().changePhosphor(false); + if (pressed) + myAdjustFunction = myOSystem.console().changePhosphor(false); return; case Event::PhosphorIncrease: - if (pressed) myOSystem.console().changePhosphor(true); + if (pressed) + myAdjustFunction = myOSystem.console().changePhosphor(true); return; case Event::TogglePhosphor: - if (pressed && !repeated) myOSystem.console().togglePhosphor(); + if(pressed && !repeated) + myAdjustFunction = myOSystem.console().togglePhosphor(); return; case Event::ToggleColorLoss: @@ -537,11 +589,13 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); return; case Event::PaletteIncrease: - if (pressed && !repeated) myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); + if (pressed && !repeated) + myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); return; case Event::ToggleInter: @@ -583,11 +637,13 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::FormatDecrease: - if (pressed) myOSystem.console().selectFormat(false); + if (pressed && !repeated) + myAdjustFunction = myOSystem.console().selectFormat(false); return; case Event::FormatIncrease: - if (pressed) myOSystem.console().selectFormat(true); + if (pressed && !repeated) + myAdjustFunction = myOSystem.console().selectFormat(true); return; case Event::ToggleGrabMouse: @@ -656,7 +712,8 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::SaveState: - if(pressed && !repeated) myOSystem.state().saveState(); + if(pressed && !repeated) + myAdjustFunction = myOSystem.state().saveState(); return; case Event::SaveAllStates: @@ -664,12 +721,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) myOSystem.frameBuffer().showMessage(myOSystem.state().rewindManager().saveAllStates()); return; - case Event::NextState: - if(pressed) myOSystem.state().changeState(1); + case Event::PreviousState: + if (pressed) + myAdjustFunction = myOSystem.state().changeState(false); return; - case Event::PreviousState: - if (pressed) myOSystem.state().changeState(-1); + case Event::NextState: + if(pressed) + myAdjustFunction = myOSystem.state().changeState(true); return; case Event::ToggleAutoSlot: @@ -677,7 +736,8 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::LoadState: - if(pressed && !repeated) myOSystem.state().loadState(); + if(pressed && !repeated) + myAdjustFunction = myOSystem.state().loadState(); return; case Event::LoadAllStates: @@ -1950,6 +2010,10 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::PhosphorIncrease, "Increase 'phosphor' blend", "" }, { Event::ScanlinesDecrease, "Decrease scanlines", "" }, { Event::ScanlinesIncrease, "Increase scanlines", "" }, + + { Event::SettingDecrease, "Decrease current setting", "" }, + { Event::SettingIncrease, "Increase current setting", "" }, + // Developer keys: { Event::ToggleFrameStats, "Toggle frame stats", "" }, { Event::ToggleP0Bit, "Toggle TIA Player0 object", "" }, @@ -2044,6 +2108,7 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, + Event::SettingDecrease, Event::SettingIncrease }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 6d19b685b..4b7e91af1 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -425,6 +425,8 @@ class EventHandler string key; }; + AdjustFunction myAdjustFunction{nullptr}; + // Global Event object Event myEvent; @@ -468,7 +470,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 152 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 154 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index cd7e2e57c..dd88c3020 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -533,11 +533,11 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, return; const int fontWidth = font().getMaxCharWidth(), - fontHeight = font().getFontHeight(); + fontHeight = font().getFontHeight(); const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; - myMsg.counter = uInt32(myOSystem.frameRate()) * 5; // Show message for 5 seconds + myMsg.counter = uInt32(myOSystem.frameRate()) * 3; // Show message for 3 seconds if(myMsg.counter == 0) myMsg.counter = 120; @@ -551,10 +551,10 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, myMsg.value = 100.F; myMsg.valueText = valueText; myMsg.w = std::min(fontWidth * MESSAGE_WIDTH, - font().getStringWidth(myMsg.text) - + fontWidth * (GAUGEBAR_WIDTH + 2) - + font().getStringWidth(myMsg.valueText)) - + HBORDER * 2; + font().getStringWidth(myMsg.text) + + fontWidth * (GAUGEBAR_WIDTH + 2) + + font().getStringWidth(myMsg.valueText)) + + HBORDER * 2; myMsg.h = fontHeight + VBORDER * 2; myMsg.position = MessagePosition::BottomCenter; myMsg.enabled = true; @@ -564,6 +564,16 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, #endif } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameBuffer::messageShown() +{ +#ifdef GUI_SUPPORT + return myMsg.enabled; +#else + return false; +#endif +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::drawFrameStats(float framesPerSecond) { @@ -662,6 +672,7 @@ inline bool FrameBuffer::drawMessage() #ifdef GUI_SUPPORT // Either erase the entire message (when time is reached), // or show again this frame + cerr << myMsg.counter << endl; if(myMsg.counter == 0) { myMsg.enabled = false; @@ -749,7 +760,7 @@ inline bool FrameBuffer::drawMessage() // align bar with bottom of text const int y = VBORDER + font().desc().ascent - bheight; - // draw bar gauge + // draw gauge bar myMsg.surface->fillRect(x - BORDER, y, swidth + BORDER * 2, bheight, kSliderBGColor); myMsg.surface->fillRect(x, y + BORDER, bwidth, bheight - BORDER * 2, kSliderColor); // draw tickmark in the middle of the bar @@ -983,7 +994,7 @@ void FrameBuffer::toggleFullscreen() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::changeOverscan(bool increase) +AdjustFunction FrameBuffer::changeOverscan(bool increase) { if (fullScreen()) { @@ -1002,10 +1013,11 @@ void FrameBuffer::changeOverscan(bool increase) val << (overscan ? overscan > 0 ? "+" : "" : " ") << overscan << "%"; myOSystem.frameBuffer().showMessage("Overscan", val.str(), overscan, 0, 10); } + return std::bind(&FrameBuffer::changeOverscan, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBuffer::selectVidMode(bool next) +AdjustFunction FrameBuffer::selectVidMode(bool next) { EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && @@ -1013,7 +1025,7 @@ bool FrameBuffer::selectVidMode(bool next) // Only applicable when in TIA/emulation mode if(!tiaMode) - return false; + return nullptr; if(next) myCurrentModeList->next(); @@ -1047,11 +1059,11 @@ bool FrameBuffer::selectVidMode(bool next) else myOSystem.settings().setValue("tia.zoom", mode.zoom); - return true; + return std::bind(&FrameBuffer::selectVidMode, this, std::placeholders::_1); } myOSystem.sound().mute(oldMuteState); - return false; + return nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 7a73b3d90..4dd55f7f5 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -148,17 +148,19 @@ class FrameBuffer MessagePosition position = MessagePosition::BottomCenter, bool force = false); /** - Shows a message with a bar gauge onscreen. + Shows a message with a gauge bar onscreen. @param message The message to be shown - @param valueText The value of the bar gauge as text - @param value The bar gauge percentage - @param minValue The minimal value of the bar gauge - @param maxValue The maximal value of the bar gauge + @param valueText The value of the gauge bar as text + @param value The gauge bar percentage + @param minValue The minimal value of the gauge bar + @param maxValue The maximal value of the gauge bar */ void showMessage(const string& message, const string& valueText, float value, float minValue = 0.F, float maxValue = 100.F); + bool messageShown(); + /** Toggles showing or hiding framerate statistics. */ @@ -265,7 +267,7 @@ class FrameBuffer @param increase Increase if true, else decrease */ - void changeOverscan(bool increase = true); + AdjustFunction changeOverscan(bool increase = true); /** This method is called when the user wants to switch to the next @@ -277,7 +279,7 @@ class FrameBuffer @param next Select next if true, else previous */ - bool selectVidMode(bool next = true); + AdjustFunction selectVidMode(bool next = true); /** Sets the state of the cursor (hidden or grabbed) based on the diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx index f74705489..a03223f71 100644 --- a/src/emucore/Sound.hxx +++ b/src/emucore/Sound.hxx @@ -88,10 +88,10 @@ class Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 =decrease) + @param increase Increase or decrease the current volume by a predefined + amount */ - virtual void adjustVolume(Int8 direction) = 0; + virtual AdjustFunction adjustVolume(bool increase) = 0; /** This method is called to provide information about the sound device. diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 98adb4bd4..88a41415c 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -200,7 +200,7 @@ void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::changeNTSC(bool next, bool show) +AdjustFunction TIASurface::changeNTSC(bool next) { constexpr NTSCFilter::Preset PRESETS[] = { NTSCFilter::Preset::OFF, NTSCFilter::Preset::RGB, NTSCFilter::Preset::SVIDEO, @@ -222,11 +222,12 @@ void TIASurface::changeNTSC(bool next, bool show) else preset--; } - setNTSC(PRESETS[preset], show); + setNTSC(PRESETS[preset], true); + return std::bind(&TIASurface::changeNTSC, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::setNTSCAdjustable(bool next) +AdjustFunction TIASurface::setNTSCAdjustable(bool next) { string text, valueText; Int32 value; @@ -234,11 +235,12 @@ void TIASurface::setNTSCAdjustable(bool next) setNTSC(NTSCFilter::Preset::CUSTOM); ntsc().selectAdjustable(next, text, valueText, value); myOSystem.frameBuffer().showMessage(text, valueText, value); + return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::changeNTSCAdjustable(bool increase) +AdjustFunction TIASurface::changeNTSCAdjustable(bool increase) { string text, valueText; Int32 newValue; @@ -246,13 +248,14 @@ void TIASurface::changeNTSCAdjustable(bool increase) setNTSC(NTSCFilter::Preset::CUSTOM); ntsc().changeAdjustable(increase, text, valueText, newValue); myOSystem.frameBuffer().showMessage(text, valueText, newValue); + return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIASurface::setScanlineIntensity(int amount) +AdjustFunction TIASurface::setScanlineIntensity(bool increase) { ostringstream buf; - uInt32 intensity = enableScanlines(amount); + uInt32 intensity = enableScanlines(increase ? 2 : -2); myOSystem.settings().setValue("tv.scanlines", intensity); enableNTSC(ntscEnabled()); @@ -262,6 +265,7 @@ void TIASurface::setScanlineIntensity(int amount) else buf << "Off"; myFB.showMessage("Scanline intensity", buf.str(), intensity); + return std::bind(&TIASurface::setScanlineIntensity, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 90aeacb14..ecb1de752 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -92,17 +92,17 @@ class TIASurface /** Switch to next/previous NTSC filtering effect. */ - void changeNTSC(bool next, bool show = true); + AdjustFunction changeNTSC(bool next); /** Switch to next/previous NTSC filtering adjustable. */ - void setNTSCAdjustable(bool next = true); + AdjustFunction setNTSCAdjustable(bool next = true); /** Increase/decrease current NTSC filtering adjustable. */ - void changeNTSCAdjustable(bool increase = true); + AdjustFunction changeNTSCAdjustable(bool increase = true); /** Retrieve palette handler. @@ -112,7 +112,7 @@ class TIASurface /** Increase/decrease current scanline intensity by given relative amount. */ - void setScanlineIntensity(int relative); + AdjustFunction setScanlineIntensity(bool increase); /** Change scanline intensity and interpolation. diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index aa98780e1..f69d71a14 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -95,10 +95,10 @@ class SoundLIBRETRO : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param direction Increase or decrease the current volume by a predefined - amount based on the direction (1 = increase, -1 = decrease) + @param increase Increase or decrease the current volume by a predefined + amount */ - void adjustVolume(Int8 direction) override { } + void adjustVolume(bool increase) override { return nullptr; } /** This method is called to provide information about the sound device. From 7b6e3e32f6a414264e2d375624c1078fb8faafde Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Thu, 14 May 2020 21:03:25 -0230 Subject: [PATCH 34/42] libretro: Fix sound code for latest refactoring. --- src/libretro/SoundLIBRETRO.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index f69d71a14..68bf9fa16 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -98,7 +98,7 @@ class SoundLIBRETRO : public Sound @param increase Increase or decrease the current volume by a predefined amount */ - void adjustVolume(bool increase) override { return nullptr; } + AdjustFunction adjustVolume(bool increase) override { return AdjustFunction{}; } /** This method is called to provide information about the sound device. From 308cc97974ae82b47e459ac2ef7ee3db8e5b3d0c Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 15 May 2020 09:33:39 -0230 Subject: [PATCH 35/42] libretro: Return nullptr when necessary. --- src/libretro/SoundLIBRETRO.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index 68bf9fa16..ad5966a9c 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -98,7 +98,7 @@ class SoundLIBRETRO : public Sound @param increase Increase or decrease the current volume by a predefined amount */ - AdjustFunction adjustVolume(bool increase) override { return AdjustFunction{}; } + AdjustFunction adjustVolume(bool increase) override { return nullptr; } /** This method is called to provide information about the sound device. From a618d27f0106e46ae226791f07a68f5927cb0aeb Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 15 May 2020 15:25:27 -0230 Subject: [PATCH 36/42] Partially revert previous commit: fix ROM launcher not showing properties in certain cases. --- src/emucore/OSystem.cxx | 31 ++----------------------------- src/emucore/PropsSet.cxx | 31 +++++++++++++++++++++++++++++++ src/emucore/PropsSet.hxx | 17 ++++++++++++++++- src/gui/RomInfoWidget.cxx | 5 +++++ 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 8d60f6fb1..9c84b4165 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -648,35 +648,8 @@ ByteBuffer OSystem::openROM(const FilesystemNode& rom, string& md5, size_t& size if(md5 == "") md5 = MD5::hash(image, size); - // Handle ROM properties, do some error checking - // Only add to the database when necessary - bool toInsert = false; - - // First, does this ROM have a per-ROM properties entry? - // If so, load it into the database - FilesystemNode propsNode(rom.getPathWithExt(".pro")); - if(propsNode.exists() && propsNode.isFile()) - { - Logger::info("Loading per-ROM properties: " + propsNode.getShortPath()); - myPropSet->load(propsNode.getPath(), false); - } - - // Next, make sure we have a valid md5 and name - Properties props; - if(!myPropSet->getMD5(md5, props)) - { - props.set(PropType::Cart_MD5, md5); - toInsert = true; - } - if(toInsert || props.get(PropType::Cart_Name) == EmptyString) - { - props.set(PropType::Cart_Name, rom.getNameWithExt("")); - toInsert = true; - } - - // Finally, insert properties if any info was missing - if(toInsert) - myPropSet->insert(props, false); + // Make sure to load a per-ROM properties entry, if one exists + myPropSet->loadPerROM(rom, md5); return image; } diff --git a/src/emucore/PropsSet.cxx b/src/emucore/PropsSet.cxx index a13a9c759..a74a999e7 100644 --- a/src/emucore/PropsSet.cxx +++ b/src/emucore/PropsSet.cxx @@ -156,6 +156,37 @@ void PropertiesSet::insert(const Properties& properties, bool save) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5) +{ + // Handle ROM properties, do some error checking + // Only add to the database when necessary + bool toInsert = false; + + // First, does this ROM have a per-ROM properties entry? + // If so, load it into the database + FilesystemNode propsNode(rom.getPathWithExt(".pro")); + if(propsNode.exists() && propsNode.isFile()) + load(propsNode.getPath(), false); + + // Next, make sure we have a valid md5 and name + Properties props; + if(!getMD5(md5, props)) + { + props.set(PropType::Cart_MD5, md5); + toInsert = true; + } + if(toInsert || props.get(PropType::Cart_Name) == EmptyString) + { + props.set(PropType::Cart_Name, rom.getNameWithExt("")); + toInsert = true; + } + + // Finally, insert properties if any info was missing + if(toInsert) + insert(props, false); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::print() const { diff --git a/src/emucore/PropsSet.hxx b/src/emucore/PropsSet.hxx index 71924749a..f5a763ef8 100644 --- a/src/emucore/PropsSet.hxx +++ b/src/emucore/PropsSet.hxx @@ -42,7 +42,7 @@ class PropertiesSet /** Trivial constructor. */ - PropertiesSet() = default; + PropertiesSet() = default; /** Load properties from the specified file, and create an internal @@ -90,6 +90,21 @@ class PropertiesSet */ void insert(const Properties& properties, bool save = true); + /** + Load properties for a specific ROM from a per-ROM properties file, + if it exists. In any event, also do some error checking, like making + sure that the properties have a valid name, etc. + + NOTE: This method is meant to be called only when starting Stella + and loading a ROM for the first time. Currently, that means + only from the ROM launcher or when actually opening the ROM. + *** FOR ALL OTHER CASES, USE getMD5() *** + + @param rom The node representing the rom file + @param md5 The md5 of the property to get + */ + void loadPerROM(const FilesystemNode& rom, const string& md5); + /** Prints the contents of the PropertiesSet as a flat file. */ diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 8b1852528..3cfa43185 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -48,6 +48,11 @@ RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font, void RomInfoWidget::setProperties(const FilesystemNode& node, const string& md5) { myHaveProperties = true; + + // Make sure to load a per-ROM properties entry, if one exists + instance().propSet().loadPerROM(node, md5); + + // And now get the properties for this ROM instance().propSet().getMD5(md5, myProperties); // Decide whether the information should be shown immediately From 378829da5a2d5bc734326bf82cb8eb8e4006b1d2 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Fri, 15 May 2020 19:22:36 -0230 Subject: [PATCH 37/42] Very small optimization for const char* instead of strings. --- src/common/FrameBufferSDL2.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 4d013a35d..93a12615d 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -144,11 +144,11 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, struct RenderName { - string sdlName; - string stellaName; + const char* const sdlName; + const char* const stellaName; }; // Create name map for all currently known SDL renderers - static const std::array RENDERER_NAMES = {{ + static constexpr std::array RENDERER_NAMES = {{ { "direct3d", "Direct3D" }, { "metal", "Metal" }, { "opengl", "OpenGL" }, From 16a3280b5685360629819b1a5a44f46063c93879 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 09:50:16 +0200 Subject: [PATCH 38/42] added four global hotkeys which allow selecting and changing several adjustable settings (addresses #631) --- src/common/PKeyboardHandler.cxx | 4 + src/common/PaletteHandler.cxx | 77 ++---- src/common/PaletteHandler.hxx | 33 ++- src/common/SoundNull.hxx | 5 +- src/common/SoundSDL2.cxx | 5 +- src/common/SoundSDL2.hxx | 5 +- src/common/StateManager.cxx | 26 +- src/common/StateManager.hxx | 8 +- src/common/bspf.hxx | 6 +- src/common/tv_filters/NTSCFilter.cxx | 34 ++- src/common/tv_filters/NTSCFilter.hxx | 16 +- src/emucore/Console.cxx | 46 +--- src/emucore/Console.hxx | 20 +- src/emucore/Event.hxx | 2 +- src/emucore/EventHandler.cxx | 373 ++++++++++++++++++++++----- src/emucore/EventHandler.hxx | 49 +++- src/emucore/FrameBuffer.cxx | 36 +-- src/emucore/FrameBuffer.hxx | 8 +- src/emucore/Sound.hxx | 5 +- src/emucore/TIASurface.cxx | 42 +-- src/emucore/TIASurface.hxx | 29 ++- src/libretro/SoundLIBRETRO.hxx | 5 +- 22 files changed, 563 insertions(+), 271 deletions(-) diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index 95cef05e8..c09cd48fb 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -493,8 +493,12 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::ToggleColorLoss, KBDK_L, KBDM_CTRL}, {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, + + {Event::PreviousSetting, KBDK_END}, + {Event::NextSetting, KBDK_HOME}, {Event::SettingDecrease, KBDK_PAGEDOWN}, {Event::SettingIncrease, KBDK_PAGEUP}, + {Event::ToggleInter, KBDK_I, KBDM_CTRL}, {Event::ToggleTurbo, KBDK_T, KBDM_CTRL}, {Event::ToggleJitter, KBDK_J, MOD3}, diff --git a/src/common/PaletteHandler.cxx b/src/common/PaletteHandler.cxx index 2c04ccd3b..d2a2a7768 100644 --- a/src/common/PaletteHandler.cxx +++ b/src/common/PaletteHandler.cxx @@ -55,33 +55,16 @@ string PaletteHandler::toPaletteName(PaletteType type) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction PaletteHandler::cyclePalette(bool next) +void PaletteHandler::cyclePalette(int direction) { const string MESSAGES[PaletteType::NumTypes] = { "Standard Stella", "Z26", "User-defined", "Custom" }; int type = toPaletteType(myOSystem.settings().getString("palette")); - if(next) - { - if(type == PaletteType::MaxType) - type = PaletteType::Standard; - else - type++; - // If we have no user-defined palette, we will skip it - if(type == PaletteType::User && !myUserPaletteDefined) - type++; - } - else - { - if(type == PaletteType::MinType) - type = PaletteType::MaxType; - else - type--; - // If we have no user-defined palette, we will skip it - if(type == PaletteType::User && !myUserPaletteDefined) - type--; - } + do { + type = BSPF::clampw(type + direction, int(PaletteType::MinType), int(PaletteType::MaxType)); + } while(type == PaletteType::User && !myUserPaletteDefined); const string palette = toPaletteName(PaletteType(type)); const string message = MESSAGES[type] + " palette"; @@ -89,7 +72,6 @@ AdjustFunction PaletteHandler::cyclePalette(bool next) myOSystem.frameBuffer().showMessage(message); setPalette(palette); - return std::bind(&PaletteHandler::cyclePalette, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -119,58 +101,55 @@ void PaletteHandler::showAdjustableMessage() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction PaletteHandler::cycleAdjustable(bool next) +void PaletteHandler::cycleAdjustable(int direction) { const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); bool isPhaseShift; do { - if(next) - { - myCurrentAdjustable++; - myCurrentAdjustable %= NUM_ADJUSTABLES; - } - else - { - if(myCurrentAdjustable == 0) - myCurrentAdjustable = NUM_ADJUSTABLES - 1; - else - myCurrentAdjustable--; - } + myCurrentAdjustable = BSPF::clampw(int(myCurrentAdjustable + direction), 0, NUM_ADJUSTABLES - 1); isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr; - // skip phase shift when 'Custom' palette is not selected + if(!direction && isPhaseShift && !isCustomPalette) + myCurrentAdjustable++; } while(isPhaseShift && !isCustomPalette); showAdjustableMessage(); - return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction PaletteHandler::changeAdjustable(bool increase) +void PaletteHandler::changeAdjustable(int adjustable, int direction) +{ + const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette"); + const bool isPhaseShift = myAdjustables[adjustable].value == nullptr; + + myCurrentAdjustable = adjustable; + if(isPhaseShift && !isCustomPalette) + myCurrentAdjustable++; + + changeCurrentAdjustable(direction); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PaletteHandler::changeCurrentAdjustable(int direction) { if(myAdjustables[myCurrentAdjustable].value == nullptr) - changeColorPhaseShift(increase); + changeColorPhaseShift(direction); else { int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value); - if(increase) - newVal += 2; // += 2% - else - newVal -= 2; // -= 2% - newVal = BSPF::clamp(newVal, 0, 100); + newVal = BSPF::clamp(newVal + direction * 2, 0, 100); *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal); showAdjustableMessage(); setPalette(); } - return std::bind(&PaletteHandler::changeAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PaletteHandler::changeColorPhaseShift(bool increase) +void PaletteHandler::changeColorPhaseShift(int direction) { const ConsoleTiming timing = myOSystem.console().timing(); @@ -181,11 +160,7 @@ void PaletteHandler::changeColorPhaseShift(bool increase) const float shift = isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT; float newPhase = isNTSC ? myPhaseNTSC : myPhasePAL; - if(increase) // increase color phase shift - newPhase += 0.3F; - else // decrease color phase shift - newPhase -= 0.3F; - newPhase = BSPF::clamp(newPhase, shift - MAX_SHIFT, shift + MAX_SHIFT); + newPhase = BSPF::clamp(newPhase + direction * 0.3F, shift - MAX_SHIFT, shift + MAX_SHIFT); if(isNTSC) myPhaseNTSC = newPhase; diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 7a4b8676d..817c5fb5e 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -37,6 +37,15 @@ class PaletteHandler static constexpr float DEF_PAL_SHIFT = 31.3F; // ~= 360 / 11.5 static constexpr float MAX_SHIFT = 4.5F; + enum Adjustables { + PHASE_SHIFT, + HUE, + SATURATION, + CONTRAST, + BRIGHTNESS, + GAMMA + }; + // Externally used adjustment parameters struct Adjustable { float phaseNtsc{0.F}, phasePal{0.F}; @@ -50,23 +59,31 @@ class PaletteHandler /** Cycle through available palettes. - @param next Select next palette, else previous one + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction cyclePalette(bool next = true); + void cyclePalette(int direction = +1); /* Cycle through each palette adjustable. - @param next Select next adjustable, else previous one + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction cycleAdjustable(bool next = true); + void cycleAdjustable(int direction = +1); + + /* + Increase or decrease given palette adjustable. + + @param adjustable The adjustable to change + @param direction +1 indicates increase, -1 indicates decrease. + */ + void changeAdjustable(int adjustable, int direction); /* Increase or decrease current palette adjustable. - @param increase Increase adjustable if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeAdjustable(bool increase = true); + void changeCurrentAdjustable(int direction = +1); // Load adjustables from settings void loadConfig(const Settings& settings); @@ -139,9 +156,9 @@ class PaletteHandler Note that there are two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - void changeColorPhaseShift(bool increase = true); + void changeColorPhaseShift(int direction = +1); /** Generates a custom palette, based on user defined phase shifts. diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index ef07090a3..8974e9834 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -97,10 +97,9 @@ class SoundNull : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction adjustVolume(bool increase) override { return nullptr; } + void adjustVolume(int direction = 1) override { } /** This method is called to provide information about the sound device. diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 234e4aae7..928ebbc44 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -229,12 +229,12 @@ void SoundSDL2::setVolume(uInt32 percent) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction SoundSDL2::adjustVolume(bool increase) +void SoundSDL2::adjustVolume(int direction) { ostringstream strval; Int32 percent = myVolume; - percent = BSPF::clamp(percent += increase ? 2 : -2, 0, 100); + percent = BSPF::clamp(percent + direction * 2, 0, 100); setVolume(percent); @@ -253,7 +253,6 @@ AdjustFunction SoundSDL2::adjustVolume(bool increase) else strval << "Off"; myOSystem.frameBuffer().showMessage("Volume", strval.str(), percent); - return std::bind(&SoundSDL2::adjustVolume, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index bea035dd3..398f1fa92 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -98,10 +98,9 @@ class SoundSDL2 : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction adjustVolume(bool increase) override; + void adjustVolume(int direction = 1) override; /** This method is called to provide information about the sound device. diff --git a/src/common/StateManager.cxx b/src/common/StateManager.cxx index 016b7a97a..a4add0889 100644 --- a/src/common/StateManager.cxx +++ b/src/common/StateManager.cxx @@ -198,7 +198,7 @@ void StateManager::update() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction StateManager::loadState(int slot) +void StateManager::loadState(int slot) { if(myOSystem.hasConsole()) { @@ -216,7 +216,7 @@ AdjustFunction StateManager::loadState(int slot) buf.str(""); buf << "Can't open/load from state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return nullptr; + return; } // First test if we have a valid header @@ -241,11 +241,10 @@ AdjustFunction StateManager::loadState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } - return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction StateManager::saveState(int slot) +void StateManager::saveState(int slot) { if(myOSystem.hasConsole()) { @@ -263,7 +262,7 @@ AdjustFunction StateManager::saveState(int slot) buf.str(""); buf << "Can't open/save to state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return nullptr; + return; } try @@ -276,7 +275,7 @@ AdjustFunction StateManager::saveState(int slot) { buf << "Error saving state " << slot; myOSystem.frameBuffer().showMessage(buf.str()); - return nullptr; + return; } // Do a complete state save using the Console @@ -295,23 +294,20 @@ AdjustFunction StateManager::saveState(int slot) myOSystem.frameBuffer().showMessage(buf.str()); } - return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction StateManager::changeState(bool next) +void StateManager::changeState(int direction) { - myCurrentSlot += next ? 1 : -1; - if (myCurrentSlot < 0) - myCurrentSlot = 9; - else - myCurrentSlot %= 10; + myCurrentSlot = BSPF::clampw(myCurrentSlot + direction, 0, 9); // Print appropriate message ostringstream buf; - buf << "Changed to slot " << myCurrentSlot; + if(direction) + buf << "Changed to state slot " << myCurrentSlot; + else + buf << "State slot " << myCurrentSlot; myOSystem.frameBuffer().showMessage(buf.str()); - return std::bind(&StateManager::changeState, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index 3739b8c31..3da98499c 100644 --- a/src/common/StateManager.hxx +++ b/src/common/StateManager.hxx @@ -104,19 +104,21 @@ class StateManager @param slot The state 'slot' to load state from */ - AdjustFunction loadState(int slot = -1); + void loadState(int slot = -1); /** Save the current state from the system. @param slot The state 'slot' to save into */ - AdjustFunction saveState(int slot = -1); + void saveState(int slot = -1); /** Switches to the next higher or lower state slot (circular queue style). + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeState(bool next); + void changeState(int direction = +1); /** Toggles auto slot mode. diff --git a/src/common/bspf.hxx b/src/common/bspf.hxx index cfb801045..f21a99a4c 100644 --- a/src/common/bspf.hxx +++ b/src/common/bspf.hxx @@ -87,7 +87,7 @@ using StringList = std::vector; using ByteBuffer = std::unique_ptr; // NOLINT using DWordBuffer = std::unique_ptr; // NOLINT -using AdjustFunction = std::function; +using AdjustFunction = std::function; // We use KB a lot; let's make a literal for it constexpr uInt32 operator "" _KB(unsigned long long size) @@ -136,6 +136,10 @@ namespace BSPF { if(val < lower || val > upper) val = setVal; } + template inline T clampw(T val, T lower, T upper) + { + return (val < lower) ? upper : (val > upper) ? lower : val; + } // Convert string to given case inline const string& toUpperCase(string& s) diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 2d0ffaa6e..9764f1ac3 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -62,9 +62,9 @@ string NTSCFilter::getPreset() const { switch(myPreset) { - case Preset::COMPOSITE: return "COMPOSITE"; - case Preset::SVIDEO: return "S-VIDEO"; case Preset::RGB: return "RGB"; + case Preset::SVIDEO: return "S-VIDEO"; + case Preset::COMPOSITE: return "COMPOSITE"; case Preset::BAD: return "BAD ADJUST"; case Preset::CUSTOM: return "CUSTOM"; default: return "Disabled"; @@ -72,9 +72,10 @@ string NTSCFilter::getPreset() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, Int32& value) +void NTSCFilter::selectAdjustable(int direction, + string& text, string& valueText, Int32& value) { - if(next) + if(direction == +1) { #ifdef BLARGG_PALETTE myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; @@ -82,7 +83,7 @@ void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, In myCurrentAdjustable = (myCurrentAdjustable + 1) % 5; #endif } - else + else if(direction == -1) { #ifdef BLARGG_PALETTE if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; @@ -103,13 +104,22 @@ void NTSCFilter::selectAdjustable(bool next, string& text, string& valueText, In } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void NTSCFilter::changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue) +void NTSCFilter::changeAdjustable(int adjustable, int direction, + string& text, string& valueText, Int32& newValue) +{ + myCurrentAdjustable = adjustable; + changeCurrentAdjustable(direction, text, valueText, newValue); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void NTSCFilter::changeCurrentAdjustable(int direction, + string& text, string& valueText, Int32& newValue) { //if(myPreset != Preset::CUSTOM) // return "'Custom' TV mode not selected"; newValue = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); - newValue = BSPF::clamp(newValue + (increase ? 2 : -2), 0, 100); + newValue = BSPF::clamp(newValue + direction * 2, 0, 100); *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newValue); @@ -166,12 +176,12 @@ void NTSCFilter::getAdjustables(Adjustable& adjustable, Preset preset) const { switch(preset) { - case Preset::COMPOSITE: - convertToAdjustable(adjustable, AtariNTSC::TV_Composite); break; - case Preset::SVIDEO: - convertToAdjustable(adjustable, AtariNTSC::TV_SVideo); break; case Preset::RGB: convertToAdjustable(adjustable, AtariNTSC::TV_RGB); break; + case Preset::SVIDEO: + convertToAdjustable(adjustable, AtariNTSC::TV_SVideo); break; + case Preset::COMPOSITE: + convertToAdjustable(adjustable, AtariNTSC::TV_Composite); break; case Preset::BAD: convertToAdjustable(adjustable, AtariNTSC::TV_Bad); break; case Preset::CUSTOM: @@ -228,7 +238,7 @@ const std::array NTSCFilter::ourCustomAdjustables { "saturation", &myCustomSetup.saturation }, { "gamma", &myCustomSetup.gamma }, #else -const std::array NTSCFilter::ourCustomAdjustables = { { +const std::array NTSCFilter::ourCustomAdjustables = { { #endif { "sharpness", &myCustomSetup.sharpness }, { "resolution", &myCustomSetup.resolution }, diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index 6ccdcd155..b4b3aa713 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -47,6 +47,14 @@ class NTSCFilter BAD, CUSTOM }; + enum class Adjustables { + SHARPNESS, + RESOLUTION, + ARTIFACTS, + FRINGING, + BLEEDING, + NUM_ADJUSTABLES + }; /* Normally used in conjunction with custom mode, contains all aspects currently adjustable in NTSC TV emulation. */ @@ -90,8 +98,12 @@ class NTSCFilter // Changes are made this way since otherwise 20 key-combinations // would be needed to dynamically change each setting, and now // only 4 combinations are necessary - void selectAdjustable(bool next, string& text, string& valueText, Int32& value); - void changeAdjustable(bool increase, string& text, string& valueText, Int32& newValue); + void selectAdjustable(int direction, + string& text, string& valueText, Int32& value); + void changeAdjustable(int adjustable, int direction, + string& text, string& valueText, Int32& newValue); + void changeCurrentAdjustable(int direction, + string& text, string& valueText, Int32& newValue); // Load and save NTSC-related settings void loadConfig(const Settings& settings); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index be5643e81..1d5bb5e6c 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -349,24 +349,20 @@ bool Console::load(Serializer& in) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::selectFormat(bool next) +void Console::selectFormat(int direction) { string saveformat, message; - uInt32 format = myCurrentFormat; + Int32 format = myCurrentFormat; - if(next) - format = (myCurrentFormat + 1) % 7; - else - format = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; + format = BSPF::clampw(format + direction, 0, 6); - setFormat(format); - return std::bind(&Console::selectFormat, this, std::placeholders::_1); + setFormat(format, true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::setFormat(uInt32 format) +void Console::setFormat(uInt32 format, bool force) { - if(myCurrentFormat == format) + if(!force && myCurrentFormat == format) return; string saveformat, message; @@ -505,7 +501,7 @@ void Console::toggleTurbo() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::togglePhosphor() +void Console::togglePhosphor() { if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled()) { @@ -519,19 +515,14 @@ AdjustFunction Console::togglePhosphor() myOSystem.frameBuffer().tiaSurface().enablePhosphor(true); myOSystem.frameBuffer().showMessage("Phosphor effect enabled"); } - return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::changePhosphor(bool increase) +void Console::changePhosphor(int direction) { int blend = BSPF::stringToInt(myProperties.get(PropType::Display_PPBlend)); - if(increase) // increase blend - blend += 2; - else // decrease blend - blend -= 2; - blend = BSPF::clamp(blend, 0, 100); + blend = BSPF::clamp(blend + direction * 2, 0, 100); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); ostringstream val; @@ -545,7 +536,6 @@ AdjustFunction Console::changePhosphor(bool increase) val << "Off"; } myOSystem.frameBuffer().showMessage("Phosphor blend", val.str(), blend); - return std::bind(&Console::changePhosphor, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -622,15 +612,11 @@ void Console::fry() const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::changeVerticalCenter(bool increase) +void Console::changeVerticalCenter(int direction) { Int32 vcenter = myTIA->vcenter(); - if(increase) // increase vcenter - ++vcenter; - else // decrease vcenter - --vcenter; - vcenter = BSPF::clamp(vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); + vcenter = BSPF::clamp(vcenter + direction, myTIA->minVcenter(), myTIA->maxVcenter()); ostringstream ss, val; ss << vcenter; @@ -641,7 +627,6 @@ AdjustFunction Console::changeVerticalCenter(bool increase) val << (vcenter ? vcenter > 0 ? "+" : "" : " ") << vcenter << "px"; myOSystem.frameBuffer().showMessage("V-Center", val.str(), vcenter, myTIA->minVcenter(), myTIA->maxVcenter()); - return std::bind(&Console::changeVerticalCenter, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -654,15 +639,11 @@ void Console::updateVcenter(Int32 vcenter) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction Console::changeVSizeAdjust(bool increase) +void Console::changeVSizeAdjust(int direction) { Int32 newAdjustVSize = myTIA->adjustVSize(); - if(increase) // increase scanline adjustment - newAdjustVSize++; - else // decrease scanline adjustment - newAdjustVSize--; - newAdjustVSize = BSPF::clamp(newAdjustVSize, -5, 5); + newAdjustVSize = BSPF::clamp(newAdjustVSize + direction, -5, 5); if (newAdjustVSize != myTIA->adjustVSize()) { myTIA->setAdjustVSize(newAdjustVSize); @@ -674,7 +655,6 @@ AdjustFunction Console::changeVSizeAdjust(bool increase) val << (newAdjustVSize ? newAdjustVSize > 0 ? "+" : "" : " ") << newAdjustVSize << "%"; myOSystem.frameBuffer().showMessage("V-Size", val.str(), newAdjustVSize, -5, 5); - return std::bind(&Console::changeVSizeAdjust, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 8c48575ad..bcf4d2cf2 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -189,14 +189,14 @@ class Console : public Serializable, public ConsoleIO /** Toggle between NTSC/PAL/SECAM (and variants) display format. - @param next Select next if true, else previous + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction selectFormat(bool next = true); + void selectFormat(int direction = +1); /** Set NTSC/PAL/SECAM (and variants) display format. */ - void setFormat(uInt32 format); + void setFormat(uInt32 format, bool force = false); /** Get NTSC/PAL/SECAM (and variants) display format name @@ -217,14 +217,14 @@ class Console : public Serializable, public ConsoleIO /** Toggles phosphor effect. */ - AdjustFunction togglePhosphor(); + void togglePhosphor(); /** Change the "Display.PPBlend" variable. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changePhosphor(bool increase = true); + void changePhosphor(int direction = +1); /** Toggles the PAL color-loss effect. @@ -257,18 +257,18 @@ class Console : public Serializable, public ConsoleIO /** Change the "Display.VCenter" variable. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeVerticalCenter(bool increase = true); + void changeVerticalCenter(int direction = +1); /** Change the "TIA scanline adjust" variable. Note that there are currently two of these (NTSC and PAL). The currently active mode will determine which one is used. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeVSizeAdjust(bool increase = true); + void changeVSizeAdjust(int direction = +1); /** Returns the current framerate. diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 2102b57f6..fa8a4d04d 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -122,7 +122,7 @@ class Event ToggleFrameStats, ToggleSAPortOrder, ExitGame, // add new events from here to avoid that user remapped events get overwritten - SettingDecrease, SettingIncrease, + SettingDecrease, SettingIncrease, PreviousSetting, NextSetting, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 883d2b744..303f8061f 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -342,6 +342,78 @@ void EventHandler::handleSystemEvent(SystemEvent e, int, int) } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AdjustFunction EventHandler::cycleAdjustSetting(int direction) +{ + const bool isFullScreen = myOSystem.frameBuffer().fullScreen(); + const bool isCustomPalette = + myOSystem.settings().getString("palette") == PaletteHandler::SETTING_CUSTOM; + const bool isCustomFilter = + myOSystem.settings().getInt("tv.filter") == int(NTSCFilter::Preset::CUSTOM); + + do + { + myAdjustSetting = + AdjustSetting(BSPF::clampw(int(myAdjustSetting) + direction, 0, int(AdjustSetting::MAX_ADJ))); + // skip currently non-relevant adjustments + } while((myAdjustSetting == AdjustSetting::OVERSCAN && !isFullScreen) + || (myAdjustSetting == AdjustSetting::PALETTE_PHASE && !isCustomPalette) + || (myAdjustSetting >= AdjustSetting::NTSC_SHARPNESS + && myAdjustSetting <= AdjustSetting::NTSC_BLEEDING + && !isCustomFilter)); + + return getAdjustSetting(myAdjustSetting); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) +{ + // MUST have the same order as AdjustSetting + const AdjustFunction ADJUST_FUNCTIONS[int(AdjustSetting::NUM_ADJ)] = + { + std::bind(&Sound::adjustVolume, &myOSystem.sound(), _1), + std::bind(&FrameBuffer::selectVidMode, &myOSystem.frameBuffer(), _1), + std::bind(&FrameBuffer::changeOverscan, &myOSystem.frameBuffer(), _1), + std::bind(&Console::selectFormat, &myOSystem.console(), _1), + std::bind(&Console::changeVerticalCenter, &myOSystem.console(), _1), + std::bind(&Console::changeVSizeAdjust, &myOSystem.console(), _1), + // Palette adjustables + std::bind(&PaletteHandler::cyclePalette, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::PHASE_SHIFT, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::HUE, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::SATURATION, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::CONTRAST, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::BRIGHTNESS, _1), + std::bind(&PaletteHandler::changeAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), + PaletteHandler::GAMMA, _1), + // NTSC filter adjustables + std::bind(&TIASurface::changeNTSC, &myOSystem.frameBuffer().tiaSurface(), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::SHARPNESS), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::RESOLUTION), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::ARTIFACTS), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::FRINGING), _1), + std::bind(&TIASurface::changeNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), + int(NTSCFilter::Adjustables::BLEEDING), _1), + std::bind(&Console::changePhosphor, &myOSystem.console(), _1), + std::bind(&TIASurface::setScanlineIntensity, &myOSystem.frameBuffer().tiaSurface(), _1), + // Following functions are not used when cycling settings but for "direct only" hotkeys + std::bind(&StateManager::changeState, &myOSystem.state(), _1), + std::bind(&PaletteHandler::changeCurrentAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), _1), + std::bind(&TIASurface::changeCurrentNTSCAdjustable, &myOSystem.frameBuffer().tiaSurface(), _1), + }; + + return ADJUST_FUNCTIONS[int(setting)]; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) { @@ -349,30 +421,61 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) // or need to be preprocessed before passing them on const bool pressed = (value != 0); - // The global settings keys react as long as the setting message from the previous event is - // still displayed. When no message is displayed, volume adjustment will be the default event. - if(!myOSystem.frameBuffer().messageShown() || myAdjustFunction == nullptr) - myAdjustFunction = std::bind(&Sound::adjustVolume, &myOSystem.sound(), std::placeholders::_1); - - // Assume no adjust function will be pressed - const AdjustFunction oldAdjustFunction = myAdjustFunction; + // The global settings keys change settings or values as long as the setting + // message from the previous settings event is still displayed. + // Therefore, do not change global settings/values or direct values if + // a) the setting message is no longer shown + // b) other keys have been pressed + if(!myOSystem.frameBuffer().messageShown()) + { + myAdjustActive = false; + myAdjustDirect = AdjustSetting::NONE; + } + const bool adjustActive = myAdjustActive; + const AdjustSetting adjustDirect = myAdjustDirect; if(pressed) - myAdjustFunction = nullptr; + { + myAdjustActive = false; + myAdjustDirect = AdjustSetting::NONE; + } switch(event) { //////////////////////////////////////////////////////////////////////// - // Allow adjusting several (mostly repeated) settings using the same two hotkeys - case Event::SettingDecrease: - if(pressed && oldAdjustFunction != nullptr) - oldAdjustFunction(false); - myAdjustFunction = oldAdjustFunction; - return; + // Allow adjusting several (mostly repeated) settings using the same four hotkeys + case Event::PreviousSetting: + case Event::NextSetting: + if(pressed && !repeated) + { + const int direction = event == Event::PreviousSetting ? -1 : +1; + // Get (and display) the previous|next adjustment function, + // but do not change its value + cycleAdjustSetting(adjustActive ? direction : 0)(0); + myAdjustActive = true; + } + break; + + case Event::SettingDecrease: case Event::SettingIncrease: - if(pressed && oldAdjustFunction != nullptr) - oldAdjustFunction(true); - myAdjustFunction = oldAdjustFunction; + if(pressed) + { + const int direction = event == Event::SettingDecrease ? -1 : +1; + + // if a "direct only" hotkey was pressed last, use this one + if(adjustDirect != AdjustSetting::NONE) + { + myAdjustDirect = adjustDirect; + getAdjustSetting(myAdjustDirect)(direction); + } + else + { + // Get (and display) the current adjustment function, + // but only change its value if the function was already active before + getAdjustSetting(myAdjustSetting)(adjustActive ? direction : 0); + myAdjustActive = true; + } + } return; //////////////////////////////////////////////////////////////////////// @@ -419,76 +522,124 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) //////////////////////////////////////////////////////////////////////// case Event::Fry: - if (!repeated) myFryingFlag = pressed; + if(!repeated) myFryingFlag = pressed; return; case Event::ReloadConsole: - if (pressed && !repeated) myOSystem.reloadConsole(); + if(pressed && !repeated) myOSystem.reloadConsole(); return; case Event::VolumeDecrease: if(pressed) - myAdjustFunction = myOSystem.sound().adjustVolume(false); + { + myOSystem.sound().adjustVolume(-1); + myAdjustSetting = AdjustSetting::VOLUME; + myAdjustActive = true; + } return; case Event::VolumeIncrease: if(pressed) - myAdjustFunction = myOSystem.sound().adjustVolume(true); + { + myOSystem.sound().adjustVolume(+1); + myAdjustSetting = AdjustSetting::VOLUME; + myAdjustActive = true; + } return; case Event::SoundToggle: if(pressed && !repeated) + { myOSystem.sound().toggleMute(); + myAdjustSetting = AdjustSetting::VOLUME; + myAdjustActive = true; + } return; case Event::VidmodeDecrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().selectVidMode(false); + { + myOSystem.frameBuffer().selectVidMode(-1); + myAdjustSetting = AdjustSetting::ZOOM; + myAdjustActive = true; + } return; case Event::VidmodeIncrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().selectVidMode(true); + { + myOSystem.frameBuffer().selectVidMode(+1); + myAdjustSetting = AdjustSetting::ZOOM; + myAdjustActive = true; + } return; case Event::VCenterDecrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVerticalCenter(false); + if(pressed) + { + myOSystem.console().changeVerticalCenter(-1); + myAdjustSetting = AdjustSetting::VCENTER; + myAdjustActive = true; + } return; case Event::VCenterIncrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVerticalCenter(true); + if(pressed) + { + myOSystem.console().changeVerticalCenter(+1); + myAdjustSetting = AdjustSetting::VCENTER; + myAdjustActive = true; + } return; case Event::VSizeAdjustDecrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVSizeAdjust(false); + if(pressed) + { + myOSystem.console().changeVSizeAdjust(-1); + myAdjustSetting = AdjustSetting::VSIZE; + myAdjustActive = true; + } return; case Event::VSizeAdjustIncrease: - if (pressed) - myAdjustFunction = myOSystem.console().changeVSizeAdjust(true); + if(pressed) + { + myOSystem.console().changeVSizeAdjust(+1); + myAdjustSetting = AdjustSetting::VSIZE; + myAdjustActive = true; + } return; case Event::PreviousPaletteAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(-1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::NextPaletteAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(true); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cycleAdjustable(+1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::PaletteAttributeDecrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(-1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::PaletteAttributeIncrease: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().changeAdjustable(true); + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().changeCurrentAdjustable(+1); + myAdjustDirect = AdjustSetting::PALETTE_CHANGE_ATTRIBUTE; + } return; case Event::ToggleFullScreen: @@ -496,23 +647,39 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::OverscanDecrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().changeOverscan(false); + if(pressed) + { + myOSystem.frameBuffer().changeOverscan(-1); + myAdjustSetting = AdjustSetting::OVERSCAN; + myAdjustActive = true; + } return; case Event::OverscanIncrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().changeOverscan(true); + if(pressed) + { + myOSystem.frameBuffer().changeOverscan(+1); + myAdjustSetting = AdjustSetting::OVERSCAN; + myAdjustActive = true; + } return; case Event::PreviousVideoMode: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(false); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().changeNTSC(-1); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::NextVideoMode: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSC(true); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().changeNTSC(+1); + myAdjustSetting = AdjustSetting::NTSC_PRESET; + myAdjustActive = true; + } return; case Event::VidmodeStd: @@ -541,47 +708,80 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::PreviousAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(-1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::NextAttribute: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(true); + if(pressed) + { + myOSystem.frameBuffer().tiaSurface().setNTSCAdjustable(+1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::DecreaseAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(false); + { + myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(-1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::IncreaseAttribute: if(pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().changeNTSCAdjustable(true); + { + myOSystem.frameBuffer().tiaSurface().changeCurrentNTSCAdjustable(+1); + myAdjustDirect = AdjustSetting::NTSC_CHANGE_ATTRIBUTE; + } return; case Event::ScanlinesDecrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(false); + if(pressed) + { + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-1); + myAdjustSetting = AdjustSetting::SCANLINES; + myAdjustActive = true; + + } return; case Event::ScanlinesIncrease: - if (pressed) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(true); + if(pressed) + { + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+1); + myAdjustSetting = AdjustSetting::SCANLINES; + myAdjustActive = true; + } return; case Event::PhosphorDecrease: - if (pressed) - myAdjustFunction = myOSystem.console().changePhosphor(false); + if(pressed) + { + myOSystem.console().changePhosphor(-1); + myAdjustSetting = AdjustSetting::PHOSPHOR; + myAdjustActive = true; + } return; case Event::PhosphorIncrease: - if (pressed) - myAdjustFunction = myOSystem.console().changePhosphor(true); + if(pressed) + { + myOSystem.console().changePhosphor(+1); + myAdjustSetting = AdjustSetting::PHOSPHOR; + myAdjustActive = true; + } return; case Event::TogglePhosphor: if(pressed && !repeated) - myAdjustFunction = myOSystem.console().togglePhosphor(); + { + myOSystem.console().togglePhosphor(); + myAdjustSetting = AdjustSetting::PHOSPHOR; + myAdjustActive = true; + } return; case Event::ToggleColorLoss: @@ -589,13 +789,21 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PaletteDecrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(false); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(-1); + myAdjustSetting = AdjustSetting::PALETTE; + myAdjustActive = true; + } return; case Event::PaletteIncrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(true); + if(pressed && !repeated) + { + myOSystem.frameBuffer().tiaSurface().paletteHandler().cyclePalette(+1); + myAdjustSetting = AdjustSetting::PALETTE; + myAdjustActive = true; + } return; case Event::ToggleInter: @@ -637,13 +845,21 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::FormatDecrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.console().selectFormat(false); + if(pressed && !repeated) + { + myOSystem.console().selectFormat(-1); + myAdjustSetting = AdjustSetting::TVFORMAT; + myAdjustActive = true; + } return; case Event::FormatIncrease: - if (pressed && !repeated) - myAdjustFunction = myOSystem.console().selectFormat(true); + if(pressed && !repeated) + { + myOSystem.console().selectFormat(+1); + myAdjustSetting = AdjustSetting::TVFORMAT; + myAdjustActive = true; + } return; case Event::ToggleGrabMouse: @@ -713,7 +929,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::SaveState: if(pressed && !repeated) - myAdjustFunction = myOSystem.state().saveState(); + { + myOSystem.state().saveState(); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::SaveAllStates: @@ -722,13 +941,19 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::PreviousState: - if (pressed) - myAdjustFunction = myOSystem.state().changeState(false); + if(pressed) + { + myOSystem.state().changeState(-1); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::NextState: if(pressed) - myAdjustFunction = myOSystem.state().changeState(true); + { + myOSystem.state().changeState(+1); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::ToggleAutoSlot: @@ -737,7 +962,10 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) case Event::LoadState: if(pressed && !repeated) - myAdjustFunction = myOSystem.state().loadState(); + { + myOSystem.state().loadState(); + myAdjustDirect = AdjustSetting::STATE; + } return; case Event::LoadAllStates: @@ -2011,6 +2239,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { { { Event::ScanlinesDecrease, "Decrease scanlines", "" }, { Event::ScanlinesIncrease, "Increase scanlines", "" }, + { Event::PreviousSetting, "Select previous setting", "" }, + { Event::NextSetting, "Select next setting", "" }, { Event::SettingDecrease, "Decrease current setting", "" }, { Event::SettingIncrease, "Increase current setting", "" }, @@ -2108,7 +2338,8 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, - Event::SettingDecrease, Event::SettingIncrease + Event::SettingDecrease, Event::SettingIncrease, + Event::PreviousSetting, Event::NextSetting, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 4b7e91af1..6051a9961 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -391,6 +391,41 @@ class EventHandler */ void removePhysicalJoystick(int index); + private: + enum class AdjustSetting + { + NONE = -1, + VOLUME, + ZOOM, + OVERSCAN, + TVFORMAT, + VCENTER, + VSIZE, + // Palette adjustables + PALETTE, + PALETTE_PHASE, + PALETTE_HUE, + PALETTE_SATURATION, + PALETTE_CONTRAST, + PALETTE_BRIGHTNESS, + PALETTE_GAMMA, + // NTSC filter adjustables + NTSC_PRESET, + NTSC_SHARPNESS, + NTSC_RESOLUTION, + NTSC_ARTIFACTS, + NTSC_FRINGING, + NTSC_BLEEDING, + PHOSPHOR, + SCANLINES, + MAX_ADJ = SCANLINES, + // Only used via direct hotkeys + STATE, + PALETTE_CHANGE_ATTRIBUTE, + NTSC_CHANGE_ATTRIBUTE, + NUM_ADJ + }; + private: // Define event groups static const Event::EventSet MiscEvents; @@ -417,6 +452,11 @@ class EventHandler int getEmulActionListIndex(int idx, const Event::EventSet& events) const; int getActionListIndex(int idx, Event::Group group) const; + // The following two methods are used for adjusting several settings using global hotkeys + // They return the function used to adjust the currenly selected setting + AdjustFunction cycleAdjustSetting(int direction); + AdjustFunction getAdjustSetting(AdjustSetting setting); + private: // Structure used for action menu items struct ActionList { @@ -425,7 +465,12 @@ class EventHandler string key; }; - AdjustFunction myAdjustFunction{nullptr}; + // ID of the currently selected global setting + AdjustSetting myAdjustSetting{AdjustSetting::VOLUME}; + // If true, the setting is visible and its value can be changed + bool myAdjustActive{false}; + // ID of the currently selected direct hotkey setting (0 if none) + AdjustSetting myAdjustDirect{AdjustSetting::NONE}; // Global Event object Event myEvent; @@ -470,7 +515,7 @@ class EventHandler #else PNG_SIZE = 0, #endif - EMUL_ACTIONLIST_SIZE = 154 + PNG_SIZE + COMBO_SIZE, + EMUL_ACTIONLIST_SIZE = 156 + PNG_SIZE + COMBO_SIZE, MENU_ACTIONLIST_SIZE = 18 ; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index dd88c3020..c49f592a2 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -537,7 +537,7 @@ void FrameBuffer::showMessage(const string& message, const string& valueText, const int VBORDER = fontHeight / 4; const int HBORDER = fontWidth * 1.25 / 2.0; - myMsg.counter = uInt32(myOSystem.frameRate()) * 3; // Show message for 3 seconds + myMsg.counter = uInt32(myOSystem.frameRate()) * 2; // Show message for 2 seconds if(myMsg.counter == 0) myMsg.counter = 120; @@ -672,7 +672,6 @@ inline bool FrameBuffer::drawMessage() #ifdef GUI_SUPPORT // Either erase the entire message (when time is reached), // or show again this frame - cerr << myMsg.counter << endl; if(myMsg.counter == 0) { myMsg.enabled = false; @@ -760,7 +759,7 @@ inline bool FrameBuffer::drawMessage() // align bar with bottom of text const int y = VBORDER + font().desc().ascent - bheight; - // draw gauge bar + // draw gauge bar myMsg.surface->fillRect(x - BORDER, y, swidth + BORDER * 2, bheight, kSliderBGColor); myMsg.surface->fillRect(x, y + BORDER, bwidth, bheight - BORDER * 2, kSliderColor); // draw tickmark in the middle of the bar @@ -994,12 +993,12 @@ void FrameBuffer::toggleFullscreen() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction FrameBuffer::changeOverscan(bool increase) +void FrameBuffer::changeOverscan(int direction) { if (fullScreen()) { int oldOverscan = myOSystem.settings().getInt("tia.fs_overscan"); - int overscan = BSPF::clamp(oldOverscan + (increase ? 1 : -1), 0, 10); + int overscan = BSPF::clamp(oldOverscan + direction, 0, 10); if (overscan != oldOverscan) { @@ -1010,14 +1009,16 @@ AdjustFunction FrameBuffer::changeOverscan(bool increase) } ostringstream val; - val << (overscan ? overscan > 0 ? "+" : "" : " ") << overscan << "%"; + if(overscan) + val << (overscan > 0 ? "+" : "" ) << overscan << "%"; + else + val << "Off"; myOSystem.frameBuffer().showMessage("Overscan", val.str(), overscan, 0, 10); } - return std::bind(&FrameBuffer::changeOverscan, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction FrameBuffer::selectVidMode(bool next) +void FrameBuffer::selectVidMode(int direction) { EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && @@ -1025,11 +1026,11 @@ AdjustFunction FrameBuffer::selectVidMode(bool next) // Only applicable when in TIA/emulation mode if(!tiaMode) - return nullptr; + return; - if(next) + if(direction == +1) myCurrentModeList->next(); - else + else if(direction == -1) myCurrentModeList->previous(); saveCurrentWindowPosition(); @@ -1050,7 +1051,10 @@ AdjustFunction FrameBuffer::selectVidMode(bool next) myTIASurface->initialize(myOSystem.console(), mode); resetSurfaces(); - showMessage("Zoom", mode.description, mode.zoom, supportedTIAMinZoom(), myTIAMaxZoom); + if(fullScreen()) + showMessage(mode.description); + else + showMessage("Zoom", mode.description, mode.zoom, supportedTIAMinZoom(), myTIAMaxZoom); myOSystem.sound().mute(oldMuteState); if(fullScreen()) @@ -1059,11 +1063,9 @@ AdjustFunction FrameBuffer::selectVidMode(bool next) else myOSystem.settings().setValue("tia.zoom", mode.zoom); - return std::bind(&FrameBuffer::selectVidMode, this, std::placeholders::_1); + return; } myOSystem.sound().mute(oldMuteState); - - return nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1196,12 +1198,12 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) VideoMode mode1(baseWidth * myTIAMaxZoom, baseHeight * myTIAMaxZoom, myFullscreenDisplays[i].w, myFullscreenDisplays[i].h, VideoMode::Stretch::Preserve, overscan, - "Preserve aspect, no stretch", myTIAMaxZoom, i); + "Fullscreen: Preserve aspect, no stretch", myTIAMaxZoom, i); myFullscreenModeLists[i].add(mode1); VideoMode mode2(baseWidth * myTIAMaxZoom, baseHeight * myTIAMaxZoom, myFullscreenDisplays[i].w, myFullscreenDisplays[i].h, VideoMode::Stretch::Fill, overscan, - "Ignore aspect, full stretch", myTIAMaxZoom, i); + "Fullscreen: Ignore aspect, full stretch", myTIAMaxZoom, i); myFullscreenModeLists[i].add(mode2); } } diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 4dd55f7f5..52f6eeae7 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -265,9 +265,9 @@ class FrameBuffer /** Changes the fullscreen overscan. - @param increase Increase if true, else decrease + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeOverscan(bool increase = true); + void changeOverscan(int direction = +1); /** This method is called when the user wants to switch to the next @@ -277,9 +277,9 @@ class FrameBuffer direction = -1 means go to the next lower video mode direction = +1 means go to the next higher video mode - @param next Select next if true, else previous + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction selectVidMode(bool next = true); + void selectVidMode(int direction = +1); /** Sets the state of the cursor (hidden or grabbed) based on the diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx index a03223f71..4e1fda0d5 100644 --- a/src/emucore/Sound.hxx +++ b/src/emucore/Sound.hxx @@ -88,10 +88,9 @@ class Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - virtual AdjustFunction adjustVolume(bool increase) = 0; + virtual void adjustVolume(int direction = 1) = 0; /** This method is called to provide information about the sound device. diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 88a41415c..afaad7855 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -200,7 +200,7 @@ void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::changeNTSC(bool next) +void TIASurface::changeNTSC(int direction) { constexpr NTSCFilter::Preset PRESETS[] = { NTSCFilter::Preset::OFF, NTSCFilter::Preset::RGB, NTSCFilter::Preset::SVIDEO, @@ -208,14 +208,14 @@ AdjustFunction TIASurface::changeNTSC(bool next) }; int preset = myOSystem.settings().getInt("tv.filter"); - if(next) + if(direction == +1) { if(preset == int(NTSCFilter::Preset::CUSTOM)) preset = int(NTSCFilter::Preset::OFF); else preset++; } - else + else if (direction == -1) { if(preset == int(NTSCFilter::Preset::OFF)) preset = int(NTSCFilter::Preset::CUSTOM); @@ -223,39 +223,46 @@ AdjustFunction TIASurface::changeNTSC(bool next) preset--; } setNTSC(PRESETS[preset], true); - return std::bind(&TIASurface::changeNTSC, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::setNTSCAdjustable(bool next) +void TIASurface::setNTSCAdjustable(int direction) { string text, valueText; Int32 value; setNTSC(NTSCFilter::Preset::CUSTOM); - ntsc().selectAdjustable(next, text, valueText, value); + ntsc().selectAdjustable(direction, text, valueText, value); myOSystem.frameBuffer().showMessage(text, valueText, value); - return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); - } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::changeNTSCAdjustable(bool increase) +void TIASurface::changeNTSCAdjustable(int adjustable, int direction) { string text, valueText; Int32 newValue; setNTSC(NTSCFilter::Preset::CUSTOM); - ntsc().changeAdjustable(increase, text, valueText, newValue); + ntsc().changeAdjustable(adjustable, direction, text, valueText, newValue); myOSystem.frameBuffer().showMessage(text, valueText, newValue); - return std::bind(&TIASurface::changeNTSCAdjustable, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -AdjustFunction TIASurface::setScanlineIntensity(bool increase) +void TIASurface::changeCurrentNTSCAdjustable(int direction) +{ + string text, valueText; + Int32 newValue; + + setNTSC(NTSCFilter::Preset::CUSTOM); + ntsc().changeCurrentAdjustable(direction, text, valueText, newValue); + myOSystem.frameBuffer().showMessage(text, valueText, newValue); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::setScanlineIntensity(int direction) { ostringstream buf; - uInt32 intensity = enableScanlines(increase ? 2 : -2); + uInt32 intensity = enableScanlines(direction * 2); myOSystem.settings().setValue("tv.scanlines", intensity); enableNTSC(ntscEnabled()); @@ -265,18 +272,15 @@ AdjustFunction TIASurface::setScanlineIntensity(bool increase) else buf << "Off"; myFB.showMessage("Scanline intensity", buf.str(), intensity); - return std::bind(&TIASurface::setScanlineIntensity, this, std::placeholders::_1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 TIASurface::enableScanlines(int relative, int absolute) +uInt32 TIASurface::enableScanlines(int change) { FBSurface::Attributes& attr = mySLineSurface->attributes(); - if(relative == 0) attr.blendalpha = absolute; - else attr.blendalpha += relative; - attr.blendalpha = std::max(0, Int32(attr.blendalpha)); - attr.blendalpha = std::min(100U, attr.blendalpha); + attr.blendalpha += change; + attr.blendalpha = BSPF::clamp(Int32(attr.blendalpha), 0, 100); mySLineSurface->applyAttributes(); return attr.blendalpha; diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index ecb1de752..826ff75d9 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -91,18 +91,32 @@ class TIASurface /** Switch to next/previous NTSC filtering effect. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeNTSC(bool next); + void changeNTSC(int direction = +1); /** Switch to next/previous NTSC filtering adjustable. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction setNTSCAdjustable(bool next = true); + void setNTSCAdjustable(int direction = +1); + + /** + Increase/decrease given NTSC filtering adjustable. + + @param adjustable The adjustable to change + @param direction +1 indicates increase, -1 indicates decrease. + */ + void changeNTSCAdjustable(int adjustable, int direction); /** Increase/decrease current NTSC filtering adjustable. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction changeNTSCAdjustable(bool increase = true); + void changeCurrentNTSCAdjustable(int direction = +1); /** Retrieve palette handler. @@ -111,17 +125,18 @@ class TIASurface /** Increase/decrease current scanline intensity by given relative amount. + + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction setScanlineIntensity(bool increase); + void setScanlineIntensity(int direction = +1); /** Change scanline intensity and interpolation. - @param relative If non-zero, change current intensity by - 'relative' amount, otherwise set to 'absolute' + @param change change current intensity by 'change' @return New current intensity */ - uInt32 enableScanlines(int relative, int absolute = 50); + uInt32 enableScanlines(int change); /** Enable/disable/query phosphor effect. diff --git a/src/libretro/SoundLIBRETRO.hxx b/src/libretro/SoundLIBRETRO.hxx index ad5966a9c..f99c8f341 100644 --- a/src/libretro/SoundLIBRETRO.hxx +++ b/src/libretro/SoundLIBRETRO.hxx @@ -95,10 +95,9 @@ class SoundLIBRETRO : public Sound /** Adjusts the volume of the sound device based on the given direction. - @param increase Increase or decrease the current volume by a predefined - amount + @param direction +1 indicates increase, -1 indicates decrease. */ - AdjustFunction adjustVolume(bool increase) override { return nullptr; } + void adjustVolume(int direction = +1) override { } /** This method is called to provide information about the sound device. From 16f5797e31b0503e61897ab65d8f2b0eee1c3caf Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 13:00:38 +0200 Subject: [PATCH 39/42] added two more methods to global hotkeys updated and restructured hotkey documentation --- Changes.txt | 11 +- docs/index.html | 290 ++++++++++++++++++-------------- src/common/PKeyboardHandler.cxx | 5 + src/emucore/Console.cxx | 9 +- src/emucore/Console.hxx | 2 +- src/emucore/EventHandler.cxx | 38 +++-- src/emucore/EventHandler.hxx | 4 +- src/emucore/FrameBuffer.cxx | 8 +- src/emucore/FrameBuffer.hxx | 2 +- 9 files changed, 219 insertions(+), 150 deletions(-) diff --git a/Changes.txt b/Changes.txt index 83f2abc26..557157f25 100644 --- a/Changes.txt +++ b/Changes.txt @@ -22,6 +22,11 @@ * Added 'Custom' palette, generated from user controlled phase shifts. + * Added that adjustable audio & video settings are displayed as gauge bars + + * Added four global hotkeys which allow selecting and changing numerous + audio & video settings without having to remember the dedicated hotkeys + * Added 'Turbo' mode, runs the game as fast as the computer allows. * Added that paddle centering (per ROM) and sensitivity can be adjusted @@ -39,6 +44,9 @@ * Added displaying last write address in the debugger. + * Added debugger pseudo-register '_scanend', which gives the number of + scanlines at the end of the last frame. + * Added detection of color and audio data in DiStella. * Restored 'cfg' directory for Distella config files. @@ -47,9 +55,6 @@ * Removed unused CV+ and DASH bank switching types. - * Added debugger pseudo-register '_scanend', which gives the number of - scanlines at the end of the last frame. - -Have fun! diff --git a/docs/index.html b/docs/index.html index 5c5204863..3bf9ee26a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1336,8 +1336,100 @@ -

    Palettes (can be remapped, only active in TIA mode)

    +

    Audio & Video Keys (can be remapped)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FunctionKey (Standard)Key (macOS)
    Toggle soundControl + ]Control + ]
    Decrease volumeAlt + [Cmd + [
    Increase volumeAlt + ]Cmd + ]
    Switch to next larger zoom level in windowed mode, +
    toggle stretching in fullscreen mode
    Alt + =Cmd + =
    Switch to next smaller zoom level in windowed mode, +
    toggle stretching in fullscreen mode
    Alt + -Cmd + -
    Toggle windowed/fullscreen modeAlt + EnterCmd + Enter
    Decrease overscan in fullscreen modeShift + PageDownShift-Fn + Down arrow
    Increase overscan in fullscreen modeShift + PageUpShift-Fn + Up arrow
    Move display down (uses "Display.VCenter")Alt + PageDownCmd-Fn + Down arrow
    Move display up (uses "Display.VCenter")Alt + PageUpCmd-Fn + Up arrow
    Decrease vertical display sizeShift-Alt + PageUpShift-Cmd-Fn + Up arrow
    Increase vertical display sizeShift-Alt + PageDownShift-Cmd-Fn + Down arrow
    Switch to previous display format (NTSC/PAL/SECAM etc.)Shift-Control + fShift-Control + f
    Switch to next display format (NTSC/PAL/SECAM etc.)Control + fControl + f
    Toggle display interpolationControl + iControl + i
    + These settings can also be changed using Global Audio & Video Keys
    +
    + +

    Palettes Keys (can be remapped)

    @@ -1346,43 +1438,48 @@ - + - + - + - + - + - + + + +
    Function
    Select previous palette (Standard/Z26/User/Custom)Select previous palette (Standard/z26/User/Custom) Shift-Control + p Shift-Control + p
    Select next palette (Standard/Z26/User/Custom)Select next palette (Standard/z26/User/Custom) Control + p Control + p
    Select previous palette attributeSelect previous palette attribute Shift-Alt + 9 Shift-Cmd + 9
    Select next palette attributeSelect next palette attribute Alt + 9 Cmd + 9
    Decrease selected palette attributeDecrease selected palette attribute Shift-Alt + 0 Shift-Cmd + 0
    Increase selected palette attributeIncrease selected palette attribute Alt + 0 Cmd + 0
    + These settings can also be changed using Global Audio & Video Keys
    +
    -

    TV effects (can be remapped, only active in TIA mode)

    +

    TV effects Keys (can be remapped)

    @@ -1391,73 +1488,112 @@ - + - + - + - + - + - + - - - + - - + - - + - + - + These settings can also be changed using Global Audio & Video Keys + + + +
    Key (macOS)
    Select previous TV effects presetSelect previous TV effects preset Shift-Alt + 1 Shift-Cmd + 1
    Select next TV effects presetSelect next TV effects preset Alt + 1 Cmd + 1
    Select previous 'Custom' mode attribute (*)Select previous 'Custom' mode attribute (*) Shift-Alt + 2 Shift-Cmd + 2
    Select next 'Custom' mode attribute (*)Select next 'Custom' mode attribute (*) Alt + 2 Cmd + 2
    Decrease 'Custom' selected attribute value (*)Decrease 'Custom' selected attribute value (*) Shift-Alt + 3 Shift-Cmd + 3
    Increase 'Custom' selected attribute value (*)Increase 'Custom' selected attribute value (*) Alt + 3 Cmd + 3
    Toggle 'phosphor' mode Alt + p Cmd + p
    Decrease 'phosphor' blendDecrease 'phosphor' blend Shift-Alt + 4 Shift-Cmd + 4
    Increase 'phosphor' blendIncrease 'phosphor' blend Alt + 4 Cmd + 4
    Decrease scanline intensityDecrease scanline intensity Shift-Alt + 5 Shift-Cmd + 5
    Increase scanline intensityIncrease scanline intensity Alt + 5 Cmd + 5
    - Items marked as (*) will also switch to 'Custom' preset mode
    + Items marked as (*) will also switch to 'Custom' mode
    +

    Global Audio & Video Keys (can be remapped)

    +

    These keys allow selecting and changing audio & video settings without having to remember the + dedicated keys.

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    FunctionKey (Standard)Key (macOS)
    Select previous AV settingEndFn + Left arrow
    Select next AV settingHomeFn + Right arrow
    Decrease current AV settingPageDownFn + Down arrow
    Increase current AV setting + PageUpFn + Up arrow
    +

    Notes: +

      +
    • Only available if UI messages are enabled.
    • +
    • Currently not available settings are automatically skipped.
    • +
    • If a setting was selected via dedicated key, its value can also be changed with the + global keys.
    • +
    +


    + -

    Developer Keys in TIA mode (can be remapped)

    +

    Developer Keys (can be remapped)

    @@ -1575,7 +1711,7 @@
    -

    Other Keys (can be remapped)

    +

    Other Emulation Keys (can be remapped)

    @@ -1583,93 +1719,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1767,27 +1821,9 @@ - - - - - - - - - - - - - - -
    Key (Standard) Key (macOS)
    Switch to next larger zoom level in windowed mode, -
    toggle stretching in fullscreen mode
    Alt + =Cmd + =
    Switch to next smaller zoom level in windowed mode, -
    toggle stretching in fullscreen mode
    Alt + -Cmd + -
    Toggle fullscreen/windowed modeAlt + EnterCmd + Enter
    Decrease overscan in fullscreen modeShift + PageDownShift + PageDown
    Increase overscan in fullscreen modeShift + PageUpShift + PageUp
    Move display up (uses "Display.VCenter")Alt + PageUpCmd + PageUp
    Move display down (uses "Display.VCenter")Alt + PageDownCmd + PageDown
    Switch display format in decreasing order (NTSC/PAL/SECAM etc.)Shift-Control + fShift-Control + f
    Switch display format in increasing order (NTSC/PAL/SECAM etc.)Control + fControl + f
    Toggle display interpolationControl + iControl + i
    Toggle 'Turbo' mode Control + t Control + t
    Toggle sound on/offControl + ]Control + ]
    Decrease volumeAlt + [Cmd + [
    Increase volumeAlt + ]Cmd + ]
    Switch mouse between controller emulation modes
    (see Game Properties - Controller)
    Control + 0Alt + Up arrow Cmd + Up arrow
    Decrease current setting (*)PageDownPageDown
    Increase current setting (*) - PageUpPageUp
    - (*) Note: These keys allow easy changing of the current displayed selection (e.g. volume (default), - phosphor, zoom...) without having to use the original keys.
    -

    UI keys in Text Editing areas (cannot be remapped)

    +

    UI Keys in Text Editing areas (cannot be remapped)

    diff --git a/src/common/PKeyboardHandler.cxx b/src/common/PKeyboardHandler.cxx index c09cd48fb..cf4a31831 100644 --- a/src/common/PKeyboardHandler.cxx +++ b/src/common/PKeyboardHandler.cxx @@ -494,8 +494,13 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo {Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL}, {Event::PaletteIncrease, KBDK_P, KBDM_CTRL}, +#ifndef BSPF_MACOS {Event::PreviousSetting, KBDK_END}, {Event::NextSetting, KBDK_HOME}, +#else + {Event::PreviousSetting, KBDK_HOME}, + {Event::NextSetting, KBDK_END}, +#endif {Event::SettingDecrease, KBDK_PAGEDOWN}, {Event::SettingIncrease, KBDK_PAGEUP}, diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 1d5bb5e6c..59c5cad32 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -468,17 +468,20 @@ void Console::enableColorLoss(bool state) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleInter() +void Console::toggleInter(bool toggle) { bool enabled = myOSystem.settings().getBool("tia.inter"); - myOSystem.settings().setValue("tia.inter", !enabled); + if(toggle) + enabled = !enabled; + + myOSystem.settings().setValue("tia.inter", enabled); // ... and apply potential setting changes to the TIA surface myOSystem.frameBuffer().tiaSurface().updateSurfaceSettings(); ostringstream ss; - ss << "Interpolation " << (!enabled ? "enabled" : "disabled"); + ss << "Interpolation " << (enabled ? "enabled" : "disabled"); myOSystem.frameBuffer().showMessage(ss.str()); } diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index bcf4d2cf2..d13588b07 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -206,7 +206,7 @@ class Console : public Serializable, public ConsoleIO /** Toggle interpolation on/off */ - void toggleInter(); + void toggleInter(bool toggle = true); /** Toggle turbo mode on/off diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 303f8061f..00f73f2be 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -368,11 +368,14 @@ AdjustFunction EventHandler::cycleAdjustSetting(int direction) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) { - // MUST have the same order as AdjustSetting + // Notes: + // - All methods MUST show a message + // - This array MUST have the same order as AdjustSetting const AdjustFunction ADJUST_FUNCTIONS[int(AdjustSetting::NUM_ADJ)] = { std::bind(&Sound::adjustVolume, &myOSystem.sound(), _1), std::bind(&FrameBuffer::selectVidMode, &myOSystem.frameBuffer(), _1), + std::bind(&FrameBuffer::toggleFullscreen, &myOSystem.frameBuffer(), _1), std::bind(&FrameBuffer::changeOverscan, &myOSystem.frameBuffer(), _1), std::bind(&Console::selectFormat, &myOSystem.console(), _1), std::bind(&Console::changeVerticalCenter, &myOSystem.console(), _1), @@ -405,6 +408,7 @@ AdjustFunction EventHandler::getAdjustSetting(AdjustSetting setting) int(NTSCFilter::Adjustables::BLEEDING), _1), std::bind(&Console::changePhosphor, &myOSystem.console(), _1), std::bind(&TIASurface::setScanlineIntensity, &myOSystem.frameBuffer().tiaSurface(), _1), + std::bind(&Console::toggleInter, &myOSystem.console(), _1), // Following functions are not used when cycling settings but for "direct only" hotkeys std::bind(&StateManager::changeState, &myOSystem.state(), _1), std::bind(&PaletteHandler::changeCurrentAdjustable, &myOSystem.frameBuffer().tiaSurface().paletteHandler(), _1), @@ -643,7 +647,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ToggleFullScreen: - if (pressed && !repeated) myOSystem.frameBuffer().toggleFullscreen(); + if(pressed && !repeated) + { + myOSystem.frameBuffer().toggleFullscreen(); + myAdjustSetting = AdjustSetting::FULLSCREEN; + myAdjustActive = true; + } return; case Event::OverscanDecrease: @@ -807,7 +816,12 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) return; case Event::ToggleInter: - if (pressed && !repeated) myOSystem.console().toggleInter(); + if(pressed && !repeated) + { + myOSystem.console().toggleInter(); + myAdjustSetting = AdjustSetting::INTERPOLATION; + myAdjustActive = true; + } return; case Event::ToggleTurbo: @@ -2338,8 +2352,6 @@ const Event::EventSet EventHandler::MiscEvents = { // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, - Event::SettingDecrease, Event::SettingIncrease, - Event::PreviousSetting, Event::NextSetting, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2347,19 +2359,21 @@ const Event::EventSet EventHandler::AudioVideoEvents = { Event::VolumeDecrease, Event::VolumeIncrease, Event::SoundToggle, Event::VidmodeDecrease, Event::VidmodeIncrease, Event::ToggleFullScreen, - Event::VidmodeStd, Event::VidmodeRGB, Event::VidmodeSVideo, Event::VidModeComposite, Event::VidModeBad, Event::VidModeCustom, - Event::PreviousAttribute, Event::NextAttribute, Event::DecreaseAttribute, Event::IncreaseAttribute, - Event::ScanlinesDecrease, Event::ScanlinesIncrease, - Event::PhosphorDecrease, Event::PhosphorIncrease, Event::TogglePhosphor, + Event::OverscanDecrease, Event::OverscanIncrease, Event::FormatDecrease, Event::FormatIncrease, Event::VCenterDecrease, Event::VCenterIncrease, Event::VSizeAdjustDecrease, Event::VSizeAdjustIncrease, - Event::OverscanDecrease, Event::OverscanIncrease, Event::PaletteDecrease, Event::PaletteIncrease, - Event::PreviousVideoMode, Event::NextVideoMode, Event::PreviousPaletteAttribute, Event::NextPaletteAttribute, Event::PaletteAttributeDecrease, Event::PaletteAttributeIncrease, - Event::ToggleInter + Event::VidmodeStd, Event::VidmodeRGB, Event::VidmodeSVideo, Event::VidModeComposite, Event::VidModeBad, Event::VidModeCustom, + Event::PreviousVideoMode, Event::NextVideoMode, + Event::PreviousAttribute, Event::NextAttribute, Event::DecreaseAttribute, Event::IncreaseAttribute, + Event::PhosphorDecrease, Event::PhosphorIncrease, Event::TogglePhosphor, + Event::ScanlinesDecrease, Event::ScanlinesIncrease, + Event::ToggleInter, + Event::PreviousSetting, Event::NextSetting, + Event::SettingDecrease, Event::SettingIncrease, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 6051a9961..0ab40c7cd 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -397,6 +397,7 @@ class EventHandler NONE = -1, VOLUME, ZOOM, + FULLSCREEN, OVERSCAN, TVFORMAT, VCENTER, @@ -418,7 +419,8 @@ class EventHandler NTSC_BLEEDING, PHOSPHOR, SCANLINES, - MAX_ADJ = SCANLINES, + INTERPOLATION, + MAX_ADJ = INTERPOLATION, // Only used via direct hotkeys STATE, PALETTE_CHANGE_ATTRIBUTE, diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index c49f592a2..4599a3860 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -987,9 +987,13 @@ void FrameBuffer::setFullscreen(bool enable) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::toggleFullscreen() +void FrameBuffer::toggleFullscreen(bool toggle) { - setFullscreen(!fullScreen()); + const bool isFullscreen = toggle ? !fullScreen() : fullScreen(); + + setFullscreen(isFullscreen); + + showMessage(string("Fullscreen ") + (isFullscreen ? "enabled" : "disabled")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 52f6eeae7..3912f38cd 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -260,7 +260,7 @@ class FrameBuffer /** Toggles between fullscreen and window mode. */ - void toggleFullscreen(); + void toggleFullscreen(bool toggle = true); /** Changes the fullscreen overscan. From af947900faa0fa8e293b73101acec0fdab1a5e88 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 16:42:12 +0200 Subject: [PATCH 40/42] Revert "removed audio dialog screenshot" This reverts commit e4ac8df6f9f4b30ac448fc145ffe5cf8b0ae0b05. --- docs/graphics/options_audio.png | Bin 0 -> 3879 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/graphics/options_audio.png diff --git a/docs/graphics/options_audio.png b/docs/graphics/options_audio.png new file mode 100644 index 0000000000000000000000000000000000000000..f37f07c6f33333eb2756b43a5e6fddaf2e48ad85 GIT binary patch literal 3879 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 literal 0 HcmV?d00001 From 77ac37e706ff0d80dd8a4df75f8af689516c2ac9 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Sat, 16 May 2020 18:41:32 -0230 Subject: [PATCH 41/42] Revert "Very small optimization for const char* instead of strings." This reverts commit 378829da5a2d5bc734326bf82cb8eb8e4006b1d2. --- src/common/FrameBufferSDL2.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 93a12615d..4d013a35d 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -144,11 +144,11 @@ void FrameBufferSDL2::queryHardware(vector& fullscreenRes, struct RenderName { - const char* const sdlName; - const char* const stellaName; + string sdlName; + string stellaName; }; // Create name map for all currently known SDL renderers - static constexpr std::array RENDERER_NAMES = {{ + static const std::array RENDERER_NAMES = {{ { "direct3d", "Direct3D" }, { "metal", "Metal" }, { "opengl", "OpenGL" }, From 63f141400770080236e289d2f886cc117cc19e2f Mon Sep 17 00:00:00 2001 From: thrust26 Date: Sat, 16 May 2020 23:47:15 +0200 Subject: [PATCH 42/42] minor fix, make sure that a message is displayed when switching TV format --- src/common/PaletteHandler.hxx | 2 +- src/emucore/Console.cxx | 2 +- src/emucore/EventHandler.cxx | 3 +++ src/gui/VideoAudioDialog.cxx | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/common/PaletteHandler.hxx b/src/common/PaletteHandler.hxx index 817c5fb5e..bd102d9f0 100644 --- a/src/common/PaletteHandler.hxx +++ b/src/common/PaletteHandler.hxx @@ -74,7 +74,7 @@ class PaletteHandler Increase or decrease given palette adjustable. @param adjustable The adjustable to change - @param direction +1 indicates increase, -1 indicates decrease. + @param direction +1 indicates increase, -1 indicates decrease. */ void changeAdjustable(int adjustable, int direction); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 59c5cad32..1e796a0bd 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -373,7 +373,7 @@ void Console::setFormat(uInt32 format, bool force) { case 0: // auto-detect { - if (myFormatAutodetected) return; + if (!force && myFormatAutodetected) return; myDisplayFormat = formatFromFilename(); if (myDisplayFormat == "AUTO") diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 00f73f2be..fa87be91d 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -456,6 +456,9 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated) // Get (and display) the previous|next adjustment function, // but do not change its value cycleAdjustSetting(adjustActive ? direction : 0)(0); + // Fallback message when no message is displayed by method + //if(!myOSystem.frameBuffer().messageShown()) + // myOSystem.frameBuffer().showMessage("Message " + std::to_string(int(myAdjustSetting))); myAdjustActive = true; } break; diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 5d569014a..48fdcc8de 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -311,11 +311,11 @@ void VideoAudioDialog::addTVEffectsTab() CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity", kScanlinesChanged) // Create buttons in 2nd column - xpos = myTVSharp->getRight() + fontWidth * 2; + int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + fontWidth * 2.5; + xpos = _w - HBORDER - 2 * 2 - cloneWidth; ypos = VBORDER - VGAP / 2; // Adjustable presets - int cloneWidth = _font.getStringWidth("Clone Bad Adjust") + fontWidth * 2.5; #define CREATE_CLONE_BUTTON(obj, desc) \ myClone ## obj = \ new ButtonWidget(myTab, _font, xpos, ypos, cloneWidth, buttonHeight,\
    KeyEditor Function