diff options
Diffstat (limited to 'engines/sci/graphics/transitions32.cpp')
-rw-r--r-- | engines/sci/graphics/transitions32.cpp | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/engines/sci/graphics/transitions32.cpp b/engines/sci/graphics/transitions32.cpp new file mode 100644 index 0000000000..37f608da85 --- /dev/null +++ b/engines/sci/graphics/transitions32.cpp @@ -0,0 +1,978 @@ +/* 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; + } + + 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->freeBitmap(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) { + + reg_t bitmapId; + SciBitmap &bitmap = *_segMan->allocateBitmap(&bitmapId, showStyle.width, showStyle.height, kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false); + + showStyle.bitmap = bitmapId; + + 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 = bitmapId; + + 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; + + SciBitmap &bitmap = *_segMan->lookupBitmap(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 |