mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-05 02:17:05 +00:00
1b42146955
* Rewrap comments to 80 columns * Clarify comments where possible
382 lines
11 KiB
C++
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
|