diff options
Diffstat (limited to 'engines/sci/graphics/remap32.h')
-rw-r--r-- | engines/sci/graphics/remap32.h | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/engines/sci/graphics/remap32.h b/engines/sci/graphics/remap32.h new file mode 100644 index 0000000000..5f629d733e --- /dev/null +++ b/engines/sci/graphics/remap32.h @@ -0,0 +1,400 @@ +/* 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; + assert(index < _remaps.size()); + 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<SingleRemap> 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 |