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 +