/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef SCI_GRAPHICS_REMAP32_H #define SCI_GRAPHICS_REMAP32_H #include "common/algorithm.h" #include "common/array.h" #include "common/scummsys.h" #include "sci/graphics/helpers.h" namespace Sci { class GfxPalette32; enum RemapType { kRemapNone = 0, kRemapByRange = 1, kRemapByPercent = 2, kRemapToGray = 3, kRemapToPercentGray = 4 }; #pragma mark - #pragma mark SingleRemap /** * SingleRemap objects each manage one remapping operation. */ class SingleRemap { public: SingleRemap() : _type(kRemapNone) {} /** * The type of remap. */ RemapType _type; /** * The first color that should be shifted by a range * remap. */ uint8 _from; /** * The last color that should be shifted a range remap. */ uint8 _to; /** * The direction and amount that the colors should be * shifted in a range remap. */ int16 _delta; /** * The difference in brightness that should be * applied by a brightness (percent) remap. * * This value may be be greater than 100, in * which case the color will be oversaturated. */ int16 _percent; /** * The amount of desaturation that should be * applied by a saturation (gray) remap, where * 0 is full saturation and 100 is full * desaturation. */ uint8 _gray; /** * The final array used by CelObj renderers to composite * remapped pixels to the screen buffer. * * Here is how it works: * * The source bitmap being rendered will have pixels * within the remap range (236-245 or 236-254), and the * target buffer will have colors in the non-remapped * range (0-235). * * To arrive at the correct color, first the source * pixel is used to look up the correct SingleRemap for * that pixel. Then, the final composited color is * looked up in this array using the target's pixel * color. In other words, * `target = _remaps[remapEndColor - source].remapColors[target]`. */ uint8 _remapColors[236]; /** * Resets this SingleRemap's color information to * default values. */ void reset(); /** * Recalculates and reapplies remap colors to the * `_remapColors` array. */ bool update(); private: /** * The previous brightness value. Used to * determine whether or not targetColors needs * to be updated. */ int16 _lastPercent; /** * The previous saturation value. Used to * determine whether or not targetColors needs * to be updated. */ uint8 _lastGray; /** * The colors from the current GfxPalette32 palette * before this SingleRemap is applied. */ Color _originalColors[236]; /** * Map of colors that changed in `_originalColors` * when this SingleRemap was updated. This map is * transient and gets reset to `false` after the * SingleRemap finishes updating. */ bool _originalColorsChanged[236]; /** * The ideal target RGB color values for each generated * remap color. */ Color _idealColors[236]; /** * Map of colors that changed in `_idealColors` when * this SingleRemap was updated. This map is transient * and gets reset to `false` after the SingleRemap * finishes applying. */ bool _idealColorsChanged[236]; /** * When applying a SingleRemap, finding an appropriate * color in the palette is the responsibility of a * distance function. Once a match is found, the * distance of that match is stored here so that the * next time the SingleRemap is applied, it can check * the distance from the previous application and avoid * triggering an expensive redraw of the entire screen * if the new palette value only changed slightly. */ int _matchDistances[236]; /** * Computes the final target values for a range remap * and applies them directly to the `_remaps` map. * * @note Was ByRange in SSCI. */ bool updateRange(); /** * Computes the intermediate target values for a * brightness remap and applies them indirectly via * the `apply` method. * * @note Was ByPercent in SSCI. */ bool updateBrightness(); /** * Computes the intermediate target values for a * saturation remap and applies them indirectly via * the `apply` method. * * @note Was ToGray in SSCI. */ bool updateSaturation(); /** * Computes the intermediate target values for a * saturation + brightness bitmap and applies them * indirectly via the `apply` method. * * @note Was ToPercentGray in SSCI. */ bool updateSaturationAndBrightness(); /** * Computes and applies the final values to the * `_remaps` map. * * @note In SSCI, a boolean array of changed values * was passed into this method, but this was done by * creating arrays on the stack in the caller. Instead * of doing this, we simply add another member property * `_idealColorsChanged` and use that instead. */ bool apply(); /** * Calculates the square distance of two colors. * * @note In SSCI this method is Rgb24::Dist, but it is * only used by SingleRemap. */ int colorDistance(const Color &a, const Color &b) const; /** * Finds the closest index in the next palette matching * the given RGB color. Returns -1 if no match can be * found that is closer than `minimumDistance`. * * @note In SSCI, this method is SOLPalette::Match, but * this particular signature is only used by * SingleRemap. */ int16 matchColor(const Color &color, const int minimumDistance, int &outDistance, const bool *const blockedIndexes) const; }; #pragma mark - #pragma mark GfxRemap32 /** * This class provides color remapping support for SCI32 * games. */ class GfxRemap32 : public Common::Serializable { public: GfxRemap32(); void saveLoadWithSerializer(Common::Serializer &s); inline uint8 getRemapCount() const { return _numActiveRemaps; } inline uint8 getStartColor() const { return _remapStartColor; } inline uint8 getEndColor() const { return _remapEndColor; } inline uint8 getBlockedRangeStart() const { return _blockedRangeStart; } inline int16 getBlockedRangeCount() const { return _blockedRangeCount; } /** * Turns off remapping of the given color. If `color` is * 0, all remaps are turned off. */ void remapOff(const uint8 color); /** * Turns off all color remaps. */ void remapAllOff(); /** * Configures a SingleRemap for the remap color `color`. * The SingleRemap will shift palette colors between * `from` and `to` (inclusive) by `delta` palette * entries when the remap is applied. */ void remapByRange(const uint8 color, const int16 from, const int16 to, const int16 delta); /** * Configures a SingleRemap for the remap color `color` * to modify the brightness of remapped colors by * `percent`. */ void remapByPercent(const uint8 color, const int16 percent); /** * Configures a SingleRemap for the remap color `color` * to modify the saturation of remapped colors by * `gray`. */ void remapToGray(const uint8 color, const int8 gray); /** * Configures a SingleRemap for the remap color `color` * to modify the brightness of remapped colors by * `percent`, and saturation of remapped colors by * `gray`. */ void remapToPercentGray(const uint8 color, const int16 gray, const int16 percent); /** * Prevents GfxRemap32 from using the given range of * palette entries as potential remap targets. * * @NOTE Was DontMapToRange in SSCI. */ void blockRange(const uint8 from, const int16 count); /** * Determines whether or not the given color has an * active remapper. If it does not, it is treated as a * skip color and the pixel is not drawn. * * @note SSCI uses a boolean array to decide whether a * a pixel is remapped, but it is possible to get the * same information from `_remaps`, as this function * does. * Presumably, the separate array was created for * performance reasons, since this is called a lot in * the most critical section of the renderer. */ inline bool remapEnabled(uint8 color) const { const uint8 index = _remapEndColor - color; // At least KQ7 DOS uses remap colors that are outside the valid remap // range; in these cases, just treat those pixels as skip pixels (which // is how they would be treated in SSCI) if (index >= _remaps.size()) { return false; } return (_remaps[index]._type != kRemapNone); } /** * Calculates the correct color for a target by looking * up the target color in the SingleRemap that controls * the given sourceColor. If there is no remap for the * given color, it will be treated as a skip color. */ inline uint8 remapColor(const uint8 sourceColor, const uint8 targetColor) const { const uint8 index = _remapEndColor - sourceColor; assert(index < _remaps.size()); const SingleRemap &singleRemap = _remaps[index]; assert(singleRemap._type != kRemapNone); return singleRemap._remapColors[targetColor]; } /** * Updates all active remaps in response to a palette * change or a remap settings change. * * `paletteChanged` is true if the next palette in * GfxPalette32 has been previously modified by other * palette operations. */ bool remapAllTables(const bool paletteUpdated); private: typedef Common::Array SingleRemapsList; /** * The first index of the remap area in the system * palette. */ const uint8 _remapStartColor; /** * The last index of the remap area in the system * palette. */ uint8 _remapEndColor; /** * The number of currently active remaps. */ uint8 _numActiveRemaps; /** * The list of SingleRemaps. */ SingleRemapsList _remaps; /** * If true, indicates that one or more SingleRemaps were * reconfigured and all remaps need to be recalculated. */ bool _needsUpdate; /** * The first color that is blocked from being used as a * remap target color. */ uint8 _blockedRangeStart; /** * The size of the range of blocked colors. If zero, * all colors are potential targets for remapping. */ int16 _blockedRangeCount; }; } // End of namespace Sci #endif