From c381a97d66e251accc6f335e41feeccda9f71a65 Mon Sep 17 00:00:00 2001 From: zrowny Date: Thu, 13 May 2021 20:54:06 -0400 Subject: [PATCH] Fix ImageImporter for colors outside of palette (#14649:) When converting to the internal palette, if a color is not in the palette, the ImageImporter now re-maps it only to those non "special" color indices ("special," meaning those for water effects, font, chain lift and so on, as well as the primary remappable color). Additionally, if the Importer is told to dither the image, it now does not dither colors that are already in the OpenRCT2 palette, or dither between remappable colors and non-remappable colors. --- src/openrct2/drawing/ImageImporter.cpp | 73 ++++++++++++++++---------- src/openrct2/drawing/ImageImporter.h | 15 +++++- 2 files changed, 58 insertions(+), 30 deletions(-) diff --git a/src/openrct2/drawing/ImageImporter.cpp b/src/openrct2/drawing/ImageImporter.cpp index fe7b313872..c447a0c3fc 100644 --- a/src/openrct2/drawing/ImageImporter.cpp +++ b/src/openrct2/drawing/ImageImporter.cpp @@ -217,24 +217,22 @@ int32_t ImageImporter::CalculatePaletteIndex( { auto& palette = StandardPalette; auto paletteIndex = GetPaletteIndex(palette, rgbaSrc); - if (mode == IMPORT_MODE::CLOSEST || mode == IMPORT_MODE::DITHERING) + if ((mode == IMPORT_MODE::CLOSEST || mode == IMPORT_MODE::DITHERING) && !IsInPalette(palette, rgbaSrc)) { - if (paletteIndex == PALETTE_TRANSPARENT && !IsTransparentPixel(rgbaSrc)) - { - paletteIndex = GetClosestPaletteIndex(palette, rgbaSrc); - } - } - if (mode == IMPORT_MODE::DITHERING) - { - if (!IsTransparentPixel(rgbaSrc) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc))) + paletteIndex = GetClosestPaletteIndex(palette, rgbaSrc); + if (mode == IMPORT_MODE::DITHERING) { auto dr = rgbaSrc[0] - static_cast(palette[paletteIndex].Red); auto dg = rgbaSrc[1] - static_cast(palette[paletteIndex].Green); auto db = rgbaSrc[2] - static_cast(palette[paletteIndex].Blue); + // We don't want to dither remappable colors with nonremappable colors, etc + PaletteIndexType thisIndexType = GetPaletteIndexType(paletteIndex); + if (x + 1 < width) { - if (!IsTransparentPixel(rgbaSrc + 4) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4))) + if (!IsInPalette(palette, rgbaSrc + 4) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4))) { // Right rgbaSrc[4] += dr * 7 / 16; @@ -247,8 +245,8 @@ int32_t ImageImporter::CalculatePaletteIndex( { if (x > 0) { - if (!IsTransparentPixel(rgbaSrc + 4 * (width - 1)) - && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * (width - 1)))) + if (!IsInPalette(palette, rgbaSrc + 4 * (width - 1)) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width - 1)))) { // Bottom left rgbaSrc[4 * (width - 1)] += dr * 3 / 16; @@ -258,7 +256,8 @@ int32_t ImageImporter::CalculatePaletteIndex( } // Bottom - if (!IsTransparentPixel(rgbaSrc + 4 * width) && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * width))) + if (!IsInPalette(palette, rgbaSrc + 4 * width) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * width))) { rgbaSrc[4 * width] += dr * 5 / 16; rgbaSrc[4 * width + 1] += dg * 5 / 16; @@ -267,8 +266,8 @@ int32_t ImageImporter::CalculatePaletteIndex( if (x + 1 < width) { - if (!IsTransparentPixel(rgbaSrc + 4 * (width + 1)) - && IsChangablePixel(GetPaletteIndex(palette, rgbaSrc + 4 * (width + 1)))) + if (!IsInPalette(palette, rgbaSrc + 4 * (width + 1)) + && thisIndexType == GetPaletteIndexType(GetClosestPaletteIndex(palette, rgbaSrc + 4 * (width + 1)))) { // Bottom right rgbaSrc[4 * (width + 1)] += dr * 1 / 16; @@ -279,6 +278,7 @@ int32_t ImageImporter::CalculatePaletteIndex( } } } + return paletteIndex; } @@ -304,23 +304,40 @@ bool ImageImporter::IsTransparentPixel(const int16_t* colour) } /** - * @returns true if pixel index is an index not used for remapping. + * @returns true if this colour is in the standard palette. + */ +bool ImageImporter::IsInPalette(const GamePalette& palette, int16_t* colour) +{ + return !(GetPaletteIndex(palette, colour) == PALETTE_TRANSPARENT && !IsTransparentPixel(colour)); +} + +/** + * @returns true if palette index is an index not used for a special purpose. */ bool ImageImporter::IsChangablePixel(int32_t paletteIndex) { - if (paletteIndex == PALETTE_TRANSPARENT) - return true; - if (paletteIndex == 0) - return false; + PaletteIndexType entryType = GetPaletteIndexType(paletteIndex); + return entryType != PaletteIndexType::Special && entryType != PaletteIndexType::PrimaryRemap; +} + +/** + * @returns the type of palette entry this is. + */ +ImageImporter::PaletteIndexType ImageImporter::GetPaletteIndexType(int32_t paletteIndex) +{ + if (paletteIndex <= 9) + return PaletteIndexType::Special; + if (paletteIndex >= 230 && paletteIndex <= 239) + return PaletteIndexType::Special; + if (paletteIndex == 255) + return PaletteIndexType::Special; + if (paletteIndex >= 243 && paletteIndex <= 254) + return PaletteIndexType::PrimaryRemap; if (paletteIndex >= 202 && paletteIndex <= 213) - return false; - if (paletteIndex == 226) - return false; - if (paletteIndex >= 227 && paletteIndex <= 229) - return false; - if (paletteIndex >= 243) - return false; - return true; + return PaletteIndexType::SecondaryRemap; + if (paletteIndex >= 46 && paletteIndex <= 57) + return PaletteIndexType::TertiaryRemap; + return PaletteIndexType::Normal; } int32_t ImageImporter::GetClosestPaletteIndex(const GamePalette& palette, const int16_t* colour) diff --git a/src/openrct2/drawing/ImageImporter.h b/src/openrct2/drawing/ImageImporter.h index def6288f39..70e61b046f 100644 --- a/src/openrct2/drawing/ImageImporter.h +++ b/src/openrct2/drawing/ImageImporter.h @@ -50,6 +50,15 @@ namespace OpenRCT2::Drawing IMPORT_MODE mode = IMPORT_MODE::DEFAULT) const; private: + enum class PaletteIndexType : uint8_t + { + Normal, + PrimaryRemap, + SecondaryRemap, + TertiaryRemap, + Special, + }; + static std::vector GetPixels( const uint8_t* pixels, uint32_t width, uint32_t height, IMPORT_FLAGS flags, IMPORT_MODE mode); static std::vector EncodeRaw(const int32_t* pixels, uint32_t width, uint32_t height); @@ -59,7 +68,9 @@ namespace OpenRCT2::Drawing IMPORT_MODE mode, int16_t* rgbaSrc, int32_t x, int32_t y, int32_t width, int32_t height); static int32_t GetPaletteIndex(const GamePalette& palette, int16_t* colour); static bool IsTransparentPixel(const int16_t* colour); + static bool IsInPalette(const GamePalette& palette, int16_t* colour); static bool IsChangablePixel(int32_t paletteIndex); + static PaletteIndexType GetPaletteIndexType(int32_t paletteIndex); static int32_t GetClosestPaletteIndex(const GamePalette& palette, const int16_t* colour); }; } // namespace OpenRCT2::Drawing @@ -176,7 +187,7 @@ constexpr const GamePalette StandardPalette = { { { 147, 219, 195, 255 }, { 167, 231, 207, 255 }, { 191, 247, 223, 255 }, - + // 94 - 105 (Green) { 0, 63, 15, 255 }, { 0, 83, 19, 255 }, @@ -353,7 +364,7 @@ constexpr const GamePalette StandardPalette = { { { 203, 203, 115, 255 }, { 151, 155, 55, 255 }, - // 240 - 242 (Exra grey) + // 240 - 242 (Extra grey) { 91, 91, 67, 255 }, { 107, 107, 83, 255 }, { 123, 123, 99, 255 },