aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics')
-rw-r--r--engines/sci/graphics/frameout.cpp610
-rw-r--r--engines/sci/graphics/frameout.h199
-rw-r--r--engines/sci/graphics/plane32.cpp6
-rw-r--r--engines/sci/graphics/plane32.h18
-rw-r--r--engines/sci/graphics/transitions32.cpp981
-rw-r--r--engines/sci/graphics/transitions32.h476
6 files changed, 1635 insertions, 655 deletions
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index b5b320637f..a264516bf7 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -51,31 +51,19 @@
#include "sci/graphics/text32.h"
#include "sci/graphics/frameout.h"
#include "sci/video/robot_decoder.h"
+#include "sci/graphics/transitions32.h"
namespace Sci {
-static int dissolveSequences[2][20] = {
- /* SCI2.1early- */ { 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080 },
- /* SCI2.1mid+ */ { 0, 0, 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080, 73728, 132096, 466944 }
-};
-static int16 divisionsDefaults[2][16] = {
- /* SCI2.1early- */ { 1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 40, 40, 101, 101 },
- /* SCI2.1mid+ */ { 1, 20, 20, 20, 20, 10, 10, 10, 10, 20, 20, 6, 10, 101, 101, 2 }
-};
-static int16 unknownCDefaults[2][16] = {
- /* SCI2.1early- */ { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 0, 0, 0, 0 },
- /* SCI2.1mid+ */ { 0, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 0, 0, 7, 7, 0 }
-};
-
-GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette) :
+GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions) :
_isHiRes(false),
_palette(palette),
_resMan(resMan),
_screen(screen),
_segMan(segMan),
+ _transitions(transitions),
_benchmarkingFinished(false),
_throttleFrameOut(true),
- _showStyles(nullptr),
_throttleState(0),
// TODO: Stop using _gfxScreen
_currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
@@ -87,14 +75,6 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_currentBuffer.setPixels(calloc(1, screen->getDisplayWidth() * screen->getDisplayHeight()));
- for (int i = 0; i < 236; i += 2) {
- _styleRanges[i] = 0;
- _styleRanges[i + 1] = -1;
- }
- for (int i = 236; i < ARRAYSIZE(_styleRanges); ++i) {
- _styleRanges[i] = 0;
- }
-
// TODO: Make hires detection work uniformly across all SCI engine
// versions (this flag is normally passed by SCI::MakeGraphicsMgr
// to the GraphicsMgr constructor depending upon video configuration,
@@ -104,16 +84,6 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_isHiRes = true;
}
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- _dissolveSequenceSeeds = dissolveSequences[0];
- _defaultDivisions = divisionsDefaults[0];
- _defaultUnknownC = unknownCDefaults[0];
- } else {
- _dissolveSequenceSeeds = dissolveSequences[1];
- _defaultDivisions = divisionsDefaults[1];
- _defaultUnknownC = unknownCDefaults[1];
- }
-
switch (g_sci->getGameId()) {
case GID_HOYLE5:
case GID_GK2:
@@ -587,6 +557,115 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &eraseR
// }
}
+void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, PlaneShowStyle *showStyle) {
+ Palette sourcePalette(_palette->getNextPalette());
+ alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
+
+ int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
+
+ Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
+ _showList.add(rect);
+ showBits();
+
+ // NOTE: The original engine allocated these as static arrays of 100
+ // pointers to ScreenItemList / RectList
+ ScreenItemListList screenItemLists;
+ EraseListList eraseLists;
+
+ screenItemLists.resize(_planes.size());
+ eraseLists.resize(_planes.size());
+
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
+
+ calcLists(screenItemLists, eraseLists);
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ list->sort();
+ }
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
+ (*drawItem)->screenItem->getCelObj().submitPalette();
+ }
+ }
+
+ _remapOccurred = _palette->updateForFrame();
+ _frameNowVisible = false;
+
+ for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
+ drawEraseList(eraseLists[i], *_planes[i]);
+ drawScreenItemList(screenItemLists[i]);
+ }
+
+ Palette nextPalette(_palette->getNextPalette());
+
+ if (prevRoom < 1000) {
+ for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
+ if (styleRanges[i] == -1 || styleRanges[i] == 0) {
+ sourcePalette.colors[i] = nextPalette.colors[i];
+ sourcePalette.colors[i].used = true;
+ }
+ }
+ } else {
+ for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
+ if (styleRanges[i] == -1 || validZeroStyle(styleRanges[i], i)) {
+ sourcePalette.colors[i] = nextPalette.colors[i];
+ sourcePalette.colors[i].used = true;
+ }
+ }
+ }
+
+ _palette->submit(sourcePalette);
+ _palette->updateFFrame();
+ _palette->updateHardware();
+ alterVmap(nextPalette, sourcePalette, 1, _transitions->_styleRanges);
+
+ if (showStyle && showStyle->type != kShowStyleMorph) {
+ _transitions->processEffects(*showStyle);
+ } else {
+ showBits();
+ }
+
+ _frameNowVisible = true;
+
+ for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) {
+ (*plane)->_redrawAllCount = getScreenCount();
+ }
+
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
+
+ calcLists(screenItemLists, eraseLists);
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ list->sort();
+ }
+
+ for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
+ for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
+ (*drawItem)->screenItem->getCelObj().submitPalette();
+ }
+ }
+
+ _remapOccurred = _palette->updateForFrame();
+ // NOTE: During this second loop, `_frameNowVisible = false` is
+ // inside the next loop in SCI2.1mid
+ _frameNowVisible = false;
+
+ for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
+ drawEraseList(eraseLists[i], *_planes[i]);
+ drawScreenItemList(screenItemLists[i]);
+ }
+
+ _palette->submit(nextPalette);
+ _palette->updateFFrame();
+ _palette->updateHardware(false);
+ showBits();
+
+ _frameNowVisible = true;
+}
+
/**
* Determines the parts of `r` that aren't overlapped by `other`.
* Returns -1 if `r` and `other` have no intersection.
@@ -1038,118 +1117,6 @@ void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showLi
}
}
-void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle) {
- Palette sourcePalette(_palette->getNextPalette());
- alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
-
- int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
-
- Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
- _showList.add(rect);
- showBits();
-
- // NOTE: The original engine allocated these as static arrays of 100
- // pointers to ScreenItemList / RectList
- ScreenItemListList screenItemLists;
- EraseListList eraseLists;
-
- screenItemLists.resize(_planes.size());
- eraseLists.resize(_planes.size());
-
- if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
- remapMarkRedraw();
- }
-
- calcLists(screenItemLists, eraseLists);
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- list->sort();
- }
-
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
- (*drawItem)->screenItem->getCelObj().submitPalette();
- }
- }
-
- _remapOccurred = _palette->updateForFrame();
- _frameNowVisible = false;
-
- for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
- drawEraseList(eraseLists[i], *_planes[i]);
- drawScreenItemList(screenItemLists[i]);
- }
-
- Palette nextPalette(_palette->getNextPalette());
-
- if (prevRoom < 1000) {
- for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
- if (styleRanges[i] == -1 || styleRanges[i] == 0) {
- sourcePalette.colors[i] = nextPalette.colors[i];
- sourcePalette.colors[i].used = true;
- }
- }
- } else {
- for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
- // TODO: Limiting range 72 to 103 is NOT present in every game
- if (styleRanges[i] == -1 || (styleRanges[i] == 0 && i > 71 && i < 104)) {
- sourcePalette.colors[i] = nextPalette.colors[i];
- sourcePalette.colors[i].used = true;
- }
- }
- }
-
- _palette->submit(sourcePalette);
- _palette->updateFFrame();
- _palette->updateHardware();
- alterVmap(nextPalette, sourcePalette, 1, _styleRanges);
-
- if (showStyle && showStyle->type != kShowStyleUnknown) {
-// TODO: SCI2.1mid transition effects
-// processEffects();
- warning("Transition %d not implemented!", showStyle->type);
- } else {
- showBits();
- }
-
- _frameNowVisible = true;
-
- for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) {
- (*plane)->_redrawAllCount = getScreenCount();
- }
-
- if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
- remapMarkRedraw();
- }
-
- calcLists(screenItemLists, eraseLists);
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- list->sort();
- }
-
- for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
- for (DrawList::iterator drawItem = list->begin(); drawItem != list->end(); ++drawItem) {
- (*drawItem)->screenItem->getCelObj().submitPalette();
- }
- }
-
- _remapOccurred = _palette->updateForFrame();
- // NOTE: During this second loop, `_frameNowVisible = false` is
- // inside the next loop in SCI2.1mid
- _frameNowVisible = false;
-
- for (PlaneList::size_type i = 0; i < _planes.size(); ++i) {
- drawEraseList(eraseLists[i], *_planes[i]);
- drawScreenItemList(screenItemLists[i]);
- }
-
- _palette->submit(nextPalette);
- _palette->updateFFrame();
- _palette->updateHardware(false);
- showBits();
-
- _frameNowVisible = true;
-}
-
void GfxFrameout::showBits() {
for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) {
Common::Rect rounded(**rect);
@@ -1233,7 +1200,6 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
}
}
- // NOTE: This is currBuffer->ptr in SCI engine
byte *pixels = (byte *)_currentBuffer.getPixels();
for (int pixelIndex = 0, numPixels = _currentBuffer.screenWidth * _currentBuffer.screenHeight; pixelIndex < numPixels; ++pixelIndex) {
@@ -1256,348 +1222,16 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
}
}
-void GfxFrameout::kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor) {
- if (toColor > fromColor) {
- return;
- }
-
- for (int i = fromColor; i < toColor; ++i) {
- _styleRanges[i] = 0;
- }
-}
-
-inline ShowStyleEntry * GfxFrameout::findShowStyleForPlane(const reg_t planeObj) const {
- ShowStyleEntry *entry = _showStyles;
- while (entry != nullptr) {
- if (entry->plane == planeObj) {
- break;
- }
- entry = entry->next;
- }
-
- return entry;
-}
-
-inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *const showStyle) {
- ShowStyleEntry *lastEntry = nullptr;
-
- for (ShowStyleEntry *testEntry = _showStyles; testEntry != nullptr; testEntry = testEntry->next) {
- if (testEntry == showStyle) {
- break;
- }
- lastEntry = testEntry;
- }
-
- if (lastEntry == nullptr) {
- _showStyles = showStyle->next;
- lastEntry = _showStyles;
- } else {
- lastEntry->next = showStyle->next;
- }
-
- delete[] showStyle->fadeColorRanges;
- delete showStyle;
-
- // TODO: Verify that this is the correct entry to return
- // for the loop in processShowStyles to work correctly
- return lastEntry;
-}
-
-// TODO: 10-argument version is only in SCI3; argc checks are currently wrong for this version
-// and need to be fixed in future
-// TODO: SQ6 does not use 'priority' (exists since SCI2) or 'blackScreen' (exists since SCI3);
-// check to see if other versions use or if they are just always ignored
-void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen) {
-
- bool hasDivisions = false;
- bool hasFadeArray = false;
-
- // KQ7 2.0b uses a mismatched version of the Styler script (SCI2.1early script
- // for SCI2.1mid engine), so the calls it makes to kSetShowStyle are wrong and
- // put `divisions` where `pFadeArray` is supposed to be
- if (getSciVersion() == SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() == GID_KQ7) {
- hasDivisions = argc > 7;
- hasFadeArray = false;
- divisions = argc > 7 ? pFadeArray.toSint16() : -1;
- pFadeArray = NULL_REG;
- } else if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- hasDivisions = argc > 7;
- hasFadeArray = false;
- } else if (getSciVersion() < SCI_VERSION_3) {
- hasDivisions = argc > 8;
- hasFadeArray = argc > 7;
- } else {
- hasDivisions = argc > 9;
- hasFadeArray = argc > 8;
- }
-
- bool isFadeUp;
- int16 color;
- if (back != -1) {
- isFadeUp = false;
- color = back;
- } else {
- isFadeUp = true;
- color = 0;
- }
-
- if ((getSciVersion() < SCI_VERSION_2_1_MIDDLE && type == 15) || type > 15) {
- error("Illegal show style %d for plane %04x:%04x", type, PRINT_REG(planeObj));
- }
-
- Plane *plane = _planes.findByObject(planeObj);
- if (plane == nullptr) {
- error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj));
- }
-
- bool createNewEntry = true;
- ShowStyleEntry *entry = findShowStyleForPlane(planeObj);
- if (entry != nullptr) {
- // TODO: SCI2.1early has different criteria for show style reuse
- bool useExisting = true;
-
- if (useExisting) {
- useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]) && entry->unknownC == _defaultUnknownC[type];
- }
-
- if (useExisting) {
- createNewEntry = false;
- isFadeUp = true;
- entry->currentStep = 0;
- } else {
- isFadeUp = true;
- color = entry->color;
- deleteShowStyleInternal(entry/*, true*/);
- entry = nullptr;
- }
- }
-
- if (type > 0) {
- if (createNewEntry) {
- entry = new ShowStyleEntry;
- // NOTE: SCI2.1 engine tests if allocation returned a null pointer
- // but then only avoids setting currentStep if this is so. Since
- // this is a nonsensical approach, we do not do that here
- entry->currentStep = 0;
- entry->unknownC = _defaultUnknownC[type];
- entry->processed = false;
- entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
- entry->plane = planeObj;
-
- entry->fadeColorRanges = nullptr;
- if (hasFadeArray) {
- // NOTE: SCI2.1mid engine does no check to verify that an array is
- // successfully retrieved, and SegMan will cause a fatal error
- // if we try to use a memory segment that is not an array
- SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
-
- uint32 rangeCount = table->getSize();
- entry->fadeColorRangesCount = rangeCount;
-
- // NOTE: SCI engine code always allocates memory even if the range
- // table has no entries, but this does not really make sense, so
- // we avoid the allocation call in this case
- if (rangeCount > 0) {
- entry->fadeColorRanges = new uint16[rangeCount];
- for (size_t i = 0; i < rangeCount; ++i) {
- entry->fadeColorRanges[i] = table->getValue(i).toUint16();
- }
- }
- } else {
- entry->fadeColorRangesCount = 0;
- }
- }
-
- // NOTE: The original engine had no nullptr check and would just crash
- // if it got to here
- if (entry == nullptr) {
- error("Cannot edit non-existing ShowStyle entry");
- }
-
- entry->fadeUp = isFadeUp;
- entry->color = color;
- entry->nextTick = g_sci->getTickCount();
- entry->type = type;
- entry->animate = animate;
- entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions;
-
- if (entry->delay == 0) {
- if (entry->fadeColorRanges != nullptr) {
- delete[] entry->fadeColorRanges;
- }
- delete entry;
- error("ShowStyle has no duration");
- }
-
- if (frameOutNow) {
- Common::Rect frameOutRect(0, 0);
- frameOut(false, frameOutRect);
- }
-
- if (createNewEntry) {
- // TODO: Implement SCI2.1early and SCI3
- entry->next = _showStyles;
- _showStyles = entry;
- }
- }
-}
-
-// NOTE: Different version of SCI engine support different show styles
-// SCI2 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12, 13, 14
-// SCI2.1 implements 0, 1/2/3/4/5/6/7/8/9/10/11/12/15, 13, 14
-// SCI3 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12/15, 13, 14
-// TODO: Sierra code needs to be replaced with code that uses the
-// computed entry->delay property instead of just counting divisors,
-// as the latter is machine-speed-dependent and leads to wrong
-// transition speeds
-void GfxFrameout::processShowStyles() {
- uint32 now = g_sci->getTickCount();
-
- bool continueProcessing;
-
- // TODO: Change to bool? Engine uses inc to set the value to true,
- // but there does not seem to be any reason to actually count how
- // many times it was set
- int doFrameOut;
- do {
- continueProcessing = false;
- doFrameOut = 0;
- ShowStyleEntry *showStyle = _showStyles;
- while (showStyle != nullptr) {
- bool retval = false;
-
- if (!showStyle->animate) {
- ++doFrameOut;
- }
-
- if (showStyle->nextTick < now || !showStyle->animate) {
- // TODO: Different versions of SCI use different processors!
- // This is the SQ6/KQ7/SCI2.1mid table.
- switch (showStyle->type) {
- case kShowStyleNone: {
- retval = processShowStyleNone(showStyle);
- break;
- }
- case kShowStyleHShutterOut:
- case kShowStyleVShutterOut:
- case kShowStyleWipeLeft:
- case kShowStyleWipeUp:
- case kShowStyleIrisOut:
- case kShowStyleHShutterIn:
- case kShowStyleVShutterIn:
- case kShowStyleWipeRight:
- case kShowStyleWipeDown:
- case kShowStyleIrisIn:
- case kShowStyle11:
- case kShowStyle12:
- case kShowStyleUnknown: {
- retval = processShowStyleMorph(showStyle);
- break;
- }
- case kShowStyleFadeOut: {
- retval = processShowStyleFade(-1, showStyle);
- break;
- }
- case kShowStyleFadeIn: {
- retval = processShowStyleFade(1, showStyle);
- break;
- }
- }
- }
-
- if (!retval) {
- continueProcessing = true;
- }
-
- if (retval && showStyle->processed) {
- showStyle = deleteShowStyleInternal(showStyle);
- } else {
- showStyle = showStyle->next;
- }
- }
-
- if (g_engine->shouldQuit()) {
- return;
- }
-
- if (doFrameOut) {
- frameOut(true);
-
- // TODO: Transitions without the “animate” flag are too
- // fast, but the throttle value is arbitrary. Someone on
- // real hardware probably needs to test what the actual
- // speed of these transitions should be
- throttle();
- }
- } while(continueProcessing && doFrameOut);
-}
-
-bool GfxFrameout::processShowStyleNone(ShowStyleEntry *const showStyle) {
- if (showStyle->fadeUp) {
- _palette->setFade(100, 0, 255);
- } else {
- _palette->setFade(0, 0, 255);
- }
-
- showStyle->processed = true;
- return true;
-}
-
-bool GfxFrameout::processShowStyleMorph(ShowStyleEntry *const showStyle) {
- palMorphFrameOut(_styleRanges, showStyle);
- showStyle->processed = true;
- return true;
-}
-
-// TODO: Normalise use of 'entry' vs 'showStyle'
-bool GfxFrameout::processShowStyleFade(const int direction, ShowStyleEntry *const showStyle) {
- bool unchanged = true;
- if (showStyle->currentStep < showStyle->divisions) {
- int percent;
- if (direction <= 0) {
- percent = showStyle->divisions - showStyle->currentStep - 1;
- } else {
- percent = showStyle->currentStep;
- }
-
- percent *= 100;
- percent /= showStyle->divisions - 1;
-
- if (showStyle->fadeColorRangesCount > 0) {
- for (int i = 0, len = showStyle->fadeColorRangesCount; i < len; i += 2) {
- _palette->setFade(percent, showStyle->fadeColorRanges[i], showStyle->fadeColorRanges[i + 1]);
- }
- } else {
- _palette->setFade(percent, 0, 255);
- }
-
- ++showStyle->currentStep;
- showStyle->nextTick += showStyle->delay;
- unchanged = false;
- }
-
- if (showStyle->currentStep >= showStyle->divisions && unchanged) {
- if (direction > 0) {
- showStyle->processed = true;
- }
-
- return true;
- }
-
- return false;
-}
-
void GfxFrameout::kernelFrameOut(const bool shouldShowBits) {
- if (_showStyles != nullptr) {
- processShowStyles();
+ if (_transitions->hasShowStyles()) {
+ _transitions->processShowStyles();
} else if (_palMorphIsOn) {
- palMorphFrameOut(_styleRanges, nullptr);
+ palMorphFrameOut(_transitions->_styleRanges, nullptr);
_palMorphIsOn = false;
} else {
-// TODO: Window scroll
-// if (g_PlaneScroll) {
-// processScrolls();
-// }
+ if (_transitions->hasScrolls()) {
+ _transitions->processScrolls();
+ }
frameOut(shouldShowBits);
}
@@ -1621,6 +1255,14 @@ void GfxFrameout::throttle() {
}
}
+void GfxFrameout::showRect(const Common::Rect &rect) {
+ if (!rect.isEmpty()) {
+ _showList.clear();
+ _showList.add(rect);
+ showBits();
+ }
+}
+
#pragma mark -
#pragma mark Mouse cursor
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 99658ede6a..035555af6f 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -27,130 +27,13 @@
#include "sci/graphics/screen_item32.h"
namespace Sci {
-// TODO: Don't do this this way
-int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]);
-
-// TODO: Verify display styles and adjust names appropriately for
-// types 1 through 12 & 15 (others are correct)
-// Names should be:
-// * VShutterIn, VShutterOut
-// * HShutterIn, HShutterOut
-// * WipeLeft, WipeRight, WipeDown, WipeUp
-// * PixelDissolve
-// * ShutDown and Kill? (and Plain and Fade?)
-enum ShowStyleType /* : uint8 */ {
- kShowStyleNone = 0,
- kShowStyleHShutterOut = 1,
- kShowStyleHShutterIn = 2,
- kShowStyleVShutterOut = 3,
- kShowStyleVShutterIn = 4,
- kShowStyleWipeLeft = 5,
- kShowStyleWipeRight = 6,
- kShowStyleWipeUp = 7,
- kShowStyleWipeDown = 8,
- kShowStyleIrisOut = 9,
- kShowStyleIrisIn = 10,
- kShowStyle11 = 11,
- kShowStyle12 = 12,
- kShowStyleFadeOut = 13,
- kShowStyleFadeIn = 14,
- // TODO: Only in SCI3
- kShowStyleUnknown = 15
-};
-
-/**
- * Show styles represent transitions applied to draw planes.
- * One show style per plane can be active at a time.
- */
-struct ShowStyleEntry {
- /**
- * The ID of the plane this show style belongs to.
- * In SCI2.1mid (at least SQ6), per-plane transitions
- * were removed and a single plane ID is used.
- */
- reg_t plane;
-
- /**
- * The type of the transition.
- */
- ShowStyleType type;
-
- // TODO: This name is probably incorrect
- bool fadeUp;
-
- /**
- * The number of steps for the show style.
- */
- int16 divisions;
-
- // NOTE: This property exists from SCI2 through at least
- // SCI2.1mid but is never used in the actual processing
- // of the styles?
- int unknownC;
-
- /**
- * The color used by transitions that draw CelObjColor
- * screen items. -1 for transitions that do not draw
- * screen items.
- */
- int16 color;
-
- // TODO: Probably uint32
- // TODO: This field probably should be used in order to
- // provide time-accurate processing of show styles. In the
- // actual SCI engine (at least 2–2.1mid) it appears that
- // style transitions are drawn “as fast as possible”, one
- // step per loop, even though this delay field exists
- int delay;
-
- // TODO: Probably bool, but never seems to be true?
- int animate;
-
- /**
- * The wall time at which the next step of the animation
- * should execute.
- */
- uint32 nextTick;
-
- /**
- * During playback of the show style, the current step
- * (out of divisions).
- */
- int currentStep;
-
- /**
- * The next show style.
- */
- ShowStyleEntry *next;
-
- /**
- * Whether or not this style has finished running and
- * is ready for disposal.
- */
- bool processed;
-
- //
- // Engine specific properties for SCI2.1mid through SCI3
- //
-
- /**
- * The number of entries in the fadeColorRanges array.
- */
- uint8 fadeColorRangesCount;
-
- /**
- * A pointer to an dynamically sized array of palette
- * indexes, in the order [ fromColor, toColor, ... ].
- * Only colors within this range are transitioned.
- */
- uint16 *fadeColorRanges;
-};
-
typedef Common::Array<DrawList> ScreenItemListList;
typedef Common::Array<RectList> EraseListList;
class GfxCoordAdjuster32;
class GfxScreen;
+class GfxTransitions32;
+class PlaneShowStyle;
/**
* Frameout class, kFrameout and relevant functions for SCI32 games.
@@ -166,7 +49,7 @@ private:
SegManager *_segMan;
public:
- GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette);
+ GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions);
~GfxFrameout();
void clear();
@@ -287,37 +170,10 @@ public:
void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX);
#pragma mark -
-
- // TODO: Remap-related?
- void kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor);
-
-#pragma mark -
-#pragma mark Transitions
-private:
- int *_dissolveSequenceSeeds;
- int16 *_defaultDivisions;
- int16 *_defaultUnknownC;
-
- /**
- * TODO: Documentation
- */
- ShowStyleEntry *_showStyles;
-
- inline ShowStyleEntry *findShowStyleForPlane(const reg_t planeObj) const;
- inline ShowStyleEntry *deleteShowStyleInternal(ShowStyleEntry *const showStyle);
- void processShowStyles();
- bool processShowStyleNone(ShowStyleEntry *showStyle);
- bool processShowStyleMorph(ShowStyleEntry *showStyle);
- bool processShowStyleFade(const int direction, ShowStyleEntry *showStyle);
-
-public:
- // NOTE: This signature is taken from SCI3 Phantasmagoria 2
- // and is valid for all implementations of SCI32
- void kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen);
-
-#pragma mark -
#pragma mark Rendering
private:
+ GfxTransitions32 *_transitions;
+
/**
* State tracker to provide more accurate 60fps
* video throttling.
@@ -325,11 +181,6 @@ private:
uint8 _throttleState;
/**
- * TODO: Documentation
- */
- int8 _styleRanges[256];
-
- /**
* The internal display pixel buffer. During frameOut,
* this buffer is drawn into according to the draw and
* erase rects calculated by `calcLists`, then drawn out
@@ -428,16 +279,35 @@ private:
void mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold);
/**
- * TODO: Documentation
- */
- void palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle);
-
- /**
* Writes the internal frame buffer out to hardware and
* clears the show list.
*/
void showBits();
+ /**
+ * Validates whether the given palette index in the
+ * style range should copy a color from the next
+ * palette to the source palette during a palette
+ * morph operation.
+ */
+ inline bool validZeroStyle(const uint8 style, const int i) const {
+ if (style != 0) {
+ return false;
+ }
+
+ // TODO: Cannot check Shivers or MGDX until those executables can be
+ // unwrapped
+ switch (g_sci->getGameId()) {
+ case GID_KQ7:
+ case GID_PHANTASMAGORIA:
+ case GID_SQ6:
+ return (i > 71 && i < 104);
+ break;
+ default:
+ return true;
+ }
+ }
+
public:
/**
* Whether palMorphFrameOut should be used instead of
@@ -467,6 +337,11 @@ public:
void frameOut(const bool shouldShowBits, const Common::Rect &eraseRect = Common::Rect());
/**
+ * TODO: Documentation
+ */
+ void palMorphFrameOut(const int8 *styleRanges, PlaneShowStyle *showStyle);
+
+ /**
* Modifies the raw pixel data for the next frame with
* new palette indexes based on matched style ranges.
*/
@@ -484,6 +359,12 @@ public:
return 1;
};
+ /**
+ * Draws a portion of the current screen buffer to
+ * hardware. Used to display show styles in SCI2.1mid+.
+ */
+ void showRect(const Common::Rect &rect);
+
#pragma mark -
#pragma mark Mouse cursor
private:
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index 6b05b2d98a..cb6ec74e8f 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -194,11 +194,11 @@ void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *p
_type = transparent ? kPlaneTypeTransparentPicture : kPlaneTypePicture;
}
-void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
+GuiResourceId Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
+ GuiResourceId oldPictureId = _pictureId;
deletePic(pictureId);
addPicInternal(pictureId, &position, mirrorX);
- // NOTE: In SCI engine this method returned the pictureId of the
- // plane, but this return value was never used
+ return oldPictureId;
}
void Plane::changePic() {
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index 3981a2b319..f55d97b6ed 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -336,14 +336,6 @@ private:
/**
* Marks all screen items to be deleted that are within
- * this plane and match the given picture ID, then sets
- * the picture ID of the plane to the new picture ID
- * without adding any screen items.
- */
- void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId);
-
- /**
- * Marks all screen items to be deleted that are within
* this plane and are picture cels.
*/
void deleteAllPics();
@@ -355,7 +347,7 @@ public:
* new picture resource to the plane at the given
* position.
*/
- void addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX);
+ GuiResourceId addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX);
/**
* If the plane is a picture plane, re-adds all cels
@@ -364,6 +356,14 @@ public:
*/
void changePic();
+ /**
+ * Marks all screen items to be deleted that are within
+ * this plane and match the given picture ID, then sets
+ * the picture ID of the plane to the new picture ID
+ * without adding any screen items.
+ */
+ void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId);
+
#pragma mark -
#pragma mark Plane - Rendering
private:
diff --git a/engines/sci/graphics/transitions32.cpp b/engines/sci/graphics/transitions32.cpp
new file mode 100644
index 0000000000..01956e6a2f
--- /dev/null
+++ b/engines/sci/graphics/transitions32.cpp
@@ -0,0 +1,981 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "sci/engine/segment.h"
+#include "sci/engine/seg_manager.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/text32.h"
+#include "sci/graphics/transitions32.h"
+#include "sci/sci.h"
+
+namespace Sci {
+static int dissolveSequences[2][20] = {
+ /* SCI2.1early- */ { 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080 },
+ /* SCI2.1mid+ */ { 0, 0, 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080, 73728, 132096, 466944 }
+};
+static int16 divisionsDefaults[2][16] = {
+ /* SCI2.1early- */ { 1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 40, 40, 101, 101 },
+ /* SCI2.1mid+ */ { 1, 20, 20, 20, 20, 10, 10, 10, 10, 20, 20, 6, 10, 101, 101, 2 }
+};
+
+GfxTransitions32::GfxTransitions32(SegManager *segMan) :
+ _segMan(segMan),
+ _throttleState(0) {
+ for (int i = 0; i < 236; i += 2) {
+ _styleRanges[i] = 0;
+ _styleRanges[i + 1] = -1;
+ }
+ for (int i = 236; i < ARRAYSIZE(_styleRanges); ++i) {
+ _styleRanges[i] = 0;
+ }
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ _dissolveSequenceSeeds = dissolveSequences[0];
+ _defaultDivisions = divisionsDefaults[0];
+ } else {
+ _dissolveSequenceSeeds = dissolveSequences[1];
+ _defaultDivisions = divisionsDefaults[1];
+ }
+}
+
+GfxTransitions32::~GfxTransitions32() {
+ for (ShowStyleList::iterator it = _showStyles.begin(); it != _showStyles.end(); ++it) {
+ deleteShowStyle(it);
+ }
+ _scrolls.clear();
+}
+
+void GfxTransitions32::throttle() {
+ uint8 throttleTime;
+ if (_throttleState == 2) {
+ throttleTime = 34;
+ _throttleState = 0;
+ } else {
+ throttleTime = 33;
+ ++_throttleState;
+ }
+
+ g_sci->getEngineState()->speedThrottler(throttleTime);
+ g_sci->getEngineState()->_throttleTrigger = true;
+}
+
+#pragma mark -
+#pragma mark Show styles
+
+void GfxTransitions32::processShowStyles() {
+ uint32 now = g_sci->getTickCount();
+
+ bool continueProcessing;
+ bool doFrameOut;
+ do {
+ continueProcessing = false;
+ doFrameOut = false;
+ ShowStyleList::iterator showStyle = _showStyles.begin();
+ while (showStyle != _showStyles.end()) {
+ bool finished = false;
+
+ if (!showStyle->animate) {
+ doFrameOut = true;
+ }
+
+ finished = processShowStyle(*showStyle, now);
+
+ if (!finished) {
+ continueProcessing = true;
+ }
+
+ if (finished && showStyle->processed) {
+ showStyle = deleteShowStyle(showStyle);
+ } else {
+ showStyle = ++showStyle;
+ }
+ }
+
+ if (g_engine->shouldQuit()) {
+ return;
+ }
+
+ if (doFrameOut) {
+ g_sci->_gfxFrameout->frameOut(true);
+ throttle();
+ }
+ } while(continueProcessing && doFrameOut);
+}
+
+void GfxTransitions32::processEffects(PlaneShowStyle &showStyle) {
+ switch(showStyle.type) {
+ case kShowStyleHShutterOut:
+ processHShutterOut(showStyle);
+ break;
+ case kShowStyleHShutterIn:
+ processHShutterIn(showStyle);
+ break;
+ case kShowStyleVShutterOut:
+ processVShutterOut(showStyle);
+ break;
+ case kShowStyleVShutterIn:
+ processVShutterIn(showStyle);
+ break;
+ case kShowStyleWipeLeft:
+ processWipeLeft(showStyle);
+ break;
+ case kShowStyleWipeRight:
+ processWipeRight(showStyle);
+ break;
+ case kShowStyleWipeUp:
+ processWipeUp(showStyle);
+ break;
+ case kShowStyleWipeDown:
+ processWipeDown(showStyle);
+ break;
+ case kShowStyleIrisOut:
+ processIrisOut(showStyle);
+ break;
+ case kShowStyleIrisIn:
+ processIrisIn(showStyle);
+ break;
+ case kShowStyleDissolveNoMorph:
+ case kShowStyleDissolve:
+ processPixelDissolve(showStyle);
+ break;
+ case kShowStyleNone:
+ case kShowStyleFadeOut:
+ case kShowStyleFadeIn:
+ case kShowStyleMorph:
+ break;
+ }
+}
+
+// TODO: 10-argument version is only in SCI3; argc checks are currently wrong for this version
+// and need to be fixed in future
+void GfxTransitions32::kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen) {
+
+ bool hasDivisions = false;
+ bool hasFadeArray = false;
+
+ // KQ7 2.0b uses a mismatched version of the Styler script (SCI2.1early script
+ // for SCI2.1mid engine), so the calls it makes to kSetShowStyle are wrong and
+ // put `divisions` where `pFadeArray` is supposed to be
+ if (getSciVersion() == SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() == GID_KQ7) {
+ hasDivisions = argc > 7;
+ hasFadeArray = false;
+ divisions = argc > 7 ? pFadeArray.toSint16() : -1;
+ pFadeArray = NULL_REG;
+ } else if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ hasDivisions = argc > 7;
+ hasFadeArray = false;
+ } else if (getSciVersion() < SCI_VERSION_3) {
+ hasDivisions = argc > 8;
+ hasFadeArray = argc > 7;
+ } else {
+ hasDivisions = argc > 9;
+ hasFadeArray = argc > 8;
+ }
+
+ bool isFadeUp;
+ int16 color;
+ if (back != -1) {
+ isFadeUp = false;
+ color = back;
+ } else {
+ isFadeUp = true;
+ color = 0;
+ }
+
+ if ((getSciVersion() < SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() != GID_KQ7 && type == 15) || type > 15) {
+ error("Illegal show style %d for plane %04x:%04x", type, PRINT_REG(planeObj));
+ }
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObj);
+ if (plane == nullptr) {
+ error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj));
+ }
+
+ bool createNewEntry = true;
+ PlaneShowStyle *entry = findShowStyleForPlane(planeObj);
+ if (entry != nullptr) {
+ bool useExisting = true;
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ useExisting = plane->_gameRect.width() == entry->width && plane->_gameRect.height() == entry->height;
+ }
+
+ if (useExisting) {
+ useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]);
+ }
+
+ if (useExisting) {
+ createNewEntry = false;
+ isFadeUp = true;
+ entry->currentStep = 0;
+ } else {
+ isFadeUp = true;
+ color = entry->color;
+ deleteShowStyle(findIteratorForPlane(planeObj));
+ entry = nullptr;
+ }
+ }
+
+ if (type > 0) {
+ if (createNewEntry) {
+ entry = new PlaneShowStyle;
+ // NOTE: SCI2.1 engine tests if allocation returned a null pointer
+ // but then only avoids setting currentStep if this is so. Since
+ // this is a nonsensical approach, we do not do that here
+ entry->currentStep = 0;
+ entry->processed = false;
+ entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
+ entry->plane = planeObj;
+ entry->fadeColorRangesCount = 0;
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ // for pixel dissolve
+ entry->bitmap = NULL_REG;
+ entry->bitmapScreenItem = nullptr;
+
+ // for wipe
+ entry->screenItems.clear();
+ entry->width = plane->_gameRect.width();
+ entry->height = plane->_gameRect.height();
+ } else {
+ entry->fadeColorRanges = nullptr;
+ if (hasFadeArray) {
+ // NOTE: SCI2.1mid engine does no check to verify that an array is
+ // successfully retrieved, and SegMan will cause a fatal error
+ // if we try to use a memory segment that is not an array
+ SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
+
+ uint32 rangeCount = table->getSize();
+ entry->fadeColorRangesCount = rangeCount;
+
+ // NOTE: SCI engine code always allocates memory even if the range
+ // table has no entries, but this does not really make sense, so
+ // we avoid the allocation call in this case
+ if (rangeCount > 0) {
+ entry->fadeColorRanges = new uint16[rangeCount];
+ for (size_t i = 0; i < rangeCount; ++i) {
+ entry->fadeColorRanges[i] = table->getValue(i).toUint16();
+ }
+ }
+ }
+ }
+ }
+
+ // NOTE: The original engine had no nullptr check and would just crash
+ // if it got to here
+ if (entry == nullptr) {
+ error("Cannot edit non-existing ShowStyle entry");
+ }
+
+ entry->fadeUp = isFadeUp;
+ entry->color = color;
+ entry->nextTick = g_sci->getTickCount();
+ entry->type = type;
+ entry->animate = animate;
+ entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions;
+
+ if (entry->delay == 0) {
+ error("ShowStyle has no duration");
+ }
+
+ if (frameOutNow) {
+ // Creates a reference frame for the pixel dissolves to use
+ g_sci->_gfxFrameout->frameOut(false);
+ }
+
+ if (createNewEntry) {
+ if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
+ switch (entry->type) {
+ case kShowStyleIrisOut:
+ case kShowStyleIrisIn:
+ configure21EarlyIris(*entry, priority);
+ break;
+ case kShowStyleDissolve:
+ configure21EarlyDissolve(*entry, priority, plane->_gameRect);
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+
+ _showStyles.push_back(*entry);
+ delete entry;
+ }
+ }
+}
+
+void GfxTransitions32::kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor) {
+ if (toColor > fromColor) {
+ return;
+ }
+
+ for (int i = fromColor; i <= toColor; ++i) {
+ _styleRanges[i] = 0;
+ }
+}
+
+PlaneShowStyle *GfxTransitions32::findShowStyleForPlane(const reg_t planeObj) {
+ for (ShowStyleList::iterator it = _showStyles.begin(); it != _showStyles.end(); ++it) {
+ if (it->plane == planeObj) {
+ return &*it;
+ }
+ }
+
+ return nullptr;
+}
+
+ShowStyleList::iterator GfxTransitions32::findIteratorForPlane(const reg_t planeObj) {
+ ShowStyleList::iterator it;
+ for (it = _showStyles.begin(); it != _showStyles.end(); ++it) {
+ if (it->plane == planeObj) {
+ break;
+ }
+ }
+
+ return it;
+}
+
+ShowStyleList::iterator GfxTransitions32::deleteShowStyle(const ShowStyleList::iterator &showStyle) {
+ switch (showStyle->type) {
+ case kShowStyleDissolveNoMorph:
+ case kShowStyleDissolve:
+ if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
+ _segMan->freeHunkEntry(showStyle->bitmap);
+ g_sci->_gfxFrameout->deleteScreenItem(*showStyle->bitmapScreenItem);
+ }
+ break;
+ case kShowStyleIrisOut:
+ case kShowStyleIrisIn:
+ if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
+ for (uint i = 0; i < showStyle->screenItems.size(); ++i) {
+ ScreenItem *screenItem = showStyle->screenItems[i];
+ if (screenItem != nullptr) {
+ g_sci->_gfxFrameout->deleteScreenItem(*screenItem);
+ }
+ }
+ }
+ break;
+ case kShowStyleFadeIn:
+ case kShowStyleFadeOut:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY && showStyle->fadeColorRangesCount > 0) {
+ delete[] showStyle->fadeColorRanges;
+ }
+ break;
+ case kShowStyleNone:
+ case kShowStyleMorph:
+ // do nothing
+ break;
+ default:
+ error("Unknown delete transition type %d", showStyle->type);
+ }
+
+ return _showStyles.erase(showStyle);
+}
+
+void GfxTransitions32::configure21EarlyIris(PlaneShowStyle &showStyle, const int16 priority) {
+ showStyle.numEdges = 4;
+ const int numScreenItems = showStyle.numEdges * showStyle.divisions;
+ showStyle.screenItems.reserve(numScreenItems);
+
+ CelInfo32 celInfo;
+ celInfo.type = kCelTypeColor;
+ celInfo.color = showStyle.color;
+
+ const int width = showStyle.width;
+ const int height = showStyle.height;
+ const int divisions = showStyle.divisions;
+
+ for (int i = 0; i < divisions; ++i) {
+ Common::Rect rect;
+
+ // Top
+ rect.left = (width * i) / (2 * divisions);
+ rect.top = (height * i) / (2 * divisions);
+ rect.right = width - rect.left;
+ rect.bottom = (height + 1) * (i + 1) / (2 * divisions);
+ const int16 topTop = rect.top;
+ const int16 topBottom = rect.bottom;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+
+ // Bottom
+ rect.top = height - rect.bottom;
+ rect.bottom = height - topTop;
+ const int16 bottomTop = rect.top;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+
+ // Left
+ rect.top = topBottom;
+ rect.right = (width + 1) * (i + 1) / (2 * divisions);
+ rect.bottom = bottomTop;
+ const int16 leftLeft = rect.left;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+
+ // Right
+ rect.left = width - rect.right;
+ rect.right = width - leftLeft;
+
+ showStyle.screenItems.push_back(new ScreenItem(showStyle.plane, celInfo, rect));
+ showStyle.screenItems.back()->_priority = priority;
+ showStyle.screenItems.back()->_fixedPriority = true;
+ }
+
+ if (showStyle.fadeUp) {
+ for (int i = 0; i < numScreenItems; ++i) {
+ g_sci->_gfxFrameout->addScreenItem(*showStyle.screenItems[i]);
+ }
+ }
+}
+
+void GfxTransitions32::configure21EarlyDissolve(PlaneShowStyle &showStyle, const int16 priority, const Common::Rect &gameRect) {
+
+ BitmapResource bitmap(_segMan, showStyle.width, showStyle.height, kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+
+ showStyle.bitmap = bitmap.getObject();
+
+ const Buffer &source = g_sci->_gfxFrameout->getCurrentBuffer();
+ Buffer target(showStyle.width, showStyle.height, bitmap.getPixels());
+
+ target.fillRect(Common::Rect(bitmap.getWidth(), bitmap.getHeight()), kDefaultSkipColor);
+ target.copyRectToSurface(source, 0, 0, gameRect);
+
+ CelInfo32 celInfo;
+ celInfo.type = kCelTypeMem;
+ celInfo.bitmap = bitmap.getObject();
+
+ showStyle.bitmapScreenItem = new ScreenItem(showStyle.plane, celInfo, Common::Point(0, 0), ScaleInfo());
+ showStyle.bitmapScreenItem->_priority = priority;
+ showStyle.bitmapScreenItem->_fixedPriority = true;
+
+ g_sci->_gfxFrameout->addScreenItem(*showStyle.bitmapScreenItem);
+}
+
+bool GfxTransitions32::processShowStyle(PlaneShowStyle &showStyle, uint32 now) {
+ if (showStyle.nextTick >= now && showStyle.animate) {
+ return false;
+ }
+
+ switch (showStyle.type) {
+ default:
+ case kShowStyleNone:
+ return processNone(showStyle);
+ case kShowStyleHShutterOut:
+ case kShowStyleHShutterIn:
+ case kShowStyleVShutterOut:
+ case kShowStyleVShutterIn:
+ case kShowStyleWipeLeft:
+ case kShowStyleWipeRight:
+ case kShowStyleWipeUp:
+ case kShowStyleWipeDown:
+ case kShowStyleDissolveNoMorph:
+ case kShowStyleMorph:
+ return processMorph(showStyle);
+ case kShowStyleDissolve:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processMorph(showStyle);
+ } else {
+ return processPixelDissolve(showStyle);
+ }
+ case kShowStyleIrisOut:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processMorph(showStyle);
+ } else {
+ return processIrisOut(showStyle);
+ }
+ case kShowStyleIrisIn:
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processMorph(showStyle);
+ } else {
+ return processIrisIn(showStyle);
+ }
+ case kShowStyleFadeOut:
+ return processFade(-1, showStyle);
+ case kShowStyleFadeIn:
+ return processFade(1, showStyle);
+ }
+}
+
+bool GfxTransitions32::processNone(PlaneShowStyle &showStyle) {
+ if (showStyle.fadeUp) {
+ g_sci->_gfxPalette32->setFade(100, 0, 255);
+ } else {
+ g_sci->_gfxPalette32->setFade(0, 0, 255);
+ }
+
+ showStyle.processed = true;
+ return true;
+}
+
+void GfxTransitions32::processHShutterOut(PlaneShowStyle &showStyle) {
+ error("HShutterOut is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processHShutterIn(PlaneShowStyle &showStyle) {
+ error("HShutterIn is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processVShutterOut(PlaneShowStyle &showStyle) {
+ error("VShutterOut is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processVShutterIn(PlaneShowStyle &showStyle) {
+ error("VShutterIn is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeLeft(PlaneShowStyle &showStyle) {
+ error("WipeLeft is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeRight(PlaneShowStyle &showStyle) {
+ error("WipeRight is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeUp(PlaneShowStyle &showStyle) {
+ error("WipeUp is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+void GfxTransitions32::processWipeDown(PlaneShowStyle &showStyle) {
+ error("WipeDown is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+bool GfxTransitions32::processIrisOut(PlaneShowStyle &showStyle) {
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ error("IrisOut is not known to be used by any SCI2.1mid+ game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+ }
+
+ return processWipe(-1, showStyle);
+}
+
+bool GfxTransitions32::processIrisIn(PlaneShowStyle &showStyle) {
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ error("IrisIn is not known to be used by any SCI2.1mid+ game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+ }
+
+ return processWipe(1, showStyle);
+}
+
+void GfxTransitions32::processDissolveNoMorph(PlaneShowStyle &showStyle) {
+ error("DissolveNoMorph is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+}
+
+inline int bitWidth(int number) {
+ int width = 0;
+ while (number != 0) {
+ number >>= 1;
+ width += 1;
+ }
+ return width;
+}
+
+bool GfxTransitions32::processPixelDissolve(PlaneShowStyle &showStyle) {
+ if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
+ return processPixelDissolve21Mid(showStyle);
+ } else {
+ return processPixelDissolve21Early(showStyle);
+ }
+}
+
+bool GfxTransitions32::processPixelDissolve21Early(PlaneShowStyle &showStyle) {
+ bool unchanged = true;
+
+ BitmapResource bitmap(showStyle.bitmap);
+ Buffer buffer(showStyle.width, showStyle.height, bitmap.getPixels());
+
+ uint32 numPixels = showStyle.width * showStyle.height;
+ uint32 numPixelsPerDivision = (numPixels + showStyle.divisions) / showStyle.divisions;
+
+ uint32 index;
+ if (showStyle.currentStep == 0) {
+ int i = 0;
+ index = numPixels;
+ if (index != 1) {
+ for (;;) {
+ index >>= 1;
+ if (index == 1) {
+ break;
+ }
+ i++;
+ }
+ }
+
+ showStyle.dissolveMask = _dissolveSequenceSeeds[i];
+ index = 53427;
+
+ showStyle.firstPixel = index;
+ showStyle.pixel = index;
+ } else {
+ index = showStyle.pixel;
+ for (;;) {
+ if (index & 1) {
+ index >>= 1;
+ index ^= showStyle.dissolveMask;
+ } else {
+ index >>= 1;
+ }
+
+ if (index < numPixels) {
+ break;
+ }
+ }
+
+ if (index == showStyle.firstPixel) {
+ index = 0;
+ }
+ }
+
+ if (showStyle.currentStep < showStyle.divisions) {
+ for (uint32 i = 0; i < numPixelsPerDivision; ++i) {
+ *(byte *)buffer.getBasePtr(index % showStyle.width, index / showStyle.width) = showStyle.color;
+
+ for (;;) {
+ if (index & 1) {
+ index >>= 1;
+ index ^= showStyle.dissolveMask;
+ } else {
+ index >>= 1;
+ }
+
+ if (index < numPixels) {
+ break;
+ }
+ }
+
+ if (index == showStyle.firstPixel) {
+ buffer.fillRect(Common::Rect(0, 0, showStyle.width, showStyle.height), showStyle.color);
+ break;
+ }
+ }
+
+ showStyle.pixel = index;
+ showStyle.nextTick += showStyle.delay;
+ ++showStyle.currentStep;
+ unchanged = false;
+ if (showStyle.bitmapScreenItem->_created == 0) {
+ showStyle.bitmapScreenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+
+ if ((showStyle.currentStep >= showStyle.divisions) && unchanged) {
+ if (showStyle.fadeUp) {
+ showStyle.processed = true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool GfxTransitions32::processPixelDissolve21Mid(PlaneShowStyle &showStyle) {
+ // SQ6 room 530
+
+ Plane* plane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(showStyle.plane);
+ const Common::Rect &screenRect = plane->_screenRect;
+ Common::Rect rect;
+
+ const int planeWidth = screenRect.width();
+ const int planeHeight = screenRect.height();
+ const int divisions = showStyle.divisions;
+ const int width = planeWidth / divisions + ((planeWidth % divisions) ? 1 : 0);
+ const int height = planeHeight / divisions + ((planeHeight % divisions) ? 1 : 0);
+
+ const uint32 mask = _dissolveSequenceSeeds[bitWidth(width * height - 1)];
+ int seq = 1;
+
+ uint iteration = 0;
+ const uint numIterationsPerTick = (width * height + divisions) / divisions;
+
+ do {
+ int row = seq / width;
+ int col = seq % width;
+
+ if (row < height) {
+ if (row == height && (planeHeight % divisions)) {
+ if (col == width && (planeWidth % divisions)) {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions + (planeWidth % divisions);
+ rect.bottom = row * divisions + (planeHeight % divisions);
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ } else {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions * 2;
+ rect.bottom = row * divisions + (planeHeight % divisions);
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ }
+ } else {
+ if (col == width && (planeWidth % divisions)) {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions + (planeWidth % divisions) + 1;
+ rect.bottom = row * divisions * 2 + 1;
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ } else {
+ rect.left = col * divisions;
+ rect.top = row * divisions;
+ rect.right = col * divisions * 2 + 1;
+ rect.bottom = row * divisions * 2 + 1;
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ }
+ }
+ }
+
+ if (seq & 1) {
+ seq = (seq >> 1) ^ mask;
+ } else {
+ seq >>= 1;
+ }
+
+ if (++iteration == numIterationsPerTick) {
+ throttle();
+ iteration = 0;
+ }
+ } while(seq != 1 && !g_engine->shouldQuit());
+
+ rect.left = screenRect.left;
+ rect.top = screenRect.top;
+ rect.right = divisions + screenRect.left;
+ rect.bottom = divisions + screenRect.bottom;
+ rect.clip(screenRect);
+ g_sci->_gfxFrameout->showRect(rect);
+ throttle();
+
+ g_sci->_gfxFrameout->showRect(screenRect);
+ return true;
+}
+
+bool GfxTransitions32::processFade(const int8 direction, PlaneShowStyle &showStyle) {
+ bool unchanged = true;
+ if (showStyle.currentStep < showStyle.divisions) {
+ int percent;
+ if (direction <= 0) {
+ percent = showStyle.divisions - showStyle.currentStep - 1;
+ } else {
+ percent = showStyle.currentStep;
+ }
+
+ percent *= 100;
+ percent /= showStyle.divisions - 1;
+
+ if (showStyle.fadeColorRangesCount > 0) {
+ for (int i = 0, len = showStyle.fadeColorRangesCount; i < len; i += 2) {
+ g_sci->_gfxPalette32->setFade(percent, showStyle.fadeColorRanges[i], showStyle.fadeColorRanges[i + 1]);
+ }
+ } else {
+ g_sci->_gfxPalette32->setFade(percent, 0, 255);
+ }
+
+ ++showStyle.currentStep;
+ showStyle.nextTick += showStyle.delay;
+ unchanged = false;
+ }
+
+ if (showStyle.currentStep >= showStyle.divisions && unchanged) {
+ if (direction > 0) {
+ showStyle.processed = true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool GfxTransitions32::processMorph(PlaneShowStyle &showStyle) {
+ g_sci->_gfxFrameout->palMorphFrameOut(_styleRanges, &showStyle);
+ showStyle.processed = true;
+ return true;
+}
+
+bool GfxTransitions32::processWipe(const int8 direction, PlaneShowStyle &showStyle) {
+ bool unchanged = true;
+ if (showStyle.currentStep < showStyle.divisions) {
+ int index;
+ if (direction > 0) {
+ index = showStyle.currentStep;
+ } else {
+ index = showStyle.divisions - showStyle.currentStep - 1;
+ }
+
+ index *= showStyle.numEdges;
+ for (int i = 0; i < showStyle.numEdges; ++i) {
+ ScreenItem *screenItem = showStyle.screenItems[index + i];
+ if (showStyle.fadeUp) {
+ g_sci->_gfxFrameout->deleteScreenItem(*screenItem);
+ showStyle.screenItems[index + i] = nullptr;
+ } else {
+ g_sci->_gfxFrameout->addScreenItem(*screenItem);
+ }
+ }
+
+ ++showStyle.currentStep;
+ showStyle.nextTick += showStyle.delay;
+ unchanged = false;
+ }
+
+ if (showStyle.currentStep >= showStyle.divisions && unchanged) {
+ if (showStyle.fadeUp) {
+ showStyle.processed = true;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+#pragma mark -
+#pragma mark Scrolls
+
+void GfxTransitions32::processScrolls() {
+ for (ScrollList::iterator it = _scrolls.begin(); it != _scrolls.end(); ) {
+ bool finished = processScroll(*it);
+ if (finished) {
+ it = _scrolls.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ throttle();
+}
+
+void GfxTransitions32::kernelSetScroll(const reg_t planeId, const int16 deltaX, const int16 deltaY, const GuiResourceId pictureId, const bool animate, const bool mirrorX) {
+
+ for (ScrollList::const_iterator it = _scrolls.begin(); it != _scrolls.end(); ++it) {
+ if (it->plane == planeId) {
+ error("Scroll already exists on plane %04x:%04x", PRINT_REG(planeId));
+ }
+ }
+
+ if (!deltaX && !deltaY) {
+ error("kSetScroll: Scroll has no movement");
+ }
+
+ if (deltaX && deltaY) {
+ error("kSetScroll: Cannot scroll in two dimensions");
+ }
+
+ PlaneScroll *scroll = new PlaneScroll;
+ scroll->plane = planeId;
+ scroll->x = 0;
+ scroll->y = 0;
+ scroll->deltaX = deltaX;
+ scroll->deltaY = deltaY;
+ scroll->newPictureId = pictureId;
+ scroll->animate = animate;
+ scroll->startTick = g_sci->getTickCount();
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeId);
+ if (plane == nullptr) {
+ error("kSetScroll: Plane %04x:%04x not found", PRINT_REG(planeId));
+ }
+
+ Plane *visiblePlane = g_sci->_gfxFrameout->getPlanes().findByObject(planeId);
+ if (visiblePlane == nullptr) {
+ error("kSetScroll: Visible plane %04x:%04x not found", PRINT_REG(planeId));
+ }
+
+ const Common::Rect &gameRect = visiblePlane->_gameRect;
+ Common::Point picOrigin;
+
+ if (deltaX) {
+ picOrigin.y = 0;
+
+ if (deltaX > 0) {
+ scroll->x = picOrigin.x = -gameRect.width();
+ } else {
+ scroll->x = picOrigin.x = gameRect.width();
+ }
+ } else {
+ picOrigin.x = 0;
+
+ if (deltaY > 0) {
+ scroll->y = picOrigin.y = -gameRect.height();
+ } else {
+ scroll->y = picOrigin.y = gameRect.height();
+ }
+ }
+
+ scroll->oldPictureId = plane->addPic(pictureId, picOrigin, mirrorX);
+
+ if (animate) {
+ _scrolls.push_front(*scroll);
+ } else {
+ bool finished = false;
+ while (!finished && !g_engine->shouldQuit()) {
+ finished = processScroll(*scroll);
+ g_sci->_gfxFrameout->frameOut(true);
+ throttle();
+ }
+ delete scroll;
+ }
+}
+
+bool GfxTransitions32::processScroll(PlaneScroll &scroll) {
+ bool finished = false;
+ uint32 now = g_sci->getTickCount();
+ if (scroll.startTick >= now) {
+ return false;
+ }
+
+ int deltaX = scroll.deltaX;
+ int deltaY = scroll.deltaY;
+ if (((scroll.x + deltaX) * scroll.y) <= 0) {
+ deltaX = -scroll.x;
+ }
+ if (((scroll.y + deltaY) * scroll.y) <= 0) {
+ deltaY = -scroll.y;
+ }
+
+ scroll.x += deltaX;
+ scroll.y += deltaY;
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(scroll.plane);
+
+ if ((scroll.x == 0) && (scroll.y == 0)) {
+ plane->deletePic(scroll.oldPictureId, scroll.newPictureId);
+ finished = true;
+ }
+
+ plane->scrollScreenItems(deltaX, deltaY, true);
+
+ return finished;
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/transitions32.h b/engines/sci/graphics/transitions32.h
new file mode 100644
index 0000000000..3968378a3c
--- /dev/null
+++ b/engines/sci/graphics/transitions32.h
@@ -0,0 +1,476 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCI_GRAPHICS_TRANSITIONS32_H
+#define SCI_GRAPHICS_TRANSITIONS32_H
+
+#include "common/list.h"
+#include "common/scummsys.h"
+#include "sci/engine/vm_types.h"
+
+namespace Sci {
+enum ShowStyleType /* : uint8 */ {
+ kShowStyleNone = 0,
+ kShowStyleHShutterOut = 1,
+ kShowStyleHShutterIn = 2,
+ kShowStyleVShutterOut = 3,
+ kShowStyleVShutterIn = 4,
+ kShowStyleWipeLeft = 5,
+ kShowStyleWipeRight = 6,
+ kShowStyleWipeUp = 7,
+ kShowStyleWipeDown = 8,
+ kShowStyleIrisOut = 9,
+ kShowStyleIrisIn = 10,
+ kShowStyleDissolveNoMorph = 11,
+ kShowStyleDissolve = 12,
+ kShowStyleFadeOut = 13,
+ kShowStyleFadeIn = 14,
+ kShowStyleMorph = 15
+};
+
+/**
+ * Show styles represent transitions applied to draw planes.
+ * One show style per plane can be active at a time.
+ */
+struct PlaneShowStyle {
+ /**
+ * The ID of the plane this show style belongs to.
+ * In SCI2.1mid (at least SQ6), per-plane transitions
+ * were removed and a single plane ID is used.
+ */
+ reg_t plane;
+
+ /**
+ * The type of the transition.
+ */
+ ShowStyleType type;
+
+ /**
+ * When true, the show style is an entry transition
+ * to a new room. When false, it is an exit
+ * transition away from an old room.
+ */
+ bool fadeUp;
+
+ /**
+ * The number of steps for the show style.
+ */
+ int16 divisions;
+
+ /**
+ * The color used by transitions that draw CelObjColor
+ * screen items. -1 for transitions that do not draw
+ * screen items.
+ */
+ int16 color;
+
+ // TODO: Probably uint32
+ // TODO: This field probably should be used in order to
+ // provide time-accurate processing of show styles. In the
+ // actual SCI engine (at least 2–2.1mid) it appears that
+ // style transitions are drawn “as fast as possible”, one
+ // step per loop, even though this delay field exists
+ int delay;
+
+ // TODO: Probably bool, but never seems to be true?
+ bool animate;
+
+ /**
+ * The wall time at which the next step of the animation
+ * should execute.
+ */
+ uint32 nextTick;
+
+ /**
+ * During playback of the show style, the current step
+ * (out of divisions).
+ */
+ int currentStep;
+
+ /**
+ * Whether or not this style has finished running and
+ * is ready for disposal.
+ */
+ bool processed;
+
+ //
+ // Engine specific properties for SCI2.1early
+ //
+
+ /**
+ * A list of screen items, each representing one
+ * block of a wipe transition.
+ */
+ Common::Array<ScreenItem *> screenItems;
+
+ /**
+ * For wipe transitions, the number of edges with a
+ * moving wipe (1, 2, or 4).
+ */
+ uint8 numEdges;
+
+ /**
+ * The dimensions of the plane, in game script
+ * coordinates.
+ */
+ int16 width, height;
+
+ /**
+ * For pixel dissolve transitions, the screen item
+ * used to render the transition.
+ */
+ ScreenItem *bitmapScreenItem;
+
+ /**
+ * For pixel dissolve transitions, the bitmap used
+ * to render the transition.
+ */
+ reg_t bitmap;
+
+ /**
+ * The bit mask used by pixel dissolve transitions.
+ */
+ uint32 dissolveMask;
+
+ /**
+ * The first pixel that was dissolved in a pixel
+ * dissolve transition.
+ */
+ uint32 firstPixel;
+
+ /**
+ * The last pixel that was dissolved. Once all
+ * pixels have been dissolved, `pixel` will once
+ * again equal `firstPixel`.
+ */
+ uint32 pixel;
+
+ //
+ // Engine specific properties for SCI2.1mid through SCI3
+ //
+
+ /**
+ * The number of entries in the fadeColorRanges array.
+ */
+ uint8 fadeColorRangesCount;
+
+ /**
+ * A pointer to an dynamically sized array of palette
+ * indexes, in the order [ fromColor, toColor, ... ].
+ * Only colors within this range are transitioned.
+ */
+ uint16 *fadeColorRanges;
+};
+
+/**
+ * PlaneScroll describes a transition between two different
+ * pictures within a single plane.
+ */
+struct PlaneScroll {
+ /**
+ * The ID of the plane to be scrolled.
+ */
+ reg_t plane;
+
+ /**
+ * The current position of the scroll.
+ */
+ int16 x, y;
+
+ /**
+ * The distance that should be scrolled. Only one of
+ * `deltaX` or `deltaY` may be set.
+ */
+ int16 deltaX, deltaY;
+
+ /**
+ * The pic that should be created and scrolled into
+ * view inside the plane.
+ */
+ GuiResourceId newPictureId;
+
+ /**
+ * The picture that should be scrolled out of view
+ * and deleted from the plane.
+ */
+ GuiResourceId oldPictureId;
+
+ /**
+ * If true, the scroll animation is interleaved
+ * with other updates to the graphics. If false,
+ * the scroll will be exclusively animated until
+ * it is finished.
+ */
+ bool animate;
+
+ /**
+ * The tick after which the animation will start.
+ */
+ uint32 startTick;
+};
+
+typedef Common::List<PlaneShowStyle> ShowStyleList;
+typedef Common::List<PlaneScroll> ScrollList;
+
+class GfxTransitions32 {
+public:
+ GfxTransitions32(SegManager *_segMan);
+ ~GfxTransitions32();
+private:
+ SegManager *_segMan;
+
+ /**
+ * Throttles transition playback to prevent
+ * transitions from being instant on fast
+ * computers.
+ */
+ void throttle();
+ int8 _throttleState;
+
+#pragma mark -
+#pragma mark Show styles
+public:
+ inline bool hasShowStyles() const { return !_showStyles.empty(); }
+
+ /**
+ * Processes all active show styles in a loop
+ * until they are finished.
+ */
+ void processShowStyles();
+
+ /**
+ * Processes show styles that are applied
+ * through `GfxFrameout::palMorphFrameOut`.
+ */
+ void processEffects(PlaneShowStyle &showStyle);
+
+ // NOTE: This signature is taken from SCI3 Phantasmagoria 2
+ // and is valid for all implementations of SCI32
+ void kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen);
+
+ /**
+ * Sets the range that will be used by
+ * `GfxFrameout::palMorphFrameOut` to alter
+ * palette entries.
+ */
+ void kernelSetPalStyleRange(const uint8 fromColor, const uint8 toColor);
+
+ /**
+ * A map of palette entries that can be morphed
+ * by the Morph show style.
+ */
+ int8 _styleRanges[256];
+
+private:
+ /**
+ * Default sequence values for pixel dissolve
+ * transition bit masks.
+ */
+ int *_dissolveSequenceSeeds;
+
+ /**
+ * Default values for `PlaneShowStyle::divisions`
+ * for the current SCI version.
+ */
+ int16 *_defaultDivisions;
+
+ /**
+ * The list of PlaneShowStyles that are
+ * currently active.
+ */
+ ShowStyleList _showStyles;
+
+ /**
+ * Finds a show style that applies to the given
+ * plane.
+ */
+ PlaneShowStyle *findShowStyleForPlane(const reg_t planeObj);
+
+ /**
+ * Finds the iterator for a show style that
+ * applies to the given plane.
+ */
+ ShowStyleList::iterator findIteratorForPlane(const reg_t planeObj);
+
+ /**
+ * Deletes the given PlaneShowStyle and returns
+ * the next PlaneShowStyle from the list of
+ * styles.
+ */
+ ShowStyleList::iterator deleteShowStyle(const ShowStyleList::iterator &showStyle);
+
+ /**
+ * Initializes the given PlaneShowStyle for an
+ * iris effect for SCI2 to 2.1early.
+ */
+ void configure21EarlyIris(PlaneShowStyle &showStyle, const int16 priority);
+
+ /**
+ * Initializes the given PlaneShowStyle for a
+ * pixel dissolve effect for SCI2 to 2.1early.
+ */
+ void configure21EarlyDissolve(PlaneShowStyle &showStyle, const int16 priority, const Common::Rect &gameRect);
+
+ /**
+ * Processes one tick of the given
+ * PlaneShowStyle.
+ */
+ bool processShowStyle(PlaneShowStyle &showStyle, uint32 now);
+
+ /**
+ * Performs an instant transition between two
+ * rooms.
+ */
+ bool processNone(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a horizontal shutter effect.
+ */
+ void processHShutterOut(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a horizontal shutter effect.
+ */
+ void processHShutterIn(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a vertical shutter effect.
+ */
+ void processVShutterOut(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a vertical shutter effect.
+ */
+ void processVShutterIn(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a wipe to the left.
+ */
+ void processWipeLeft(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a wipe to the right.
+ */
+ void processWipeRight(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with a wipe upwards.
+ */
+ void processWipeUp(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with a wipe downwards.
+ */
+ void processWipeDown(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders into a room
+ * with an iris effect.
+ */
+ bool processIrisOut(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders to black
+ * with an iris effect.
+ */
+ bool processIrisIn(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders between
+ * rooms using a block dissolve effect.
+ */
+ void processDissolveNoMorph(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that renders between
+ * rooms with a pixel dissolve effect.
+ */
+ bool processPixelDissolve(PlaneShowStyle &showStyle);
+
+ /**
+ * SCI2 to 2.1early implementation of pixel
+ * dissolve.
+ */
+ bool processPixelDissolve21Early(PlaneShowStyle &showStyle);
+
+ /**
+ * SCI2.1mid and later implementation of
+ * pixel dissolve.
+ */
+ bool processPixelDissolve21Mid(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a transition that fades to black
+ * between rooms.
+ */
+ bool processFade(const int8 direction, PlaneShowStyle &showStyle);
+
+ /**
+ * Morph transition calls back into the
+ * transition system's `processEffects`
+ * method, which then applies transitions
+ * other than None, Fade, or Morph.
+ */
+ bool processMorph(PlaneShowStyle &showStyle);
+
+ /**
+ * Performs a generic transition for any of
+ * the wipe/shutter/iris effects.
+ */
+ bool processWipe(const int8 direction, PlaneShowStyle &showStyle);
+
+#pragma mark -
+#pragma mark Scrolls
+public:
+ inline bool hasScrolls() const { return !_scrolls.empty(); }
+
+ /**
+ * Processes all active plane scrolls
+ * in a loop until they are finished.
+ */
+ void processScrolls();
+
+ void kernelSetScroll(const reg_t plane, const int16 deltaX, const int16 deltaY, const GuiResourceId pictureId, const bool animate, const bool mirrorX);
+
+private:
+ /**
+ * A list of active plane scrolls.
+ */
+ ScrollList _scrolls;
+
+ /**
+ * Performs a scroll of the content of
+ * a plane.
+ */
+ bool processScroll(PlaneScroll &scroll);
+};
+
+} // End of namespace Sci
+#endif