1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
|
/* 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]`.
*
* Mac SSCI includes entry 236 in the non-remapped range at the cost of one
* remap entry and so the Mac remap range starts at 237. The final entry in
* this array, and the others in this class, is not used by PC games.
*/
uint8 _remapColors[237];
/**
* 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[237];
/**
* 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[237];
/**
* The ideal target RGB color values for each generated remap color.
*/
Color _idealColors[237];
/**
* 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[237];
/**
* 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[237];
/**
* 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) override;
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 >= _remapStartColor) {
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.
*/
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
|