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 * Gets the palette index for black based on the platform 272 */ 273 uint8 getPlatformBlack() const; 274 275 /** 276 * Gets the palette index for white based on the platform 277 */ 278 uint8 getPlatformWhite() const; 279 280 /** 281 * Submits a palette to display. Entries marked as "used" in the submitted 282 * palette are merged into `_sourcePalette`. 283 */ 284 void submit(const Palette &palette); 285 void submit(const HunkPalette &palette); 286 287 /** 288 * Applies all fades, cycles, remaps, and varies for the current frame to 289 * `nextPalette`. 290 */ 291 bool updateForFrame(); 292 293 /** 294 * Copies all palette entries from `sourcePalette` to `nextPalette` and 295 * applies remaps. Unlike `updateForFrame`, this call does not apply fades, 296 * cycles, or varies. 297 */ 298 void updateFFrame(); 299 300 /** 301 * Copies all entries from `nextPalette` to `currentPalette` and updates the 302 * backend's raw palette. 303 */ 304 void updateHardware(); 305 306 private: 307 ResourceManager *_resMan; 308 309 /** 310 * The palette revision version. Increments once per game loop that changes 311 * the source palette. 312 */ 313 uint32 _version; 314 315 /** 316 * Whether or not the hardware palette needs updating. 317 */ 318 bool _needsUpdate; 319 320 #ifdef USE_RGB_COLOR 321 /** 322 * A local copy of the hardware palette. Used when the backend is in a true 323 * color mode and a change to the game's internal framebuffer occurs that 324 * needs to be reconverted from 8bpp to the backend's bit depth. 325 */ 326 uint8 _hardwarePalette[256 * 3]; 327 #endif 328 329 /** 330 * The currently displayed palette. 331 */ 332 Palette _currentPalette; 333 334 /** 335 * The unmodified source palette loaded by kPalette. Additional palette 336 * entries may be mixed into the source palette by CelObj objects, which 337 * contain their own palettes. 338 */ 339 Palette _sourcePalette; 340 341 /** 342 * The palette to be used when the hardware is next updated. 343 * On update, `_nextPalette` is transferred to `_currentPalette`. 344 */ 345 Palette _nextPalette; 346 347 /** 348 * Creates and returns a new Palette object with data from the given 349 * resource ID. 350 */ 351 Palette getPaletteFromResource(const GuiResourceId paletteId) const; 352 353 /** 354 * Merges used colors in the `from` palette into the `to` palette. 355 */ 356 void mergePalette(Palette &to, const Palette &from); 357 358 /** 359 * Applies all varies, cycles, and fades to `_nextPalette`. 360 */ 361 void applyAll(); 362 363 #pragma mark - 364 #pragma mark Varying 365 public: 366 /** 367 * Blends the `target` palette into the current palette over `time` ticks. 368 * 369 * @param target The target palette. 370 * @param percent The amount that the target palette should be blended into 371 * the source palette by the end of the vary. 372 * @param ticks The number of ticks that it should take for the blend to be 373 * completed. 374 * @param fromColor The first palette entry that should be blended. 375 * @param toColor The last palette entry that should be blended. 376 */ 377 void setVary(const Palette &target, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor); 378 379 /** 380 * Gets the current vary blend amount. 381 */ getVaryPercent()382 inline int16 getVaryPercent() const { return ABS(_varyPercent); } 383 384 /** 385 * Changes the percentage of the current vary to `percent`, to be completed 386 * over `time` ticks, if there is a currently active vary target palette. 387 */ 388 void setVaryPercent(const int16 percent, const int32 time); 389 390 /** 391 * Changes the amount of time, in ticks, an in-progress palette vary should 392 * take to finish. 393 */ 394 void setVaryTime(const int32 ticks); 395 396 /** 397 * Changes the vary percent and time to perform the vary. 398 */ 399 void setVaryTime(const int16 percent, const int32 ticks); 400 401 /** 402 * Removes the active palette vary. 403 */ 404 void varyOff(); 405 406 /** 407 * Pauses any active palette vary. 408 */ 409 void varyPause(); 410 411 /** 412 * Unpauses any paused palette vary. 413 */ 414 void varyOn(); 415 416 /** 417 * Sets the target palette for the blend. 418 */ 419 void setTarget(const Palette &palette); 420 421 /** 422 * Sets the start palette for the blend. 423 */ 424 void setStart(const Palette &palette); 425 426 /** 427 * Merges a new start palette into the existing start palette. 428 */ 429 void mergeStart(const Palette &palette); 430 431 /** 432 * Merges a new target palette into the existing target palette. 433 */ 434 void mergeTarget(const Palette &palette); 435 436 /** 437 * Applies any active palette vary to `_nextPalette`. 438 */ 439 void applyVary(); 440 441 void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor); 442 void kernelPalVaryMergeTarget(const GuiResourceId paletteId); 443 void kernelPalVarySetTarget(const GuiResourceId paletteId); 444 void kernelPalVarySetStart(const GuiResourceId paletteId); 445 void kernelPalVaryMergeStart(const GuiResourceId paletteId); 446 void kernelPalVaryPause(const bool pause); 447 448 private: 449 /** 450 * An optional palette used to provide source colors for a palette vary 451 * operation. If this palette is not specified, `_sourcePalette` is used 452 * instead. 453 */ 454 Common::ScopedPtr<Palette> _varyStartPalette; 455 456 /** 457 * An optional palette used to provide target colors for a palette vary 458 * operation. 459 */ 460 Common::ScopedPtr<Palette> _varyTargetPalette; 461 462 /** 463 * The minimum palette index that has been varied from the source palette. 464 */ 465 uint8 _varyFromColor; 466 467 /** 468 * The maximum palette index that has been varied from the source palette. 469 */ 470 uint8 _varyToColor; 471 472 /** 473 * The tick at the last time the palette vary was updated. 474 */ 475 uint32 _varyLastTick; 476 477 /** 478 * The amount of time that should elapse, in ticks, between each cycle of a 479 * palette vary animation. 480 */ 481 int32 _varyTime; 482 483 /** 484 * The direction of change: -1, 0, or 1. 485 */ 486 int16 _varyDirection; 487 488 /** 489 * The amount, in percent, that the vary color is currently blended into the 490 * source color. 491 */ 492 int16 _varyPercent; 493 494 /** 495 * The target amount that a vary color will be blended into the source 496 * color. 497 */ 498 int16 _varyTargetPercent; 499 500 /** 501 * The number of times palette varying has been paused. 502 */ 503 uint16 _varyNumTimesPaused; 504 505 #pragma mark - 506 #pragma mark Cycling 507 public: getCycleMap()508 inline const bool *getCycleMap() const { return _cycleMap; } 509 510 /** 511 * Cycle palette entries between `fromColor` and `toColor`, inclusive. 512 * Palette cyclers may not overlap. `fromColor` is used in other methods as 513 * the key for looking up a cycler. 514 * 515 * @param fromColor The first color in the cycle. 516 * @param toColor The last color in the cycle. 517 * @param delay The number of ticks that should elapse between cycles. 518 * @param direction A negative `direction` will cycle backwards instead of 519 * forwards. The numeric value of this argument is ignored; 520 * only its sign is used to determine direction. 521 */ 522 void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay); 523 524 /** 525 * Performs a round of palette cycling. 526 * 527 * @param fromColor The color key for the cycler. 528 * @param speed The number of entries that should be cycled this round. 529 */ 530 void doCycle(const uint8 fromColor, const int16 speed); 531 532 /** 533 * Unpauses the cycler starting at `fromColor`. 534 */ 535 void cycleOn(const uint8 fromColor); 536 537 /** 538 * Pauses the cycler starting at `fromColor`. 539 */ 540 void cyclePause(const uint8 fromColor); 541 542 /** 543 * Unpauses all cyclers. 544 */ 545 void cycleAllOn(); 546 547 /** 548 * Pauses all cyclers. 549 */ 550 void cycleAllPause(); 551 552 /** 553 * Removes the cycler starting at `fromColor`. 554 */ 555 void cycleOff(const uint8 fromColor); 556 557 /** 558 * Removes all cyclers. 559 */ 560 void cycleAllOff(); 561 562 private: 563 enum { 564 kNumCyclers = 10 565 }; 566 567 typedef Common::ScopedPtr<PalCycler> PalCyclerOwner; 568 PalCyclerOwner _cyclers[kNumCyclers]; 569 570 /** 571 * Updates the `currentCycle` of the given `cycler` by `speed` entries. 572 */ 573 void updateCycler(PalCycler &cycler, const int16 speed); 574 575 /** 576 * The cycle map is used to detect overlapping cyclers, and to avoid 577 * remapping to palette entries that are being cycled. 578 * 579 * According to SSCI, when two cyclers overlap, a fatal error has occurred 580 * and the engine will display an error and then exit. 581 * 582 * The color remapping system avoids attempts to remap to palette entries 583 * that are cycling because they won't be the expected color once the cycler 584 * updates the palette entries. 585 */ 586 bool _cycleMap[256]; 587 588 /** 589 * Marks `numColorsToClear` colors starting at `fromColor` in the cycle 590 * map as inactive. 591 */ 592 void clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear); 593 594 /** 595 * Marks `numColorsToClear` colors starting at `fromColor` in the cycle 596 * map as active. 597 */ 598 void setCycleMap(const uint16 fromColor, const uint16 numColorsToClear); 599 600 /** 601 * Gets the cycler object that starts at the given `fromColor`, or NULL if 602 * there is no cycler for that color. 603 */ 604 PalCycler *getCycler(const uint16 fromColor); 605 606 /** 607 * Advances all cyclers by one step, regardless of whether or not it is time 608 * to perform another cycle. 609 */ 610 void applyAllCycles(); 611 612 /** 613 * Advances, by one step, only the cyclers whose time has come to cycle. 614 */ 615 void applyCycles(); 616 617 #pragma mark - 618 #pragma mark Fading 619 public: 620 /** 621 * Sets the intensity level for a range of palette entries. An intensity of 622 * zero indicates total darkness. Intensity may also be set above 100 623 * percent to increase the intensity of a palette entry. 624 */ 625 void setFade(const uint16 percent, const uint8 fromColor, const uint16 toColor); 626 627 /** 628 * Resets the intensity of all palette entries to 100%. 629 */ 630 void fadeOff(); 631 632 /** 633 * Applies intensity values to the palette entries in `_nextPalette`. 634 */ 635 void applyFade(); 636 637 private: 638 /** 639 * The intensity levels of each palette entry, in percent. Defaults to 100. 640 */ 641 uint16 _fadeTable[256]; 642 643 #pragma mark - 644 #pragma mark Gamma correction 645 public: 646 enum { 647 /** 648 * The number of available gamma corrections. 649 */ 650 numGammaTables = 6 651 }; 652 653 /** 654 * Sets the gamma correction level, from 0 (off) to `numGammaTables`, 655 * inclusive. 656 */ setGamma(const int16 level)657 void setGamma(const int16 level) { 658 _gammaLevel = CLIP<int16>(level, 0, numGammaTables) - 1; 659 _gammaChanged = true; 660 } 661 662 private: 663 /** 664 * The current gamma correction level. -1 means no correction. 665 */ 666 int8 _gammaLevel; 667 668 /** 669 * Whether the gamma correction has changed since the last call to update 670 * the hardware palette. 671 */ 672 bool _gammaChanged; 673 }; 674 675 } // End of namespace Sci 676 677 #endif 678