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 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
|
/* 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<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
|