diff options
author | Colin Snover | 2016-09-28 13:05:50 -0500 |
---|---|---|
committer | Colin Snover | 2016-09-29 19:39:16 -0500 |
commit | e412eaffbc47e5087401dc57912863bd59dcbf48 (patch) | |
tree | 0a5afb6caae9ce9d759a39b389270e620c58bb0d /engines | |
parent | 7ad9418583a6a5a15356d1ee6920d2cfa56f7d4d (diff) | |
download | scummvm-rg350-e412eaffbc47e5087401dc57912863bd59dcbf48.tar.gz scummvm-rg350-e412eaffbc47e5087401dc57912863bd59dcbf48.tar.bz2 scummvm-rg350-e412eaffbc47e5087401dc57912863bd59dcbf48.zip |
SCI32: Clean up and document GfxPalette32
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/engine/kgraphics32.cpp | 30 | ||||
-rw-r--r-- | engines/sci/graphics/celobj32.cpp | 2 | ||||
-rw-r--r-- | engines/sci/graphics/palette32.cpp | 499 | ||||
-rw-r--r-- | engines/sci/graphics/palette32.h | 451 |
4 files changed, 535 insertions, 447 deletions
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index cceb710f33..49215b27f4 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -961,17 +961,17 @@ reg_t kPaletteSetGamma(EngineState *s, int argc, reg_t *argv) { } reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) { - uint16 fromColor = argv[0].toUint16(); - uint16 toColor = argv[1].toUint16(); - uint16 percent = argv[2].toUint16(); + const uint16 fromColor = argv[0].toUint16(); + const uint16 toColor = argv[1].toUint16(); + const uint16 percent = argv[2].toUint16(); g_sci->_gfxPalette32->setFade(percent, fromColor, toColor); return s->r_acc; } reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) { - GuiResourceId paletteId = argv[0].toUint16(); - int time = argc > 1 ? argv[1].toSint16() * 60 : 0; - int16 percent = argc > 2 ? argv[2].toSint16() : 100; + const GuiResourceId paletteId = argv[0].toUint16(); + const int32 time = argc > 1 ? argv[1].toSint16() * 60 : 0; + const int16 percent = argc > 2 ? argv[2].toSint16() : 100; int16 fromColor; int16 toColor; @@ -987,9 +987,9 @@ reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) { } reg_t kPalVarySetPercent(EngineState *s, int argc, reg_t *argv) { - int time = argc > 0 ? argv[0].toSint16() * 60 : 0; - int16 percent = argc > 1 ? argv[1].toSint16() : 0; - g_sci->_gfxPalette32->setVaryPercent(percent, time, -1, -1); + const int32 time = argc > 0 ? argv[0].toSint16() * 60 : 0; + const int16 percent = argc > 1 ? argv[1].toSint16() : 0; + g_sci->_gfxPalette32->setVaryPercent(percent, time); return s->r_acc; } @@ -1003,31 +1003,31 @@ reg_t kPalVaryOff(EngineState *s, int argc, reg_t *argv) { } reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv) { - GuiResourceId paletteId = argv[0].toUint16(); + const GuiResourceId paletteId = argv[0].toUint16(); g_sci->_gfxPalette32->kernelPalVaryMergeTarget(paletteId); return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); } reg_t kPalVarySetTime(EngineState *s, int argc, reg_t *argv) { - int time = argv[0].toSint16() * 60; + const int32 time = argv[0].toSint16() * 60; g_sci->_gfxPalette32->setVaryTime(time); return s->r_acc; } reg_t kPalVarySetTarget(EngineState *s, int argc, reg_t *argv) { - GuiResourceId paletteId = argv[0].toUint16(); + const GuiResourceId paletteId = argv[0].toUint16(); g_sci->_gfxPalette32->kernelPalVarySetTarget(paletteId); return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); } reg_t kPalVarySetStart(EngineState *s, int argc, reg_t *argv) { - GuiResourceId paletteId = argv[0].toUint16(); + const GuiResourceId paletteId = argv[0].toUint16(); g_sci->_gfxPalette32->kernelPalVarySetStart(paletteId); return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); } reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv) { - GuiResourceId paletteId = argv[0].toUint16(); + const GuiResourceId paletteId = argv[0].toUint16(); g_sci->_gfxPalette32->kernelPalVaryMergeStart(paletteId); return make_reg(0, g_sci->_gfxPalette32->getVaryPercent()); } @@ -1043,7 +1043,6 @@ reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv) { const uint16 toColor = argv[1].toUint16(); const int16 direction = argv[2].toSint16(); const uint16 delay = argc > 3 ? argv[3].toUint16() : 0; - g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay); return s->r_acc; } @@ -1051,7 +1050,6 @@ reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv) { reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv) { const uint16 fromColor = argv[0].toUint16(); const int16 speed = argc > 1 ? argv[1].toSint16() : 1; - g_sci->_gfxPalette32->doCycle(fromColor, speed); return s->r_acc; } diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp index 5aa6ea3fb3..75140527d0 100644 --- a/engines/sci/graphics/celobj32.cpp +++ b/engines/sci/graphics/celobj32.cpp @@ -568,7 +568,7 @@ uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const { void CelObj::submitPalette() const { if (_hunkPaletteOffset) { - HunkPalette palette(getResPointer() + _hunkPaletteOffset); + const HunkPalette palette(getResPointer() + _hunkPaletteOffset); g_sci->_gfxPalette32->submit(palette); } } diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp index 135badb5a2..6b719f8e86 100644 --- a/engines/sci/graphics/palette32.cpp +++ b/engines/sci/graphics/palette32.cpp @@ -52,7 +52,7 @@ HunkPalette::HunkPalette(byte *rawPalette) : } } -void HunkPalette::setVersion(const uint32 version) { +void HunkPalette::setVersion(const uint32 version) const { if (_numPalettes != _data[10]) { error("Invalid HunkPalette"); } @@ -93,9 +93,9 @@ const Palette HunkPalette::toPalette() const { if (_numPalettes) { const EntryHeader header = getEntryHeader(); - byte *data = getPalPointer() + kEntryHeaderSize; + const byte *data = getPalPointer() + kEntryHeaderSize; - int16 end = header.startColor + header.numColors; + const int16 end = header.startColor + header.numColors; assert(end <= 256); if (header.sharedUsed) { @@ -118,20 +118,19 @@ const Palette HunkPalette::toPalette() const { return outPalette; } - #pragma mark - #pragma mark GfxPalette32 GfxPalette32::GfxPalette32(ResourceManager *resMan) : _resMan(resMan), + // Palette versioning _version(1), _needsUpdate(false), _currentPalette(), _sourcePalette(), _nextPalette(), - // Clut - _clutTable(nullptr), + // Palette varying _varyStartPalette(nullptr), _varyTargetPalette(nullptr), @@ -142,6 +141,7 @@ GfxPalette32::GfxPalette32(ResourceManager *resMan) _varyDirection(0), _varyTargetPercent(0), _varyNumTimesPaused(0), + // Palette cycling _cyclers(), _cycleMap() { @@ -161,44 +161,6 @@ GfxPalette32::~GfxPalette32() { cycleAllOff(); } -inline void mergePaletteInternal(Palette *const to, const Palette *const from) { - // The last color is always white, so it is not copied. - // (Some palettes try to set the last color, which causes - // churning in the palettes when they are merged) - for (int i = 0, len = ARRAYSIZE(to->colors) - 1; i < len; ++i) { - if (from->colors[i].used) { - to->colors[i] = from->colors[i]; - } - } -} - -void GfxPalette32::submit(const Palette &palette) { - const Palette oldSourcePalette(_sourcePalette); - mergePaletteInternal(&_sourcePalette, &palette); - - if (!_needsUpdate && _sourcePalette != oldSourcePalette) { - ++_version; - _needsUpdate = true; - } -} - -void GfxPalette32::submit(HunkPalette &hunkPalette) { - if (hunkPalette.getVersion() == _version) { - return; - } - - const Palette oldSourcePalette(_sourcePalette); - const Palette palette = hunkPalette.toPalette(); - mergePaletteInternal(&_sourcePalette, &palette); - - if (!_needsUpdate && oldSourcePalette != _sourcePalette) { - ++_version; - _needsUpdate = true; - } - - hunkPalette.setVersion(_version); -} - bool GfxPalette32::loadPalette(const GuiResourceId resourceId) { Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false); @@ -206,7 +168,7 @@ bool GfxPalette32::loadPalette(const GuiResourceId resourceId) { return false; } - HunkPalette palette(palResource->data); + const HunkPalette palette(palResource->data); submit(palette); return true; } @@ -241,6 +203,33 @@ int16 GfxPalette32::matchColor(const uint8 r, const uint8 g, const uint8 b) { return bestIndex; } +void GfxPalette32::submit(const Palette &palette) { + const Palette oldSourcePalette(_sourcePalette); + mergePalette(_sourcePalette, palette); + + if (!_needsUpdate && _sourcePalette != oldSourcePalette) { + ++_version; + _needsUpdate = true; + } +} + +void GfxPalette32::submit(const HunkPalette &hunkPalette) { + if (hunkPalette.getVersion() == _version) { + return; + } + + const Palette oldSourcePalette(_sourcePalette); + const Palette palette = hunkPalette.toPalette(); + mergePalette(_sourcePalette, palette); + + if (!_needsUpdate && oldSourcePalette != _sourcePalette) { + ++_version; + _needsUpdate = true; + } + + hunkPalette.setVersion(_version); +} + bool GfxPalette32::updateForFrame() { applyAll(); _needsUpdate = false; @@ -266,10 +255,10 @@ void GfxPalette32::updateHardware(const bool updateScreen) { _currentPalette.colors[i] = _nextPalette.colors[i]; // NOTE: If the brightness option in the user configuration file is set, - // SCI engine adjusts palette brightnesses here by mapping RGB values to values - // in some hard-coded brightness tables. There is no reason on modern hardware - // to implement this, unless it is discovered that some game uses a non-standard - // brightness setting by default + // SCI engine adjusts palette brightnesses here by mapping RGB values to + // values in some hard-coded brightness tables. There is no reason on + // modern hardware to implement this, unless it is discovered that some + // game uses a non-standard brightness setting by default // All color entries MUST be copied, not just "used" entries, otherwise // uninitialised memory from bpal makes its way into the system palette. @@ -299,6 +288,29 @@ void GfxPalette32::updateHardware(const bool updateScreen) { } } +Palette GfxPalette32::getPaletteFromResource(const GuiResourceId resourceId) const { + Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false); + + if (!palResource) { + error("Could not load vary palette %d", resourceId); + } + + const HunkPalette rawPalette(palResource->data); + return rawPalette.toPalette(); +} + +void GfxPalette32::mergePalette(Palette &to, const Palette &from) { + // The last color is always white in SCI, so it is not copied. (Some + // palettes, particularly in KQ7, try to set the last color, which causes + // unnecessary palette updates since the last color is forced by SSCI to a + // specific value) + for (int i = 0; i < ARRAYSIZE(to.colors) - 1; ++i) { + if (from.colors[i].used) { + to.colors[i] = from.colors[i]; + } + } +} + void GfxPalette32::applyAll() { applyVary(); applyCycles(); @@ -306,81 +318,43 @@ void GfxPalette32::applyAll() { } #pragma mark - -#pragma mark Colour look-up - -#ifdef ENABLE_SCI3_GAMES -bool GfxPalette32::loadClut(uint16 clutId) { - // loadClut() will load a color lookup table from a clu file and set - // the palette found in the file. This is to be used with Phantasmagoria 2. - - unloadClut(); - - Common::String filename = Common::String::format("%d.clu", clutId); - Common::File clut; - - if (!clut.open(filename) || clut.size() != 0x10000 + 236 * 3) - return false; - - // Read in the lookup table - // It maps each RGB565 color to a palette index - _clutTable = new byte[0x10000]; - clut.read(_clutTable, 0x10000); +#pragma mark Varying - Palette pal; - memset(&pal, 0, sizeof(Palette)); +void GfxPalette32::setVary(const Palette &target, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor) { + setTarget(target); + setVaryTime(percent, ticks); - // Setup 1:1 mapping - for (int i = 0; i < 256; i++) { - pal.mapping[i] = i; + if (fromColor > -1) { + _varyFromColor = fromColor; } - - // Now load in the palette - for (int i = 1; i <= 236; i++) { - pal.colors[i].used = 1; - pal.colors[i].r = clut.readByte(); - pal.colors[i].g = clut.readByte(); - pal.colors[i].b = clut.readByte(); + if (toColor > -1) { + assert(toColor < 256); + _varyToColor = toColor; } - - set(&pal, true); - setOnScreen(); - return true; } -byte GfxPalette32::matchClutColor(uint16 color) { - // Match a color in RGB565 format to a palette index based on the loaded CLUT - assert(_clutTable); - return _clutTable[color]; -} +void GfxPalette32::setVaryPercent(const int16 percent, const int32 ticks) { + if (_varyTargetPalette != nullptr) { + setVaryTime(percent, ticks); + } -void GfxPalette32::unloadClut() { - // This will only unload the actual table, but not reset any palette - delete[] _clutTable; - _clutTable = nullptr; + // NOTE: SSCI had two additional parameters for this function to change the + // `_varyFromColor`, but they were always hardcoded to be ignored } -#endif -#pragma mark - -#pragma mark Varying - -inline Palette GfxPalette32::getPaletteFromResourceInternal(const GuiResourceId resourceId) const { - Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false); - - if (!palResource) { - error("Could not load vary palette %d", resourceId); +void GfxPalette32::setVaryTime(const int32 time) { + if (_varyTargetPalette != nullptr) { + setVaryTime(_varyTargetPercent, time); } - - HunkPalette rawPalette(palResource->data); - return rawPalette.toPalette(); } -inline void GfxPalette32::setVaryTimeInternal(const int16 percent, const int time) { +void GfxPalette32::setVaryTime(const int16 percent, const int32 ticks) { _varyLastTick = g_sci->getTickCount(); - if (!time || _varyPercent == percent) { + if (!ticks || _varyPercent == percent) { _varyDirection = 0; _varyTargetPercent = _varyPercent = percent; } else { - _varyTime = time / (percent - _varyPercent); + _varyTime = ticks / (percent - _varyPercent); _varyTargetPercent = percent; if (_varyTime > 0) { @@ -395,72 +369,6 @@ inline void GfxPalette32::setVaryTimeInternal(const int16 percent, const int tim } } -void GfxPalette32::kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor) { - Palette palette = getPaletteFromResourceInternal(paletteId); - setVary(&palette, percent, time, fromColor, toColor); -} - -void GfxPalette32::kernelPalVaryMergeTarget(GuiResourceId paletteId) { - Palette palette = getPaletteFromResourceInternal(paletteId); - mergeTarget(&palette); -} - -void GfxPalette32::kernelPalVarySetTarget(GuiResourceId paletteId) { - Palette palette = getPaletteFromResourceInternal(paletteId); - setTarget(&palette); -} - -void GfxPalette32::kernelPalVarySetStart(GuiResourceId paletteId) { - Palette palette = getPaletteFromResourceInternal(paletteId); - setStart(&palette); -} - -void GfxPalette32::kernelPalVaryMergeStart(GuiResourceId paletteId) { - Palette palette = getPaletteFromResourceInternal(paletteId); - mergeStart(&palette); -} - -void GfxPalette32::kernelPalVaryPause(bool pause) { - if (pause) { - varyPause(); - } else { - varyOn(); - } -} - -void GfxPalette32::setVary(const Palette *const target, const int16 percent, const int time, const int16 fromColor, const int16 toColor) { - setTarget(target); - setVaryTimeInternal(percent, time); - - if (fromColor > -1) { - _varyFromColor = fromColor; - } - if (toColor > -1) { - assert(toColor < 256); - _varyToColor = toColor; - } -} - -void GfxPalette32::setVaryPercent(const int16 percent, const int time, const int16 fromColor, const int16 fromColorAlternate) { - if (_varyTargetPalette != nullptr) { - setVaryTimeInternal(percent, time); - } - - // This looks like a mistake in the actual SCI engine (both SQ6 and Lighthouse); - // the values are always hardcoded to -1 in kPalVary, so this code can never - // actually be executed - if (fromColor > -1) { - _varyFromColor = fromColor; - } - if (fromColorAlternate > -1) { - _varyFromColor = fromColorAlternate; - } -} - -int16 GfxPalette32::getVaryPercent() const { - return ABS(_varyPercent); -} - void GfxPalette32::varyOff() { _varyNumTimesPaused = 0; _varyPercent = _varyTargetPercent = 0; @@ -479,14 +387,6 @@ void GfxPalette32::varyOff() { } } -void GfxPalette32::mergeTarget(const Palette *const palette) { - if (_varyTargetPalette != nullptr) { - mergePaletteInternal(_varyTargetPalette, palette); - } else { - _varyTargetPalette = new Palette(*palette); - } -} - void GfxPalette32::varyPause() { _varyDirection = 0; ++_varyNumTimesPaused; @@ -497,51 +397,44 @@ void GfxPalette32::varyOn() { --_varyNumTimesPaused; } - if (_varyTargetPalette != nullptr && _varyNumTimesPaused == 0 && _varyPercent != _varyTargetPercent) { - if (_varyTime == 0) { - _varyPercent = _varyTargetPercent; - } else if (_varyTargetPercent < _varyPercent) { - _varyDirection = -1; + if (_varyTargetPalette != nullptr && _varyNumTimesPaused == 0) { + if (_varyPercent != _varyTargetPercent && _varyTime != 0) { + _varyDirection = (_varyTargetPercent - _varyPercent > 0) ? 1 : -1; } else { - _varyDirection = 1; + _varyPercent = _varyTargetPercent; } } } -void GfxPalette32::setVaryTime(const int time) { - if (_varyTargetPalette == nullptr) { - return; - } - - setVaryTimeInternal(_varyTargetPercent, time); +void GfxPalette32::setTarget(const Palette &palette) { + delete _varyTargetPalette; + _varyTargetPalette = new Palette(palette); } -void GfxPalette32::setTarget(const Palette *const palette) { - if (_varyTargetPalette != nullptr) { - delete _varyTargetPalette; - } - - _varyTargetPalette = new Palette(*palette); +void GfxPalette32::setStart(const Palette &palette) { + delete _varyStartPalette; + _varyStartPalette = new Palette(palette); } -void GfxPalette32::setStart(const Palette *const palette) { +void GfxPalette32::mergeStart(const Palette &palette) { if (_varyStartPalette != nullptr) { - delete _varyStartPalette; + mergePalette(*_varyStartPalette, palette); + } else { + _varyStartPalette = new Palette(palette); } - - _varyStartPalette = new Palette(*palette); } -void GfxPalette32::mergeStart(const Palette *const palette) { - if (_varyStartPalette != nullptr) { - mergePaletteInternal(_varyStartPalette, palette); +void GfxPalette32::mergeTarget(const Palette &palette) { + if (_varyTargetPalette != nullptr) { + mergePalette(*_varyTargetPalette, palette); } else { - _varyStartPalette = new Palette(*palette); + _varyTargetPalette = new Palette(palette); } } void GfxPalette32::applyVary() { - while (g_sci->getTickCount() - _varyLastTick > (uint32)_varyTime && _varyDirection != 0) { + const uint32 now = g_sci->getTickCount(); + while ((int32)(now - _varyLastTick) > _varyTime && _varyDirection != 0) { _varyLastTick += _varyTime; if (_varyPercent == _varyTargetPercent) { @@ -552,7 +445,7 @@ void GfxPalette32::applyVary() { } if (_varyPercent == 0 || _varyTargetPalette == nullptr) { - for (int i = 0, len = ARRAYSIZE(_nextPalette.colors); i < len; ++i) { + for (int i = 0; i < ARRAYSIZE(_nextPalette.colors); ++i) { if (_varyStartPalette != nullptr && i >= _varyFromColor && i <= _varyToColor) { _nextPalette.colors[i] = _varyStartPalette->colors[i]; } else { @@ -560,7 +453,7 @@ void GfxPalette32::applyVary() { } } } else { - for (int i = 0, len = ARRAYSIZE(_nextPalette.colors); i < len; ++i) { + for (int i = 0; i < ARRAYSIZE(_nextPalette.colors); ++i) { if (i >= _varyFromColor && i <= _varyToColor) { Color targetColor = _varyTargetPalette->colors[i]; Color sourceColor; @@ -591,82 +484,67 @@ void GfxPalette32::applyVary() { } } -#pragma mark - -#pragma mark Cycling - -inline void GfxPalette32::clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear) { - bool *mapEntry = _cycleMap + fromColor; - const bool *lastEntry = _cycleMap + numColorsToClear; - while (mapEntry < lastEntry) { - *mapEntry++ = false; - } +void GfxPalette32::kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor) { + const Palette palette = getPaletteFromResource(paletteId); + setVary(palette, percent, ticks, fromColor, toColor); } -inline void GfxPalette32::setCycleMap(const uint16 fromColor, const uint16 numColorsToSet) { - bool *mapEntry = _cycleMap + fromColor; - const bool *lastEntry = _cycleMap + numColorsToSet; - while (mapEntry < lastEntry) { - if (*mapEntry != false) { - error("Cycles intersect"); - } - *mapEntry++ = true; - } +void GfxPalette32::kernelPalVaryMergeTarget(const GuiResourceId paletteId) { + const Palette palette = getPaletteFromResource(paletteId); + mergeTarget(palette); } -inline PalCycler *GfxPalette32::getCycler(const uint16 fromColor) { - const int numCyclers = ARRAYSIZE(_cyclers); - - for (int cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) { - PalCycler *cycler = _cyclers[cyclerIndex]; - if (cycler != nullptr && cycler->fromColor == fromColor) { - return cycler; - } - } +void GfxPalette32::kernelPalVarySetTarget(const GuiResourceId paletteId) { + const Palette palette = getPaletteFromResource(paletteId); + setTarget(palette); +} - return nullptr; +void GfxPalette32::kernelPalVarySetStart(const GuiResourceId paletteId) { + const Palette palette = getPaletteFromResource(paletteId); + setStart(palette); } -inline void doCycleInternal(PalCycler *cycler, const int16 speed) { - int16 currentCycle = cycler->currentCycle; - const uint16 numColorsToCycle = cycler->numColorsToCycle; +void GfxPalette32::kernelPalVaryMergeStart(const GuiResourceId paletteId) { + const Palette palette = getPaletteFromResource(paletteId); + mergeStart(palette); +} - if (cycler->direction == 0) { - currentCycle = (currentCycle - (speed % numColorsToCycle)) + numColorsToCycle; +void GfxPalette32::kernelPalVaryPause(const bool pause) { + if (pause) { + varyPause(); } else { - currentCycle = currentCycle + speed; + varyOn(); } - - cycler->currentCycle = (uint8) (currentCycle % numColorsToCycle); } +#pragma mark - +#pragma mark Cycling + void GfxPalette32::setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay) { assert(fromColor < toColor); - int cyclerIndex; - const int numCyclers = ARRAYSIZE(_cyclers); - PalCycler *cycler = getCycler(fromColor); if (cycler != nullptr) { clearCycleMap(fromColor, cycler->numColorsToCycle); } else { - for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) { - if (_cyclers[cyclerIndex] == nullptr) { - cycler = new PalCycler; - _cyclers[cyclerIndex] = cycler; + for (int i = 0; i < kNumCyclers; ++i) { + if (_cyclers[i] == nullptr) { + _cyclers[i] = cycler = new PalCycler; break; } } } - // SCI engine overrides the first oldest cycler that it finds where - // “oldest” is determined by the difference between the tick and now + // If there are no free cycler slots, SCI engine overrides the first oldest + // cycler that it finds, where "oldest" is determined by the difference + // between the tick and now if (cycler == nullptr) { const uint32 now = g_sci->getTickCount(); uint32 minUpdateDelta = 0xFFFFFFFF; - for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) { - PalCycler *candidate = _cyclers[cyclerIndex]; + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const candidate = _cyclers[i]; const uint32 updateDelta = now - candidate->lastUpdateTick; if (updateDelta < minUpdateDelta) { @@ -678,11 +556,11 @@ void GfxPalette32::setCycle(const uint8 fromColor, const uint8 toColor, const in clearCycleMap(cycler->fromColor, cycler->numColorsToCycle); } - const uint16 numColorsToCycle = 1 + ((uint8) toColor) - fromColor; - cycler->fromColor = (uint8) fromColor; - cycler->numColorsToCycle = (uint8) numColorsToCycle; - cycler->currentCycle = (uint8) fromColor; - cycler->direction = direction < 0 ? PalCycleBackward : PalCycleForward; + const uint16 numColorsToCycle = toColor - fromColor + 1; + cycler->fromColor = fromColor; + cycler->numColorsToCycle = numColorsToCycle; + cycler->currentCycle = fromColor; + cycler->direction = direction < 0 ? kPalCycleBackward : kPalCycleForward; cycler->delay = delay; cycler->lastUpdateTick = g_sci->getTickCount(); cycler->numTimesPaused = 0; @@ -691,30 +569,30 @@ void GfxPalette32::setCycle(const uint8 fromColor, const uint8 toColor, const in } void GfxPalette32::doCycle(const uint8 fromColor, const int16 speed) { - PalCycler *cycler = getCycler(fromColor); + PalCycler *const cycler = getCycler(fromColor); if (cycler != nullptr) { cycler->lastUpdateTick = g_sci->getTickCount(); - doCycleInternal(cycler, speed); + updateCycler(*cycler, speed); } } void GfxPalette32::cycleOn(const uint8 fromColor) { - PalCycler *cycler = getCycler(fromColor); + PalCycler *const cycler = getCycler(fromColor); if (cycler != nullptr && cycler->numTimesPaused > 0) { --cycler->numTimesPaused; } } void GfxPalette32::cyclePause(const uint8 fromColor) { - PalCycler *cycler = getCycler(fromColor); + PalCycler *const cycler = getCycler(fromColor); if (cycler != nullptr) { ++cycler->numTimesPaused; } } void GfxPalette32::cycleAllOn() { - for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { - PalCycler *cycler = _cyclers[i]; + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const cycler = _cyclers[i]; if (cycler != nullptr && cycler->numTimesPaused > 0) { --cycler->numTimesPaused; } @@ -724,8 +602,8 @@ void GfxPalette32::cycleAllOn() { void GfxPalette32::cycleAllPause() { // NOTE: The original engine did not check for null pointers in the // palette cyclers pointer array. - for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { - PalCycler *cycler = _cyclers[i]; + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const cycler = _cyclers[i]; if (cycler != nullptr) { // This seems odd, because currentCycle is 0..numColorsPerCycle, // but fromColor is 0..255. When applyAllCycles runs, the values @@ -736,8 +614,8 @@ void GfxPalette32::cycleAllPause() { applyAllCycles(); - for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { - PalCycler *cycler = _cyclers[i]; + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const cycler = _cyclers[i]; if (cycler != nullptr) { ++cycler->numTimesPaused; } @@ -745,8 +623,8 @@ void GfxPalette32::cycleAllPause() { } void GfxPalette32::cycleOff(const uint8 fromColor) { - for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { - PalCycler *cycler = _cyclers[i]; + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const cycler = _cyclers[i]; if (cycler != nullptr && cycler->fromColor == fromColor) { clearCycleMap(fromColor, cycler->numColorsToCycle); delete cycler; @@ -757,8 +635,8 @@ void GfxPalette32::cycleOff(const uint8 fromColor) { } void GfxPalette32::cycleAllOff() { - for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { - PalCycler *cycler = _cyclers[i]; + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const cycler = _cyclers[i]; if (cycler != nullptr) { clearCycleMap(cycler->fromColor, cycler->numColorsToCycle); delete cycler; @@ -767,16 +645,57 @@ void GfxPalette32::cycleAllOff() { } } +void GfxPalette32::updateCycler(PalCycler &cycler, const int16 speed) { + int16 currentCycle = cycler.currentCycle; + const uint16 numColorsToCycle = cycler.numColorsToCycle; + + if (cycler.direction == kPalCycleBackward) { + currentCycle = (currentCycle - (speed % numColorsToCycle)) + numColorsToCycle; + } else { + currentCycle = currentCycle + speed; + } + + cycler.currentCycle = currentCycle % numColorsToCycle; +} + +void GfxPalette32::clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear) { + bool *mapEntry = _cycleMap + fromColor; + const bool *const lastEntry = _cycleMap + numColorsToClear; + while (mapEntry < lastEntry) { + *mapEntry++ = false; + } +} + +void GfxPalette32::setCycleMap(const uint16 fromColor, const uint16 numColorsToSet) { + bool *mapEntry = _cycleMap + fromColor; + const bool *const lastEntry = _cycleMap + numColorsToSet; + while (mapEntry < lastEntry) { + if (*mapEntry != false) { + error("Cycles intersect"); + } + *mapEntry++ = true; + } +} + +PalCycler *GfxPalette32::getCycler(const uint16 fromColor) { + for (int cyclerIndex = 0; cyclerIndex < kNumCyclers; ++cyclerIndex) { + PalCycler *cycler = _cyclers[cyclerIndex]; + if (cycler != nullptr && cycler->fromColor == fromColor) { + return cycler; + } + } + + return nullptr; +} + void GfxPalette32::applyAllCycles() { Color paletteCopy[256]; memcpy(paletteCopy, _nextPalette.colors, sizeof(Color) * 256); - for (int cyclerIndex = 0, numCyclers = ARRAYSIZE(_cyclers); cyclerIndex < numCyclers; ++cyclerIndex) { - PalCycler *cycler = _cyclers[cyclerIndex]; + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const cycler = _cyclers[i]; if (cycler != nullptr) { - cycler->currentCycle = (uint8) ((((int) cycler->currentCycle) + 1) % cycler->numColorsToCycle); - // Disassembly was not fully evaluated to verify this is exactly the same - // as the code from applyCycles, but it appeared to be at a glance + cycler->currentCycle = (((int) cycler->currentCycle) + 1) % cycler->numColorsToCycle; for (int j = 0; j < cycler->numColorsToCycle; j++) { _nextPalette.colors[cycler->fromColor + j] = paletteCopy[cycler->fromColor + (cycler->currentCycle + j) % cycler->numColorsToCycle]; } @@ -788,15 +707,16 @@ void GfxPalette32::applyCycles() { Color paletteCopy[256]; memcpy(paletteCopy, _nextPalette.colors, sizeof(Color) * 256); - for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) { - PalCycler *cycler = _cyclers[i]; + const uint32 now = g_sci->getTickCount(); + for (int i = 0; i < kNumCyclers; ++i) { + PalCycler *const cycler = _cyclers[i]; if (cycler == nullptr) { continue; } if (cycler->delay != 0 && cycler->numTimesPaused == 0) { - while ((cycler->delay + cycler->lastUpdateTick) < g_sci->getTickCount()) { - doCycleInternal(cycler, 1); + while ((cycler->delay + cycler->lastUpdateTick) < now) { + updateCycler(*cycler, 1); cycler->lastUpdateTick += cycler->delay; } } @@ -810,7 +730,7 @@ void GfxPalette32::applyCycles() { #pragma mark - #pragma mark Fading -void GfxPalette32::setFade(uint16 percent, uint8 fromColor, uint16 toColor) { +void GfxPalette32::setFade(const uint16 percent, const uint8 fromColor, uint16 toColor) { if (fromColor > toColor) { return; } @@ -827,13 +747,14 @@ void GfxPalette32::setFade(uint16 percent, uint8 fromColor, uint16 toColor) { } void GfxPalette32::fadeOff() { - setFade(100, 0, 256); + setFade(100, 0, 255); } void GfxPalette32::applyFade() { for (int i = 0; i < ARRAYSIZE(_fadeTable); ++i) { - if (_fadeTable[i] == 100) + if (_fadeTable[i] == 100) { continue; + } Color &color = _nextPalette.colors[i]; diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h index dc2158022f..81e9bbbfd3 100644 --- a/engines/sci/graphics/palette32.h +++ b/engines/sci/graphics/palette32.h @@ -24,30 +24,33 @@ #define SCI_GRAPHICS_PALETTE32_H #include "sci/graphics/palette.h" - namespace Sci { +#pragma mark HunkPalette + /** - * HunkPalette represents a raw palette resource - * read from disk. + * HunkPalette represents a raw palette resource read from disk. The data + * structure of a HunkPalette allows palettes to be smaller than 256 colors. It + * also allows multiple palettes to be stored in one HunkPalette, though in + * SCI32 games there seems to only ever be one palette per HunkPalette. */ class HunkPalette { public: HunkPalette(byte *rawPalette); /** - * Gets the version of the palette. + * Gets the version of the palette. Used to avoid resubmitting a HunkPalette + * which has already been submitted for the next frame. */ uint32 getVersion() const { return _version; } /** * Sets the version of the palette. */ - void setVersion(const uint32 version); + void setVersion(const uint32 version) const; /** - * Converts the hunk palette to a standard - * palette. + * Converts the hunk palette to a standard Palette. */ const Palette toPalette() const; @@ -64,15 +67,14 @@ private: kEntryHeaderSize = 22, /** - * The offset of the hunk palette version - * within the palette entry header. + * The offset of the hunk palette version within the palette entry + * header. */ kEntryVersionOffset = 18 }; /** - * The header for a palette inside the - * HunkPalette. + * The header for a palette inside the HunkPalette. */ struct EntryHeader { /** @@ -81,8 +83,7 @@ private: uint8 startColor; /** - * The number of palette colors in this - * entry. + * The number of palette colors in this entry. */ uint16 numColors; @@ -92,8 +93,7 @@ private: bool used; /** - * Whether or not all palette entries - * share the same `used` value in + * Whether or not all palette entries share the same `used` value in * `defaultFlag`. */ bool sharedUsed; @@ -105,14 +105,14 @@ private: }; /** - * The version number from the last time this - * palette was submitted to GfxPalette32. + * The version number from the last time this palette was submitted to + * GfxPalette32. */ - uint32 _version; + mutable uint32 _version; /** - * The number of palettes stored in the hunk - * palette. In SCI32 games this is always 1. + * The number of palettes stored in the hunk palette. In SCI32 games this is + * always 1. */ uint8 _numPalettes; @@ -122,41 +122,44 @@ private: byte *_data; /** - * Returns a struct that describes the palette - * held by this HunkPalette. The entry header - * is reconstructed on every call from the raw - * palette data. + * Returns a struct that describes the palette held by this HunkPalette. The + * entry header is reconstructed on every call from the raw palette data. */ const EntryHeader getEntryHeader() const; /** - * Returns a pointer to the palette data within - * the hunk palette. + * Returns a pointer to the palette data within the hunk palette. */ byte *getPalPointer() const { return _data + kHunkPaletteHeaderSize + (2 * _numPalettes); } }; +#pragma mark - +#pragma mark PalCycler + enum PalCyclerDirection { - PalCycleBackward = 0, - PalCycleForward = 1 + kPalCycleBackward = 0, + kPalCycleForward = 1 }; +/** + * PalCycler represents a range of palette entries that are rotated on a timer. + */ struct PalCycler { /** - * The color index of the palette cycler. This value is effectively used as the ID for the - * cycler. + * The color index of this palette cycler. This value is used as the unique + * key for this PalCycler object. */ uint8 fromColor; /** - * The number of palette slots which are cycled by the palette cycler. + * The number of palette slots which are to be cycled by this cycler. */ uint16 numColorsToCycle; /** - * The position of the cursor in its cycle. + * The current position of the first palette entry. */ uint8 currentCycle; @@ -166,15 +169,15 @@ struct PalCycler { PalCyclerDirection direction; /** - * The cycle tick at the last time the cycler’s currentCycle was updated. - * 795 days of game time ought to be enough for everyone? :) + * The last tick the cycler cycled. */ uint32 lastUpdateTick; /** - * The amount of time in ticks each cycle should take to complete. In other words, - * the higher the delay, the slower the cycle animation. If delay is 0, the cycler - * does not automatically cycle and needs to be pumped manually with DoCycle. + * The amount of time in ticks each cycle should take to complete. In other + * words, the higher the delay, the slower the cycle animation. If delay is + * 0, the cycler does not automatically cycle and needs to be cycled + * manually by calling `doCycle`. */ int16 delay; @@ -184,17 +187,72 @@ struct PalCycler { uint16 numTimesPaused; }; +#pragma mark - +#pragma mark GfxPalette32 + class GfxPalette32 { public: GfxPalette32(ResourceManager *resMan); ~GfxPalette32(); + void saveLoadWithSerializer(Common::Serializer &s); + + /** + * Gets the palette that will be use for the next frame. + */ + inline const Palette &getNextPalette() const { return _nextPalette; }; + + /** + * Gets the palette that is used for the current frame. + */ + inline const Palette &getCurrentPalette() const { return _currentPalette; }; + + /** + * Loads a palette into GfxPalette32 with the given resource ID. + */ + bool loadPalette(const GuiResourceId resourceId); + + /** + * Finds the nearest color in the current palette matching the given RGB + * value. + */ + int16 matchColor(const uint8 r, const uint8 g, const uint8 b); + + /** + * Submits a palette to display. Entries marked as "used" in the submitted + * palette are merged into `_sourcePalette`. + */ + void submit(const Palette &palette); + void submit(const HunkPalette &palette); + + /** + * Applies all fades, cycles, remaps, and varies for the current frame to + * `nextPalette`. + */ + bool updateForFrame(); + + /** + * Copies all palette entries from `sourcePalette` to `nextPalette` and + * applies remaps. Unlike `updateForFrame`, this call does not apply fades, + * cycles, or varies. + */ + void updateFFrame(); + + /** + * Copies all entries from `nextPalette` to `currentPalette` and updates the + * backend's raw palette. + * + * @param updateScreen If true, this call will also tell the backend to draw + * to the screen. + */ + void updateHardware(const bool updateScreen = true); + private: ResourceManager *_resMan; /** - * The palette revision version. Increments once per game - * loop that changes the source palette. + * The palette revision version. Increments once per game loop that changes + * the source palette. */ uint32 _version; @@ -209,90 +267,140 @@ private: Palette _currentPalette; /** - * The unmodified source palette loaded by kPalette. Additional - * palette entries may be mixed into the source palette by - * CelObj objects, which contain their own palettes. + * The unmodified source palette loaded by kPalette. Additional palette + * entries may be mixed into the source palette by CelObj objects, which + * contain their own palettes. */ Palette _sourcePalette; /** * The palette to be used when the hardware is next updated. - * On update, _nextPalette is transferred to _currentPalette. + * On update, `_nextPalette` is transferred to `_currentPalette`. */ Palette _nextPalette; - bool createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const; - Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const; + /** + * Creates and returns a new Palette object with data from the given + * resource ID. + */ + Palette getPaletteFromResource(const GuiResourceId paletteId) const; + + /** + * Merges used colors in the `from` palette into the `to` palette. + */ + void mergePalette(Palette &to, const Palette &from); + + /** + * Applies all varies, cycles, and fades to `_nextPalette`. + */ + void applyAll(); +#pragma mark - +#pragma mark Varying public: - void saveLoadWithSerializer(Common::Serializer &s); - inline const Palette &getNextPalette() const { return _nextPalette; }; - inline const Palette &getCurrentPalette() const { return _currentPalette; }; + /** + * Blends the `target` palette into the current palette over `time` ticks. + * + * @param target The target palette. + * @param percent The amount that the target palette should be blended into + * the source palette by the end of the vary. + * @param ticks The number of ticks that it should take for the blend to be + * completed. + * @param fromColor The first palette entry that should be blended. + * @param toColor The last palette entry that should be blended. + */ + void setVary(const Palette &target, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor); /** - * Loads a palette into GfxPalette32 with the given resource - * ID. + * Gets the current vary blend amount. */ - bool loadPalette(const GuiResourceId resourceId); + inline int16 getVaryPercent() const { return ABS(_varyPercent); } /** - * Finds the nearest color in the current palette matching the - * given RGB value. + * Changes the percentage of the current vary to `percent`, to be completed + * over `time` ticks, if there is a currently active vary target palette. */ - int16 matchColor(const uint8 r, const uint8 g, const uint8 b); + void setVaryPercent(const int16 percent, const int32 time); /** - * Submits a palette to display. Entries marked as “used” in the - * submitted palette are merged into the existing entries of - * _sourcePalette. + * Changes the amount of time, in ticks, an in-progress palette vary should + * take to finish. */ - void submit(const Palette &palette); - void submit(HunkPalette &palette); + void setVaryTime(const int32 ticks); - bool updateForFrame(); - void updateFFrame(); - void updateHardware(const bool updateScreen = true); - void applyAll(); + /** + * Changes the vary percent and time to perform the vary. + */ + void setVaryTime(const int16 percent, const int32 ticks); -#pragma mark - -#pragma mark Color look-up -private: /** - * An optional lookup table used to remap RGB565 colors to a palette - * index. Used by Phantasmagoria 2 in 8-bit color environments. + * Removes the active palette vary. */ - byte *_clutTable; + void varyOff(); -public: - bool loadClut(uint16 clutId); - byte matchClutColor(uint16 color); - void unloadClut(); + /** + * Pauses any active palette vary. + */ + void varyPause(); + + /** + * Unpauses any paused palette vary. + */ + void varyOn(); + + /** + * Sets the target palette for the blend. + */ + void setTarget(const Palette &palette); + + /** + * Sets the start palette for the blend. + */ + void setStart(const Palette &palette); + + /** + * Merges a new start palette into the existing start palette. + */ + void mergeStart(const Palette &palette); + + /** + * Merges a new target palette into the existing target palette. + */ + void mergeTarget(const Palette &palette); + + /** + * Applies any active palette vary to `_nextPalette`. + */ + void applyVary(); + + void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int32 ticks, const int16 fromColor, const int16 toColor); + void kernelPalVaryMergeTarget(const GuiResourceId paletteId); + void kernelPalVarySetTarget(const GuiResourceId paletteId); + void kernelPalVarySetStart(const GuiResourceId paletteId); + void kernelPalVaryMergeStart(const GuiResourceId paletteId); + void kernelPalVaryPause(const bool pause); -#pragma mark - -#pragma mark Varying private: /** - * An optional palette used to describe the source colors used - * in a palette vary operation. If this palette is not specified, - * sourcePalette is used instead. + * An optional palette used to provide source colors for a palette vary + * operation. If this palette is not specified, `_sourcePalette` is used + * instead. */ Palette *_varyStartPalette; /** - * An optional palette used to describe the target colors used - * in a palette vary operation. + * An optional palette used to provide target colors for a palette vary + * operation. */ Palette *_varyTargetPalette; /** - * The minimum palette index that has been varied from the - * source palette. 0–255 + * The minimum palette index that has been varied from the source palette. */ uint8 _varyFromColor; /** - * The maximum palette index that is has been varied from the - * source palette. 0-255 + * The maximum palette index that has been varied from the source palette. */ uint8 _varyToColor; @@ -302,10 +410,10 @@ private: uint32 _varyLastTick; /** - * The amount of time to elapse, in ticks, between each cycle - * of a palette vary animation. + * The amount of time that should elapse, in ticks, between each cycle of a + * palette vary animation. */ - int _varyTime; + int32 _varyTime; /** * The direction of change: -1, 0, or 1. @@ -313,97 +421,158 @@ private: int16 _varyDirection; /** - * The amount, in percent, that the vary color is currently - * blended into the source color. + * The amount, in percent, that the vary color is currently blended into the + * source color. */ int16 _varyPercent; /** - * The target amount that a vary color will be blended into - * the source color. + * The target amount that a vary color will be blended into the source + * color. */ int16 _varyTargetPercent; /** - * The number of time palette varying has been paused. + * The number of times palette varying has been paused. */ uint16 _varyNumTimesPaused; -public: - void kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor); - void kernelPalVaryMergeTarget(const GuiResourceId paletteId); - void kernelPalVarySetTarget(const GuiResourceId paletteId); - void kernelPalVarySetStart(const GuiResourceId paletteId); - void kernelPalVaryMergeStart(const GuiResourceId paletteId); - void kernelPalVaryPause(bool pause); - - void setVary(const Palette *const targetPalette, const int16 percent, const int time, const int16 fromColor, const int16 toColor); - void setVaryPercent(const int16 percent, const int time, const int16 fromColor, const int16 fromColorAlternate); - int16 getVaryPercent() const; - void varyOff(); - void mergeTarget(const Palette *const palette); - void varyPause(); - void varyOn(); - void setVaryTime(const int time); - void setTarget(const Palette *const palette); - void setStart(const Palette *const palette); - void mergeStart(const Palette *const palette); - void setVaryTimeInternal(const int16 percent, const int time); - void applyVary(); - #pragma mark - #pragma mark Cycling -private: - // SQ6 defines 10 cyclers - PalCycler *_cyclers[10]; +public: + inline const bool *getCycleMap() const { return _cycleMap; } /** - * The cycle map is used to detect overlapping cyclers. - * According to SCI engine code, when two cyclers overlap, - * a fatal error has occurred and the engine will display - * an error and then exit. + * Cycle palette entries between `fromColor` and `toColor`, inclusive. + * Palette cyclers may not overlap. `fromColor` is used in other methods as + * the key for looking up a cycler. * - * The cycle map is also by the color remapping system to - * avoid attempting to remap to palette entries that are - * cycling (so won't be the expected color once the cycler - * runs again). + * @param fromColor The first color in the cycle. + * @param toColor The last color in the cycle. + * @param delay The number of ticks that should elapse between cycles. + * @param direction A negative `direction` will cycle backwards instead of + * forwards. The numeric value of this argument is ignored; + * only its sign is used to determine direction. */ - bool _cycleMap[256]; - inline void clearCycleMap(uint16 fromColor, uint16 numColorsToClear); - inline void setCycleMap(uint16 fromColor, uint16 numColorsToClear); - inline PalCycler *getCycler(uint16 fromColor); - -public: void setCycle(const uint8 fromColor, const uint8 toColor, const int16 direction, const int16 delay); + + /** + * Performs a round of palette cycling. + * + * @param fromColor The color key for the cycler. + * @param speed The number of entries that should be cycled this round. + */ void doCycle(const uint8 fromColor, const int16 speed); + + /** + * Unpauses the cycler starting at `fromColor`. + */ void cycleOn(const uint8 fromColor); + + /** + * Pauses the cycler starting at `fromColor`. + */ void cyclePause(const uint8 fromColor); + + /** + * Unpauses all cyclers. + */ void cycleAllOn(); + + /** + * Pauses all cyclers. + */ void cycleAllPause(); + + /** + * Removes the cycler starting at `fromColor`. + */ void cycleOff(const uint8 fromColor); + + /** + * Removes all cyclers. + */ void cycleAllOff(); + +private: + enum { + kNumCyclers = 10 + }; + + PalCycler *_cyclers[kNumCyclers]; + + /** + * Updates the `currentCycle` of the given `cycler` by `speed` entries. + */ + void updateCycler(PalCycler &cycler, const int16 speed); + + /** + * The cycle map is used to detect overlapping cyclers, and to avoid + * remapping to palette entries that are being cycled. + * + * According to SCI engine code, when two cyclers overlap, a fatal error has + * occurred and the engine will display an error and then exit. + * + * The color remapping system avoids attempts to remap to palette entries + * that are cycling because they won't be the expected color once the cycler + * updates the palette entries. + */ + bool _cycleMap[256]; + + /** + * Marks `numColorsToClear` colors starting at `fromColor` in the cycle + * map as inactive. + */ + void clearCycleMap(const uint16 fromColor, const uint16 numColorsToClear); + + /** + * Marks `numColorsToClear` colors starting at `fromColor` in the cycle + * map as active. + */ + void setCycleMap(const uint16 fromColor, const uint16 numColorsToClear); + + /** + * Gets the cycler object that starts at the given `fromColor`, or NULL if + * there is no cycler for that color. + */ + PalCycler *getCycler(const uint16 fromColor); + + /** + * Advances all cyclers by one step, regardless of whether or not it is time + * to perform another cycle. + */ void applyAllCycles(); + + /** + * Advances, by one step, only the cyclers whose time has come to cycle. + */ void applyCycles(); - inline const bool *getCycleMap() const { return _cycleMap; } #pragma mark - #pragma mark Fading -private: +public: /** - * The fade table records the expected intensity level of each pixel - * in the palette that will be displayed on the next frame. + * Sets the intensity level for a range of palette entries. An intensity of + * zero indicates total darkness. Intensity may also be set above 100 + * percent to increase the intensity of a palette entry. */ - uint16 _fadeTable[256]; + void setFade(const uint16 percent, const uint8 fromColor, const uint16 toColor); -public: /** - * Sets the intensity level for a range of palette - * entries. An intensity of zero indicates total - * darkness. Intensity may be set to over 100 percent. + * Resets the intensity of all palette entries to 100%. */ - void setFade(const uint16 percent, const uint8 fromColor, const uint16 toColor); void fadeOff(); + + /** + * Applies intensity values to the palette entries in `_nextPalette`. + */ void applyFade(); + +private: + /** + * The intensity levels of each palette entry, in percent. Defaults to 100. + */ + uint16 _fadeTable[256]; }; } // End of namespace Sci |