1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef SCI_GRAPHICS_PALETTE32_H 24 #define SCI_GRAPHICS_PALETTE32_H 25 26 #include "common/ptr.h" 27 28 namespace Sci { 29 30 #pragma mark HunkPalette 31 32 /** 33 * HunkPalette represents a raw palette resource read from disk. The data 34 * structure of a HunkPalette allows palettes to be smaller than 256 colors. It 35 * also allows multiple palettes to be stored in one HunkPalette, though in 36 * SCI32 games there seems to only ever be one palette per HunkPalette. 37 */ 38 class HunkPalette { 39 public: 40 HunkPalette(const SciSpan<const byte> &rawPalette); 41 42 static void write(SciSpan<byte> &out, const Palette &palette); 43 44 static uint32 calculateHunkPaletteSize(const uint16 numIndexes = 256, const bool sharedUsed = true) { 45 const int numPalettes = 1; 46 return kHunkPaletteHeaderSize + 47 /* slack bytes between hunk header & palette offset table */ 2 + 48 /* palette offset table */ 2 * numPalettes + 49 /* palette data */ (kEntryHeaderSize + numIndexes * (/* RGB */ 3 + !sharedUsed)) * numPalettes; 50 } 51 52 /** 53 * Gets the version of the palette. Used to avoid resubmitting a HunkPalette 54 * which has already been submitted for the next frame. 55 */ getVersion()56 uint32 getVersion() const { return _version; } 57 58 /** 59 * Sets the version of the palette. 60 */ 61 void setVersion(const uint32 version) const; 62 63 /** 64 * Converts the hunk palette to a standard Palette. 65 */ 66 const Palette toPalette() const; 67 68 private: 69 enum { 70 /** 71 * The offset into the HunkPalette header of the number of palettes in 72 * the HunkPalette. 73 */ 74 kNumPaletteEntriesOffset = 10, 75 76 /** 77 * The size of the HunkPalette header. 78 */ 79 kHunkPaletteHeaderSize = 13, 80 81 /** 82 * The size of a palette entry header. 83 */ 84 kEntryHeaderSize = 22 85 }; 86 87 enum { 88 /** 89 * The offset of the start color within the palette entry header. 90 */ 91 kEntryStartColorOffset = 10, 92 93 /** 94 * The offset of the color count within the palette entry header. 95 */ 96 kEntryNumColorsOffset = 14, 97 98 /** 99 * The offset of the shared used palette index flag within the palette 100 * entry header. 101 */ 102 kEntryUsedOffset = 16, 103 104 /** 105 * The offset of the flag within the palette entry header that says 106 * whether or not the corresponding palette data includes used flags for 107 * each palette index individually. 108 */ 109 kEntrySharedUsedOffset = 17, 110 111 /** 112 * The offset of the hunk palette version within the palette entry 113 * header. 114 */ 115 kEntryVersionOffset = 18 116 }; 117 118 /** 119 * The header for a palette inside the HunkPalette. 120 */ 121 struct EntryHeader { 122 /** 123 * The start color. 124 */ 125 uint8 startColor; 126 127 /** 128 * The number of palette colors in this entry. 129 */ 130 uint16 numColors; 131 132 /** 133 * The default `used` flag. 134 */ 135 bool used; 136 137 /** 138 * Whether or not all palette entries share the same `used` value in 139 * `defaultFlag`. 140 */ 141 bool sharedUsed; 142 143 /** 144 * The palette version. 145 */ 146 uint32 version; 147 }; 148 149 /** 150 * The version number from the last time this palette was submitted to 151 * GfxPalette32. 152 */ 153 mutable uint32 _version; 154 155 /** 156 * The number of palettes stored in the hunk palette. In SCI32 games this is 157 * always 1. 158 */ 159 uint8 _numPalettes; 160 161 /** 162 * The raw palette data for this hunk palette. 163 */ 164 SciSpan<const byte> _data; 165 166 /** 167 * Returns a struct that describes the palette held by this HunkPalette. The 168 * entry header is reconstructed on every call from the raw palette data. 169 */ 170 const EntryHeader getEntryHeader() const; 171 172 /** 173 * Returns a pointer to the palette data within the hunk palette. 174 */ getPalPointer()175 SciSpan<const byte> getPalPointer() const { 176 return _data.subspan(kHunkPaletteHeaderSize + (2 * _numPalettes)); 177 } 178 }; 179 180 #pragma mark - 181 #pragma mark PalCycler 182 183 enum PalCyclerDirection { 184 kPalCycleBackward = 0, 185 kPalCycleForward = 1 186 }; 187 188 /** 189 * PalCycler represents a range of palette entries that are rotated on a timer. 190 */ 191 struct PalCycler { 192 /** 193 * The color index of this palette cycler. This value is used as the unique 194 * key for this PalCycler object. 195 */ 196 uint8 fromColor; 197 198 /** 199 * The number of palette slots which are to be cycled by this cycler. 200 */ 201 uint16 numColorsToCycle; 202 203 /** 204 * The current position of the first palette entry. 205 */ 206 uint8 currentCycle; 207 208 /** 209 * The direction of the cycler. 210 */ 211 PalCyclerDirection direction; 212 213 /** 214 * The last tick the cycler cycled. 215 */ 216 uint32 lastUpdateTick; 217 218 /** 219 * The amount of time in ticks each cycle should take to complete. In other 220 * words, the higher the delay, the slower the cycle animation. If delay is 221 * 0, the cycler does not automatically cycle and needs to be cycled 222 * manually by calling `doCycle`. 223 */ 224 int16 delay; 225 226 /** 227 * The number of times this cycler has been paused. 228 */ 229 uint16 numTimesPaused; 230 }; 231 232 #pragma mark - 233 #pragma mark GfxPalette32 234 235 class GfxPalette32 { 236 public: 237 GfxPalette32(ResourceManager *resMan); 238 239 void saveLoadWithSerializer(Common::Serializer &s); 240 241 /** 242 * Gets the palette that will be use for the next frame. 243 */ getNextPalette()244 inline const Palette &getNextPalette() const { return _nextPalette; }; 245 246 /** 247 * Gets the palette that is used for the current frame. 248 */ getCurrentPalette()249 inline const Palette &getCurrentPalette() const { return _currentPalette; }; 250 251 #ifdef USE_RGB_COLOR 252 /** 253 * Gets the raw hardware palette in RGB format. This should be used instead 254 * of `::PaletteManager::grabPalette` when the OSystem screen is >8bpp. 255 */ getHardwarePalette()256 inline const uint8 *getHardwarePalette() const { return _hardwarePalette; }; 257 #endif 258 259 /** 260 * Loads a palette into GfxPalette32 with the given resource ID. 261 */ 262 bool loadPalette(const GuiResourceId resourceId); 263 264 /** 265 * Finds the nearest color in the current palette matching the given RGB 266 * value. 267 */ 268 int16 matchColor(const uint8 r, const uint8 g, const uint8 b); 269 270 /** 271 * Submits a palette to display. Entries marked as "used" in the submitted 272 * palette are merged into `_sourcePalette`. 273 */ 274 void submit(const Palette &palette); 275 void submit(const HunkPalette &palette); 276 277 /** 278 * Applies all fades, cycles, remaps, and varies for the current frame to 279 * `nextPalette`. 280 */ 281 bool updateForFrame(); 282 283 /** 284 * Copies all palette entries from `sourcePalette` to `nextPalette` and 285 * applies remaps. Unlike `updateForFrame`, this call does not apply fades, 286 * cycles, or varies. 287 */ 288 void updateFFrame(); 289 290 /** 291 * Copies all entries from `nextPalette` to `currentPalette` and updates the 292 * backend's raw palette. 293 */ 294 void updateHardware(); 295 296 private: 297 ResourceManager *_resMan; 298 299 /** 300 * The palette revision version. Increments once per game loop that changes 301 * the source palette. 302 */ 303 uint32 _version; 304 305 /** 306 * Whether or not the hardware palette needs updating. 307 */ 308 bool _needsUpdate; 309 310 #ifdef USE_RGB_COLOR 311 /** 312 * A local copy of the hardware palette. Used when the backend is in a true 313 * color mode and a change to the game's internal framebuffer occurs that 314 * needs to be reconverted from 8bpp to the backend's bit depth. 315 */ 316 uint8 _hardwarePalette[256 * 3]; 317 #endif 318 319 /** 320 * The currently displayed palette. 321 */ 322 Palette _currentPalette; 323 324 /** 325 * The unmodified source palette loaded by kPalette. Additional palette 326 * entries may be mixed into the source palette by CelObj objects, which 327 * contain their own palettes. 328 */ 329 Palette _sourcePalette; 330 331 /** 332 * The palette to be used when the hardware is next updated. 333 * On update, `_nextPalette` is transferred to `_currentPalette`. 334 */ 335 Palette _nextPalette; 336 337 /** 338 * Creates and returns a new Palette object with data from the given 339 * resource ID. 340 */ 341 Palette getPaletteFromResource(const GuiResourceId paletteId) const; 342 343 /** 344 * Merges used colors in the `from` palette into the `to` palette. 345 */ 346 void mergePalette(Palette &to, const Palette &from); 347 348 /** 349 * Applies all varies, cycles, and fades to `_nextPalette`. 350 */ 351 void applyAll(); 352 353 #pragma mark - 354 #pragma mark Varying 355 public: 356 /** 357 * Blends the `target` palette into the current palette over `time` ticks. 358 * 359 * @param target The target palette. 360 * @param percent The amount that the target palette should be blended into 361 * the source palette by the end of the vary. 362 * @param ticks The number of ticks that it should take for the blend to be 363 * completed. 364 * @param fromColor The first palette entry that should be blended. 365 * @param toColor The last palette entry that should be blended. 366 */ 367 void setVary(const Palette &target, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor); 368 369 /** 370 * Gets the current vary blend amount. 371 */ getVaryPercent()372 inline int16 getVaryPercent() const { return ABS(_varyPercent); } 373 374 /** 375 * Changes the percentage of the current vary to `percent`, to be completed 376 * over `time` ticks, if there is a currently active vary target palette. 377 */ 378 void setVaryPercent(const int16 percent, const int32 time); 379 380 /** 381 * Changes the amount of time, in ticks, an in-progress palette vary should 382 * take to finish. 383 */ 384 void setVaryTime(const int32 ticks); 385 386 /** 387 * Changes the vary percent and time to perform the vary. 388 */ 389 void setVaryTime(const int16 percent, const int32 ticks); 390 391 /** 392 * Removes the active palette vary. 393 */ 394 void varyOff(); 395 396 /** 397 * Pauses any active palette vary. 398 */ 399 void varyPause(); 400 401 /** 402 * Unpauses any paused palette vary. 403 */ 404 void varyOn(); 405 406 /** 407 * Sets the target palette for the blend. 408 */ 409 void setTarget(const Palette &palette); 410 411 /** 412 * Sets the start palette for the blend. 413 */ 414 void setStart(const Palette &palette); 415 416 /** 417 * Merges a new start palette into the existing start palette. 418 */ 419 void mergeStart(const Palette &palette); 420 421 /** 422 * Merges a new target palette into the existing target palette. 423 */ 424 void mergeTarget(const Palette &palette); 425 426 /** 427 * Applies any active palette vary to `_nextPalette`. 428 */ 429 void applyVary(); 430 431 void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor); 432 void kernelPalVaryMergeTarget(const GuiResourceId paletteId); 433 void kernelPalVarySetTarget(const GuiResourceId paletteId); 434 void kernelPalVarySetStart(const GuiResourceId paletteId); 435 void kernelPalVaryMergeStart(const GuiResourceId paletteId); 436 void kernelPalVaryPause(const bool pause); 437 438 private: 439 /** 440 * An optional palette used to provide source colors for a palette vary 441 * operation. If this palette is not specified, `_sourcePalette` is used 442 * instead. 443 */ 444 Common::ScopedPtr<Palette> _varyStartPalette; 445 446 /** 447 * An optional palette used to provide target colors for a palette vary 448 * operation. 449 */ 450 Common::ScopedPtr<Palette> _varyTargetPalette; 451 452 /** 453 * The minimum palette index that has been varied from the source palette. 454 */ 455 uint8 _varyFromColor; 456 457 /** 458 * The maximum palette index that has been varied from the source palette. 459 */ 460 uint8 _varyToColor; 461 462 /** 463 * The tick at the last time the palette vary was updated. 464 */ 465 uint32 _varyLastTick; 466 467 /** 468 * The amount of time that should elapse, in ticks, between each cycle of a 469 * palette vary animation. 470 */ 471 int32 _varyTime; 472 473 /** 474 * The direction of change: -1, 0, or 1. 475 */ 476 int16 _varyDirection; 477 478 /** 479 * The amount, in percent, that the vary color is currently blended into the 480 * source color. 481 */ 482 int16 _varyPercent; 483 484 /** 485 * The target amount that a vary color will be blended into the source 486 * color. 487 */ 488 int16 _varyTargetPercent; 489 490 /** 491 * The number of times palette varying has been paused. 492 */ 493 uint16 _varyNumTimesPaused; 494 495 #pragma mark - 496 #pragma mark Cycling 497 public: getCycleMap()498 inline const bool *getCycleMap() const { return _cycleMap; } 499 500 /** 501 * Cycle palette entries between `fromColor` and `toColor`, inclusive. 502 * Palette cyclers may not overlap. `fromColor` is used in other methods as 503 * the key for looking up a cycler. 504 * 505 * @param fromColor The first color in the cycle. 506 * @param toColor The last color in the cycle. 507 * @param delay The number of ticks that should elapse between cycles. 508 * @param direction A negative `direction` will cycle backwards instead of 509 * forwards. The numeric value of this argument is ignored; 510 * only its sign is used to determine direction. 511 */ 512 void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay); 513 514 /** 515 * Performs a round of palette cycling. 516 * 517 * @param fromColor The color key for the cycler. 518 * @param speed The number of entries that should be cycled this round. 519 */ 520 void doCycle(const uint8 fromColor, const int16 speed); 521 522 /** 523 * Unpauses the cycler starting at `fromColor`. 524 */ 525 void cycleOn(const uint8 fromColor); 526 527 /** 528 * Pauses the cycler starting at `fromColor`. 529 */ 530 void cyclePause(const uint8 fromColor); 531 532 /** 533 * Unpauses all cyclers. 534 */ 535 void cycleAllOn(); 536 537 /** 538 * Pauses all cyclers. 539 */ 540 void cycleAllPause(); 541 542 /** 543 * Removes the cycler starting at `fromColor`. 544 */ 545 void cycleOff(const uint8 fromColor); 546 547 /** 548 * Removes all cyclers. 549 */ 550 void cycleAllOff(); 551 552 private: 553 enum { 554 kNumCyclers = 10 555 }; 556 557 typedef Common::ScopedPtr<PalCycler> PalCyclerOwner; 558 PalCyclerOwner _cyclers[kNumCyclers]; 559 560 /** 561 * Updates the `currentCycle` of the given `cycler` by `speed` entries. 562 */ 563 void updateCycler(PalCycler &cycler, const int16 speed); 564 565 /** 566 * The cycle map is used to detect overlapping cyclers, and to avoid 567 * remapping to palette entries that are being cycled. 568 * 569 * According to SSCI, when two cyclers overlap, a fatal error has occurred 570 * and the engine will display an error and then exit. 571 * 572 * The color remapping system avoids attempts to remap to palette entries 573 * that are cycling because they won't be the expected color once the cycler 574 * updates the palette entries. 575 */ 576 bool _cycleMap[256]; 577 578 /** 579 * Marks `numColorsToClear` colors starting at `fromColor` in the cycle 580 * map as inactive. 581 */ 582 void clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear); 583 584 /** 585 * Marks `numColorsToClear` colors starting at `fromColor` in the cycle 586 * map as active. 587 */ 588 void setCycleMap(const uint16 fromColor, const uint16 numColorsToClear); 589 590 /** 591 * Gets the cycler object that starts at the given `fromColor`, or NULL if 592 * there is no cycler for that color. 593 */ 594 PalCycler *getCycler(const uint16 fromColor); 595 596 /** 597 * Advances all cyclers by one step, regardless of whether or not it is time 598 * to perform another cycle. 599 */ 600 void applyAllCycles(); 601 602 /** 603 * Advances, by one step, only the cyclers whose time has come to cycle. 604 */ 605 void applyCycles(); 606 607 #pragma mark - 608 #pragma mark Fading 609 public: 610 /** 611 * Sets the intensity level for a range of palette entries. An intensity of 612 * zero indicates total darkness. Intensity may also be set above 100 613 * percent to increase the intensity of a palette entry. 614 */ 615 void setFade(const uint16 percent, const uint8 fromColor, const uint16 toColor); 616 617 /** 618 * Resets the intensity of all palette entries to 100%. 619 */ 620 void fadeOff(); 621 622 /** 623 * Applies intensity values to the palette entries in `_nextPalette`. 624 */ 625 void applyFade(); 626 627 private: 628 /** 629 * The intensity levels of each palette entry, in percent. Defaults to 100. 630 */ 631 uint16 _fadeTable[256]; 632 633 #pragma mark - 634 #pragma mark Gamma correction 635 public: 636 enum { 637 /** 638 * The number of available gamma corrections. 639 */ 640 numGammaTables = 6 641 }; 642 643 /** 644 * Sets the gamma correction level, from 0 (off) to `numGammaTables`, 645 * inclusive. 646 */ setGamma(const int16 level)647 void setGamma(const int16 level) { 648 _gammaLevel = CLIP<int16>(level, 0, numGammaTables) - 1; 649 _gammaChanged = true; 650 } 651 652 private: 653 /** 654 * The current gamma correction level. -1 means no correction. 655 */ 656 int8 _gammaLevel; 657 658 /** 659 * Whether the gamma correction has changed since the last call to update 660 * the hardware palette. 661 */ 662 bool _gammaChanged; 663 }; 664 665 } // End of namespace Sci 666 667 #endif 668