aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics
diff options
context:
space:
mode:
authorColin Snover2016-07-25 11:06:27 -0500
committerColin Snover2016-08-01 10:37:14 -0500
commit156c68fe58eb9f8d923d1f9dc1c3dac8436c9d82 (patch)
tree12b08a5cbc9dc2487ac3dc6a0eefc48317ff41f9 /engines/sci/graphics
parent4a637d65c36d7dad3a4d4ec75c243e12bb3b5449 (diff)
downloadscummvm-rg350-156c68fe58eb9f8d923d1f9dc1c3dac8436c9d82.tar.gz
scummvm-rg350-156c68fe58eb9f8d923d1f9dc1c3dac8436c9d82.tar.bz2
scummvm-rg350-156c68fe58eb9f8d923d1f9dc1c3dac8436c9d82.zip
SCI32: Implement plane transitions (kSetShowStyle and kSetScroll)
This commit implements all of the known plane transitions from SCI2 through SCI2.1mid games. Because kSetShowStyle is always called indirectly via the Styler game script, it is difficult to find all the places where transitions are used. As such, transitions that appeared to never be used have been added as stubs which will trigger a game crash with a message to report what was being done, so any missed transition types can be identified quickly and then implemented.
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