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