This transition style was used when exiting the asteroids minigame in PQ4, though it appears likely that this was an error in the original game script since it does not actually do anything in the context that it is used (neither here nor in the original interpreter). Still, this code is already written, and it fixes the crash, so in it goes. Fixes Trac#9856.
1138 lines
32 KiB
C++
1138 lines
32 KiB
C++
/* 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/console.h"
|
|
#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) {
|
|
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(const uint32 ms) {
|
|
g_sci->getEngineState()->speedThrottler(ms);
|
|
g_sci->getEngineState()->_throttleTrigger = true;
|
|
}
|
|
|
|
void GfxTransitions32::clearShowRects() {
|
|
g_sci->_gfxFrameout->_showList.clear();
|
|
}
|
|
|
|
void GfxTransitions32::addShowRect(const Common::Rect &rect) {
|
|
if (!rect.isEmpty()) {
|
|
g_sci->_gfxFrameout->_showList.add(rect);
|
|
}
|
|
}
|
|
|
|
void GfxTransitions32::sendShowRects() {
|
|
g_sci->_gfxFrameout->showBits();
|
|
throttle();
|
|
}
|
|
|
|
#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 == kShowStyleNone) {
|
|
if (createNewEntry == false) {
|
|
deleteShowStyle(findIteratorForPlane(planeObj));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
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 &table = *_segMan->lookupArray(pFadeArray);
|
|
|
|
uint32 rangeCount = table.size();
|
|
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.getAsInt16(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 kShowStyleWipeLeft:
|
|
case kShowStyleWipeRight:
|
|
configure21EarlyHorizontalWipe(*entry, priority);
|
|
break;
|
|
case kShowStyleHShutterOut:
|
|
configure21EarlyHorizontalShutter(*entry, priority);
|
|
break;
|
|
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 kShowStyleWipeLeft:
|
|
case kShowStyleWipeRight:
|
|
case kShowStyleIrisOut:
|
|
case kShowStyleIrisIn:
|
|
case kShowStyleHShutterOut:
|
|
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:
|
|
case kShowStyleHShutterIn:
|
|
// do nothing
|
|
break;
|
|
default:
|
|
error("Unknown delete transition type %d", showStyle->type);
|
|
}
|
|
|
|
return _showStyles.erase(showStyle);
|
|
}
|
|
|
|
void GfxTransitions32::configure21EarlyHorizontalWipe(PlaneShowStyle &showStyle, const int16 priority) {
|
|
showStyle.numEdges = 1;
|
|
const int divisions = showStyle.divisions;
|
|
showStyle.screenItems.reserve(divisions);
|
|
|
|
CelInfo32 celInfo;
|
|
celInfo.type = kCelTypeColor;
|
|
celInfo.color = showStyle.color;
|
|
|
|
for (int i = 0; i < divisions; ++i) {
|
|
Common::Rect rect;
|
|
rect.left = showStyle.width * i / divisions;
|
|
rect.top = 0;
|
|
rect.right = showStyle.width * (i + 1) / divisions;
|
|
rect.bottom = showStyle.height;
|
|
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 < divisions; ++i) {
|
|
g_sci->_gfxFrameout->addScreenItem(*showStyle.screenItems[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GfxTransitions32::configure21EarlyHorizontalShutter(PlaneShowStyle &showStyle, const int16 priority) {
|
|
showStyle.numEdges = 2;
|
|
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 divisions = showStyle.divisions;
|
|
|
|
for (int i = 0; i < divisions; ++i) {
|
|
Common::Rect rect;
|
|
|
|
// Left
|
|
rect.top = 0;
|
|
rect.right = (width + 1) * (i + 1) / (2 * divisions);
|
|
rect.bottom = showStyle.height;
|
|
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::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 kShowStyleHShutterIn:
|
|
case kShowStyleVShutterOut:
|
|
case kShowStyleVShutterIn:
|
|
case kShowStyleWipeUp:
|
|
case kShowStyleWipeDown:
|
|
case kShowStyleDissolveNoMorph:
|
|
case kShowStyleMorph:
|
|
return processMorph(showStyle);
|
|
case kShowStyleHShutterOut:
|
|
if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
|
|
return processMorph(showStyle);
|
|
} else {
|
|
return processHShutterOut(showStyle);
|
|
}
|
|
case kShowStyleWipeLeft:
|
|
if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
|
|
return processMorph(showStyle);
|
|
} else {
|
|
return processWipe(-1, showStyle);
|
|
}
|
|
case kShowStyleWipeRight:
|
|
if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
|
|
return processMorph(showStyle);
|
|
} else {
|
|
return processWipe(1, 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;
|
|
}
|
|
|
|
bool GfxTransitions32::processHShutterOut(PlaneShowStyle &showStyle) {
|
|
if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
|
|
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!");
|
|
}
|
|
|
|
return processWipe(-1, showStyle);
|
|
}
|
|
|
|
void GfxTransitions32::processHShutterIn(const PlaneShowStyle &showStyle) {
|
|
if (getSciVersion() <= SCI_VERSION_2_1_EARLY) {
|
|
error("HShutterIn is not known to be used by any SCI2.1early- game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
|
|
}
|
|
|
|
Plane* plane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(showStyle.plane);
|
|
const Common::Rect &screenRect = plane->_screenRect;
|
|
Common::Rect rect;
|
|
|
|
const int divisions = showStyle.divisions;
|
|
const int width = screenRect.width();
|
|
const int divisionWidth = width / divisions - 1;
|
|
|
|
clearShowRects();
|
|
|
|
if (width % divisions) {
|
|
rect.left = (divisionWidth + 1) * divisions + screenRect.left;
|
|
rect.top = screenRect.top;
|
|
rect.right = (divisionWidth + 1) * divisions + (width % divisions) + screenRect.left;
|
|
rect.bottom = screenRect.bottom;
|
|
addShowRect(rect);
|
|
sendShowRects();
|
|
}
|
|
|
|
for (int i = 0; i < width / (2 * divisions); ++i) {
|
|
// Left side
|
|
rect.left = i * divisions + screenRect.left;
|
|
rect.top = screenRect.top;
|
|
rect.right = i * divisions + divisions + screenRect.left;
|
|
rect.bottom = screenRect.bottom;
|
|
addShowRect(rect);
|
|
|
|
// Right side
|
|
rect.left = (divisionWidth - i) * divisions + screenRect.left;
|
|
rect.top = screenRect.top;
|
|
rect.right = (divisionWidth - i) * divisions + divisions + screenRect.left;
|
|
rect.bottom = screenRect.bottom;
|
|
addShowRect(rect);
|
|
|
|
sendShowRects();
|
|
}
|
|
|
|
addShowRect(screenRect);
|
|
sendShowRects();
|
|
}
|
|
|
|
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) {
|
|
if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
|
|
error("WipeLeft 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!");
|
|
}
|
|
}
|
|
|
|
void GfxTransitions32::processWipeRight(PlaneShowStyle &showStyle) {
|
|
if (getSciVersion() > SCI_VERSION_2_1_EARLY) {
|
|
error("WipeRight 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!");
|
|
}
|
|
}
|
|
|
|
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(const PlaneShowStyle &showStyle) {
|
|
// SQ6 room 530, LSL7 room 130
|
|
|
|
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 = g_sci->_gfxFrameout->_showList.max_size();
|
|
|
|
clearShowRects();
|
|
|
|
do {
|
|
int row = seq / width;
|
|
int col = seq % width;
|
|
|
|
if (row < height) {
|
|
if (row == height - 1 && (planeHeight % divisions)) {
|
|
if (col == width - 1 && (planeWidth % divisions)) {
|
|
rect.left = col * divisions;
|
|
rect.top = row * divisions;
|
|
rect.right = col * divisions + (planeWidth % divisions);
|
|
rect.bottom = row * divisions + (planeHeight % divisions);
|
|
addShowRect(rect);
|
|
} else {
|
|
rect.left = col * divisions;
|
|
rect.top = row * divisions;
|
|
rect.right = col * divisions + divisions;
|
|
rect.bottom = row * divisions + (planeHeight % divisions);
|
|
addShowRect(rect);
|
|
}
|
|
} else {
|
|
if (col == width - 1 && (planeWidth % divisions)) {
|
|
rect.left = col * divisions;
|
|
rect.top = row * divisions;
|
|
rect.right = col * divisions + (planeWidth % divisions);
|
|
rect.bottom = row * divisions + divisions;
|
|
addShowRect(rect);
|
|
} else {
|
|
rect.left = col * divisions;
|
|
rect.top = row * divisions;
|
|
rect.right = col * divisions + divisions;
|
|
rect.bottom = row * divisions + divisions;
|
|
addShowRect(rect);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (seq & 1) {
|
|
seq = (seq >> 1) ^ mask;
|
|
} else {
|
|
seq >>= 1;
|
|
}
|
|
|
|
if (++iteration == numIterationsPerTick) {
|
|
sendShowRects();
|
|
iteration = 0;
|
|
}
|
|
} while (seq != 1 && !g_engine->shouldQuit());
|
|
|
|
rect.left = screenRect.left;
|
|
rect.top = screenRect.top;
|
|
rect.right = screenRect.left + divisions;
|
|
rect.bottom = screenRect.top + divisions;
|
|
addShowRect(rect);
|
|
sendShowRects();
|
|
|
|
addShowRect(screenRect);
|
|
sendShowRects();
|
|
|
|
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(33);
|
|
}
|
|
|
|
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(33);
|
|
}
|
|
}
|
|
|
|
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.x) <= 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 (plane == nullptr) {
|
|
error("[GfxTransitions32::processScroll]: Plane %04x:%04x not found", PRINT_REG(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
|