mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
Consolidated kSetShowStyle version/argument checks and updated them to handle SCI2.1 Mac games and PC demos. (The demos where the wrong arguments were being applied happened to work anyway.) Fixes LSL7 Mac pixel dissolve at the start of the game between the postcard and the boat (rooms 120 and 130)
1136 lines
32 KiB
C++
1136 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#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:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void GfxTransitions32::kernelSetShowStyle(const reg_t planeObj, const ShowStyleType type, const int16 seconds,
|
|
const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow,
|
|
const reg_t pFadeArray, const int16 divisions, const int16 blackScreen) {
|
|
|
|
const bool hasFadeArray = !pFadeArray.isNull();
|
|
const bool hasDivisions = (divisions != -1);
|
|
|
|
bool isFadeUp;
|
|
int16 color;
|
|
if (back != -1) {
|
|
isFadeUp = false;
|
|
color = back;
|
|
} else {
|
|
isFadeUp = true;
|
|
color = g_sci->_gfxPalette32->getPlatformBlack();
|
|
}
|
|
|
|
// HACK: Swap Mac black/white colors to PC palette for kShowStyleDissolve.
|
|
// We perform most SCI32 Mac palette conversions while drawing pics, views, and color CelObjs.
|
|
// That doesn't work for kShowStyleDisolve, it uses a CelObjMem that's initialized from the
|
|
// current frameout buffer after Mac palette conversions have already taken place.
|
|
// Example: GK1 room 471 which dissolves from an already black screen to black.
|
|
if (type == kShowStyleDissolve && g_sci->getPlatform() == Common::kPlatformMacintosh) {
|
|
if (color == 0) {
|
|
color = 255;
|
|
} else if (color == 255) {
|
|
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));
|
|
}
|
|
|
|
// Do not add kShowStyleNone types to the showStyles list.
|
|
//
|
|
// This return was removed in some interpreters, notably the Windows
|
|
// version of Hoyle 5. In this version, a fade out is done and then
|
|
// kShowStyleNone is called to enter the new screen without a fade in.
|
|
// In such cases, we should not return here, so that the code for
|
|
// queuing kShowStyleNone calls is enabled and the screen palette is
|
|
// restored in the processNone() call inside processShowStyle().
|
|
if (g_sci->getGameId() != GID_HOYLE5)
|
|
return;
|
|
}
|
|
|
|
if (createNewEntry) {
|
|
entry = new PlaneShowStyle;
|
|
// SSCI2.1 tests if allocation returned a null pointer but then only
|
|
// avoids setting currentStep if this is so. Since this nonsensical, we
|
|
// do not do that here
|
|
entry->currentStep = 0;
|
|
entry->processed = false;
|
|
entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
|
|
entry->plane = planeObj;
|
|
|
|
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 if (hasFadeArray) {
|
|
// SSCI2.1mid does no check to verify that an array is successfully
|
|
// retrieved
|
|
SciArray &table = *_segMan->lookupArray(pFadeArray);
|
|
|
|
const uint32 rangeCount = table.size();
|
|
|
|
// SSCI 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.reserve(rangeCount);
|
|
for (uint32 i = 0; i < rangeCount; ++i) {
|
|
entry->fadeColorRanges.push_back(table.getAsInt16(i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// SSCI 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:
|
|
// SSCI manually allocated the color ranges for fades and deleted that
|
|
// memory here, but we use a container so there is no extra cleanup
|
|
// needed
|
|
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;
|
|
target.init(showStyle.width, showStyle.height, showStyle.width, bitmap.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
|
|
|
|
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;
|
|
buffer.init(showStyle.width, showStyle.height, showStyle.width, bitmap.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
|
|
|
|
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.fadeColorRanges.size()) {
|
|
for (uint i = 0, len = showStyle.fadeColorRanges.size(); 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
|