Colin Snover 1b42146955 SCI32: Clean up GfxRemap32
* Rewrap comments to 80 columns
* Clarify comments where possible
2017-10-06 22:11:03 -05:00

382 lines
11 KiB
C++

/* 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
* `_idealColors` needs to be updated.
*/
int16 _lastPercent;
/**
* The previous saturation value. Used to determine whether or not
* `_idealColors` 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 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);
// SSCI never really properly handled attempts to draw to a target with
// pixels above the remap color maximum. In RAMA, the cursor views have
// a remap color outlining the cursor, and so get drawn into a target
// surface filled with a skip color of 255. In SSCI, this causes the
// remapped color to be read from some statically allocated, never
// written memory and so always ends up being 0 (black).
if (targetColor >= ARRAYSIZE(singleRemap._remapColors)) {
return 0;
}
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