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