Initial commit
This commit is contained in:
1
engines/mediastation/POTFILES
Normal file
1
engines/mediastation/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/mediastation/metaengine.cpp
|
||||
494
engines/mediastation/actor.cpp
Normal file
494
engines/mediastation/actor.cpp
Normal file
@@ -0,0 +1,494 @@
|
||||
/* 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 "common/util.h"
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/actors/camera.h"
|
||||
#include "mediastation/actors/stage.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
Actor::~Actor() {
|
||||
for (auto it = _eventHandlers.begin(); it != _eventHandlers.end(); ++it) {
|
||||
Common::Array<EventHandler *> &handlersForType = it->_value;
|
||||
for (EventHandler *handler : handlersForType) {
|
||||
delete handler;
|
||||
}
|
||||
handlersForType.clear();
|
||||
}
|
||||
_eventHandlers.clear();
|
||||
}
|
||||
|
||||
void Actor::initFromParameterStream(Chunk &chunk) {
|
||||
ActorHeaderSectionType paramType = kActorHeaderEmptySection;
|
||||
while (true) {
|
||||
paramType = static_cast<ActorHeaderSectionType>(chunk.readTypedUint16());
|
||||
if (paramType == 0) {
|
||||
break;
|
||||
} else {
|
||||
readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderEventHandler: {
|
||||
EventHandler *eventHandler = new EventHandler(chunk);
|
||||
Common::Array<EventHandler *> &eventHandlersForType = _eventHandlers.getOrCreateVal(eventHandler->_type);
|
||||
|
||||
// This is not a hashmap because we don't want to have to hash ScriptValues.
|
||||
for (EventHandler *existingEventHandler : eventHandlersForType) {
|
||||
if (existingEventHandler->_argumentValue == eventHandler->_argumentValue) {
|
||||
error("%s: Event handler for %s (%s) already exists", __func__,
|
||||
eventTypeToStr(eventHandler->_type), eventHandler->_argumentValue.getDebugString().c_str());
|
||||
}
|
||||
}
|
||||
eventHandlersForType.push_back(eventHandler);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("Got unimplemented actor parameter 0x%x", static_cast<uint>(paramType));
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::loadIsComplete() {
|
||||
if (_loadIsComplete) {
|
||||
warning("%s: Called more than once for actor %d", __func__, _id);
|
||||
}
|
||||
_loadIsComplete = true;
|
||||
}
|
||||
|
||||
ScriptValue Actor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
warning("%s: Got unimplemented method call 0x%x (%s)", __func__, static_cast<uint>(methodId), builtInMethodToStr(methodId));
|
||||
return ScriptValue();
|
||||
}
|
||||
|
||||
void Actor::processTimeEventHandlers() {
|
||||
// TODO: Replace with a queue.
|
||||
uint currentTime = g_system->getMillis();
|
||||
const Common::Array<EventHandler *> &_timeHandlers = _eventHandlers.getValOrDefault(kTimerEvent);
|
||||
for (EventHandler *timeEvent : _timeHandlers) {
|
||||
// Indeed float, not time.
|
||||
double timeEventInFractionalSeconds = timeEvent->_argumentValue.asFloat();
|
||||
uint timeEventInMilliseconds = timeEventInFractionalSeconds * 1000;
|
||||
bool timeEventAlreadyProcessed = timeEventInMilliseconds < _lastProcessedTime;
|
||||
bool timeEventNeedsToBeProcessed = timeEventInMilliseconds <= currentTime - _startTime;
|
||||
if (!timeEventAlreadyProcessed && timeEventNeedsToBeProcessed) {
|
||||
debugC(5, kDebugScript, "Actor::processTimeEventHandlers(): Running On Time handler for time %d ms", timeEventInMilliseconds);
|
||||
timeEvent->execute(_id);
|
||||
}
|
||||
}
|
||||
_lastProcessedTime = currentTime - _startTime;
|
||||
}
|
||||
|
||||
void Actor::runEventHandlerIfExists(EventType eventType, const ScriptValue &arg) {
|
||||
const Common::Array<EventHandler *> &eventHandlers = _eventHandlers.getValOrDefault(eventType);
|
||||
for (EventHandler *eventHandler : eventHandlers) {
|
||||
const ScriptValue &argToCheck = eventHandler->_argumentValue;
|
||||
|
||||
if (arg.getType() != argToCheck.getType()) {
|
||||
warning("Got event handler arg type %s, expected %s",
|
||||
scriptValueTypeToStr(arg.getType()), scriptValueTypeToStr(argToCheck.getType()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == argToCheck) {
|
||||
debugC(5, kDebugScript, "Executing handler for event type %s on actor %d", eventTypeToStr(eventType), _id);
|
||||
eventHandler->execute(_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
debugC(5, kDebugScript, "No event handler for event type %s on actor %d", eventTypeToStr(eventType), _id);
|
||||
}
|
||||
|
||||
void Actor::runEventHandlerIfExists(EventType eventType) {
|
||||
ScriptValue scriptValue;
|
||||
runEventHandlerIfExists(eventType, scriptValue);
|
||||
}
|
||||
|
||||
SpatialEntity::~SpatialEntity() {
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->removeChildSpatialEntity(this);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue SpatialEntity::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
switch (methodId) {
|
||||
case kSpatialMoveToMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 x = static_cast<int16>(args[0].asFloat());
|
||||
int16 y = static_cast<int16>(args[1].asFloat());
|
||||
moveTo(x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
case kSpatialMoveToByOffsetMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 dx = static_cast<int16>(args[0].asFloat());
|
||||
int16 dy = static_cast<int16>(args[1].asFloat());
|
||||
int16 newX = _boundingBox.left + dx;
|
||||
int16 newY = _boundingBox.top + dy;
|
||||
moveTo(newX, newY);
|
||||
break;
|
||||
}
|
||||
|
||||
case kSpatialZMoveToMethod: {
|
||||
assert(args.size() == 1);
|
||||
int zIndex = static_cast<int>(args[0].asFloat());
|
||||
setZIndex(zIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
case kSpatialCenterMoveToMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 x = static_cast<int16>(args[0].asFloat());
|
||||
int16 y = static_cast<int16>(args[1].asFloat());
|
||||
moveToCentered(x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
case kGetLeftXMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(_boundingBox.left);
|
||||
break;
|
||||
|
||||
case kGetTopYMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(_boundingBox.top);
|
||||
break;
|
||||
|
||||
case kGetWidthMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(_boundingBox.width());
|
||||
break;
|
||||
|
||||
case kGetHeightMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(_boundingBox.height());
|
||||
break;
|
||||
|
||||
case kGetCenterXMethod: {
|
||||
assert(args.empty());
|
||||
int centerX = _boundingBox.left + (_boundingBox.width() / 2);
|
||||
returnValue.setToFloat(centerX);
|
||||
break;
|
||||
}
|
||||
|
||||
case kGetCenterYMethod: {
|
||||
assert(args.empty());
|
||||
int centerY = _boundingBox.top + (_boundingBox.height() / 2);
|
||||
returnValue.setToFloat(centerY);
|
||||
break;
|
||||
}
|
||||
|
||||
case kGetZCoordinateMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(_zIndex);
|
||||
break;
|
||||
|
||||
case kSetDissolveFactorMethod: {
|
||||
assert(args.size() == 1);
|
||||
double dissolveFactor = args[0].asFloat();
|
||||
setDissolveFactor(dissolveFactor);
|
||||
break;
|
||||
}
|
||||
|
||||
case kIsVisibleMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToBool(isVisible());
|
||||
break;
|
||||
|
||||
case kSetMousePositionMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 x = static_cast<int16>(args[0].asFloat());
|
||||
int16 y = static_cast<int16>(args[1].asFloat());
|
||||
setMousePosition(x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
case kGetXScaleMethod1:
|
||||
case kGetXScaleMethod2:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(_scaleX);
|
||||
break;
|
||||
|
||||
case kSetScaleMethod:
|
||||
assert(args.size() == 1);
|
||||
invalidateLocalBounds();
|
||||
_scaleX = _scaleY = args[0].asFloat();
|
||||
invalidateLocalBounds();
|
||||
break;
|
||||
|
||||
case kSetXScaleMethod:
|
||||
assert(args.size() == 1);
|
||||
invalidateLocalBounds();
|
||||
_scaleX = args[0].asFloat();
|
||||
invalidateLocalBounds();
|
||||
break;
|
||||
|
||||
case kGetYScaleMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(_scaleY);
|
||||
break;
|
||||
|
||||
case kSetYScaleMethod:
|
||||
assert(args.size() == 1);
|
||||
invalidateLocalBounds();
|
||||
_scaleY = args[0].asFloat();
|
||||
invalidateLocalBounds();
|
||||
break;
|
||||
|
||||
default:
|
||||
Actor::callMethod(methodId, args);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void SpatialEntity::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderBoundingBox:
|
||||
_originalBoundingBox = chunk.readTypedRect();
|
||||
setAdjustedBounds(kWrapNone);
|
||||
break;
|
||||
|
||||
case kActorHeaderDissolveFactor:
|
||||
_dissolveFactor = chunk.readTypedDouble();
|
||||
break;
|
||||
|
||||
case kActorHeaderZIndex:
|
||||
_zIndex = chunk.readTypedGraphicUnit();
|
||||
break;
|
||||
|
||||
case kActorHeaderTransparency:
|
||||
_hasTransparency = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderChildActorId:
|
||||
_stageId = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderScaleXAndY:
|
||||
_scaleX = _scaleY = chunk.readTypedDouble();
|
||||
break;
|
||||
|
||||
case kActorHeaderScaleX:
|
||||
_scaleX = chunk.readTypedDouble();
|
||||
break;
|
||||
|
||||
case kActorHeaderScaleY:
|
||||
_scaleY = chunk.readTypedDouble();
|
||||
break;
|
||||
|
||||
default:
|
||||
Actor::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::loadIsComplete() {
|
||||
Actor::loadIsComplete();
|
||||
if (_stageId != 0) {
|
||||
Actor *pendingParentStageActor = g_engine->getActorById(_stageId);
|
||||
if (pendingParentStageActor == nullptr) {
|
||||
error("%s: Actor %d doesn't exist", __func__, _stageId);
|
||||
} else if (pendingParentStageActor->type() != kActorTypeStage) {
|
||||
error("%s: Requested parent stage %d is not a stage", __func__, _stageId);
|
||||
}
|
||||
StageActor *pendingParentStage = static_cast<StageActor *>(pendingParentStageActor);
|
||||
pendingParentStage->addChildSpatialEntity(this);
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::invalidateMouse() {
|
||||
// TODO: Invalidate the mouse properly when we have custom events.
|
||||
// For now, we simulate the mouse update event with a mouse moved event.
|
||||
Common::Event mouseEvent;
|
||||
mouseEvent.type = Common::EVENT_MOUSEMOVE;
|
||||
mouseEvent.mouse = g_system->getEventManager()->getMousePos();
|
||||
g_system->getEventManager()->pushEvent(mouseEvent);
|
||||
}
|
||||
|
||||
void SpatialEntity::moveTo(int16 x, int16 y) {
|
||||
Common::Point dest(x, y);
|
||||
if (dest == _boundingBox.origin()) {
|
||||
// We aren't actually moving anywhere.
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
_originalBoundingBox.moveTo(dest);
|
||||
setAdjustedBounds(kWrapNone);
|
||||
if (isVisible()) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
if (interactsWithMouse()) {
|
||||
invalidateMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::moveToCentered(int16 x, int16 y) {
|
||||
int16 targetX = x - (_boundingBox.width() / 2);
|
||||
int16 targetY = y - (_boundingBox.height() / 2);
|
||||
moveTo(targetX, targetY);
|
||||
}
|
||||
|
||||
void SpatialEntity::setBounds(const Common::Rect &bounds) {
|
||||
if (_boundingBox == bounds) {
|
||||
// We aren't actually moving anywhere.
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
_originalBoundingBox = bounds;
|
||||
setAdjustedBounds(kWrapNone);
|
||||
if (isVisible()) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
if (interactsWithMouse()) {
|
||||
invalidateMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::setZIndex(int zIndex) {
|
||||
if (_zIndex == zIndex) {
|
||||
// We aren't actually moving anywhere.
|
||||
return;
|
||||
}
|
||||
|
||||
_zIndex = zIndex;
|
||||
invalidateLocalZIndex();
|
||||
if (interactsWithMouse()) {
|
||||
invalidateMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::setMousePosition(int16 x, int16 y) {
|
||||
if (_parentStage) {
|
||||
_parentStage->setMousePosition(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::setDissolveFactor(double dissolveFactor) {
|
||||
dissolveFactor = CLIP(dissolveFactor, 0.0, 1.0);
|
||||
if (dissolveFactor != _dissolveFactor) {
|
||||
_dissolveFactor = dissolveFactor;
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::invalidateLocalBounds() {
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->setAdjustedBounds(kWrapNone);
|
||||
_parentStage->invalidateRect(getBbox());
|
||||
} else {
|
||||
error("%s: No parent stage for entity %d", __func__, _id);
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialEntity::invalidateLocalZIndex() {
|
||||
warning("STUB: %s", __func__);
|
||||
}
|
||||
|
||||
void SpatialEntity::setAdjustedBounds(CylindricalWrapMode alignmentMode) {
|
||||
_boundingBox = _originalBoundingBox;
|
||||
if (_parentStage == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Point offset(0, 0);
|
||||
Common::Point stageExtent = _parentStage->extent();
|
||||
switch (alignmentMode) {
|
||||
case kWrapRight: {
|
||||
offset.x = stageExtent.x;
|
||||
offset.y = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapLeft: {
|
||||
offset.x = -stageExtent.x;
|
||||
offset.y = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapBottom: {
|
||||
offset.x = 0;
|
||||
offset.y = stageExtent.y;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapLeftTop: {
|
||||
offset.x = 0;
|
||||
offset.y = -stageExtent.y;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapTop: {
|
||||
offset.x = stageExtent.x;
|
||||
offset.y = stageExtent.y;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapRightBottom: {
|
||||
offset.x = -stageExtent.x;
|
||||
offset.y = -stageExtent.y;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapRightTop: {
|
||||
offset.x = -stageExtent.x;
|
||||
offset.y = stageExtent.y;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapLeftBottom: {
|
||||
offset.x = stageExtent.x;
|
||||
offset.y = -stageExtent.y;
|
||||
break;
|
||||
}
|
||||
|
||||
case kWrapNone:
|
||||
default:
|
||||
// No offset adjustment.
|
||||
break;
|
||||
}
|
||||
|
||||
if (alignmentMode != kWrapNone) {
|
||||
// TODO: Implement this once we have a title that actually uses it.
|
||||
warning("%s: Actor %d: Wrapping mode %d not handled yet: (%d, %d, %d, %d) -= (%d, %d)", __func__, _id, static_cast<uint>(alignmentMode), PRINT_RECT(_boundingBox), offset.x, offset.y);
|
||||
}
|
||||
|
||||
if (_scaleX != 0.0 || _scaleY != 0.0) {
|
||||
// TODO: Implement this once we have a title that actually uses it.
|
||||
warning("%s: Scale not handled yet (scaleX: %f, scaleY: %f)", __func__, _scaleX, _scaleY);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
275
engines/mediastation/actor.h
Normal file
275
engines/mediastation/actor.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_ACTOR_H
|
||||
#define MEDIASTATION_ACTOR_H
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/keyboard.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/eventhandler.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class DisplayContext;
|
||||
class SpatialEntity;
|
||||
class StageActor;
|
||||
|
||||
enum ActorType {
|
||||
kActorTypeEmpty = 0x0000,
|
||||
kActorTypeScreen = 0x0001, // SCR
|
||||
kActorTypeStage = 0x0002, // STG
|
||||
kActorTypePath = 0x0004, // PTH
|
||||
kActorTypeSound = 0x0005, // SND
|
||||
kActorTypeTimer = 0x0006, // TMR
|
||||
kActorTypeImage = 0x0007, // IMG
|
||||
kActorTypeHotspot = 0x000b, // HSP
|
||||
kActorTypeSprite = 0x000e, // SPR
|
||||
kActorTypeLKZazu = 0x000f,
|
||||
kActorTypeLKConstellations = 0x0010,
|
||||
kActorTypeDocument = 0x0011,
|
||||
kActorTypeImageSet = 0x001d,
|
||||
kActorTypeCursor = 0x000c, // CSR
|
||||
kActorTypePrinter = 0x0019, // PRT
|
||||
kActorTypeMovie = 0x0016, // MOV
|
||||
kActorTypePalette = 0x0017,
|
||||
kActorTypeText = 0x001a, // TXT
|
||||
kActorTypeFont = 0x001b, // FON
|
||||
kActorTypeCamera = 0x001c, // CAM
|
||||
kActorTypeDiskImageActor = 0x001d,
|
||||
kActorTypeCanvas = 0x001e, // CVS
|
||||
kActorTypeXsnd = 0x001f,
|
||||
kActorTypeXsndMidi = 0x0020,
|
||||
kActorTypeRecorder = 0x0021,
|
||||
kActorTypeFunction = 0x0069 // FUN
|
||||
};
|
||||
|
||||
enum ActorHeaderSectionType {
|
||||
kActorHeaderEmptySection = 0x0000,
|
||||
kActorHeaderEventHandler = 0x0017,
|
||||
kActorHeaderChildActorId = 0x0019,
|
||||
kActorHeaderActorId = 0x001a,
|
||||
kActorHeaderChannelIdent = 0x001b,
|
||||
kActorHeaderMovieAnimationChannelIdent = 0x06a4,
|
||||
kActorHeaderMovieAudioChannelIdent = 0x06a5,
|
||||
kActorHeaderActorReference = 0x077b,
|
||||
kActorHeaderBoundingBox = 0x001c,
|
||||
kActorHeaderMouseActiveArea = 0x001d,
|
||||
kActorHeaderZIndex = 0x001e,
|
||||
kActorHeaderStartup = 0x001f,
|
||||
kActorHeaderTransparency = 0x0020,
|
||||
kActorHeaderHasOwnSubfile = 0x0021,
|
||||
kActorHeaderCursorResourceId = 0x0022,
|
||||
kActorHeaderFrameRate = 0x0024,
|
||||
kActorHeaderLoadType = 0x0032,
|
||||
kActorHeaderSoundInfo = 0x0033,
|
||||
kActorHeaderMovieLoadType = 0x0037,
|
||||
kActorHeaderSpriteChunkCount = 0x03e8,
|
||||
kActorHeaderPalette = 0x05aa,
|
||||
kActorHeaderDissolveFactor = 0x05dc,
|
||||
kActorHeaderGetOffstageEvents = 0x05dd,
|
||||
kActorHeaderX = 0x05de,
|
||||
kActorHeaderY = 0x05df,
|
||||
kActorHeaderScaleXAndY = 0x77a,
|
||||
kActorHeaderScaleX = 0x77c,
|
||||
kActorHeaderScaleY = 0x77d,
|
||||
kActorHeaderUnk0 = 0x7d0,
|
||||
kActorHeaderActorName = 0x0bb8,
|
||||
|
||||
// PATH FIELDS.
|
||||
kActorHeaderStartPoint = 0x060e,
|
||||
kActorHeaderEndPoint = 0x060f,
|
||||
kActorHeaderPathTotalSteps = 0x0610,
|
||||
kActorHeaderStepRate = 0x0611,
|
||||
kActorHeaderDuration = 0x0612,
|
||||
|
||||
// CAMERA FIELDS.
|
||||
kActorHeaderCameraViewportOrigin = 0x076f,
|
||||
kActorHeaderCameraLensOpen = 0x0770,
|
||||
kActorHeaderCameraImageActor = 0x77b,
|
||||
|
||||
// CANVAS FIELDS.
|
||||
kActorHeaderCanvasUnk1 = 0x491,
|
||||
kActorHeaderCanvasDissolveFactor = 0x493,
|
||||
kActorHeaderCanvasUnk2 = 0x494,
|
||||
kActorHeaderCanvasUnk3 = 0x495,
|
||||
|
||||
// STAGE FIELDS.
|
||||
kActorHeaderStageExtent = 0x0771,
|
||||
kActorHeaderCylindricalX = 0x0772,
|
||||
kActorHeaderCylindricalY = 0x0773,
|
||||
|
||||
// TEXT FIELDS.
|
||||
kActorHeaderEditable = 0x03eb,
|
||||
kActorHeaderFontId = 0x0258,
|
||||
kActorHeaderInitialText = 0x0259,
|
||||
kActorHeaderTextMaxLength = 0x25a,
|
||||
kActorHeaderTextJustification = 0x025b,
|
||||
kActorHeaderTextPosition = 0x25f,
|
||||
kActorHeaderTextUnk1 = 0x262,
|
||||
kActorHeaderTextUnk2 = 0x263,
|
||||
kActorHeaderTextCharacterClass = 0x0266,
|
||||
|
||||
// SPRITE FIELDS.
|
||||
kActorHeaderSpriteClip = 0x03e9,
|
||||
kActorHeaderCurrentSpriteClip = 0x03ea
|
||||
};
|
||||
|
||||
enum CylindricalWrapMode : int;
|
||||
|
||||
struct MouseActorState {
|
||||
SpatialEntity *keyDown = nullptr;
|
||||
// There is no key up event.
|
||||
SpatialEntity *mouseDown = nullptr;
|
||||
SpatialEntity *mouseUp = nullptr;
|
||||
SpatialEntity *mouseMoved = nullptr;
|
||||
SpatialEntity *mouseExit = nullptr;
|
||||
SpatialEntity *mouseEnter = nullptr;
|
||||
SpatialEntity *mouseOutOfFocus = nullptr;
|
||||
};
|
||||
|
||||
enum MouseEventFlag {
|
||||
kNoFlag = 0x00,
|
||||
kMouseDownFlag = 0x01,
|
||||
kMouseUpFlag = 0x02,
|
||||
kMouseMovedFlag = 0x04,
|
||||
kMouseExitFlag = 0x10,
|
||||
kMouseEnterFlag = 0x08,
|
||||
kMouseUnk1Flag = 0x20,
|
||||
kMouseOutOfFocusFlag = 0x40,
|
||||
kKeyDownFlag = 0x80,
|
||||
// There is no key up event.
|
||||
};
|
||||
|
||||
class Actor {
|
||||
public:
|
||||
Actor(ActorType type) : _type(type) {};
|
||||
virtual ~Actor();
|
||||
|
||||
// Does any needed frame drawing, audio playing, event handlers, etc.
|
||||
virtual void process() { return; }
|
||||
|
||||
// Runs built-in bytecode methods.
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args);
|
||||
|
||||
virtual bool isSpatialActor() const { return false; }
|
||||
|
||||
virtual void initFromParameterStream(Chunk &chunk);
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType);
|
||||
virtual void loadIsComplete();
|
||||
|
||||
void processTimeEventHandlers();
|
||||
void runEventHandlerIfExists(EventType eventType, const ScriptValue &arg);
|
||||
void runEventHandlerIfExists(EventType eventType);
|
||||
|
||||
ActorType type() const { return _type; }
|
||||
uint id() const { return _id; }
|
||||
uint contextId() const { return _contextId; }
|
||||
void setId(uint id) { _id = id; }
|
||||
void setContextId(uint id) { _contextId = id; }
|
||||
|
||||
protected:
|
||||
ActorType _type = kActorTypeEmpty;
|
||||
bool _loadIsComplete = false;
|
||||
uint _id = 0;
|
||||
uint _contextId = 0;
|
||||
|
||||
uint _startTime = 0;
|
||||
uint _lastProcessedTime = 0;
|
||||
uint _duration = 0;
|
||||
Common::HashMap<uint, Common::Array<EventHandler *> > _eventHandlers;
|
||||
};
|
||||
|
||||
class SpatialEntity : public Actor {
|
||||
public:
|
||||
SpatialEntity(ActorType type) : Actor(type) {};
|
||||
~SpatialEntity();
|
||||
|
||||
virtual void draw(DisplayContext &displayContext) { return; }
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual void loadIsComplete() override;
|
||||
virtual void preload(const Common::Rect &rect) {};
|
||||
virtual bool isRectInMemory(const Common::Rect &rect) { return true; }
|
||||
virtual bool isLoading() { return false; }
|
||||
|
||||
virtual bool isSpatialActor() const override { return true; }
|
||||
virtual bool isVisible() const { return _isVisible; }
|
||||
virtual Common::Rect getBbox() const { return _boundingBox; }
|
||||
int zIndex() const { return _zIndex; }
|
||||
|
||||
virtual void invalidateMouse();
|
||||
virtual bool interactsWithMouse() const { return false; }
|
||||
|
||||
virtual uint16 findActorToAcceptMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) { return kNoFlag; }
|
||||
virtual uint16 findActorToAcceptKeyboardEvents(
|
||||
uint16 asciiCode,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state) { return kNoFlag; }
|
||||
|
||||
virtual void mouseDownEvent(const Common::Event &event) { return; }
|
||||
virtual void mouseUpEvent(const Common::Event &event) { return; }
|
||||
virtual void mouseEnteredEvent(const Common::Event &event) { return; }
|
||||
virtual void mouseExitedEvent(const Common::Event &event) { return; }
|
||||
virtual void mouseMovedEvent(const Common::Event &event) { return; }
|
||||
virtual void mouseOutOfFocusEvent(const Common::Event &event) { return; }
|
||||
virtual void keyboardEvent(const Common::Event &event) { return; }
|
||||
|
||||
void setParentStage(StageActor *parentStage) { _parentStage = parentStage; }
|
||||
void setToNoParentStage() { _parentStage = nullptr; }
|
||||
StageActor *getParentStage() const { return _parentStage; }
|
||||
|
||||
virtual void invalidateLocalBounds();
|
||||
virtual void setAdjustedBounds(CylindricalWrapMode alignmentMode);
|
||||
|
||||
protected:
|
||||
uint _stageId = 0;
|
||||
int _zIndex = 0;
|
||||
double _dissolveFactor = 0.0;
|
||||
double _scaleX = 0.0;
|
||||
double _scaleY = 0.0;
|
||||
Common::Rect _boundingBox;
|
||||
Common::Rect _originalBoundingBox;
|
||||
bool _isVisible = false;
|
||||
bool _hasTransparency = false;
|
||||
bool _getOffstageEvents = false;
|
||||
StageActor *_parentStage = nullptr;
|
||||
|
||||
void moveTo(int16 x, int16 y);
|
||||
void moveToCentered(int16 x, int16 y);
|
||||
void setBounds(const Common::Rect &bounds);
|
||||
void setZIndex(int zIndex);
|
||||
virtual void setMousePosition(int16 x, int16 y);
|
||||
|
||||
virtual void setDissolveFactor(double dissolveFactor);
|
||||
virtual void invalidateLocalZIndex();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
637
engines/mediastation/actors/camera.cpp
Normal file
637
engines/mediastation/actors/camera.cpp
Normal file
@@ -0,0 +1,637 @@
|
||||
/* 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 "mediastation/actors/camera.h"
|
||||
#include "mediastation/actors/stage.h"
|
||||
#include "mediastation/actors/image.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
CameraActor::~CameraActor() {
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->removeCamera(this);
|
||||
_parentStage->removeChildSpatialEntity(this);
|
||||
}
|
||||
}
|
||||
|
||||
void CameraActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderChannelIdent:
|
||||
_channelIdent = chunk.readTypedChannelIdent();
|
||||
registerWithStreamManager();
|
||||
_image = Common::SharedPtr<ImageAsset>(new ImageAsset);
|
||||
break;
|
||||
|
||||
case kActorHeaderStartup:
|
||||
_isVisible = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderX:
|
||||
_offset.x = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderY:
|
||||
_offset.y = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderCameraViewportOrigin: {
|
||||
Common::Point origin = chunk.readTypedPoint();
|
||||
setViewportOrigin(origin);
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderCameraLensOpen:
|
||||
_lensOpen = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderCameraImageActor: {
|
||||
uint actorReference = chunk.readTypedUint16();
|
||||
Actor *referencedActor = g_engine->getActorById(actorReference);
|
||||
if (referencedActor == nullptr) {
|
||||
error("%s: Referenced actor %d doesn't exist or has not been read yet in this title", __func__, actorReference);
|
||||
}
|
||||
if (referencedActor->type() != kActorTypeCamera) {
|
||||
error("%s: Type mismatch of referenced actor %d", __func__, actorReference);
|
||||
}
|
||||
CameraActor *referencedImage = static_cast<CameraActor *>(referencedActor);
|
||||
_image = referencedImage->_image;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
void CameraActor::readChunk(Chunk &chunk) {
|
||||
BitmapHeader *bitmapHeader = new BitmapHeader(chunk);
|
||||
_image->bitmap = new Bitmap(chunk, bitmapHeader);
|
||||
}
|
||||
|
||||
ScriptValue CameraActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
switch (methodId) {
|
||||
case kSpatialMoveToMethod:
|
||||
case kSpatialMoveToByOffsetMethod:
|
||||
case kSpatialCenterMoveToMethod:
|
||||
invalidateLocalBounds();
|
||||
returnValue = SpatialEntity::callMethod(methodId, args);
|
||||
invalidateLocalBounds();
|
||||
break;
|
||||
|
||||
case kAddToStageMethod:
|
||||
assert(args.empty());
|
||||
addToStage();
|
||||
break;
|
||||
|
||||
case kRemoveFromStageMethod: {
|
||||
bool stopPan = false;
|
||||
if (args.size() >= 1) {
|
||||
stopPan = args[0].asBool();
|
||||
}
|
||||
removeFromStage(stopPan);
|
||||
break;
|
||||
}
|
||||
|
||||
case kAddedToStageMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToBool(_addedToStage);
|
||||
break;
|
||||
|
||||
case kStartPanMethod: {
|
||||
assert(args.size() == 3);
|
||||
int16 deltaX = static_cast<uint16>(args[0].asFloat());
|
||||
int16 deltaY = static_cast<int16>(args[1].asFloat());
|
||||
double duration = args[2].asTime();
|
||||
_nextViewportOrigin = Common::Point(deltaX, deltaY) + _currentViewportOrigin;
|
||||
adjustCameraViewport(_nextViewportOrigin);
|
||||
startPan(deltaX, deltaY, duration);
|
||||
break;
|
||||
}
|
||||
|
||||
case kStopPanMethod:
|
||||
assert(args.empty());
|
||||
stopPan();
|
||||
break;
|
||||
|
||||
case kIsPanningMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToBool(_panState);
|
||||
break;
|
||||
|
||||
case kViewportMoveToMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 x = static_cast<int16>(args[0].asFloat());
|
||||
int16 y = static_cast<int16>(args[1].asFloat());
|
||||
_nextViewportOrigin = Common::Point(x, y);
|
||||
if (!_addedToStage) {
|
||||
_currentViewportOrigin = _nextViewportOrigin;
|
||||
} else {
|
||||
bool viewportMovedSuccessfully = processViewportMove();
|
||||
if (!viewportMovedSuccessfully) {
|
||||
startPan(0, 0, 0.0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kAdjustCameraViewportMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 xDiff = static_cast<int16>(args[0].asFloat());
|
||||
int16 yDiff = static_cast<int16>(args[1].asFloat());
|
||||
Common::Point viewportDelta(xDiff, yDiff);
|
||||
_nextViewportOrigin = getViewportOrigin() + viewportDelta;
|
||||
adjustCameraViewport(_nextViewportOrigin);
|
||||
if (!_addedToStage) {
|
||||
_currentViewportOrigin = _nextViewportOrigin;
|
||||
} else {
|
||||
bool viewportMovedSuccessfully = processViewportMove();
|
||||
if (!viewportMovedSuccessfully) {
|
||||
startPan(0, 0, 0.0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kAdjustCameraViewportSpatialCenterMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 xDiff = static_cast<int16>(args[0].asFloat());
|
||||
int16 yDiff = static_cast<int16>(args[1].asFloat());
|
||||
|
||||
// Apply centering adjustment, which is indeed based on the entire camera actor's
|
||||
// bounds, not just the current viewport bounds.
|
||||
int16 centeredXDiff = xDiff - (getBbox().width() / 2);
|
||||
int16 centeredYDiff = yDiff - (getBbox().height() / 2);
|
||||
Common::Point viewportDelta(centeredXDiff, centeredYDiff);
|
||||
_nextViewportOrigin = getViewportOrigin() + viewportDelta;
|
||||
adjustCameraViewport(_nextViewportOrigin);
|
||||
if (!_addedToStage) {
|
||||
_currentViewportOrigin = _nextViewportOrigin;
|
||||
} else {
|
||||
bool viewportMovedSuccessfully = processViewportMove();
|
||||
if (!viewportMovedSuccessfully) {
|
||||
startPan(0, 0, 0.0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kSetCameraBoundsMethod: {
|
||||
assert(args.size() == 2);
|
||||
int16 width = static_cast<int16>(args[0].asFloat());
|
||||
int16 height = static_cast<int16>(args[1].asFloat());
|
||||
Common::Rect newBounds(_originalBoundingBox.origin(), width, height);
|
||||
|
||||
// invalidateLocalBounds is already called in the setBounds call, but these extra calls are
|
||||
// in the original, so they are kept.
|
||||
invalidateLocalBounds();
|
||||
setBounds(newBounds);
|
||||
invalidateLocalBounds();
|
||||
break;
|
||||
}
|
||||
|
||||
case kXViewportPositionMethod:
|
||||
assert(args.size() == 0);
|
||||
returnValue.setToFloat(getViewportOrigin().x);
|
||||
break;
|
||||
|
||||
case kYViewportPositionMethod:
|
||||
assert(args.size() == 0);
|
||||
returnValue.setToFloat(getViewportOrigin().y);
|
||||
break;
|
||||
|
||||
case kPanToMethod: {
|
||||
assert(args.size() >= 3);
|
||||
int16 x = static_cast<int16>(args[0].asFloat());
|
||||
int16 y = static_cast<int16>(args[1].asFloat());
|
||||
|
||||
if (args.size() == 4) {
|
||||
uint panSteps = static_cast<uint>(args[2].asFloat());
|
||||
double duration = args[3].asFloat();
|
||||
panToByStepCount(x, y, panSteps, duration);
|
||||
} else if (args.size() == 3) {
|
||||
double duration = args[2].asFloat();
|
||||
panToByTime(x, y, duration);
|
||||
} else {
|
||||
error("%s: Incorrect number of args for method %s", __func__, builtInMethodToStr(methodId));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
returnValue = SpatialEntity::callMethod(methodId, args);
|
||||
break;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void CameraActor::invalidateLocalBounds() {
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void CameraActor::loadIsComplete() {
|
||||
SpatialEntity::loadIsComplete();
|
||||
if (_lensOpen) {
|
||||
addToStage();
|
||||
}
|
||||
|
||||
if (_image != nullptr) {
|
||||
warning("%s: STUB: Camera image asset not handled yet", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void CameraActor::addToStage() {
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->addCamera(this);
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void CameraActor::removeFromStage(bool shouldStopPan) {
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->removeCamera(this);
|
||||
invalidateLocalBounds();
|
||||
_addedToStage = false;
|
||||
if (shouldStopPan && _panState != kCameraNotPanning) {
|
||||
stopPan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CameraActor::setViewportOrigin(const Common::Point &newViewpointOrigin) {
|
||||
_currentViewportOrigin = newViewpointOrigin;
|
||||
}
|
||||
|
||||
Common::Point CameraActor::getViewportOrigin() {
|
||||
return _currentViewportOrigin;
|
||||
}
|
||||
|
||||
Common::Rect CameraActor::getViewportBounds() {
|
||||
Common::Rect viewportBounds(getBbox());
|
||||
viewportBounds.moveTo(_currentViewportOrigin);
|
||||
return viewportBounds;
|
||||
}
|
||||
|
||||
void CameraActor::drawUsingCamera(DisplayContext &displayContext, const Common::Array<SpatialEntity *> &entitiesToDraw) {
|
||||
Clip *currentClip = displayContext.currentClip();
|
||||
if (currentClip != nullptr) {
|
||||
Clip *previousClip = displayContext.previousClip();
|
||||
if (previousClip == nullptr) {
|
||||
currentClip->addToRegion(currentClip->_bounds);
|
||||
} else {
|
||||
*currentClip = *previousClip;
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect cameraBounds = getBbox();
|
||||
displayContext.intersectClipWith(cameraBounds);
|
||||
displayContext.pushOrigin();
|
||||
|
||||
Common::Point viewportOrigin = getViewportOrigin();
|
||||
Common::Point viewportOffset(
|
||||
-viewportOrigin.x + cameraBounds.left,
|
||||
-viewportOrigin.y + cameraBounds.top
|
||||
);
|
||||
displayContext._origin.x += viewportOffset.x;
|
||||
displayContext._origin.y += viewportOffset.y;
|
||||
|
||||
if (_image != nullptr) {
|
||||
// TODO: Handle image asset stuff.
|
||||
warning("%s: Camera image asset not handled yet", __func__);
|
||||
}
|
||||
|
||||
for (SpatialEntity *entityToDraw : entitiesToDraw) {
|
||||
if (entityToDraw->isVisible()) {
|
||||
drawObject(displayContext, displayContext, entityToDraw);
|
||||
}
|
||||
}
|
||||
|
||||
displayContext.popOrigin();
|
||||
displayContext.emptyCurrentClip();
|
||||
}
|
||||
|
||||
void CameraActor::drawObject(DisplayContext &sourceContext, DisplayContext &destContext, SpatialEntity *objectToDraw) {
|
||||
if (_parentStage == nullptr) {
|
||||
warning("%s: No parent stage", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
objectToDraw->setAdjustedBounds(kWrapNone);
|
||||
Common::Rect visibleBounds = objectToDraw->getBbox();
|
||||
if (sourceContext.rectIsInClip(visibleBounds)) {
|
||||
objectToDraw->draw(destContext);
|
||||
}
|
||||
|
||||
if (_parentStage->cylindricalX()) {
|
||||
warning("%s: CylindricalX not handled yet", __func__);
|
||||
}
|
||||
|
||||
if (_parentStage->cylindricalY()) {
|
||||
warning("%s: CylindricalY not handled yet", __func__);
|
||||
}
|
||||
objectToDraw->setAdjustedBounds(kWrapNone);
|
||||
}
|
||||
|
||||
void CameraActor::setXYDelta(uint xDelta, uint yDelta) {
|
||||
_panDelta.x = xDelta;
|
||||
_panDelta.y = yDelta;
|
||||
debugC(6, kDebugCamera, "%s: (%d, %d)", __func__, _panDelta.x, _panDelta.y);
|
||||
}
|
||||
|
||||
void CameraActor::setXYDelta() {
|
||||
// If we have no parameters for setting the delta,
|
||||
// just set the delta to 1 in whatever direction we are going.
|
||||
if (_panStart.x < _panDest.x) {
|
||||
_panDelta.x = 1;
|
||||
} else if (_panDest.x < _panStart.x) {
|
||||
_panDelta.x = -1;
|
||||
}
|
||||
|
||||
if (_panStart.y < _panDest.y) {
|
||||
_panDelta.y = 1;
|
||||
} else if (_panDest.y < _panStart.y) {
|
||||
_panDelta.y = -1;
|
||||
}
|
||||
debugC(6, kDebugCamera, "%s: (%d, %d)", __func__, _panDelta.x, _panDelta.y);
|
||||
}
|
||||
|
||||
void CameraActor::panToByTime(int16 x, int16 y, double duration) {
|
||||
_panState = kCameraPanToByTime;
|
||||
_panStart = _currentViewportOrigin;
|
||||
_panDest = Common::Point(x, y);
|
||||
_panDuration = duration;
|
||||
_currentPanStep = 1;
|
||||
_startTime = g_system->getMillis();
|
||||
_nextPanStepTime = 0;
|
||||
debugC(6, kDebugCamera, "%s: panStart: (%d, %d); panDest: (%d, %d); panDuration: %f",
|
||||
__func__, _panStart.x, _panStart.y, _panDest.x, _panDest.y, _panDuration);
|
||||
setXYDelta();
|
||||
calcNewViewportOrigin();
|
||||
}
|
||||
|
||||
void CameraActor::panToByStepCount(int16 x, int16 y, uint panSteps, double duration) {
|
||||
_panState = kCameraPanByStepCount;
|
||||
_panStart = _currentViewportOrigin;
|
||||
_panDest = Common::Point(x, y);
|
||||
_panDuration = duration;
|
||||
_currentPanStep = 1;
|
||||
_maxPanStep = panSteps;
|
||||
_startTime = g_system->getMillis();
|
||||
_nextPanStepTime = 0;
|
||||
debugC(6, kDebugCamera, "%s: panStart: (%d, %d); panDest: (%d, %d); panDuration: %f; maxPanStep: %d",
|
||||
__func__, _panStart.x, _panStart.y, _panDest.x, _panDest.y, _panDuration, _maxPanStep);
|
||||
setXYDelta();
|
||||
calcNewViewportOrigin();
|
||||
}
|
||||
|
||||
void CameraActor::startPan(uint xOffset, uint yOffset, double duration) {
|
||||
_panState = kCameraPanningStarted;
|
||||
_panDuration = duration;
|
||||
_startTime = g_system->getMillis();
|
||||
_nextPanStepTime = 0;
|
||||
_currentPanStep = 0;
|
||||
_maxPanStep = 0;
|
||||
setXYDelta(xOffset, yOffset);
|
||||
debugC(6, kDebugCamera, "%s: xOffset: %u, yOffset: %u, duration: %f", __func__, xOffset, yOffset, duration);
|
||||
}
|
||||
|
||||
void CameraActor::stopPan() {
|
||||
_panState = kCameraNotPanning;
|
||||
_panDuration = 0.0;
|
||||
_startTime = 0;
|
||||
_nextPanStepTime = 0;
|
||||
_currentPanStep = 0;
|
||||
_maxPanStep = 0;
|
||||
debugC(6, kDebugCamera, "%s: nextViewportOrigin: (%d, %d); actualViewportOrigin: (%d, %d)",
|
||||
__func__, _nextViewportOrigin.x, _nextViewportOrigin.y, _currentViewportOrigin.x, _currentViewportOrigin.y);
|
||||
}
|
||||
|
||||
bool CameraActor::continuePan() {
|
||||
bool panShouldContinue = true;
|
||||
if (_panState == kCameraPanningStarted) {
|
||||
if (_panDelta == Common::Point(0, 0)) {
|
||||
panShouldContinue = false;
|
||||
}
|
||||
} else {
|
||||
if (percentComplete() >= 1.0) {
|
||||
panShouldContinue = false;
|
||||
}
|
||||
}
|
||||
debugC(6, kDebugCamera, "%s: %s", __func__, panShouldContinue ? "true": "false");
|
||||
return panShouldContinue;
|
||||
}
|
||||
|
||||
void CameraActor::process() {
|
||||
// Only process panning if we're actively panning.
|
||||
if (_panState == kCameraNotPanning) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's time for the next pan step.
|
||||
uint currentTime = g_system->getMillis() - _startTime;
|
||||
if (currentTime < _nextPanStepTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
debugC(7, kDebugCamera, "*** START PAN STEP ***");
|
||||
timerEvent();
|
||||
debugC(7, kDebugCamera, "*** END PAN STEP ***");
|
||||
}
|
||||
|
||||
void CameraActor::timerEvent() {
|
||||
if (_parentStage != nullptr) {
|
||||
if (processViewportMove()) {
|
||||
processNextPanStep();
|
||||
if (continuePan()) {
|
||||
if (cameraWithinStage(_nextViewportOrigin)) {
|
||||
adjustCameraViewport(_nextViewportOrigin);
|
||||
|
||||
// The original had logic to pre-load the items that were going to be scrolled
|
||||
// into view next, but since we load actors more all-at-once, we don't actually need this.
|
||||
// The calls that would be made are kept commented out.
|
||||
// Common::Rect advanceRect = getAdvanceRect();
|
||||
// _parentStage->preload(advanceRect);
|
||||
} else {
|
||||
runEventHandlerIfExists(kCameraPanAbortEvent);
|
||||
stopPan();
|
||||
}
|
||||
} else {
|
||||
bool success = true;
|
||||
if (_panState == kCameraPanToByTime) {
|
||||
_nextViewportOrigin = _panDest;
|
||||
adjustCameraViewport(_nextViewportOrigin);
|
||||
success = processViewportMove();
|
||||
}
|
||||
if (success) {
|
||||
runEventHandlerIfExists(kCameraPanEndEvent);
|
||||
stopPan();
|
||||
} else {
|
||||
Common::Rect currentBounds = getBbox();
|
||||
Common::Rect preloadBounds(_nextViewportOrigin, currentBounds.width(), currentBounds.height());
|
||||
_parentStage->preload(preloadBounds);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Common::Rect currentBounds = getBbox();
|
||||
Common::Rect preloadBounds(_nextViewportOrigin, currentBounds.width(), currentBounds.height());
|
||||
_parentStage->preload(preloadBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraActor::processViewportMove() {
|
||||
bool isRectInMemory = true;
|
||||
if (_parentStage != nullptr) {
|
||||
Common::Rect boundsInViewport = getBbox();
|
||||
boundsInViewport.moveTo(_nextViewportOrigin);
|
||||
_parentStage->setCurrentCamera(this);
|
||||
isRectInMemory = _parentStage->isRectInMemory(boundsInViewport);
|
||||
if (isRectInMemory) {
|
||||
invalidateLocalBounds();
|
||||
setViewportOrigin(_nextViewportOrigin);
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
return isRectInMemory;
|
||||
}
|
||||
|
||||
void CameraActor::processNextPanStep() {
|
||||
// If pan type includes per-step updates (4-arg pan in original engine),
|
||||
// advance the pan step counter. Then compute the new viewport origin
|
||||
// and notify any script handlers registered for the pan-step event.
|
||||
if (_panState == kCameraPanByStepCount) {
|
||||
_currentPanStep += 1;
|
||||
}
|
||||
|
||||
calcNewViewportOrigin();
|
||||
runEventHandlerIfExists(kCameraPanStepEvent);
|
||||
|
||||
uint stepDurationInMilliseconds = 20; // Visually smooth.
|
||||
_nextPanStepTime += stepDurationInMilliseconds;
|
||||
}
|
||||
|
||||
void CameraActor::adjustCameraViewport(Common::Point &viewportToAdjust) {
|
||||
if (_parentStage == nullptr) {
|
||||
warning("%s: No parent stage", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_parentStage->cylindricalX()) {
|
||||
warning("%s: CylindricalX not handled yet", __func__);
|
||||
}
|
||||
|
||||
if (_parentStage->cylindricalY()) {
|
||||
warning("%s: CylindricalY not handled yet", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void CameraActor::calcNewViewportOrigin() {
|
||||
if (_panState == kCameraPanningStarted) {
|
||||
_nextViewportOrigin = _currentViewportOrigin + _panDelta;
|
||||
debugC(6, kDebugCamera, "%s: (%d, %d) [panDelta: (%d, %d)]",
|
||||
__func__, _nextViewportOrigin.x, _nextViewportOrigin.y, _panDelta.x, _panDelta.y);
|
||||
} else {
|
||||
// Interpolate from the start to the dest based on percent complete.
|
||||
double progress = percentComplete();
|
||||
double startX = static_cast<double>(_panStart.x);
|
||||
double endX = static_cast<double>(_panDest.x);
|
||||
double interpolatedX = startX + (endX - startX) * progress + 0.5;
|
||||
_nextViewportOrigin.x = static_cast<int16>(interpolatedX);
|
||||
|
||||
double startY = static_cast<double>(_panStart.y);
|
||||
double endY = static_cast<double>(_panDest.y);
|
||||
double interpolatedY = startY + (endY - startY) * progress + 0.5;
|
||||
_nextViewportOrigin.y = static_cast<int16>(interpolatedY);
|
||||
debugC(6, kDebugCamera, "%s: (%d, %d) [panStart: (%d, %d); panDest: (%d, %d); percentComplete: %f]",
|
||||
__func__, _nextViewportOrigin.x, _nextViewportOrigin.y, _panStart.x, _panStart.y, _panDest.x, _panDest.y, progress);
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraActor::cameraWithinStage(const Common::Point &candidate) {
|
||||
if (_parentStage == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
// We can only be out of horizontal bounds if we have a requested delta and
|
||||
// are not doing X axis wrapping.
|
||||
bool canBeOutOfHorizontalBounds = !_parentStage->cylindricalX() && _panDelta.x != 0;
|
||||
if (canBeOutOfHorizontalBounds) {
|
||||
int16 candidateRightBoundary = getBbox().width() + candidate.x;
|
||||
bool cameraPastRightBoundary = _parentStage->extent().x < candidateRightBoundary;
|
||||
if (cameraPastRightBoundary) {
|
||||
result = false;
|
||||
} else if (candidate.x < 0) {
|
||||
result = false;
|
||||
}
|
||||
debugC(6, kDebugCamera, "%s: %s [rightBoundary: %d, extent: %d]", __func__, result ? "true" : "false", candidateRightBoundary, _parentStage->extent().x);
|
||||
}
|
||||
|
||||
// We can only be out of vertical bounds if we have a requested delta and
|
||||
// are not doing Y axis wrapping.
|
||||
bool canBeOutOfVerticalBounds = !_parentStage->cylindricalY() && _panDelta.y != 0;
|
||||
if (canBeOutOfVerticalBounds) {
|
||||
int16 candidateBottomBoundary = getBbox().height() + candidate.y;
|
||||
bool cameraPastBottomBoundary = _parentStage->extent().y < candidateBottomBoundary;
|
||||
if (cameraPastBottomBoundary) {
|
||||
result = false;
|
||||
} else if (candidate.y < 0) {
|
||||
result = false;
|
||||
}
|
||||
debugC(6, kDebugCamera, "%s: %s [bottomBoundary: %d, extent: %d]", __func__, result ? "true" : "false", candidateBottomBoundary, _parentStage->extent().y);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double CameraActor::percentComplete() {
|
||||
double percentValue = 0.0;
|
||||
switch (_panState) {
|
||||
case kCameraPanByStepCount: {
|
||||
percentValue = static_cast<double>(_maxPanStep - _currentPanStep) / static_cast<double>(_maxPanStep);
|
||||
percentValue = 1.0 - percentValue;
|
||||
break;
|
||||
}
|
||||
|
||||
case kCameraPanToByTime: {
|
||||
const double MILLISECONDS_IN_ONE_SECOND = 1000.0;
|
||||
uint currentRuntime = g_system->getMillis();
|
||||
uint elapsedTime = currentRuntime - _startTime;
|
||||
double elapsedSeconds = elapsedTime / MILLISECONDS_IN_ONE_SECOND;
|
||||
percentValue = elapsedSeconds / _panDuration;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
percentValue = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
percentValue = CLIP<double>(percentValue, 0.0, 1.0);
|
||||
return percentValue;
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
103
engines/mediastation/actors/camera.h
Normal file
103
engines/mediastation/actors/camera.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_CAMERA_H
|
||||
#define MEDIASTATION_CAMERA_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/graphics.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum CameraPanState {
|
||||
kCameraNotPanning = 0,
|
||||
kCameraPanningStarted = 1,
|
||||
// We pan for a certain total amount of time.
|
||||
kCameraPanToByTime = 2,
|
||||
// We pan for a certain number of steps, waiting a given time between each step.
|
||||
kCameraPanByStepCount = 3
|
||||
};
|
||||
|
||||
struct ImageAsset;
|
||||
|
||||
// A Camera's main purpose is panning around a stage that is too large to fit on screen all at once.
|
||||
class CameraActor : public SpatialEntity, public ChannelClient {
|
||||
public:
|
||||
CameraActor() : SpatialEntity(kActorTypeCamera) {};
|
||||
~CameraActor();
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
virtual void loadIsComplete() override;
|
||||
virtual void process() override;
|
||||
|
||||
Common::Point getViewportOrigin();
|
||||
Common::Rect getViewportBounds();
|
||||
virtual void invalidateLocalBounds() override;
|
||||
|
||||
void drawUsingCamera(DisplayContext &displayContext, const Common::Array<SpatialEntity *> &entitiesToDraw);
|
||||
|
||||
private:
|
||||
bool _lensOpen = false;
|
||||
bool _addedToStage = false;
|
||||
double _panDuration = 0.0;
|
||||
uint _currentPanStep = 0;
|
||||
uint _maxPanStep = 0;
|
||||
uint _startTime = 0;
|
||||
uint _nextPanStepTime = 0;
|
||||
CameraPanState _panState = kCameraNotPanning;
|
||||
Common::Point _offset;
|
||||
Common::Point _currentViewportOrigin;
|
||||
Common::Point _nextViewportOrigin;
|
||||
Common::Point _panStart;
|
||||
Common::Point _panDest;
|
||||
Common::Point _panDelta;
|
||||
Common::SharedPtr<ImageAsset> _image;
|
||||
DisplayContext _displayContext;
|
||||
|
||||
void addToStage();
|
||||
void removeFromStage(bool stopPan);
|
||||
void setViewportOrigin(const Common::Point &newViewportOrigin);
|
||||
void drawObject(DisplayContext &sourceContext, DisplayContext &destContext, SpatialEntity *objectToDraw);
|
||||
void setXYDelta(uint xDelta, uint yDelta);
|
||||
void setXYDelta();
|
||||
bool cameraWithinStage(const Common::Point &candidate);
|
||||
|
||||
void panToByTime(int16 x, int16 y, double duration);
|
||||
void panToByStepCount(int16 x, int16 y, uint maxPanStep, double duration);
|
||||
void startPan(uint xOffset, uint yOffset, double duration);
|
||||
void stopPan();
|
||||
bool continuePan();
|
||||
|
||||
void timerEvent();
|
||||
bool processViewportMove();
|
||||
void processNextPanStep();
|
||||
void adjustCameraViewport(Common::Point &viewportToAdjust);
|
||||
void calcNewViewportOrigin();
|
||||
double percentComplete();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
48
engines/mediastation/actors/canvas.cpp
Normal file
48
engines/mediastation/actors/canvas.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 "mediastation/actors/canvas.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
void CanvasActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderStartup:
|
||||
_isVisible = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue CanvasActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
switch (methodId) {
|
||||
case kClearToPaletteMethod: {
|
||||
error("%s: clearToPalette is not implemented yet", __func__);
|
||||
}
|
||||
|
||||
default:
|
||||
return SpatialEntity::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
41
engines/mediastation/actors/canvas.h
Normal file
41
engines/mediastation/actors/canvas.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_CANVAS_H
|
||||
#define MEDIASTATION_CANVAS_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class CanvasActor : public SpatialEntity {
|
||||
public:
|
||||
CanvasActor() : SpatialEntity(kActorTypeCanvas) {};
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
100
engines/mediastation/actors/document.cpp
Normal file
100
engines/mediastation/actors/document.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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 "mediastation/mediastation.h"
|
||||
#include "mediastation/actors/document.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
const uint MediaStation::DocumentActor::DOCUMENT_ACTOR_ID;
|
||||
|
||||
ScriptValue DocumentActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
switch (methodId) {
|
||||
case kDocumentBranchToScreenMethod:
|
||||
processBranch(args);
|
||||
break;
|
||||
|
||||
case kDocumentQuitMethod:
|
||||
g_engine->quitGame();
|
||||
break;
|
||||
|
||||
case kDocumentContextLoadInProgressMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint contextId = args[0].asActorId();
|
||||
bool isLoading = g_engine->getDocument()->isContextLoadInProgress(contextId);
|
||||
returnValue.setToBool(isLoading);
|
||||
break;
|
||||
}
|
||||
|
||||
case kDocumentSetMultipleStreamsMethod:
|
||||
case kDocumentSetMultipleSoundsMethod: {
|
||||
assert(args.size() == 1);
|
||||
bool value = args[0].asBool();
|
||||
warning("%s: STUB: %s: %d", __func__, builtInMethodToStr(methodId), value);
|
||||
break;
|
||||
}
|
||||
|
||||
case kDocumentLoadContextMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint contextId = args[0].asActorId();
|
||||
g_engine->getDocument()->startContextLoad(contextId);
|
||||
break;
|
||||
}
|
||||
|
||||
case kDocumentReleaseContextMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint contextId = args[0].asActorId();
|
||||
g_engine->getDocument()->scheduleContextRelease(contextId);
|
||||
break;
|
||||
}
|
||||
|
||||
case kDocumentContextIsLoadedMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint contextId = args[0].asActorId();
|
||||
|
||||
// We are looking for the screen actor with the same ID as the context.
|
||||
Actor *screenActor = g_engine->getActorById(contextId);
|
||||
bool contextIsLoading = g_engine->getDocument()->isContextLoadInProgress(contextId);
|
||||
bool contextIsLoaded = (screenActor != nullptr) && !contextIsLoading;
|
||||
returnValue.setToBool(contextIsLoaded);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
returnValue = Actor::callMethod(methodId, args);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void DocumentActor::processBranch(Common::Array<ScriptValue> &args) {
|
||||
assert(args.size() >= 1);
|
||||
uint contextId = args[0].asActorId();
|
||||
if (args.size() > 1) {
|
||||
bool disableUpdates = static_cast<bool>(args[1].asParamToken());
|
||||
if (disableUpdates)
|
||||
warning("%s: disableUpdates parameter not handled yet", __func__);
|
||||
}
|
||||
|
||||
g_engine->getDocument()->scheduleScreenBranch(contextId);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
44
engines/mediastation/actors/document.h
Normal file
44
engines/mediastation/actors/document.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_DOCUMENT_H
|
||||
#define MEDIASTATION_DOCUMENT_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class DocumentActor : public Actor {
|
||||
public:
|
||||
static const uint DOCUMENT_ACTOR_ID = 1;
|
||||
DocumentActor() : Actor(kActorTypeDocument) { _id = DOCUMENT_ACTOR_ID; };
|
||||
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
|
||||
private:
|
||||
void processBranch(Common::Array<ScriptValue> &args);
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
66
engines/mediastation/actors/font.cpp
Normal file
66
engines/mediastation/actors/font.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 "mediastation/debugchannels.h"
|
||||
#include "mediastation/actors/font.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
FontGlyph::FontGlyph(Chunk &chunk, uint asciiCode, uint unk1, uint unk2, BitmapHeader *header) : Bitmap(chunk, header) {
|
||||
_asciiCode = asciiCode;
|
||||
_unk1 = unk1;
|
||||
_unk2 = unk2;
|
||||
}
|
||||
|
||||
FontActor::~FontActor() {
|
||||
unregisterWithStreamManager();
|
||||
for (auto it = _glyphs.begin(); it != _glyphs.end(); ++it) {
|
||||
delete it->_value;
|
||||
}
|
||||
_glyphs.clear();
|
||||
}
|
||||
|
||||
void FontActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderChannelIdent:
|
||||
_channelIdent = chunk.readTypedChannelIdent();
|
||||
registerWithStreamManager();
|
||||
break;
|
||||
|
||||
default:
|
||||
Actor::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
void FontActor::readChunk(Chunk &chunk) {
|
||||
debugC(5, kDebugLoading, "FontActor::readChunk(): Reading font glyph (@0x%llx)", static_cast<long long int>(chunk.pos()));
|
||||
uint asciiCode = chunk.readTypedUint16();
|
||||
int unk1 = chunk.readTypedUint16();
|
||||
int unk2 = chunk.readTypedUint16();
|
||||
BitmapHeader *header = new BitmapHeader(chunk);
|
||||
FontGlyph *glyph = new FontGlyph(chunk, asciiCode, unk1, unk2, header);
|
||||
if (_glyphs.getValOrDefault(asciiCode) != nullptr) {
|
||||
error("%s: Glyph for ASCII code 0x%x already exists", __func__, asciiCode);
|
||||
}
|
||||
_glyphs.setVal(asciiCode, glyph);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
57
engines/mediastation/actors/font.h
Normal file
57
engines/mediastation/actors/font.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_FONT_H
|
||||
#define MEDIASTATION_FONT_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/bitmap.h"
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class FontGlyph : public Bitmap {
|
||||
public:
|
||||
FontGlyph(Chunk &chunk, uint asciiCode, uint unk1, uint unk2, BitmapHeader *header);
|
||||
uint _asciiCode = 0;
|
||||
|
||||
private:
|
||||
int _unk1 = 0;
|
||||
int _unk2 = 0;
|
||||
};
|
||||
|
||||
class FontActor : public Actor, public ChannelClient {
|
||||
public:
|
||||
FontActor() : Actor(kActorTypeFont) {};
|
||||
~FontActor();
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
|
||||
private:
|
||||
Common::HashMap<uint, FontGlyph *> _glyphs;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
252
engines/mediastation/actors/hotspot.cpp
Normal file
252
engines/mediastation/actors/hotspot.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/* 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 "mediastation/debugchannels.h"
|
||||
#include "mediastation/actors/hotspot.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
void HotspotActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderMouseActiveArea: {
|
||||
uint16 total_points = chunk.readTypedUint16();
|
||||
for (int i = 0; i < total_points; i++) {
|
||||
Common::Point point = chunk.readTypedPoint();
|
||||
_mouseActiveArea.push_back(point);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderStartup:
|
||||
_isActive = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderCursorResourceId:
|
||||
_cursorResourceId = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderGetOffstageEvents:
|
||||
_getOffstageEvents = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
bool HotspotActor::isInside(const Common::Point &pointToCheck) {
|
||||
// No sense checking the polygon if we're not even in the bbox.
|
||||
if (!_boundingBox.contains(pointToCheck)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're in the bbox, but there might not be a polygon to check.
|
||||
if (_mouseActiveArea.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Polygon intersection code adapted from HADESCH engine, might need more
|
||||
// refinement once more testing is possible.
|
||||
Common::Point point = pointToCheck - Common::Point(_boundingBox.left, _boundingBox.top);
|
||||
int rcross = 0; // Number of right-side overlaps
|
||||
|
||||
// Each edge is checked whether it cuts the outgoing stream from the point
|
||||
Common::Array<Common::Point> _polygon = _mouseActiveArea;
|
||||
for (unsigned i = 0; i < _polygon.size(); i++) {
|
||||
const Common::Point &edgeStart = _polygon[i];
|
||||
const Common::Point &edgeEnd = _polygon[(i + 1) % _polygon.size()];
|
||||
|
||||
// A vertex is a point? Then it lies on one edge of the polygon
|
||||
if (point == edgeStart)
|
||||
return true;
|
||||
|
||||
if ((edgeStart.y > point.y) != (edgeEnd.y > point.y)) {
|
||||
int term1 = (edgeStart.x - point.x) * (edgeEnd.y - point.y) - (edgeEnd.x - point.x) * (edgeStart.y - point.y);
|
||||
int term2 = (edgeEnd.y - point.y) - (edgeStart.y - edgeEnd.y);
|
||||
if ((term1 > 0) == (term2 >= 0))
|
||||
rcross++;
|
||||
}
|
||||
}
|
||||
|
||||
// The point is strictly inside the polygon if and only if the number of overlaps is odd
|
||||
return ((rcross % 2) == 1);
|
||||
}
|
||||
|
||||
ScriptValue HotspotActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
switch (methodId) {
|
||||
case kMouseActivateMethod: {
|
||||
assert(args.empty());
|
||||
activate();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kMouseDeactivateMethod: {
|
||||
assert(args.empty());
|
||||
deactivate();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kIsActiveMethod: {
|
||||
assert(args.empty());
|
||||
returnValue.setToBool(_isActive);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kTriggerAbsXPositionMethod: {
|
||||
double mouseX = static_cast<double>(g_system->getEventManager()->getMousePos().x);
|
||||
returnValue.setToFloat(mouseX);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kTriggerAbsYPositionMethod: {
|
||||
double mouseY = static_cast<double>(g_system->getEventManager()->getMousePos().y);
|
||||
returnValue.setToFloat(mouseY);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return SpatialEntity::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 HotspotActor::findActorToAcceptMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool clipMouseEvents) {
|
||||
|
||||
uint16 result = 0;
|
||||
if (isActive()) {
|
||||
if (isInside(point)) {
|
||||
if (eventMask & kMouseDownFlag) {
|
||||
state.mouseDown = this;
|
||||
result |= kMouseDownFlag;
|
||||
}
|
||||
|
||||
if (eventMask & kMouseEnterFlag) {
|
||||
state.mouseEnter = this;
|
||||
result |= kMouseEnterFlag;
|
||||
}
|
||||
|
||||
if (eventMask & kMouseMovedFlag) {
|
||||
state.mouseMoved = this;
|
||||
result |= kMouseMovedFlag;
|
||||
}
|
||||
}
|
||||
|
||||
if (this == g_engine->getMouseInsideHotspot() && (eventMask & kMouseExitFlag)) {
|
||||
state.mouseExit = this;
|
||||
result |= kMouseExitFlag;
|
||||
}
|
||||
|
||||
if (this == g_engine->getMouseDownHotspot() && (eventMask & kMouseUpFlag)) {
|
||||
state.mouseUp = this;
|
||||
result |= kMouseUpFlag;
|
||||
}
|
||||
} else {
|
||||
debugC(5, kDebugEvents, "%s: %d: Inactive", __func__, id());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void HotspotActor::activate() {
|
||||
if (!_isActive) {
|
||||
_isActive = true;
|
||||
invalidateMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void HotspotActor::deactivate() {
|
||||
if (_isActive) {
|
||||
_isActive = false;
|
||||
if (g_engine->getMouseDownHotspot() == this) {
|
||||
g_engine->setMouseDownHotspot(nullptr);
|
||||
}
|
||||
if (g_engine->getMouseInsideHotspot() == this) {
|
||||
g_engine->setMouseDownHotspot(nullptr);
|
||||
}
|
||||
|
||||
invalidateMouse();
|
||||
}
|
||||
}
|
||||
|
||||
void HotspotActor::mouseDownEvent(const Common::Event &event) {
|
||||
if (!_isActive) {
|
||||
warning("%s: Called on inactive hotspot", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
g_engine->setMouseDownHotspot(this);
|
||||
runEventHandlerIfExists(kMouseDownEvent);
|
||||
}
|
||||
|
||||
void HotspotActor::mouseUpEvent(const Common::Event &event) {
|
||||
if (!_isActive) {
|
||||
warning("%s: Called on inactive hotspot", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
g_engine->setMouseDownHotspot(nullptr);
|
||||
runEventHandlerIfExists(kMouseUpEvent);
|
||||
}
|
||||
|
||||
void HotspotActor::mouseEnteredEvent(const Common::Event &event) {
|
||||
if (!_isActive) {
|
||||
warning("%s: Called on inactive hotspot", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
g_engine->setMouseInsideHotspot(this);
|
||||
if (_cursorResourceId != 0) {
|
||||
debugC(5, kDebugEvents, "%s: Setting cursor %d for asset %d", __func__, _cursorResourceId, id());
|
||||
g_engine->getCursorManager()->setAsTemporary(_cursorResourceId);
|
||||
} else {
|
||||
debugC(5, kDebugEvents, "%s: Unsetting cursor for asset %d", __func__, id());
|
||||
g_engine->getCursorManager()->unsetTemporary();
|
||||
}
|
||||
|
||||
runEventHandlerIfExists(kMouseEnteredEvent);
|
||||
}
|
||||
|
||||
void HotspotActor::mouseMovedEvent(const Common::Event &event) {
|
||||
if (!_isActive) {
|
||||
warning("%s: Called on inactive hotspot", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
runEventHandlerIfExists(kMouseMovedEvent);
|
||||
}
|
||||
|
||||
void HotspotActor::mouseExitedEvent(const Common::Event &event) {
|
||||
if (!_isActive) {
|
||||
warning("%s: Called on inactive hotspot", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
g_engine->setMouseInsideHotspot(nullptr);
|
||||
runEventHandlerIfExists(kMouseExitedEvent);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
68
engines/mediastation/actors/hotspot.h
Normal file
68
engines/mediastation/actors/hotspot.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_HOTSPOT_H
|
||||
#define MEDIASTATION_HOTSPOT_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class HotspotActor : public SpatialEntity {
|
||||
public:
|
||||
HotspotActor() : SpatialEntity(kActorTypeHotspot) {};
|
||||
virtual ~HotspotActor() { _mouseActiveArea.clear(); }
|
||||
|
||||
bool isInside(const Common::Point &pointToCheck);
|
||||
virtual bool isVisible() const override { return false; }
|
||||
bool isActive() const { return _isActive; }
|
||||
virtual bool interactsWithMouse() const override { return isActive(); }
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
|
||||
virtual uint16 findActorToAcceptMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) override;
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
virtual void mouseDownEvent(const Common::Event &event) override;
|
||||
virtual void mouseUpEvent(const Common::Event &event) override;
|
||||
virtual void mouseEnteredEvent(const Common::Event &event) override;
|
||||
virtual void mouseExitedEvent(const Common::Event &event) override;
|
||||
virtual void mouseMovedEvent(const Common::Event &event) override;
|
||||
|
||||
uint _cursorResourceId = 0;
|
||||
Common::Array<Common::Point> _mouseActiveArea;
|
||||
|
||||
private:
|
||||
bool _isActive = false;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
128
engines/mediastation/actors/image.cpp
Normal file
128
engines/mediastation/actors/image.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/* 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 "mediastation/mediastation.h"
|
||||
#include "mediastation/actors/image.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
ImageAsset::~ImageAsset() {
|
||||
delete bitmap;
|
||||
bitmap = nullptr;
|
||||
}
|
||||
|
||||
ImageActor::~ImageActor() {
|
||||
unregisterWithStreamManager();
|
||||
}
|
||||
|
||||
void ImageActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderChannelIdent:
|
||||
_channelIdent = chunk.readTypedChannelIdent();
|
||||
registerWithStreamManager();
|
||||
_asset = Common::SharedPtr<ImageAsset>(new ImageAsset);
|
||||
break;
|
||||
|
||||
case kActorHeaderStartup:
|
||||
_isVisible = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderLoadType:
|
||||
_loadType = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
case kActorHeaderX:
|
||||
_xOffset = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderY:
|
||||
_yOffset = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderActorReference: {
|
||||
_actorReference = chunk.readTypedUint16();
|
||||
Actor *referencedActor = g_engine->getActorById(_actorReference);
|
||||
if (referencedActor == nullptr) {
|
||||
error("%s: Referenced actor %d doesn't exist or has not been read yet in this title", __func__, _actorReference);
|
||||
}
|
||||
if (referencedActor->type() != kActorTypeImage) {
|
||||
error("%s: Type mismatch of referenced actor %d", __func__, _actorReference);
|
||||
}
|
||||
ImageActor *referencedImage = static_cast<ImageActor *>(referencedActor);
|
||||
_asset = referencedImage->_asset;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue ImageActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
switch (methodId) {
|
||||
case kSpatialShowMethod: {
|
||||
assert(args.empty());
|
||||
spatialShow();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSpatialHideMethod: {
|
||||
assert(args.empty());
|
||||
spatialHide();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return SpatialEntity::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageActor::draw(DisplayContext &displayContext) {
|
||||
if (_isVisible) {
|
||||
Common::Point origin = getBbox().origin();
|
||||
g_engine->getDisplayManager()->imageBlit(origin, _asset->bitmap, _dissolveFactor, &displayContext);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageActor::spatialShow() {
|
||||
_isVisible = true;
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
|
||||
void ImageActor::spatialHide() {
|
||||
_isVisible = false;
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
|
||||
Common::Rect ImageActor::getBbox() const {
|
||||
Common::Point origin(_xOffset + _boundingBox.left, _yOffset + _boundingBox.top);
|
||||
Common::Rect bbox(origin, _asset->bitmap->width(), _asset->bitmap->height());
|
||||
return bbox;
|
||||
}
|
||||
|
||||
void ImageActor::readChunk(Chunk &chunk) {
|
||||
BitmapHeader *bitmapHeader = new BitmapHeader(chunk);
|
||||
_asset->bitmap = new Bitmap(chunk, bitmapHeader);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
68
engines/mediastation/actors/image.h
Normal file
68
engines/mediastation/actors/image.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_IMAGE_H
|
||||
#define MEDIASTATION_IMAGE_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/bitmap.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
// The original had a separate class that did reference counting,
|
||||
// for sharing an asset across actors, but we can just use a SharedPtr.
|
||||
struct ImageAsset {
|
||||
~ImageAsset();
|
||||
|
||||
Bitmap *bitmap = nullptr;
|
||||
};
|
||||
|
||||
class ImageActor : public SpatialEntity, public ChannelClient {
|
||||
public:
|
||||
ImageActor() : SpatialEntity(kActorTypeImage) {};
|
||||
virtual ~ImageActor() override;
|
||||
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
virtual void draw(DisplayContext &displayContext) override;
|
||||
virtual Common::Rect getBbox() const override;
|
||||
|
||||
private:
|
||||
Common::SharedPtr<ImageAsset> _asset;
|
||||
uint _loadType = 0;
|
||||
int _xOffset = 0;
|
||||
int _yOffset = 0;
|
||||
uint _actorReference = 0;
|
||||
|
||||
// Script method implementations.
|
||||
void spatialShow();
|
||||
void spatialHide();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
503
engines/mediastation/actors/movie.cpp
Normal file
503
engines/mediastation/actors/movie.cpp
Normal file
@@ -0,0 +1,503 @@
|
||||
/* 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 "mediastation/actors/movie.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
MovieFrameHeader::MovieFrameHeader(Chunk &chunk) : BitmapHeader(chunk) {
|
||||
_index = chunk.readTypedUint32();
|
||||
debugC(5, kDebugLoading, "MovieFrameHeader::MovieFrameHeader(): _index = 0x%x (@0x%llx)", _index, static_cast<long long int>(chunk.pos()));
|
||||
_keyframeEndInMilliseconds = chunk.readTypedUint32();
|
||||
}
|
||||
|
||||
MovieFrame::MovieFrame(Chunk &chunk) {
|
||||
if (g_engine->isFirstGenerationEngine()) {
|
||||
blitType = static_cast<MovieBlitType>(chunk.readTypedUint16());
|
||||
startInMilliseconds = chunk.readTypedUint32();
|
||||
endInMilliseconds = chunk.readTypedUint32();
|
||||
// These are unsigned in the data files but ScummVM expects signed.
|
||||
leftTop.x = static_cast<int16>(chunk.readTypedUint16());
|
||||
leftTop.y = static_cast<int16>(chunk.readTypedUint16());
|
||||
index = chunk.readTypedUint32();
|
||||
keyframeIndex = chunk.readTypedUint32();
|
||||
keepAfterEnd = chunk.readTypedByte();
|
||||
} else {
|
||||
layerId = chunk.readTypedUint32();
|
||||
blitType = static_cast<MovieBlitType>(chunk.readTypedUint16());
|
||||
startInMilliseconds = chunk.readTypedUint32();
|
||||
endInMilliseconds = chunk.readTypedUint32();
|
||||
// These are unsigned in the data files but ScummVM expects signed.
|
||||
leftTop.x = static_cast<int16>(chunk.readTypedUint16());
|
||||
leftTop.y = static_cast<int16>(chunk.readTypedUint16());
|
||||
zIndex = chunk.readTypedSint16();
|
||||
// This represents the difference between the left-top coordinate of the
|
||||
// keyframe (if applicable) and the left coordinate of this frame. Zero
|
||||
// if there is no keyframe.
|
||||
diffBetweenKeyframeAndFrame.x = chunk.readTypedSint16();
|
||||
diffBetweenKeyframeAndFrame.y = chunk.readTypedSint16();
|
||||
index = chunk.readTypedUint32();
|
||||
keyframeIndex = chunk.readTypedUint32();
|
||||
keepAfterEnd = chunk.readTypedByte();
|
||||
debugC(5, kDebugLoading, "MovieFrame::MovieFrame(): _blitType = %d, _startInMilliseconds = %d, \
|
||||
_endInMilliseconds = %d, _left = %d, _top = %d, _zIndex = %d, _diffBetweenKeyframeAndFrameX = %d, \
|
||||
_diffBetweenKeyframeAndFrameY = %d, _index = %d, _keyframeIndex = %d, _keepAfterEnd = %d (@0x%llx)",
|
||||
blitType, startInMilliseconds, endInMilliseconds, leftTop.x, leftTop.y, zIndex, diffBetweenKeyframeAndFrame.x, \
|
||||
diffBetweenKeyframeAndFrame.y, index, keyframeIndex, keepAfterEnd, static_cast<long long int>(chunk.pos()));
|
||||
}
|
||||
}
|
||||
|
||||
MovieFrameImage::MovieFrameImage(Chunk &chunk, MovieFrameHeader *header) : Bitmap(chunk, header) {
|
||||
_bitmapHeader = header;
|
||||
}
|
||||
|
||||
MovieFrameImage::~MovieFrameImage() {
|
||||
// The base class destructor takes care of deleting the bitmap header, so
|
||||
// we don't need to delete that here.
|
||||
}
|
||||
|
||||
StreamMovieActor::~StreamMovieActor() {
|
||||
unregisterWithStreamManager();
|
||||
if (_streamFeed != nullptr) {
|
||||
g_engine->getStreamFeedManager()->closeStreamFeed(_streamFeed);
|
||||
_streamFeed = nullptr;
|
||||
}
|
||||
|
||||
delete _streamFrames;
|
||||
_streamFrames = nullptr;
|
||||
|
||||
delete _streamSound;
|
||||
_streamSound = nullptr;
|
||||
}
|
||||
|
||||
void StreamMovieActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderActorId: {
|
||||
// We already have this actor's ID, so we will just verify it is the same
|
||||
// as the ID we have already read.
|
||||
uint32 duplicateActorId = chunk.readTypedUint16();
|
||||
if (duplicateActorId != _id) {
|
||||
warning("%s: Duplicate actor ID %d does not match original ID %d", __func__, duplicateActorId, _id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderMovieLoadType:
|
||||
_loadType = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
case kActorHeaderChannelIdent:
|
||||
_channelIdent = chunk.readTypedChannelIdent();
|
||||
registerWithStreamManager();
|
||||
break;
|
||||
|
||||
case kActorHeaderHasOwnSubfile: {
|
||||
bool hasOwnSubfile = static_cast<bool>(chunk.readTypedByte());
|
||||
if (!hasOwnSubfile) {
|
||||
error("%s: StreamMovieActor doesn't have a subfile", __func__);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderStartup:
|
||||
_isVisible = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderMovieAudioChannelIdent: {
|
||||
ChannelIdent soundChannelIdent = chunk.readTypedChannelIdent();
|
||||
_streamSound->setChannelIdent(soundChannelIdent);
|
||||
_streamSound->registerWithStreamManager();
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderMovieAnimationChannelIdent: {
|
||||
ChannelIdent framesChannelIdent = chunk.readTypedChannelIdent();
|
||||
_streamFrames->setChannelIdent(framesChannelIdent);
|
||||
_streamFrames->registerWithStreamManager();
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderSoundInfo:
|
||||
_streamSound->_audioSequence.readParameters(chunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue StreamMovieActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
switch (methodId) {
|
||||
case kTimePlayMethod: {
|
||||
assert(args.empty());
|
||||
timePlay();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSpatialShowMethod: {
|
||||
assert(args.empty());
|
||||
setVisibility(true);
|
||||
updateFrameState();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kTimeStopMethod: {
|
||||
assert(args.empty());
|
||||
timeStop();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSpatialHideMethod: {
|
||||
assert(args.empty());
|
||||
setVisibility(false);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kIsPlayingMethod: {
|
||||
assert(args.empty());
|
||||
returnValue.setToBool(_isPlaying);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kGetLeftXMethod: {
|
||||
assert(args.empty());
|
||||
double left = static_cast<double>(_boundingBox.left);
|
||||
returnValue.setToFloat(left);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kGetTopYMethod: {
|
||||
assert(args.empty());
|
||||
double top = static_cast<double>(_boundingBox.top);
|
||||
returnValue.setToFloat(top);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return SpatialEntity::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamMovieActor::timePlay() {
|
||||
if (_streamFeed == nullptr) {
|
||||
_streamFeed = g_engine->getStreamFeedManager()->openStreamFeed(_id);
|
||||
_streamFeed->readData();
|
||||
}
|
||||
|
||||
if (_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
_streamSound->_audioSequence.play();
|
||||
_framesNotYetShown = _streamFrames->_frames;
|
||||
_framesOnScreen.clear();
|
||||
_isPlaying = true;
|
||||
_startTime = g_system->getMillis();
|
||||
_lastProcessedTime = 0;
|
||||
runEventHandlerIfExists(kMovieBeginEvent);
|
||||
process();
|
||||
}
|
||||
|
||||
void StreamMovieActor::timeStop() {
|
||||
if (!_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MovieFrame *frame : _framesOnScreen) {
|
||||
invalidateRect(getFrameBoundingBox(frame));
|
||||
}
|
||||
_streamSound->_audioSequence.stop();
|
||||
_framesNotYetShown.empty();
|
||||
if (_hasStill) {
|
||||
_framesNotYetShown = _streamFrames->_frames;
|
||||
}
|
||||
_framesOnScreen.clear();
|
||||
_startTime = 0;
|
||||
_lastProcessedTime = 0;
|
||||
_isPlaying = false;
|
||||
runEventHandlerIfExists(kMovieStoppedEvent);
|
||||
}
|
||||
|
||||
void StreamMovieActor::process() {
|
||||
if (_isVisible) {
|
||||
if (_isPlaying) {
|
||||
processTimeEventHandlers();
|
||||
}
|
||||
updateFrameState();
|
||||
}
|
||||
}
|
||||
|
||||
void StreamMovieActor::setVisibility(bool visibility) {
|
||||
if (visibility != _isVisible) {
|
||||
_isVisible = visibility;
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void StreamMovieActor::updateFrameState() {
|
||||
uint movieTime = 0;
|
||||
if (_isPlaying) {
|
||||
uint currentTime = g_system->getMillis();
|
||||
movieTime = currentTime - _startTime;
|
||||
}
|
||||
debugC(5, kDebugGraphics, "StreamMovieActor::updateFrameState (%d): Starting update (movie time: %d)", _id, movieTime);
|
||||
|
||||
// This complexity is necessary becuase movies can have more than one frame
|
||||
// showing at the same time - for instance, a movie background and an
|
||||
// animation on that background are a part of the saem movie and are on
|
||||
// screen at the same time, it's just the starting and ending times of one
|
||||
// can be different from the starting and ending times of another.
|
||||
//
|
||||
// We can rely on the frames being ordered in order of their start. First,
|
||||
// see if there are any new frames to show.
|
||||
for (auto it = _framesNotYetShown.begin(); it != _framesNotYetShown.end();) {
|
||||
MovieFrame *frame = *it;
|
||||
bool isAfterStart = movieTime >= frame->startInMilliseconds;
|
||||
if (isAfterStart) {
|
||||
_framesOnScreen.insert(frame);
|
||||
invalidateRect(getFrameBoundingBox(frame));
|
||||
|
||||
// We don't need ++it because we will either have another frame
|
||||
// that needs to be drawn, or we have reached the end of the new
|
||||
// frames.
|
||||
it = _framesNotYetShown.erase(it);
|
||||
} else {
|
||||
// We've hit a frame that shouldn't yet be shown.
|
||||
// Rely on the ordering to not bother with any further frames.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now see if there are any old frames that no longer need to be shown.
|
||||
for (auto it = _framesOnScreen.begin(); it != _framesOnScreen.end();) {
|
||||
MovieFrame *frame = *it;
|
||||
bool isAfterEnd = movieTime >= frame->endInMilliseconds;
|
||||
if (isAfterEnd) {
|
||||
invalidateRect(getFrameBoundingBox(frame));
|
||||
it = _framesOnScreen.erase(it);
|
||||
|
||||
if (_framesOnScreen.empty() && movieTime >= _fullTime) {
|
||||
_isPlaying = false;
|
||||
if (_hasStill) {
|
||||
_framesNotYetShown = _streamFrames->_frames;
|
||||
updateFrameState();
|
||||
}
|
||||
runEventHandlerIfExists(kMovieEndEvent);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Show the frames that are currently active, for debugging purposes.
|
||||
for (MovieFrame *frame : _framesOnScreen) {
|
||||
debugC(5, kDebugGraphics, " (time: %d ms) Frame %d (%d x %d) @ (%d, %d); start: %d ms, end: %d ms, zIndex = %d", \
|
||||
movieTime, frame->index, frame->image->width(), frame->image->height(), frame->leftTop.x, frame->leftTop.y, frame->startInMilliseconds, frame->endInMilliseconds, frame->zIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamMovieActor::draw(DisplayContext &displayContext) {
|
||||
for (MovieFrame *frame : _framesOnScreen) {
|
||||
Common::Rect bbox = getFrameBoundingBox(frame);
|
||||
|
||||
switch (frame->blitType) {
|
||||
case kUncompressedMovieBlit:
|
||||
g_engine->getDisplayManager()->imageBlit(bbox.origin(), frame->image, _dissolveFactor, &displayContext);
|
||||
break;
|
||||
|
||||
case kUncompressedDeltaMovieBlit:
|
||||
g_engine->getDisplayManager()->imageDeltaBlit(
|
||||
bbox.origin(), frame->diffBetweenKeyframeAndFrame,
|
||||
frame->image, frame->keyframeImage, _dissolveFactor, &displayContext);
|
||||
break;
|
||||
|
||||
case kCompressedDeltaMovieBlit:
|
||||
if (frame->keyframeImage->isCompressed()) {
|
||||
decompressIntoAuxImage(frame);
|
||||
}
|
||||
g_engine->getDisplayManager()->imageDeltaBlit(
|
||||
bbox.origin(), frame->diffBetweenKeyframeAndFrame,
|
||||
frame->image, frame->keyframeImage, _dissolveFactor, &displayContext);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Got unknown movie frame blit type: %d", __func__, frame->blitType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect StreamMovieActor::getFrameBoundingBox(MovieFrame *frame) {
|
||||
// Use _boundingBox directly (which may be temporarily offset by camera rendering)
|
||||
// The camera offset is already applied to _boundingBox by pushBoundingBoxOffset()
|
||||
Common::Point origin = _boundingBox.origin() + frame->leftTop;
|
||||
Common::Rect bbox = Common::Rect(origin, frame->image->width(), frame->image->height());
|
||||
return bbox;
|
||||
}
|
||||
|
||||
StreamMovieActorFrames::~StreamMovieActorFrames() {
|
||||
unregisterWithStreamManager();
|
||||
|
||||
for (MovieFrame *frame : _frames) {
|
||||
delete frame;
|
||||
}
|
||||
_frames.clear();
|
||||
|
||||
for (MovieFrameImage *image : _images) {
|
||||
delete image;
|
||||
}
|
||||
_images.clear();
|
||||
}
|
||||
|
||||
void StreamMovieActorFrames::readChunk(Chunk &chunk) {
|
||||
uint sectionType = chunk.readTypedUint16();
|
||||
switch ((MovieSectionType)sectionType) {
|
||||
case kMovieImageDataSection:
|
||||
readImageData(chunk);
|
||||
break;
|
||||
|
||||
case kMovieFrameDataSection:
|
||||
readFrameData(chunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Unknown movie still section type", __func__);
|
||||
}
|
||||
|
||||
for (MovieFrame *frame : _frames) {
|
||||
if (frame->endInMilliseconds > _parent->_fullTime) {
|
||||
_parent->_fullTime = frame->endInMilliseconds;
|
||||
}
|
||||
if (frame->keepAfterEnd) {
|
||||
_parent->_hasStill = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_parent->_hasStill) {
|
||||
_parent->_framesNotYetShown = _frames;
|
||||
}
|
||||
}
|
||||
|
||||
StreamMovieActorSound::~StreamMovieActorSound() {
|
||||
unregisterWithStreamManager();
|
||||
}
|
||||
|
||||
void StreamMovieActorSound::readChunk(Chunk &chunk) {
|
||||
_audioSequence.readChunk(chunk);
|
||||
}
|
||||
|
||||
StreamMovieActor::StreamMovieActor() : _framesOnScreen(StreamMovieActor::compareFramesByZIndex), SpatialEntity(kActorTypeMovie) {
|
||||
_streamFrames = new StreamMovieActorFrames(this);
|
||||
_streamSound = new StreamMovieActorSound();
|
||||
}
|
||||
|
||||
void StreamMovieActor::readChunk(Chunk &chunk) {
|
||||
MovieSectionType sectionType = static_cast<MovieSectionType>(chunk.readTypedUint16());
|
||||
if (sectionType == kMovieRootSection) {
|
||||
parseMovieHeader(chunk);
|
||||
} else if (sectionType == kMovieChunkMarkerSection) {
|
||||
parseMovieChunkMarker(chunk);
|
||||
} else {
|
||||
error("%s: Got unused movie chunk header section", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamMovieActor::parseMovieHeader(Chunk &chunk) {
|
||||
_chunkCount = chunk.readTypedUint16();
|
||||
_frameRate = chunk.readTypedDouble();
|
||||
debugC(5, kDebugLoading, "%s: chunkCount = 0x%x, frameRate = %f (@0x%llx)", __func__, _chunkCount, _frameRate, static_cast<long long int>(chunk.pos()));
|
||||
|
||||
Common::Array<uint> chunkLengths;
|
||||
for (uint i = 0; i < _chunkCount; i++) {
|
||||
uint chunkLength = chunk.readTypedUint32();
|
||||
debugC(5, kDebugLoading, "StreamMovieActor::readSubfile(): chunkLength = 0x%x (@0x%llx)", chunkLength, static_cast<long long int>(chunk.pos()));
|
||||
chunkLengths.push_back(chunkLength);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamMovieActor::parseMovieChunkMarker(Chunk &chunk) {
|
||||
// TODO: There is no warning here because that would spam with thousands of warnings.
|
||||
// This takes care of scheduling stream load and such - it doesn't actually read from the
|
||||
// chunk that is passed in. Since we don't need that scheduling since we are currently reading
|
||||
// the whole movie at once rather than streaming it from the CD-ROM, we don't currently need
|
||||
// to do much here anyway.
|
||||
}
|
||||
|
||||
void StreamMovieActor::invalidateRect(const Common::Rect &rect) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
|
||||
void StreamMovieActor::decompressIntoAuxImage(MovieFrame *frame) {
|
||||
const Common::Point origin(0, 0);
|
||||
frame->keyframeImage->_image.create(frame->keyframeImage->width(), frame->keyframeImage->height(), Graphics::PixelFormat::createFormatCLUT8());
|
||||
frame->keyframeImage->_image.setTransparentColor(0);
|
||||
g_engine->getDisplayManager()->imageBlit(origin, frame->keyframeImage, 1.0, nullptr, &frame->keyframeImage->_image);
|
||||
}
|
||||
|
||||
void StreamMovieActorFrames::readImageData(Chunk &chunk) {
|
||||
MovieFrameHeader *header = new MovieFrameHeader(chunk);
|
||||
MovieFrameImage *frame = new MovieFrameImage(chunk, header);
|
||||
_images.push_back(frame);
|
||||
}
|
||||
|
||||
void StreamMovieActorFrames::readFrameData(Chunk &chunk) {
|
||||
uint frameDataToRead = chunk.readTypedUint16();
|
||||
for (uint i = 0; i < frameDataToRead; i++) {
|
||||
MovieFrame *frame = new MovieFrame(chunk);
|
||||
|
||||
// We cannot use a hashmap here because multiple frames can have the
|
||||
// same index, and frames are not necessarily in index order. So we'll
|
||||
// do a linear search, which is how the original does it.
|
||||
for (MovieFrameImage *image : _images) {
|
||||
if (image->index() == frame->index) {
|
||||
frame->image = image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->keyframeIndex != 0) {
|
||||
for (MovieFrameImage *image : _images) {
|
||||
if (image->index() == frame->keyframeIndex) {
|
||||
frame->keyframeImage = image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_frames.push_back(frame);
|
||||
}
|
||||
}
|
||||
|
||||
int StreamMovieActor::compareFramesByZIndex(const MovieFrame *a, const MovieFrame *b) {
|
||||
if (b->zIndex > a->zIndex) {
|
||||
return 1;
|
||||
} else if (a->zIndex > b->zIndex) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
167
engines/mediastation/actors/movie.h
Normal file
167
engines/mediastation/actors/movie.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_MOVIE_H
|
||||
#define MEDIASTATION_MOVIE_H
|
||||
|
||||
#include "common/array.h"
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/audio.h"
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/bitmap.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum MovieBlitType {
|
||||
kInvalidMovieBlit = 0,
|
||||
kUncompressedMovieBlit = 1,
|
||||
kUncompressedDeltaMovieBlit = 2,
|
||||
kCompressedDeltaMovieBlit = 3,
|
||||
};
|
||||
|
||||
class MovieFrameHeader : public BitmapHeader {
|
||||
public:
|
||||
MovieFrameHeader(Chunk &chunk);
|
||||
|
||||
uint _index = 0;
|
||||
uint _keyframeEndInMilliseconds = 0;
|
||||
};
|
||||
|
||||
class MovieFrameImage : public Bitmap {
|
||||
public:
|
||||
MovieFrameImage(Chunk &chunk, MovieFrameHeader *header);
|
||||
virtual ~MovieFrameImage() override;
|
||||
|
||||
uint32 index() { return _bitmapHeader->_index; }
|
||||
|
||||
private:
|
||||
MovieFrameHeader *_bitmapHeader = nullptr;
|
||||
};
|
||||
|
||||
enum MovieSectionType {
|
||||
kMovieRootSection = 0x06a8,
|
||||
kMovieImageDataSection = 0x06a9,
|
||||
kMovieFrameDataSection = 0x06aa,
|
||||
kMovieChunkMarkerSection = 0x06ab
|
||||
};
|
||||
|
||||
struct MovieFrame {
|
||||
MovieFrame(Chunk &chunk);
|
||||
uint unk3 = 0;
|
||||
uint unk4 = 0;
|
||||
uint layerId = 0;
|
||||
uint startInMilliseconds = 0;
|
||||
uint endInMilliseconds = 0;
|
||||
Common::Point leftTop;
|
||||
Common::Point diffBetweenKeyframeAndFrame;
|
||||
MovieBlitType blitType = kInvalidMovieBlit;
|
||||
int16 zIndex = 0;
|
||||
uint keyframeIndex = 0;
|
||||
bool keepAfterEnd = false;
|
||||
uint index = 0;
|
||||
MovieFrameImage *image = nullptr;
|
||||
MovieFrameImage *keyframeImage = nullptr;
|
||||
};
|
||||
|
||||
class StreamMovieActor;
|
||||
|
||||
// This is called `RT_stmvFrames` in the original.
|
||||
class StreamMovieActorFrames : public ChannelClient {
|
||||
public:
|
||||
StreamMovieActorFrames(StreamMovieActor *parent) : ChannelClient(), _parent(parent) {}
|
||||
~StreamMovieActorFrames();
|
||||
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
|
||||
Common::Array<MovieFrame *> _frames;
|
||||
Common::Array<MovieFrameImage *> _images;
|
||||
|
||||
private:
|
||||
StreamMovieActor *_parent = nullptr;
|
||||
|
||||
void readImageData(Chunk &chunk);
|
||||
void readFrameData(Chunk &chunk);
|
||||
};
|
||||
|
||||
// This is called `RT_stmvSound` in the original.
|
||||
class StreamMovieActorSound : public ChannelClient {
|
||||
public:
|
||||
~StreamMovieActorSound();
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
|
||||
AudioSequence _audioSequence;
|
||||
};
|
||||
|
||||
class StreamMovieActor : public SpatialEntity, public ChannelClient {
|
||||
friend class StreamMovieActorFrames;
|
||||
friend class StreamMovieActorSound;
|
||||
|
||||
public:
|
||||
StreamMovieActor();
|
||||
virtual ~StreamMovieActor() override;
|
||||
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
virtual void process() override;
|
||||
|
||||
virtual void draw(DisplayContext &displayContext) override;
|
||||
|
||||
virtual bool isVisible() const override { return _isVisible; }
|
||||
|
||||
private:
|
||||
ImtStreamFeed *_streamFeed = nullptr;
|
||||
uint _fullTime = 0;
|
||||
uint _chunkCount = 0;
|
||||
double _frameRate = 0;
|
||||
|
||||
uint _loadType = 0;
|
||||
bool _isPlaying = false;
|
||||
bool _hasStill = false;
|
||||
|
||||
StreamMovieActorFrames *_streamFrames = nullptr;
|
||||
StreamMovieActorSound *_streamSound = nullptr;
|
||||
|
||||
Common::Array<MovieFrame *> _framesNotYetShown;
|
||||
Common::SortedArray<MovieFrame *, const MovieFrame *> _framesOnScreen;
|
||||
|
||||
// Script method implementations.
|
||||
void timePlay();
|
||||
void timeStop();
|
||||
|
||||
void setVisibility(bool visibility);
|
||||
void updateFrameState();
|
||||
void invalidateRect(const Common::Rect &rect);
|
||||
void decompressIntoAuxImage(MovieFrame *frame);
|
||||
|
||||
void parseMovieHeader(Chunk &chunk);
|
||||
void parseMovieChunkMarker(Chunk &chunk);
|
||||
|
||||
Common::Rect getFrameBoundingBox(MovieFrame *frame);
|
||||
static int compareFramesByZIndex(const MovieFrame *a, const MovieFrame *b);
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
47
engines/mediastation/actors/palette.cpp
Normal file
47
engines/mediastation/actors/palette.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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 "mediastation/mediastation.h"
|
||||
#include "mediastation/actors/palette.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
PaletteActor::~PaletteActor() {
|
||||
delete _palette;
|
||||
_palette = nullptr;
|
||||
}
|
||||
|
||||
void PaletteActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderPalette: {
|
||||
byte *buffer = new byte[Graphics::PALETTE_SIZE];
|
||||
chunk.read(buffer, Graphics::PALETTE_SIZE);
|
||||
_palette = new Graphics::Palette(buffer, Graphics::PALETTE_COUNT, DisposeAfterUse::YES);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Actor::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
45
engines/mediastation/actors/palette.h
Normal file
45
engines/mediastation/actors/palette.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_PALETTE_H
|
||||
#define MEDIASTATION_PALETTE_H
|
||||
|
||||
#include "graphics/palette.h"
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class PaletteActor : public Actor {
|
||||
public:
|
||||
PaletteActor() : Actor(kActorTypePalette) {};
|
||||
virtual ~PaletteActor() override;
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
|
||||
Graphics::Palette *_palette = nullptr;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
165
engines/mediastation/actors/path.cpp
Normal file
165
engines/mediastation/actors/path.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/* 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 "mediastation/actors/path.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
void PathActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderStartPoint:
|
||||
_startPoint = chunk.readTypedPoint();
|
||||
break;
|
||||
|
||||
case kActorHeaderEndPoint:
|
||||
_endPoint = chunk.readTypedPoint();
|
||||
break;
|
||||
|
||||
case kActorHeaderStepRate: {
|
||||
double _stepRateFloat = chunk.readTypedDouble();
|
||||
// This should always be an integer anyway,
|
||||
// so we'll cast away any fractional part.
|
||||
_stepRate = static_cast<uint32>(_stepRateFloat);
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderDuration:
|
||||
// These are stored in the file as fractional seconds,
|
||||
// but we want milliseconds.
|
||||
_duration = static_cast<uint32>(chunk.readTypedTime() * 1000);
|
||||
break;
|
||||
|
||||
case kActorHeaderPathTotalSteps:
|
||||
_totalSteps = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
default:
|
||||
Actor::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue PathActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
switch (methodId) {
|
||||
case kTimePlayMethod: {
|
||||
assert(args.size() == 0);
|
||||
timePlay();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSetDurationMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint durationInMilliseconds = static_cast<uint>(args[0].asTime() * 1000);
|
||||
setDuration(durationInMilliseconds);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kPercentCompleteMethod: {
|
||||
assert(args.size() == 0);
|
||||
returnValue.setToFloat(percentComplete());
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kIsPlayingMethod: {
|
||||
assert(args.empty());
|
||||
returnValue.setToBool(_isPlaying);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return Actor::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
void PathActor::timePlay() {
|
||||
if (_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_duration == 0) {
|
||||
warning("%s: Got zero duration", __func__);
|
||||
} else if (_stepRate == 0) {
|
||||
error("%s: Got zero step rate", __func__);
|
||||
}
|
||||
|
||||
_isPlaying = true;
|
||||
_startTime = g_system->getMillis();
|
||||
_lastProcessedTime = 0;
|
||||
_percentComplete = 0;
|
||||
_nextPathStepTime = 0;
|
||||
_currentStep = 0;
|
||||
_totalSteps = (_duration * _stepRate) / 1000;
|
||||
_stepDurationInMilliseconds = 1000 / _stepRate;
|
||||
|
||||
// TODO: Run the path start event. Haven't seen one the wild yet, don't know its ID.
|
||||
debugC(5, kDebugScript, "Path::timePlay(): No PathStart event handler");
|
||||
}
|
||||
|
||||
void PathActor::process() {
|
||||
if (!_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint currentTime = g_system->getMillis();
|
||||
uint pathTime = currentTime - _startTime;
|
||||
|
||||
bool doNextStep = pathTime >= _nextPathStepTime;
|
||||
if (!doNextStep) {
|
||||
return;
|
||||
}
|
||||
|
||||
_percentComplete = static_cast<double>(_currentStep + 1) / _totalSteps;
|
||||
debugC(2, kDebugScript, "Path::timePlay(): Step %d of %d", _currentStep, _totalSteps);
|
||||
|
||||
if (_currentStep < _totalSteps) {
|
||||
// TODO: Actually step the path. It seems they mostly just use this for
|
||||
// palette animation in the On Step event handler, so nothing is actually drawn on the screen now.
|
||||
|
||||
// We don't run a step event for the last step.
|
||||
runEventHandlerIfExists(kPathStepEvent);
|
||||
_nextPathStepTime = ++_currentStep * _stepDurationInMilliseconds;
|
||||
} else {
|
||||
_isPlaying = false;
|
||||
_percentComplete = 0;
|
||||
_nextPathStepTime = 0;
|
||||
_currentStep = 0;
|
||||
_totalSteps = 0;
|
||||
_stepDurationInMilliseconds = 0;
|
||||
|
||||
runEventHandlerIfExists(kPathEndEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void PathActor::setDuration(uint durationInMilliseconds) {
|
||||
// TODO: Do we need to save the original duration?
|
||||
debugC(5, kDebugScript, "Path::setDuration(): Setting duration to %d ms", durationInMilliseconds);
|
||||
_duration = durationInMilliseconds;
|
||||
}
|
||||
|
||||
double PathActor::percentComplete() {
|
||||
debugC(5, kDebugScript, "Path::percentComplete(): Returning percent complete %f%%", _percentComplete * 100);
|
||||
return _percentComplete;
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
61
engines/mediastation/actors/path.h
Normal file
61
engines/mediastation/actors/path.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_PATH_H
|
||||
#define MEDIASTATION_PATH_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class PathActor : public Actor {
|
||||
public:
|
||||
PathActor() : Actor(kActorTypePath) {};
|
||||
|
||||
virtual void process() override;
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
|
||||
private:
|
||||
double _percentComplete = 0.0;
|
||||
uint _totalSteps = 0;
|
||||
uint _currentStep = 0;
|
||||
uint _nextPathStepTime = 0;
|
||||
uint _stepDurationInMilliseconds = 0;
|
||||
bool _isPlaying = false;
|
||||
|
||||
Common::Point _startPoint;
|
||||
Common::Point _endPoint;
|
||||
uint32 _stepRate = 0;
|
||||
uint32 _duration = 0;
|
||||
|
||||
// Method implementations.
|
||||
void timePlay();
|
||||
void setDuration(uint durationInMilliseconds);
|
||||
double percentComplete();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
42
engines/mediastation/actors/screen.cpp
Normal file
42
engines/mediastation/actors/screen.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 "mediastation/actors/screen.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
void ScreenActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderCursorResourceId:
|
||||
_cursorResourceId = chunk.readTypedUint16();
|
||||
if (_cursorResourceId != 0) {
|
||||
g_engine->getCursorManager()->registerAsPermanent(_cursorResourceId);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Actor::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
45
engines/mediastation/actors/screen.h
Normal file
45
engines/mediastation/actors/screen.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_SCREEN_H
|
||||
#define MEDIASTATION_SCREEN_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
// A Screen holds actor data and processes event handlers for a Context.
|
||||
// The original separated them this way - there is a ContextParameters section,
|
||||
// then a Screen actor header.
|
||||
class ScreenActor : public Actor {
|
||||
public:
|
||||
ScreenActor() : Actor(kActorTypeScreen) {};
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
|
||||
uint _cursorResourceId = 0;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
149
engines/mediastation/actors/sound.cpp
Normal file
149
engines/mediastation/actors/sound.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/* 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 "mediastation/audio.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/actors/sound.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
SoundActor::~SoundActor() {
|
||||
unregisterWithStreamManager();
|
||||
if (_streamFeed != nullptr) {
|
||||
g_engine->getStreamFeedManager()->closeStreamFeed(_streamFeed);
|
||||
_streamFeed = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderActorId: {
|
||||
// We already have this actor's ID, so we will just verify it is the same
|
||||
// as the ID we have already read.
|
||||
uint32 duplicateActorId = chunk.readTypedUint16();
|
||||
if (duplicateActorId != _id) {
|
||||
warning("Duplicate actor ID %d does not match original ID %d", duplicateActorId, _id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderChannelIdent:
|
||||
_channelIdent = chunk.readTypedChannelIdent();
|
||||
registerWithStreamManager();
|
||||
break;
|
||||
|
||||
case kActorHeaderHasOwnSubfile:
|
||||
_hasOwnSubfile = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderSoundInfo:
|
||||
_sequence.readParameters(chunk);
|
||||
break;
|
||||
|
||||
case kActorHeaderMovieLoadType:
|
||||
_loadType = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
default:
|
||||
Actor::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundActor::process() {
|
||||
if (!_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
processTimeEventHandlers();
|
||||
if (!_sequence.isActive()) {
|
||||
_isPlaying = false;
|
||||
_sequence.stop();
|
||||
runEventHandlerIfExists(kSoundEndEvent);
|
||||
}
|
||||
}
|
||||
void SoundActor::readChunk(Chunk &chunk) {
|
||||
_isLoadedFromChunk = true;
|
||||
_sequence.readChunk(chunk);
|
||||
}
|
||||
|
||||
ScriptValue SoundActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
switch (methodId) {
|
||||
case kSpatialShowMethod:
|
||||
// WORKAROUND: No-op to avoid triggering error on Dalmatians
|
||||
// timer_6c06_AnsweringMachine, which calls SpatialShow on a sound.
|
||||
// Since the engine is currently flagging errors on unimplemented
|
||||
// methods for easier debugging, a no-op is used here to avoid the error.
|
||||
assert(args.empty());
|
||||
return returnValue;
|
||||
|
||||
case kTimePlayMethod: {
|
||||
assert(args.empty());
|
||||
timePlay();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kTimeStopMethod: {
|
||||
assert(args.empty());
|
||||
timeStop();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return Actor::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundActor::timePlay() {
|
||||
if (_streamFeed == nullptr && !_isLoadedFromChunk) {
|
||||
_streamFeed = g_engine->getStreamFeedManager()->openStreamFeed(_id);
|
||||
_streamFeed->readData();
|
||||
}
|
||||
|
||||
if (_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_sequence.isEmpty()) {
|
||||
_isPlaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_isPlaying = true;
|
||||
_startTime = g_system->getMillis();
|
||||
_lastProcessedTime = 0;
|
||||
_sequence.play();
|
||||
runEventHandlerIfExists(kSoundBeginEvent);
|
||||
}
|
||||
|
||||
void SoundActor::timeStop() {
|
||||
if (!_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isPlaying = false;
|
||||
_sequence.stop();
|
||||
runEventHandlerIfExists(kSoundStoppedEvent);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
59
engines/mediastation/actors/sound.h
Normal file
59
engines/mediastation/actors/sound.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_ACTORS_SOUND_H
|
||||
#define MEDIASTATION_ACTORS_SOUND_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/audio.h"
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class SoundActor : public Actor, public ChannelClient {
|
||||
public:
|
||||
SoundActor() : Actor(kActorTypeSound) {};
|
||||
~SoundActor();
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
virtual void process() override;
|
||||
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
|
||||
private:
|
||||
ImtStreamFeed *_streamFeed = nullptr;
|
||||
bool _isLoadedFromChunk = false;
|
||||
uint _loadType = 0;
|
||||
bool _hasOwnSubfile = false;
|
||||
bool _isPlaying = false;
|
||||
AudioSequence _sequence;
|
||||
|
||||
// Script method implementations
|
||||
void timePlay();
|
||||
void timeStop();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
387
engines/mediastation/actors/sprite.cpp
Normal file
387
engines/mediastation/actors/sprite.cpp
Normal file
@@ -0,0 +1,387 @@
|
||||
/* 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 "mediastation/actors/sprite.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
SpriteFrameHeader::SpriteFrameHeader(Chunk &chunk) : BitmapHeader(chunk) {
|
||||
_index = chunk.readTypedUint16();
|
||||
_offset = chunk.readTypedPoint();
|
||||
}
|
||||
|
||||
SpriteFrame::SpriteFrame(Chunk &chunk, SpriteFrameHeader *header) : Bitmap(chunk, header) {
|
||||
_bitmapHeader = header;
|
||||
}
|
||||
|
||||
SpriteFrame::~SpriteFrame() {
|
||||
// The base class destructor takes care of deleting the bitmap header.
|
||||
}
|
||||
|
||||
uint32 SpriteFrame::left() {
|
||||
return _bitmapHeader->_offset.x;
|
||||
}
|
||||
|
||||
uint32 SpriteFrame::top() {
|
||||
return _bitmapHeader->_offset.y;
|
||||
}
|
||||
|
||||
Common::Point SpriteFrame::topLeft() {
|
||||
return Common::Point(left(), top());
|
||||
}
|
||||
|
||||
Common::Rect SpriteFrame::boundingBox() {
|
||||
return Common::Rect(topLeft(), width(), height());
|
||||
}
|
||||
|
||||
uint32 SpriteFrame::index() {
|
||||
return _bitmapHeader->_index;
|
||||
}
|
||||
|
||||
SpriteAsset::~SpriteAsset() {
|
||||
for (SpriteFrame *frame : frames) {
|
||||
delete frame;
|
||||
}
|
||||
}
|
||||
|
||||
SpriteMovieActor::~SpriteMovieActor() {
|
||||
unregisterWithStreamManager();
|
||||
}
|
||||
|
||||
void SpriteMovieActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderChannelIdent:
|
||||
_channelIdent = chunk.readTypedChannelIdent();
|
||||
registerWithStreamManager();
|
||||
_asset = Common::SharedPtr<SpriteAsset>(new SpriteAsset);
|
||||
break;
|
||||
|
||||
case kActorHeaderFrameRate:
|
||||
_frameRate = static_cast<uint32>(chunk.readTypedDouble());
|
||||
break;
|
||||
|
||||
case kActorHeaderLoadType:
|
||||
_loadType = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
case kActorHeaderStartup:
|
||||
_isVisible = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderSpriteChunkCount: {
|
||||
_frameCount = chunk.readTypedUint16();
|
||||
|
||||
// Set the default clip.
|
||||
SpriteClip clip;
|
||||
clip.id = DEFAULT_CLIP_ID;
|
||||
clip.firstFrameIndex = 0;
|
||||
clip.lastFrameIndex = _frameCount - 1;
|
||||
_clips.setVal(clip.id, clip);
|
||||
setCurrentClip(clip.id);
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderSpriteClip: {
|
||||
SpriteClip spriteClip;
|
||||
spriteClip.id = chunk.readTypedUint16();
|
||||
spriteClip.firstFrameIndex = chunk.readTypedUint16();
|
||||
spriteClip.lastFrameIndex = chunk.readTypedUint16();
|
||||
_clips.setVal(spriteClip.id, spriteClip);
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderCurrentSpriteClip: {
|
||||
uint clipId = chunk.readTypedUint16();
|
||||
setCurrentClip(clipId);
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderActorReference: {
|
||||
_actorReference = chunk.readTypedUint16();
|
||||
Actor *referencedActor = g_engine->getActorById(_actorReference);
|
||||
if (referencedActor == nullptr) {
|
||||
error("%s: Referenced actor %d doesn't exist or has not been read yet in this title", __func__, _actorReference);
|
||||
}
|
||||
if (referencedActor->type() != kActorTypeSprite) {
|
||||
error("%s: Type mismatch of referenced actor %d", __func__, _actorReference);
|
||||
}
|
||||
SpriteMovieActor *referencedSprite = static_cast<SpriteMovieActor *>(referencedActor);
|
||||
_asset = referencedSprite->_asset;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue SpriteMovieActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
switch (methodId) {
|
||||
case kSpatialShowMethod: {
|
||||
assert(args.empty());
|
||||
setVisibility(true);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSpatialHideMethod: {
|
||||
assert(args.empty());
|
||||
setVisibility(false);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kTimePlayMethod: {
|
||||
assert(args.empty());
|
||||
play();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kTimeStopMethod: {
|
||||
assert(args.empty());
|
||||
stop();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kMovieResetMethod: {
|
||||
assert(args.empty());
|
||||
setCurrentFrameToInitial();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSetCurrentClipMethod: {
|
||||
assert(args.size() <= 1);
|
||||
uint clipId = DEFAULT_CLIP_ID;
|
||||
if (args.size() == 1) {
|
||||
clipId = args[0].asParamToken();
|
||||
}
|
||||
setCurrentClip(clipId);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kIncrementFrameMethod: {
|
||||
assert(args.size() <= 1);
|
||||
bool loopAround = false;
|
||||
if (args.size() == 1) {
|
||||
loopAround = args[0].asBool();
|
||||
}
|
||||
|
||||
bool moreFrames = activateNextFrame();
|
||||
if (!moreFrames) {
|
||||
if (loopAround) {
|
||||
setCurrentFrameToInitial();
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kDecrementFrameMethod: {
|
||||
bool shouldSetCurrentFrameToFinal = false;
|
||||
if (args.size() == 1) {
|
||||
shouldSetCurrentFrameToFinal = args[0].asBool();
|
||||
}
|
||||
|
||||
bool moreFrames = activatePreviousFrame();
|
||||
if (!moreFrames) {
|
||||
if (shouldSetCurrentFrameToFinal) {
|
||||
setCurrentFrameToFinal();
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kGetCurrentClipIdMethod: {
|
||||
returnValue.setToParamToken(_activeClip.id);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kIsPlayingMethod: {
|
||||
returnValue.setToBool(_isPlaying);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return SpatialEntity::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
bool SpriteMovieActor::activateNextFrame() {
|
||||
if (_currentFrameIndex < _activeClip.lastFrameIndex) {
|
||||
_currentFrameIndex++;
|
||||
dirtyIfVisible();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpriteMovieActor::activatePreviousFrame() {
|
||||
if (_currentFrameIndex > _activeClip.firstFrameIndex) {
|
||||
_currentFrameIndex--;
|
||||
dirtyIfVisible();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SpriteMovieActor::dirtyIfVisible() {
|
||||
if (_isVisible) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMovieActor::setVisibility(bool visibility) {
|
||||
if (_isVisible != visibility) {
|
||||
_isVisible = visibility;
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMovieActor::play() {
|
||||
_isPlaying = true;
|
||||
_startTime = g_system->getMillis();
|
||||
_lastProcessedTime = 0;
|
||||
_nextFrameTime = 0;
|
||||
|
||||
scheduleNextFrame();
|
||||
}
|
||||
|
||||
void SpriteMovieActor::stop() {
|
||||
_nextFrameTime = 0;
|
||||
_isPlaying = false;
|
||||
}
|
||||
|
||||
void SpriteMovieActor::setCurrentClip(uint clipId) {
|
||||
if (_activeClip.id != clipId) {
|
||||
if (_clips.contains(clipId)) {
|
||||
_activeClip = _clips.getVal(clipId);
|
||||
} else {
|
||||
_activeClip.id = clipId;
|
||||
warning("%s: Sprite clip %d not found in sprite %d", __func__, clipId, _id);
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentFrameToInitial();
|
||||
}
|
||||
|
||||
void SpriteMovieActor::setCurrentFrameToInitial() {
|
||||
if (_currentFrameIndex != _activeClip.firstFrameIndex) {
|
||||
_currentFrameIndex = _activeClip.firstFrameIndex;
|
||||
dirtyIfVisible();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMovieActor::setCurrentFrameToFinal() {
|
||||
if (_currentFrameIndex != _activeClip.lastFrameIndex) {
|
||||
_currentFrameIndex = _activeClip.lastFrameIndex;
|
||||
dirtyIfVisible();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMovieActor::process() {
|
||||
updateFrameState();
|
||||
// Sprites don't have time event handlers, separate timers do time handling.
|
||||
}
|
||||
|
||||
void SpriteMovieActor::readChunk(Chunk &chunk) {
|
||||
// Reads one frame from the sprite.
|
||||
debugC(5, kDebugLoading, "Sprite::readFrame(): Reading sprite frame (@0x%llx)", static_cast<long long int>(chunk.pos()));
|
||||
SpriteFrameHeader *header = new SpriteFrameHeader(chunk);
|
||||
SpriteFrame *frame = new SpriteFrame(chunk, header);
|
||||
_asset->frames.push_back(frame);
|
||||
|
||||
// TODO: Are these in exactly reverse order? If we can just reverse the
|
||||
// whole thing once.
|
||||
Common::sort(_asset->frames.begin(), _asset->frames.end(), [](SpriteFrame *a, SpriteFrame *b) {
|
||||
return a->index() < b->index();
|
||||
});
|
||||
}
|
||||
|
||||
void SpriteMovieActor::scheduleNextFrame() {
|
||||
if (!_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentFrameIndex < _activeClip.lastFrameIndex) {
|
||||
scheduleNextTimerEvent();
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMovieActor::scheduleNextTimerEvent() {
|
||||
uint frameDuration = 1000 / _frameRate;
|
||||
_nextFrameTime += frameDuration;
|
||||
}
|
||||
|
||||
void SpriteMovieActor::updateFrameState() {
|
||||
if (!_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint currentTime = g_system->getMillis() - _startTime;
|
||||
bool drawNextFrame = currentTime >= _nextFrameTime;
|
||||
debugC(kDebugGraphics, "nextFrameTime: %d; startTime: %d, currentTime: %d", _nextFrameTime, _startTime, currentTime);
|
||||
if (drawNextFrame) {
|
||||
timerEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMovieActor::timerEvent() {
|
||||
if (!_isPlaying) {
|
||||
error("%s: Attempt to activate sprite frame when sprite is not playing", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
bool result = activateNextFrame();
|
||||
if (!result) {
|
||||
stop();
|
||||
} else {
|
||||
postMovieEndEventIfNecessary();
|
||||
scheduleNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMovieActor::postMovieEndEventIfNecessary() {
|
||||
if (_currentFrameIndex != _activeClip.lastFrameIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isPlaying = false;
|
||||
_startTime = 0;
|
||||
_nextFrameTime = 0;
|
||||
|
||||
ScriptValue value;
|
||||
value.setToParamToken(_activeClip.id);
|
||||
runEventHandlerIfExists(kSpriteMovieEndEvent, value);
|
||||
}
|
||||
|
||||
void SpriteMovieActor::draw(DisplayContext &displayContext) {
|
||||
SpriteFrame *activeFrame = _asset->frames[_currentFrameIndex];
|
||||
if (_isVisible) {
|
||||
Common::Rect frameBbox = activeFrame->boundingBox();
|
||||
frameBbox.translate(_boundingBox.left, _boundingBox.top);
|
||||
g_engine->getDisplayManager()->imageBlit(frameBbox.origin(), activeFrame, _dissolveFactor, &displayContext);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
126
engines/mediastation/actors/sprite.h
Normal file
126
engines/mediastation/actors/sprite.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_SPRITE_H
|
||||
#define MEDIASTATION_SPRITE_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/array.h"
|
||||
#include "common/ptr.h"
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/bitmap.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
struct SpriteClip {
|
||||
uint id = 0;
|
||||
uint firstFrameIndex = 0;
|
||||
uint lastFrameIndex = 0;
|
||||
};
|
||||
|
||||
class SpriteFrameHeader : public BitmapHeader {
|
||||
public:
|
||||
SpriteFrameHeader(Chunk &chunk);
|
||||
|
||||
uint _index;
|
||||
Common::Point _offset;
|
||||
};
|
||||
|
||||
class SpriteFrame : public Bitmap {
|
||||
public:
|
||||
SpriteFrame(Chunk &chunk, SpriteFrameHeader *header);
|
||||
virtual ~SpriteFrame() override;
|
||||
|
||||
uint32 left();
|
||||
uint32 top();
|
||||
Common::Point topLeft();
|
||||
Common::Rect boundingBox();
|
||||
uint32 index();
|
||||
|
||||
private:
|
||||
SpriteFrameHeader *_bitmapHeader = nullptr;
|
||||
};
|
||||
|
||||
// The original had a separate class that did reference counting,
|
||||
// for sharing an asset across actors, but we can just use a SharedPtr.
|
||||
struct SpriteAsset {
|
||||
~SpriteAsset();
|
||||
|
||||
Common::Array<SpriteFrame *> frames;
|
||||
};
|
||||
|
||||
// Sprites are somewhat like movies, but they strictly show one frame at a time
|
||||
// and don't have sound. They are intended for background/recurrent animations.
|
||||
class SpriteMovieActor : public SpatialEntity, public ChannelClient {
|
||||
public:
|
||||
SpriteMovieActor() : SpatialEntity(kActorTypeSprite) {};
|
||||
~SpriteMovieActor();
|
||||
|
||||
virtual void process() override;
|
||||
virtual void draw(DisplayContext &displayContext) override;
|
||||
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
|
||||
virtual bool isVisible() const override { return _isVisible; }
|
||||
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
|
||||
private:
|
||||
static const uint DEFAULT_CLIP_ID = 1200;
|
||||
uint _loadType = 0;
|
||||
uint _frameRate = 0;
|
||||
uint _frameCount = 0;
|
||||
uint _actorReference = 0;
|
||||
Common::HashMap<uint, SpriteClip> _clips;
|
||||
Common::SharedPtr<SpriteAsset> _asset;
|
||||
bool _isPlaying = false;
|
||||
uint _currentFrameIndex = 0;
|
||||
uint _nextFrameTime = 0;
|
||||
SpriteClip _activeClip;
|
||||
|
||||
void play();
|
||||
void stop();
|
||||
void setCurrentClip(uint clipId);
|
||||
|
||||
bool activateNextFrame();
|
||||
bool activatePreviousFrame();
|
||||
|
||||
void dirtyIfVisible();
|
||||
void setCurrentFrameToInitial();
|
||||
void setCurrentFrameToFinal();
|
||||
|
||||
void scheduleNextFrame();
|
||||
void scheduleNextTimerEvent();
|
||||
void postMovieEndEventIfNecessary();
|
||||
void setVisibility(bool visibility);
|
||||
|
||||
void updateFrameState();
|
||||
void timerEvent();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
817
engines/mediastation/actors/stage.cpp
Normal file
817
engines/mediastation/actors/stage.cpp
Normal file
@@ -0,0 +1,817 @@
|
||||
/* 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 "mediastation/mediastation.h"
|
||||
#include "mediastation/actors/camera.h"
|
||||
#include "mediastation/actors/stage.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
StageActor::StageActor() : SpatialEntity(kActorTypeStage),
|
||||
_children(StageActor::compareSpatialActorByZIndex),
|
||||
_cameras(StageActor::compareSpatialActorByZIndex) {
|
||||
}
|
||||
|
||||
StageActor::~StageActor() {
|
||||
removeAllChildren();
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->removeChildSpatialEntity(this);
|
||||
}
|
||||
_currentCamera = nullptr;
|
||||
}
|
||||
|
||||
void StageActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderChildActorId: {
|
||||
// In stages, this basically has the oppose meaning it has outside of stages. Here,
|
||||
// it specifies an actor that is a parent of this stage.
|
||||
uint parentActorId = chunk.readTypedUint16();
|
||||
_pendingParent = g_engine->getSpatialEntityById(parentActorId);
|
||||
break;
|
||||
}
|
||||
|
||||
case kActorHeaderStageExtent:
|
||||
_extent = chunk.readTypedGraphicSize();
|
||||
break;
|
||||
|
||||
case kActorHeaderCylindricalX:
|
||||
_cylindricalX = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderCylindricalY:
|
||||
_cylindricalY = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::preload(const Common::Rect &rect) {
|
||||
if (cylindricalX()) {
|
||||
preloadTest(rect, kWrapLeft);
|
||||
}
|
||||
if (cylindricalY()) {
|
||||
preloadTest(rect, kWrapTop);
|
||||
}
|
||||
if (cylindricalX() && cylindricalY()) {
|
||||
preloadTest(rect, kWrapLeftTop);
|
||||
}
|
||||
preloadTest(rect, kWrapNone);
|
||||
}
|
||||
|
||||
void StageActor::preloadTest(const Common::Rect &rect, CylindricalWrapMode wrapMode) {
|
||||
for (SpatialEntity *entity : _children) {
|
||||
entity->setAdjustedBounds(wrapMode);
|
||||
if (!entity->isRectInMemory(rect) && !entity->isLoading()) {
|
||||
entity->preload(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool StageActor::isRectInMemory(const Common::Rect &rect) {
|
||||
bool result = true;
|
||||
if (cylindricalX()) {
|
||||
result = isRectInMemoryTest(rect, kWrapLeft);
|
||||
}
|
||||
if (result && cylindricalY()) {
|
||||
result = isRectInMemoryTest(rect, kWrapTop);
|
||||
}
|
||||
if (result && cylindricalY() && cylindricalX()) {
|
||||
result = isRectInMemoryTest(rect, kWrapLeftTop);
|
||||
}
|
||||
if (result) {
|
||||
result = isRectInMemoryTest(rect, kWrapNone);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StageActor::isRectInMemoryTest(const Common::Rect &rect, CylindricalWrapMode wrapMode) {
|
||||
for (SpatialEntity *entity : _children) {
|
||||
entity->setAdjustedBounds(wrapMode);
|
||||
if (!entity->isRectInMemory(rect)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void StageActor::draw(DisplayContext &displayContext) {
|
||||
Clip *currentClip = displayContext.currentClip();
|
||||
if (currentClip != nullptr) {
|
||||
Clip *previousClip = displayContext.previousClip();
|
||||
if (previousClip == nullptr) {
|
||||
currentClip->addToRegion(currentClip->_bounds);
|
||||
} else {
|
||||
currentClip = previousClip;
|
||||
}
|
||||
}
|
||||
|
||||
displayContext.intersectClipWith(getBbox());
|
||||
if (displayContext.clipIsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool boundsNeedsAdjustment = false;
|
||||
Common::Rect bounds = getBbox();
|
||||
if (bounds.left != 0 || bounds.top != 0) {
|
||||
boundsNeedsAdjustment = true;
|
||||
}
|
||||
if (boundsNeedsAdjustment) {
|
||||
displayContext.pushOrigin();
|
||||
displayContext._origin.x = bounds.left + displayContext._origin.x;
|
||||
displayContext._origin.y = bounds.top + displayContext._origin.y;
|
||||
}
|
||||
|
||||
if (_cameras.empty()) {
|
||||
drawUsingStage(displayContext);
|
||||
} else {
|
||||
for (CameraActor *camera : _cameras) {
|
||||
setCurrentCamera(camera);
|
||||
camera->drawUsingCamera(displayContext, _children);
|
||||
}
|
||||
}
|
||||
|
||||
if (boundsNeedsAdjustment) {
|
||||
displayContext.popOrigin();
|
||||
}
|
||||
displayContext.emptyCurrentClip();
|
||||
}
|
||||
|
||||
void StageActor::drawUsingStage(DisplayContext &displayContext) {
|
||||
for (SpatialEntity *entity : _children) {
|
||||
entity->setAdjustedBounds(kWrapNone);
|
||||
if (entity->isVisible()) {
|
||||
if (displayContext.rectIsInClip(entity->getBbox())) {
|
||||
debugC(5, kDebugGraphics, "%s: Redrawing actor %d", __func__, entity->id());
|
||||
entity->draw(displayContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::invalidateRect(const Common::Rect &rect) {
|
||||
if (_parentStage != nullptr) {
|
||||
Common::Point origin = _boundingBox.origin();
|
||||
Common::Rect rectRelativeToParent = rect;
|
||||
rectRelativeToParent.translate(origin.x, origin.y);
|
||||
|
||||
if (_cameras.size() == 0) {
|
||||
_parentStage->invalidateRect(rectRelativeToParent);
|
||||
} else {
|
||||
invalidateUsingCameras(rectRelativeToParent);
|
||||
}
|
||||
} else {
|
||||
error("%s: Attempt to invalidate rect without a parent stage", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::invalidateUsingCameras(const Common::Rect &rect) {
|
||||
for (CameraActor *camera : _cameras) {
|
||||
Common::Rect adjustedRectToInvalidate = rect;
|
||||
Common::Rect cameraBounds = camera->getBbox();
|
||||
|
||||
Common::Rect cameraBoundsInStageCoordinates = cameraBounds;
|
||||
Common::Rect stageOrigin = getBbox();
|
||||
cameraBoundsInStageCoordinates.translate(stageOrigin.left, stageOrigin.top);
|
||||
|
||||
Common::Point cameraViewportOrigin = camera->getViewportOrigin();
|
||||
Common::Point viewportOffsetFromCameraBounds(
|
||||
cameraViewportOrigin.x - cameraBounds.left,
|
||||
cameraViewportOrigin.y - cameraBounds.top
|
||||
);
|
||||
|
||||
adjustedRectToInvalidate.translate(
|
||||
-viewportOffsetFromCameraBounds.x,
|
||||
-viewportOffsetFromCameraBounds.y
|
||||
);
|
||||
invalidateObject(adjustedRectToInvalidate, cameraBoundsInStageCoordinates);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::invalidateObject(const Common::Rect &rect, const Common::Rect &visibleRegion) {
|
||||
Common::Point xyAdjustment(0, 0);
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
|
||||
if (_cylindricalX) {
|
||||
xyAdjustment.x = _extent.x;
|
||||
xyAdjustment.y = 0;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
|
||||
xyAdjustment.x = -_extent.x;
|
||||
xyAdjustment.y = 0;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
}
|
||||
|
||||
if (_cylindricalY) {
|
||||
xyAdjustment.x = 0;
|
||||
xyAdjustment.y = _extent.y;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
|
||||
xyAdjustment.x = 0;
|
||||
xyAdjustment.y = -_extent.y;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
}
|
||||
|
||||
if (_cylindricalX && _cylindricalY) {
|
||||
xyAdjustment.x = _extent.x;
|
||||
xyAdjustment.y = _extent.y;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
|
||||
xyAdjustment.x = -_extent.x;
|
||||
xyAdjustment.y = -_extent.y;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
|
||||
xyAdjustment.x = -_extent.x;
|
||||
xyAdjustment.y = _extent.y;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
|
||||
xyAdjustment.x = _extent.x;
|
||||
xyAdjustment.y = -_extent.y;
|
||||
invalidateTest(rect, visibleRegion, xyAdjustment);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::invalidateTest(const Common::Rect &rect, const Common::Rect &visibleRegion, const Common::Point &originAdjustment) {
|
||||
Common::Rect rectToInvalidateRelative = rect;
|
||||
rectToInvalidateRelative.translate(-originAdjustment.x, -originAdjustment.y);
|
||||
rectToInvalidateRelative.clip(visibleRegion);
|
||||
_parentStage->invalidateRect(rectToInvalidateRelative);
|
||||
}
|
||||
|
||||
void StageActor::loadIsComplete() {
|
||||
// This is deliberately calling down to Actor, rather than calling
|
||||
// to SpatialEntity first.
|
||||
Actor::loadIsComplete();
|
||||
|
||||
if (_pendingParent != nullptr) {
|
||||
if (_pendingParent->type() != kActorTypeStage) {
|
||||
error("%s: Parent must be a stage", __func__);
|
||||
}
|
||||
StageActor *parentStage = static_cast<StageActor *>(_pendingParent);
|
||||
parentStage->addChildSpatialEntity(this);
|
||||
_pendingParent = nullptr;
|
||||
}
|
||||
|
||||
if (_extent.x == 0 || _extent.y == 0) {
|
||||
_extent.x = _boundingBox.width();
|
||||
_extent.y = _boundingBox.height();
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::addActorToStage(uint actorId) {
|
||||
// If actor has a current parent, remove it from that parent first.
|
||||
SpatialEntity *spatialEntity = g_engine->getSpatialEntityById(actorId);
|
||||
StageActor *currentParent = spatialEntity->getParentStage();
|
||||
if (currentParent != nullptr) {
|
||||
currentParent->removeChildSpatialEntity(spatialEntity);
|
||||
}
|
||||
addChildSpatialEntity(spatialEntity);
|
||||
}
|
||||
|
||||
void StageActor::removeActorFromStage(uint actorId) {
|
||||
SpatialEntity *spatialEntity = g_engine->getSpatialEntityById(actorId);
|
||||
StageActor *currentParent = spatialEntity->getParentStage();
|
||||
if (currentParent == this) {
|
||||
// Remove the actor from this stage, and add it back to the root stage.
|
||||
removeChildSpatialEntity(spatialEntity);
|
||||
RootStage *rootStage = g_engine->getRootStage();
|
||||
rootStage->addChildSpatialEntity(spatialEntity);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::addCamera(CameraActor *camera) {
|
||||
_cameras.insert(camera);
|
||||
}
|
||||
|
||||
void StageActor::removeCamera(CameraActor *camera) {
|
||||
for (auto it = _cameras.begin(); it != _cameras.end(); ++it) {
|
||||
if (*it == camera) {
|
||||
_cameras.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::setCurrentCamera(CameraActor *camera) {
|
||||
_currentCamera = camera;
|
||||
}
|
||||
|
||||
ScriptValue StageActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
switch (methodId) {
|
||||
case kAddActorToStageMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint actorId = args[0].asActorId();
|
||||
addActorToStage(actorId);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kRemoveActorFromStageMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint actorId = args[0].asActorId();
|
||||
removeActorFromStage(actorId);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSetBoundsMethod: {
|
||||
assert(args.size() == 4);
|
||||
int16 x = static_cast<int16>(args[0].asFloat());
|
||||
int16 y = static_cast<int16>(args[1].asFloat());
|
||||
int16 width = static_cast<int16>(args[2].asFloat());
|
||||
int16 height = static_cast<int16>(args[3].asFloat());
|
||||
Common::Rect newBounds(Common::Point(x, y), width, height);
|
||||
setBounds(newBounds);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kStageSetSizeMethod:
|
||||
assert(args.size() == 2);
|
||||
_boundingBox.setWidth(static_cast<int16>(args[0].asFloat()));
|
||||
_boundingBox.setHeight(static_cast<int16>(args[1].asFloat()));
|
||||
return returnValue;
|
||||
|
||||
case kStageGetWidthMethod:
|
||||
returnValue.setToFloat(_boundingBox.width());
|
||||
return returnValue;
|
||||
|
||||
case kStageGetHeightMethod:
|
||||
returnValue.setToFloat(_boundingBox.height());
|
||||
return returnValue;
|
||||
|
||||
default:
|
||||
return SpatialEntity::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::addChildSpatialEntity(SpatialEntity *entity) {
|
||||
if (!assertHasNoParent(entity)) {
|
||||
error("%s: Attempt to add entity that already has a parent", __func__);
|
||||
}
|
||||
|
||||
entity->setParentStage(this);
|
||||
_children.insert(entity);
|
||||
|
||||
if (isVisible()) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::removeChildSpatialEntity(SpatialEntity *entity) {
|
||||
if (!assertIsMyChild(entity)) {
|
||||
error("%s: Attempt to remove entity that is not a child", __func__);
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
|
||||
entity->setToNoParentStage();
|
||||
for (auto it = _children.begin(); it != _children.end(); ++it) {
|
||||
if (*it == entity) {
|
||||
_children.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16 StageActor::queryChildrenAboutMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
CylindricalWrapMode wrapMode) {
|
||||
|
||||
uint16 result = 0;
|
||||
Common::Point adjustedPoint = point - _boundingBox.origin();
|
||||
for (auto childIterator = _children.end(); childIterator != _children.begin();) {
|
||||
--childIterator; // Decrement first, then dereference
|
||||
SpatialEntity *child = *childIterator;
|
||||
debugC(7, kDebugEvents, " %s: Checking actor %d (z-index: %d) (eventMask: 0x%02x) (result: 0x%02x) (wrapMode: %d)", __func__, child->id(), child->zIndex(), eventMask, result, wrapMode);
|
||||
|
||||
child->setAdjustedBounds(wrapMode);
|
||||
uint16 handledEvents = child->findActorToAcceptMouseEvents(adjustedPoint, eventMask, state, true);
|
||||
child->setAdjustedBounds(kWrapNone);
|
||||
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16 StageActor::findActorToAcceptMouseEventsObject(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) {
|
||||
|
||||
uint16 result = 0;
|
||||
|
||||
uint16 handledEvents = queryChildrenAboutMouseEvents(point, eventMask, state, kWrapNone);
|
||||
if (handledEvents != 0) {
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
|
||||
if ((eventMask != 0) && cylindricalX()) {
|
||||
handledEvents = queryChildrenAboutMouseEvents(point, eventMask, state, kWrapLeft);
|
||||
if (handledEvents != 0) {
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
}
|
||||
|
||||
if ((eventMask != 0) && cylindricalX()) {
|
||||
handledEvents = queryChildrenAboutMouseEvents(point, eventMask, state, kWrapRight);
|
||||
if (handledEvents != 0) {
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
}
|
||||
|
||||
if ((eventMask != 0) && cylindricalY()) {
|
||||
handledEvents = queryChildrenAboutMouseEvents(point, eventMask, state, kWrapTop);
|
||||
if (handledEvents != 0) {
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
}
|
||||
|
||||
if ((eventMask != 0) && cylindricalY()) {
|
||||
handledEvents = queryChildrenAboutMouseEvents(point, eventMask, state, kWrapBottom);
|
||||
if (handledEvents != 0) {
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
}
|
||||
|
||||
if ((eventMask != 0) && cylindricalY() && cylindricalX()) {
|
||||
handledEvents = queryChildrenAboutMouseEvents(point, eventMask, state, kWrapLeftTop);
|
||||
if (handledEvents != 0) {
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
}
|
||||
|
||||
if ((eventMask != 0) && cylindricalY() && cylindricalX()) {
|
||||
handledEvents = queryChildrenAboutMouseEvents(point, eventMask, state, kWrapRightBottom);
|
||||
if (handledEvents != 0) {
|
||||
result |= handledEvents;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16 StageActor::findActorToAcceptMouseEventsCamera(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) {
|
||||
|
||||
uint16 result = 0;
|
||||
for (CameraActor *camera : _cameras) {
|
||||
Common::Point mousePosRelativeToCamera = point;
|
||||
setCurrentCamera(camera);
|
||||
|
||||
Common::Point cameraViewportOrigin = camera->getViewportOrigin();
|
||||
mousePosRelativeToCamera.x += cameraViewportOrigin.x;
|
||||
mousePosRelativeToCamera.y += cameraViewportOrigin.y;
|
||||
|
||||
if (!inBounds) {
|
||||
Common::Rect viewportBounds = camera->getViewportBounds();
|
||||
if (!viewportBounds.contains(mousePosRelativeToCamera)) {
|
||||
inBounds = true;
|
||||
}
|
||||
}
|
||||
|
||||
result = findActorToAcceptMouseEventsObject(mousePosRelativeToCamera, eventMask, state, inBounds);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16 StageActor::findActorToAcceptMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) {
|
||||
|
||||
debugC(6, kDebugEvents, " --- %s ---", __func__);
|
||||
|
||||
Common::Point mousePosAdjustedByStageOrigin = point;
|
||||
mousePosAdjustedByStageOrigin.x -= _boundingBox.left;
|
||||
mousePosAdjustedByStageOrigin.y -= _boundingBox.top;
|
||||
|
||||
uint16 result;
|
||||
if (_cameras.empty()) {
|
||||
if (!inBounds) {
|
||||
if (!_boundingBox.contains(point)) {
|
||||
inBounds = true;
|
||||
}
|
||||
}
|
||||
result = queryChildrenAboutMouseEvents(mousePosAdjustedByStageOrigin, eventMask, state, kWrapNone);
|
||||
} else {
|
||||
result = findActorToAcceptMouseEventsCamera(mousePosAdjustedByStageOrigin, eventMask, state, inBounds);
|
||||
}
|
||||
|
||||
debugC(6, kDebugEvents, " --- END %s ---", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16 StageActor::findActorToAcceptKeyboardEvents(
|
||||
uint16 asciiCode,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state) {
|
||||
|
||||
uint16 result = 0;
|
||||
for (SpatialEntity *child : _children) {
|
||||
uint16 handledEvents = child->findActorToAcceptKeyboardEvents(asciiCode, eventMask, state);
|
||||
if (handledEvents != 0) {
|
||||
eventMask &= ~handledEvents;
|
||||
result |= handledEvents;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StageActor::assertHasNoParent(const SpatialEntity *entity) {
|
||||
// Make sure entity is not in our children.
|
||||
for (SpatialEntity *child : _children) {
|
||||
if (child == entity) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure entity doesn't have a parent.
|
||||
if (entity->getParentStage() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StageActor::removeAllChildren() {
|
||||
for (SpatialEntity *child : _children) {
|
||||
child->setToNoParentStage();
|
||||
}
|
||||
_children.clear();
|
||||
}
|
||||
|
||||
void StageActor::setMousePosition(int16 x, int16 y) {
|
||||
if (_parentStage != nullptr) {
|
||||
x += _boundingBox.left;
|
||||
y += _boundingBox.top;
|
||||
_parentStage->setMousePosition(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::invalidateLocalBounds() {
|
||||
for (SpatialEntity *child : _children) {
|
||||
if (child->isVisible()) {
|
||||
child->invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::invalidateLocalZIndex() {
|
||||
if (_parentStage != nullptr) {
|
||||
_parentStage->invalidateZIndexOf(this);
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::invalidateZIndexOf(const SpatialEntity *entity) {
|
||||
if (!assertIsMyChild(entity)) {
|
||||
error("%s: Attempt to invalidate local z-index of non-child", __func__);
|
||||
}
|
||||
|
||||
// Remove the entity from the sorted array and re-insert it at the correct position.
|
||||
for (auto it = _children.begin(); it != _children.end(); ++it) {
|
||||
if (*it == entity) {
|
||||
_children.erase(it);
|
||||
_children.insert(const_cast<SpatialEntity *>(entity));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the whole stage dirty since z-order changed.
|
||||
if (isVisible()) {
|
||||
invalidateLocalBounds();
|
||||
}
|
||||
}
|
||||
|
||||
int StageActor::compareSpatialActorByZIndex(const SpatialEntity *a, const SpatialEntity *b) {
|
||||
int diff = b->zIndex() - a->zIndex();
|
||||
if (diff < 0)
|
||||
return -1; // a should come before b
|
||||
else if (diff > 0)
|
||||
return 1; // b should come before a
|
||||
else {
|
||||
// If z-indices are equal, compare pointers for stable sort
|
||||
return (a < b) ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
void StageActor::currentMousePosition(Common::Point &point) {
|
||||
if (getParentStage() != nullptr) {
|
||||
getParentStage()->currentMousePosition(point);
|
||||
point -= getBbox().origin();
|
||||
}
|
||||
}
|
||||
|
||||
void RootStage::invalidateRect(const Common::Rect &rect) {
|
||||
Common::Rect rectToAdd = rect;
|
||||
rectToAdd.clip(_boundingBox);
|
||||
_dirtyRegion.addRect(rectToAdd);
|
||||
}
|
||||
|
||||
void RootStage::currentMousePosition(Common::Point &point) {
|
||||
point = g_engine->getEventManager()->getMousePos();
|
||||
point -= getBbox().origin();
|
||||
}
|
||||
|
||||
void RootStage::drawAll(DisplayContext &displayContext) {
|
||||
StageActor::draw(displayContext);
|
||||
}
|
||||
|
||||
void RootStage::drawDirtyRegion(DisplayContext &displayContext) {
|
||||
displayContext.setClipTo(_dirtyRegion);
|
||||
StageActor::draw(displayContext);
|
||||
displayContext.emptyCurrentClip();
|
||||
}
|
||||
|
||||
uint16 RootStage::findActorToAcceptMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) {
|
||||
|
||||
// Handle any mouse moved events.
|
||||
uint16 result = StageActor::findActorToAcceptMouseEvents(point, eventMask, state, inBounds);
|
||||
eventMask &= ~result;
|
||||
if (eventMask & kMouseEnterFlag) {
|
||||
state.mouseEnter = this;
|
||||
result |= kMouseEnterFlag;
|
||||
}
|
||||
if (eventMask & kMouseOutOfFocusFlag) {
|
||||
state.mouseOutOfFocus = this;
|
||||
result |= kMouseOutOfFocusFlag;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RootStage::mouseEnteredEvent(const Common::Event &event) {
|
||||
_isMouseInside = true;
|
||||
g_engine->getCursorManager()->unsetTemporary();
|
||||
}
|
||||
|
||||
void RootStage::mouseExitedEvent(const Common::Event &event) {
|
||||
_isMouseInside = false;
|
||||
}
|
||||
|
||||
void RootStage::mouseOutOfFocusEvent(const Common::Event &event) {
|
||||
_isMouseInside = true;
|
||||
g_engine->getCursorManager()->unsetTemporary();
|
||||
}
|
||||
|
||||
void RootStage::deleteChildrenFromContextId(uint contextId) {
|
||||
for (auto it = _children.begin(); it != _children.end();) {
|
||||
uint actorContextId = (*it)->contextId();
|
||||
if (actorContextId == contextId) {
|
||||
it = _children.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RootStage::setMousePosition(int16 x, int16 y) {
|
||||
x += _boundingBox.left;
|
||||
y += _boundingBox.top;
|
||||
warning("%s: STUB: (%d, %d)", __func__, x, y);
|
||||
}
|
||||
|
||||
StageDirector::StageDirector() {
|
||||
_rootStage = new RootStage;
|
||||
Common::Rect rootStageBounds(MediaStationEngine::SCREEN_WIDTH, MediaStationEngine::SCREEN_HEIGHT);
|
||||
_rootStage->setBounds(rootStageBounds);
|
||||
g_engine->registerActor(_rootStage);
|
||||
}
|
||||
|
||||
StageDirector::~StageDirector() {
|
||||
g_engine->destroyActor(RootStage::ROOT_STAGE_ACTOR_ID);
|
||||
_rootStage = nullptr;
|
||||
}
|
||||
|
||||
void StageDirector::drawAll() {
|
||||
_rootStage->drawAll(g_engine->getDisplayManager()->_displayContext);
|
||||
}
|
||||
|
||||
void StageDirector::drawDirtyRegion() {
|
||||
_rootStage->drawDirtyRegion(g_engine->getDisplayManager()->_displayContext);
|
||||
}
|
||||
|
||||
void StageDirector::clearDirtyRegion() {
|
||||
_rootStage->_dirtyRegion._rects.clear();
|
||||
_rootStage->_dirtyRegion._bounds = Common::Rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void StageDirector::handleKeyboardEvent(const Common::Event &event) {
|
||||
MouseActorState state;
|
||||
uint16 flags = _rootStage->findActorToAcceptKeyboardEvents(event.kbd.ascii, kKeyDownFlag, state);
|
||||
if (flags & kKeyDownFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching to actor %d", __func__, state.keyDown->id());
|
||||
state.keyDown->keyboardEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void StageDirector::handleMouseDownEvent(const Common::Event &event) {
|
||||
MouseActorState state;
|
||||
uint16 flags = _rootStage->findActorToAcceptMouseEvents(event.mouse, kMouseDownFlag, state, false);
|
||||
if (flags & kMouseDownFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching to actor %d", __func__, state.mouseDown->id());
|
||||
state.mouseDown->mouseDownEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void StageDirector::handleMouseUpEvent(const Common::Event &event) {
|
||||
MouseActorState state;
|
||||
uint16 flags = _rootStage->findActorToAcceptMouseEvents(event.mouse, kMouseUpFlag, state, false);
|
||||
if (flags & kMouseUpFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching to actor %d", __func__, state.mouseUp->id());
|
||||
state.mouseUp->mouseUpEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void StageDirector::handleMouseMovedEvent(const Common::Event &event) {
|
||||
MouseActorState state;
|
||||
uint16 flags = _rootStage->findActorToAcceptMouseEvents(
|
||||
event.mouse,
|
||||
kMouseEnterFlag | kMouseExitFlag | kMouseMovedFlag,
|
||||
state, false);
|
||||
debugC(5, kDebugEvents, "%s: Calling sendMouseEnterExitEvent", __func__);
|
||||
|
||||
sendMouseEnterExitEvent(flags, state, event);
|
||||
if (flags & kMouseMovedFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching mouse moved to actor %d", __func__, state.mouseMoved->id());
|
||||
state.mouseMoved->mouseMovedEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void StageDirector::handleMouseEnterExitEvent(const Common::Event &event) {
|
||||
MouseActorState state;
|
||||
uint16 flags = _rootStage->findActorToAcceptMouseEvents(event.mouse, kMouseEnterFlag | kMouseExitFlag, state, false);
|
||||
sendMouseEnterExitEvent(flags, state, event);
|
||||
}
|
||||
|
||||
void StageDirector::handleMouseOutOfFocusEvent(const Common::Event &event) {
|
||||
MouseActorState state;
|
||||
uint16 flags = _rootStage->findActorToAcceptMouseEvents(event.mouse, kMouseExitFlag | kMouseOutOfFocusFlag, state, false);
|
||||
|
||||
if (flags & kMouseExitFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching mouse enter to actor %d", __func__, state.mouseExit->id());
|
||||
state.mouseExit->mouseExitedEvent(event);
|
||||
}
|
||||
|
||||
if (flags & kMouseOutOfFocusFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching mouse out of focus to actor %d", __func__, state.mouseOutOfFocus->id());
|
||||
state.mouseOutOfFocus->mouseOutOfFocusEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void StageDirector::sendMouseEnterExitEvent(uint16 flags, MouseActorState &state, const Common::Event &event) {
|
||||
if (state.mouseMoved != state.mouseEnter || state.mouseMoved != state.mouseExit) {
|
||||
if (flags & kMouseEnterFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching mouse enter to actor %d", __func__, state.mouseEnter->id());
|
||||
state.mouseEnter->mouseEnteredEvent(event);
|
||||
}
|
||||
|
||||
if (flags & kMouseExitFlag) {
|
||||
debugC(5, kDebugEvents, "%s: Dispatching mouse exit to actor %d", __func__, state.mouseExit->id());
|
||||
state.mouseExit->mouseExitedEvent(event);
|
||||
}
|
||||
} else {
|
||||
debugC(5, kDebugEvents, "%s: No hotspot to dispatch to", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
191
engines/mediastation/actors/stage.h
Normal file
191
engines/mediastation/actors/stage.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_STAGE_H
|
||||
#define MEDIASTATION_STAGE_H
|
||||
|
||||
#include "common/events.h"
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/graphics.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
// Cylindrical wrapping allows content on a stage to wrap around like a cylinder - for example, when you scroll past the
|
||||
// right edge, content from the left edge appears, creating the illusion of an infinite looping world.
|
||||
enum CylindricalWrapMode : int {
|
||||
kWrapNone = 0, // No offset (default)
|
||||
kWrapRight = 1, // Right wrap (X + extent.x)
|
||||
kWrapBottom = 2, // Bottom wrap (Y + extent.y)
|
||||
kWrapLeftTop = 3, // Left + Top wrap (X - extent.x, Y - extent.y)
|
||||
kWrapLeft = 4, // Left wrap (X - extent.x)
|
||||
kWrapRightBottom = 5, // Right + Bottom wrap (X + extent.x, Y + extent.y)
|
||||
kWrapTop = 6, // Top wrap (Y - extent.y)
|
||||
kWrapLeftBottom = 7, // Left + Bottom wrap (X - extent.x, Y + extent.y)
|
||||
kWrapRightTop = 8 // Right + Top wrap (X + extent.x, Y - extent.y)
|
||||
};
|
||||
|
||||
class CameraActor;
|
||||
class StageActor : public SpatialEntity {
|
||||
public:
|
||||
StageActor();
|
||||
virtual ~StageActor();
|
||||
|
||||
virtual void draw(DisplayContext &displayContext) override;
|
||||
void drawUsingStage(DisplayContext &displayContext);
|
||||
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual void preload(const Common::Rect &rect) override;
|
||||
virtual bool isVisible() const override { return _children.size() > 0; }
|
||||
virtual bool isRectInMemory(const Common::Rect &rect) override;
|
||||
|
||||
void addChildSpatialEntity(SpatialEntity *entity);
|
||||
void removeChildSpatialEntity(SpatialEntity *entity);
|
||||
void addCamera(CameraActor *camera);
|
||||
void removeCamera(CameraActor *camera);
|
||||
void setCurrentCamera(CameraActor *camera);
|
||||
CameraActor *getCurrentCamera() const { return _currentCamera; }
|
||||
|
||||
uint16 queryChildrenAboutMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
CylindricalWrapMode wrapMode = kWrapNone);
|
||||
uint16 findActorToAcceptMouseEventsObject(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds);
|
||||
uint16 findActorToAcceptMouseEventsCamera(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds);
|
||||
virtual uint16 findActorToAcceptMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) override;
|
||||
virtual uint16 findActorToAcceptKeyboardEvents(
|
||||
uint16 asciiCode,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state) override;
|
||||
virtual void currentMousePosition(Common::Point &point);
|
||||
virtual void setMousePosition(int16 x, int16 y) override;
|
||||
|
||||
void invalidateZIndexOf(const SpatialEntity *entity);
|
||||
virtual void invalidateLocalBounds() override;
|
||||
virtual void invalidateRect(const Common::Rect &rect);
|
||||
|
||||
bool cylindricalX() const { return _cylindricalX; }
|
||||
bool cylindricalY() const { return _cylindricalY; }
|
||||
Common::Point extent() const { return _extent; }
|
||||
|
||||
protected:
|
||||
// Whether or not cameras on this stage should wrap around this stage.
|
||||
bool _cylindricalX = false;
|
||||
bool _cylindricalY = false;
|
||||
Common::Point _extent;
|
||||
SpatialEntity *_pendingParent = nullptr;
|
||||
CameraActor *_currentCamera = nullptr;
|
||||
|
||||
void addActorToStage(uint actorId);
|
||||
void removeActorFromStage(uint actorId);
|
||||
bool isRectInMemoryTest(const Common::Rect &rect, CylindricalWrapMode wrapMode);
|
||||
void preloadTest(const Common::Rect &rect, CylindricalWrapMode wrapMode);
|
||||
|
||||
bool assertHasNoParent(const SpatialEntity *entity);
|
||||
bool assertHasParentThatIsNotMe(const SpatialEntity *entity) { return !assertIsMyChild(entity); }
|
||||
bool assertIsMyChild(const SpatialEntity *entity) { return this == entity->getParentStage();}
|
||||
void removeAllChildren();
|
||||
|
||||
virtual void invalidateLocalZIndex() override;
|
||||
void invalidateUsingCameras(const Common::Rect &rect);
|
||||
void invalidateObject(const Common::Rect &rect, const Common::Rect &visibleRegion);
|
||||
// The function is called this in the original; not sure why though.
|
||||
void invalidateTest(const Common::Rect &rect, const Common::Rect &clip, const Common::Point &originAdjustment);
|
||||
|
||||
virtual void loadIsComplete() override;
|
||||
|
||||
static int compareSpatialActorByZIndex(const SpatialEntity *a, const SpatialEntity *b);
|
||||
|
||||
Common::SortedArray<SpatialEntity *, const SpatialEntity *> _children;
|
||||
Common::SortedArray<CameraActor *, const SpatialEntity *> _cameras;
|
||||
};
|
||||
|
||||
class RootStage : public StageActor {
|
||||
public:
|
||||
friend class StageDirector;
|
||||
RootStage() : StageActor() { _id = ROOT_STAGE_ACTOR_ID; };
|
||||
|
||||
virtual uint16 findActorToAcceptMouseEvents(
|
||||
const Common::Point &point,
|
||||
uint16 eventMask,
|
||||
MouseActorState &state,
|
||||
bool inBounds) override;
|
||||
virtual void currentMousePosition(Common::Point &point) override;
|
||||
virtual void setMousePosition(int16 x, int16 y) override;
|
||||
virtual void invalidateRect(const Common::Rect &rect) override;
|
||||
virtual void deleteChildrenFromContextId(uint contextId);
|
||||
|
||||
virtual void mouseEnteredEvent(const Common::Event &event) override;
|
||||
virtual void mouseExitedEvent(const Common::Event &event) override;
|
||||
virtual void mouseOutOfFocusEvent(const Common::Event &event) override;
|
||||
|
||||
void drawAll(DisplayContext &displayContext);
|
||||
void drawDirtyRegion(DisplayContext &displayContext);
|
||||
|
||||
Region _dirtyRegion;
|
||||
|
||||
private:
|
||||
static const uint ROOT_STAGE_ACTOR_ID = 2;
|
||||
bool _isMouseInside = false;
|
||||
};
|
||||
|
||||
class StageDirector {
|
||||
public:
|
||||
StageDirector();
|
||||
~StageDirector();
|
||||
|
||||
RootStage *getRootStage() const { return _rootStage; }
|
||||
|
||||
void drawAll();
|
||||
void drawDirtyRegion();
|
||||
void clearDirtyRegion();
|
||||
|
||||
void handleKeyboardEvent(const Common::Event &event);
|
||||
void handleMouseDownEvent(const Common::Event &event);
|
||||
void handleMouseUpEvent(const Common::Event &event);
|
||||
void handleMouseMovedEvent(const Common::Event &event);
|
||||
void handleMouseEnterExitEvent(const Common::Event &event);
|
||||
void handleMouseOutOfFocusEvent(const Common::Event &event);
|
||||
void sendMouseEnterExitEvent(uint16 flags, MouseActorState &state, const Common::Event &event);
|
||||
|
||||
private:
|
||||
RootStage *_rootStage = nullptr;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
114
engines/mediastation/actors/text.cpp
Normal file
114
engines/mediastation/actors/text.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 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 "mediastation/actors/text.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
void TextActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
|
||||
switch (paramType) {
|
||||
case kActorHeaderStartup:
|
||||
_isVisible = static_cast<bool>(chunk.readTypedByte());
|
||||
break;
|
||||
|
||||
case kActorHeaderEditable:
|
||||
_editable = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
case kActorHeaderLoadType:
|
||||
_loadType = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
case kActorHeaderFontId:
|
||||
_fontActorId = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderTextMaxLength:
|
||||
_maxTextLength = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kActorHeaderInitialText:
|
||||
_text = chunk.readTypedString();
|
||||
break;
|
||||
|
||||
case kActorHeaderTextJustification:
|
||||
_justification = static_cast<TextJustification>(chunk.readTypedUint16());
|
||||
break;
|
||||
|
||||
case kActorHeaderTextPosition:
|
||||
_position = static_cast<TextPosition>(chunk.readTypedUint16());
|
||||
break;
|
||||
|
||||
case kActorHeaderTextCharacterClass: {
|
||||
CharacterClass characterClass;
|
||||
characterClass.firstAsciiCode = chunk.readTypedUint16();
|
||||
characterClass.lastAsciiCode = chunk.readTypedUint16();
|
||||
_acceptedInput.push_back(characterClass);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
SpatialEntity::readParameter(chunk, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue TextActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
switch (methodId) {
|
||||
case kTextMethod: {
|
||||
assert(args.empty());
|
||||
error("%s: Text() method not implemented yet", __func__);
|
||||
}
|
||||
|
||||
case kSetTextMethod: {
|
||||
assert(args.size() == 1);
|
||||
error("%s: getText() method not implemented yet", __func__);
|
||||
}
|
||||
|
||||
case kSpatialShowMethod: {
|
||||
assert(args.empty());
|
||||
_isVisible = true;
|
||||
warning("%s: spatialShow method not implemented yet", __func__);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kSpatialHideMethod: {
|
||||
assert(args.empty());
|
||||
_isVisible = false;
|
||||
warning("%s: spatialHide method not implemented yet", __func__);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return SpatialEntity::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
Common::String TextActor::text() const {
|
||||
return _text;
|
||||
}
|
||||
|
||||
void TextActor::setText(Common::String text) {
|
||||
error("%s: Setting text not implemented yet", __func__);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
76
engines/mediastation/actors/text.h
Normal file
76
engines/mediastation/actors/text.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_TEXT_H
|
||||
#define MEDIASTATION_TEXT_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum TextJustification {
|
||||
kTextJustificationLeft = 0x25c,
|
||||
kTextJustificationRight = 0x25d,
|
||||
kTextJustificationCenter = 0x25e
|
||||
};
|
||||
|
||||
enum TextPosition {
|
||||
kTextPositionMiddle = 0x25e,
|
||||
kTextPositionTop = 0x260,
|
||||
kTextPositionBotom = 0x261
|
||||
};
|
||||
|
||||
struct CharacterClass {
|
||||
uint firstAsciiCode = 0;
|
||||
uint lastAsciiCode = 0;
|
||||
};
|
||||
|
||||
class TextActor : public SpatialEntity {
|
||||
public:
|
||||
TextActor() : SpatialEntity(kActorTypeText) {};
|
||||
|
||||
virtual bool isVisible() const override { return _isVisible; }
|
||||
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
|
||||
private:
|
||||
bool _editable = false;
|
||||
uint _loadType = 0;
|
||||
bool _isVisible = false;
|
||||
Common::String _text;
|
||||
uint _maxTextLength = 0;
|
||||
uint _fontActorId = 0;
|
||||
TextJustification _justification;
|
||||
TextPosition _position;
|
||||
Common::Array<CharacterClass> _acceptedInput;
|
||||
|
||||
// Method implementations.
|
||||
Common::String text() const;
|
||||
void setText(Common::String text);
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
94
engines/mediastation/actors/timer.cpp
Normal file
94
engines/mediastation/actors/timer.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 "mediastation/mediastation.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
#include "mediastation/actors/timer.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
ScriptValue TimerActor::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
switch (methodId) {
|
||||
case kTimePlayMethod: {
|
||||
assert(args.size() == 0);
|
||||
timePlay();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kTimeStopMethod: {
|
||||
assert(args.size() == 0);
|
||||
timeStop();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kIsPlayingMethod: {
|
||||
assert(args.size() == 0);
|
||||
returnValue.setToBool(_isPlaying);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
return Actor::callMethod(methodId, args);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerActor::timePlay() {
|
||||
_isPlaying = true;
|
||||
_startTime = g_system->getMillis();
|
||||
_lastProcessedTime = 0;
|
||||
|
||||
// Get the duration of the timer.
|
||||
// TODO: Is there a better way to find out what the max time is? Do we have to look
|
||||
// through each of the timer event handlers to figure it out?
|
||||
_duration = 0;
|
||||
const Common::Array<EventHandler *> &timeHandlers = _eventHandlers.getValOrDefault(kTimerEvent);
|
||||
for (EventHandler *timeEvent : timeHandlers) {
|
||||
// Indeed float, not time.
|
||||
double timeEventInFractionalSeconds = timeEvent->_argumentValue.asFloat();
|
||||
uint timeEventInMilliseconds = timeEventInFractionalSeconds * 1000;
|
||||
if (timeEventInMilliseconds > _duration) {
|
||||
_duration = timeEventInMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
debugC(5, kDebugScript, "Timer::timePlay(): Now playing for %d ms", _duration);
|
||||
}
|
||||
|
||||
void TimerActor::timeStop() {
|
||||
if (!_isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isPlaying = false;
|
||||
_startTime = 0;
|
||||
_lastProcessedTime = 0;
|
||||
}
|
||||
|
||||
void TimerActor::process() {
|
||||
if (_isPlaying) {
|
||||
processTimeEventHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
47
engines/mediastation/actors/timer.h
Normal file
47
engines/mediastation/actors/timer.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_TIMER_H
|
||||
#define MEDIASTATION_TIMER_H
|
||||
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class TimerActor : public Actor {
|
||||
public:
|
||||
TimerActor() : Actor(kActorTypeTimer) {};
|
||||
|
||||
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
|
||||
virtual void process() override;
|
||||
|
||||
private:
|
||||
bool _isPlaying = false;
|
||||
|
||||
void timePlay();
|
||||
void timeStop();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
88
engines/mediastation/audio.cpp
Normal file
88
engines/mediastation/audio.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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 "audio/decoders/adpcm.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "mediastation/audio.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
AudioSequence::~AudioSequence() {
|
||||
g_engine->_mixer->stopHandle(_handle);
|
||||
|
||||
for (Audio::SeekableAudioStream *stream : _streams) {
|
||||
delete stream;
|
||||
}
|
||||
_streams.clear();
|
||||
}
|
||||
|
||||
void AudioSequence::play() {
|
||||
_handle = Audio::SoundHandle();
|
||||
if (!_streams.empty()) {
|
||||
Audio::QueuingAudioStream *audio = Audio::makeQueuingAudioStream(22050, false);
|
||||
for (Audio::SeekableAudioStream *stream : _streams) {
|
||||
stream->rewind();
|
||||
audio->queueAudioStream(stream, DisposeAfterUse::NO);
|
||||
}
|
||||
g_engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audio, -1, Audio::Mixer::kMaxChannelVolume, DisposeAfterUse::YES);
|
||||
audio->finish();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSequence::stop() {
|
||||
g_engine->_mixer->stopHandle(_handle);
|
||||
_handle = Audio::SoundHandle();
|
||||
}
|
||||
|
||||
void AudioSequence::readParameters(Chunk &chunk) {
|
||||
_chunkCount = chunk.readTypedUint16();
|
||||
_rate = chunk.readTypedUint32();
|
||||
_channelCount = chunk.readTypedUint16();
|
||||
_bitsPerSample = chunk.readTypedUint16();
|
||||
}
|
||||
|
||||
void AudioSequence::readChunk(Chunk &chunk) {
|
||||
Common::SeekableReadStream *buffer = chunk.readStream(chunk._length);
|
||||
Audio::SeekableAudioStream *stream = nullptr;
|
||||
switch (_bitsPerSample) {
|
||||
case 16:
|
||||
stream = Audio::makeRawStream(buffer, _rate, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN);
|
||||
break;
|
||||
|
||||
case 4: // IMA ADPCM-encoded, raw nibbles (no headers).
|
||||
stream = Audio::makeADPCMStream(buffer, DisposeAfterUse::YES, 0, Audio::kADPCMDVI, _rate, 1, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Unknown audio encoding 0x%x", __func__, static_cast<uint>(_bitsPerSample));
|
||||
}
|
||||
_streams.push_back(stream);
|
||||
debugC(5, kDebugLoading, "Finished reading audio chunk (@0x%llx)", static_cast<long long int>(chunk.pos()));
|
||||
}
|
||||
|
||||
bool AudioSequence::isActive() {
|
||||
return g_engine->_mixer->isSoundHandleActive(_handle);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
58
engines/mediastation/audio.h
Normal file
58
engines/mediastation/audio.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_AUDIO_H
|
||||
#define MEDIASTATION_AUDIO_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class AudioSequence {
|
||||
public:
|
||||
AudioSequence() {};
|
||||
~AudioSequence();
|
||||
|
||||
void play();
|
||||
void stop();
|
||||
|
||||
void readParameters(Chunk &chunk);
|
||||
void readChunk(Chunk &chunk);
|
||||
bool isActive();
|
||||
bool isEmpty() { return _streams.empty(); }
|
||||
|
||||
uint _rate = 0;
|
||||
uint _channelCount = 0;
|
||||
uint _bitsPerSample = 0;
|
||||
uint _chunkCount = 0;
|
||||
|
||||
private:
|
||||
Common::Array<Audio::SeekableAudioStream *> _streams;
|
||||
Audio::SoundHandle _handle;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
73
engines/mediastation/bitmap.cpp
Normal file
73
engines/mediastation/bitmap.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/* 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 "mediastation/bitmap.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
BitmapHeader::BitmapHeader(Chunk &chunk) {
|
||||
uint headerSizeInBytes = chunk.readTypedUint16();
|
||||
_dimensions = chunk.readTypedGraphicSize();
|
||||
_compressionType = static_cast<BitmapCompressionType>(chunk.readTypedUint16());
|
||||
_stride = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "BitmapHeader::BitmapHeader(): headerSize: %d, _compressionType = 0x%x, _stride = %d",
|
||||
headerSizeInBytes, static_cast<uint>(_compressionType), _stride);
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(Chunk &chunk, BitmapHeader *bitmapHeader) : _bitmapHeader(bitmapHeader) {
|
||||
if (stride() < width()) {
|
||||
warning("%s: Got stride less than width", __func__);
|
||||
}
|
||||
|
||||
_unk1 = chunk.readUint16LE();
|
||||
if (chunk.bytesRemaining() > 0) {
|
||||
if (isCompressed()) {
|
||||
_compressedStream = chunk.readStream(chunk.bytesRemaining());
|
||||
} else {
|
||||
_image.create(stride(), height(), Graphics::PixelFormat::createFormatCLUT8());
|
||||
if (getCompressionType() == kUncompressedTransparentBitmap)
|
||||
_image.setTransparentColor(0);
|
||||
byte *pixels = static_cast<byte *>(_image.getPixels());
|
||||
|
||||
chunk.read(pixels, stride() * height());
|
||||
if (chunk.bytesRemaining() > 0) {
|
||||
warning("%s: %d bytes remaining in bitmap chunk after reading image data", __func__, chunk.bytesRemaining());
|
||||
chunk.skip(chunk.bytesRemaining());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap::~Bitmap() {
|
||||
delete _bitmapHeader;
|
||||
_bitmapHeader = nullptr;
|
||||
|
||||
delete _compressedStream;
|
||||
_compressedStream = nullptr;
|
||||
}
|
||||
|
||||
bool Bitmap::isCompressed() const {
|
||||
return (getCompressionType() != kUncompressedBitmap) && \
|
||||
(getCompressionType() != kUncompressedTransparentBitmap);
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
71
engines/mediastation/bitmap.h
Normal file
71
engines/mediastation/bitmap.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_BITMAP_H
|
||||
#define MEDIASTATION_BITMAP_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/actor.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum BitmapCompressionType {
|
||||
kUncompressedBitmap = 0,
|
||||
kRle8BitmapCompression = 1,
|
||||
kCccBitmapCompression = 5,
|
||||
kCccTransparentBitmapCompression = 6,
|
||||
kUncompressedTransparentBitmap = 7,
|
||||
};
|
||||
|
||||
class BitmapHeader {
|
||||
public:
|
||||
BitmapHeader(Chunk &chunk);
|
||||
|
||||
Common::Point _dimensions;
|
||||
BitmapCompressionType _compressionType = kUncompressedBitmap;
|
||||
int16 _stride = 0;
|
||||
};
|
||||
|
||||
class Bitmap {
|
||||
public:
|
||||
Bitmap(Chunk &chunk, BitmapHeader *bitmapHeader);
|
||||
virtual ~Bitmap();
|
||||
|
||||
bool isCompressed() const;
|
||||
BitmapCompressionType getCompressionType() const { return _bitmapHeader->_compressionType; }
|
||||
int16 width() const { return _bitmapHeader->_dimensions.x; }
|
||||
int16 height() const { return _bitmapHeader->_dimensions.y; }
|
||||
int16 stride() const { return _bitmapHeader->_stride; }
|
||||
|
||||
Common::SeekableReadStream *_compressedStream = nullptr;
|
||||
Graphics::ManagedSurface _image;
|
||||
|
||||
private:
|
||||
BitmapHeader *_bitmapHeader = nullptr;
|
||||
uint _unk1 = 0;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
255
engines/mediastation/boot.cpp
Normal file
255
engines/mediastation/boot.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/* 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 "mediastation/boot.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
#pragma region ContextReference
|
||||
ContextReference::ContextReference(Chunk &chunk) {
|
||||
// Read the file number.
|
||||
ContextReferenceSectionType sectionType = getSectionType(chunk);
|
||||
if (kContextReferenceContextId != sectionType) {
|
||||
error("%s: Got unexpected section type %d", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_contextId = chunk.readTypedUint16();
|
||||
|
||||
sectionType = getSectionType(chunk);
|
||||
if (kContextReferenceStreamId != sectionType) {
|
||||
error("%s: Got unexpected section type %d", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_streamId = chunk.readTypedUint16();
|
||||
|
||||
// Read the context name. Only some titles have context names,
|
||||
// and unfortunately we can't determine which just by relying
|
||||
// on the title compiler version number.
|
||||
sectionType = getSectionType(chunk);
|
||||
if (kContextReferenceName == sectionType) {
|
||||
_name = chunk.readTypedString();
|
||||
sectionType = getSectionType(chunk);
|
||||
}
|
||||
|
||||
// Read the parent context IDs. We don't know how many file
|
||||
// references there are beforehand, so we'll just read until
|
||||
// we get something else.
|
||||
uint rewindOffset = chunk.pos();
|
||||
while (kContextReferenceParentContextId == sectionType) {
|
||||
int fileReference = chunk.readTypedUint16();
|
||||
_parentContextIds.push_back(fileReference);
|
||||
rewindOffset = chunk.pos();
|
||||
sectionType = getSectionType(chunk);
|
||||
}
|
||||
chunk.seek(rewindOffset);
|
||||
}
|
||||
|
||||
ContextReferenceSectionType ContextReference::getSectionType(Chunk &chunk) {
|
||||
return static_cast<ContextReferenceSectionType>(chunk.readTypedUint16());
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ScreenReference
|
||||
ScreenReference::ScreenReference(Chunk &chunk) {
|
||||
// Make sure this declaration isn't empty.
|
||||
ScreenReferenceSectionType sectionType = getSectionType(chunk);
|
||||
if (kScreenReferenceScreenId != sectionType) {
|
||||
error("%s: Got unexpected section type %d", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_screenActorId = chunk.readTypedUint16();
|
||||
|
||||
sectionType = getSectionType(chunk);
|
||||
if (kScreenReferenceContextId != sectionType) {
|
||||
error("%s: Got unexpected section type %d", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_contextId = chunk.readTypedUint16();
|
||||
}
|
||||
|
||||
ScreenReferenceSectionType ScreenReference::getSectionType(Chunk &chunk) {
|
||||
return static_cast<ScreenReferenceSectionType>(chunk.readTypedUint16());
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region FileInfo
|
||||
FileInfo::FileInfo(Chunk &chunk) {
|
||||
// Read the file ID.
|
||||
FileInfoSectionType sectionType = getSectionType(chunk);
|
||||
if (kFileInfoFileId != sectionType) {
|
||||
error("%s: Got unexpected section type %d", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_id = chunk.readTypedUint16();
|
||||
|
||||
// Read the intended file location.
|
||||
sectionType = getSectionType(chunk);
|
||||
if (kFileInfoFileNameAndType != sectionType) {
|
||||
error("%s: Got unexpected section type %d", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_intendedLocation = static_cast<IntendedFileLocation>(chunk.readTypedUint16());
|
||||
|
||||
// Since the platforms that Media Station originally targeted were case-insensitive,
|
||||
// the case of these filenames might not match the case of the files actually in
|
||||
// the directory. All files should be matched case-insensitively.
|
||||
_name = chunk.readTypedFilename();
|
||||
}
|
||||
|
||||
FileInfoSectionType FileInfo::getSectionType(Chunk &chunk) {
|
||||
return static_cast<FileInfoSectionType>(chunk.readTypedUint16());
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region StreamInfo
|
||||
StreamInfo::StreamInfo(Chunk &chunk) {
|
||||
// Read the actor ID.
|
||||
StreamInfoSectionType sectionType = getSectionType(chunk);
|
||||
if (kStreamInfoActorId != sectionType) {
|
||||
error("%s: Got unexpected section type %d", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_actorId = chunk.readTypedUint16();
|
||||
|
||||
// Read the file ID.
|
||||
sectionType = getSectionType(chunk);
|
||||
if (kStreamInfoFileId != sectionType) {
|
||||
error("%s: Expected section type FILE_ID, got 0x%x", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_fileId = chunk.readTypedUint16();
|
||||
|
||||
// Read the start offset from the absolute start of the file.
|
||||
sectionType = getSectionType(chunk);
|
||||
if (kStreamInfoStartOffset != sectionType) {
|
||||
error("%s: Expected section type START_OFFSET, got 0x%x", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
_startOffsetInFile = chunk.readTypedUint32();
|
||||
}
|
||||
|
||||
StreamInfoSectionType StreamInfo::getSectionType(Chunk &chunk) {
|
||||
return static_cast<StreamInfoSectionType>(chunk.readTypedUint16());
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CursorDeclaration
|
||||
CursorDeclaration::CursorDeclaration(Chunk &chunk) {
|
||||
uint16 unk1 = chunk.readTypedUint16(); // Always 0x0001
|
||||
_id = chunk.readTypedUint16();
|
||||
_unk = chunk.readTypedUint16();
|
||||
_name = chunk.readTypedFilename();
|
||||
debugC(5, kDebugLoading, " - CursorDeclaration(): unk1 = 0x%x, id = 0x%x, unk = 0x%x, name = %s", unk1, _id, _unk, _name.c_str());
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Boot
|
||||
void MediaStationEngine::readDocumentDef(Chunk &chunk) {
|
||||
BootSectionType sectionType = kBootLastSection;
|
||||
while (true) {
|
||||
sectionType = static_cast<BootSectionType>(chunk.readTypedUint16());
|
||||
if (sectionType == kBootLastSection) {
|
||||
break;
|
||||
}
|
||||
readDocumentInfoFromStream(chunk, sectionType);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readDocumentInfoFromStream(Chunk &chunk, BootSectionType sectionType) {
|
||||
switch (sectionType) {
|
||||
case kBootVersionInformation:
|
||||
readVersionInfoFromStream(chunk);
|
||||
break;
|
||||
|
||||
case kBootContextReference:
|
||||
readContextReferencesFromStream(chunk);
|
||||
break;
|
||||
|
||||
case kBootScreenReference:
|
||||
readScreenReferencesFromStream(chunk);
|
||||
break;
|
||||
|
||||
case kBootFileInfo:
|
||||
readAndAddFileMaps(chunk);
|
||||
break;
|
||||
|
||||
case kBootStreamInfo:
|
||||
readAndAddStreamMaps(chunk);
|
||||
break;
|
||||
|
||||
case kBootUnk1:
|
||||
_unk1 = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kBootFunctionTableSize:
|
||||
_functionTableSize = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
case kBootUnk3:
|
||||
_unk3 = chunk.readTypedUint16();
|
||||
break;
|
||||
|
||||
default:
|
||||
// See if any registered parameter clients know how to
|
||||
// handle this parameter.
|
||||
readUnrecognizedFromStream(chunk, static_cast<uint>(sectionType));
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readVersionInfoFromStream(Chunk &chunk) {
|
||||
_gameTitle = chunk.readTypedString();
|
||||
_versionInfo = chunk.readTypedVersion();
|
||||
_engineInfo = chunk.readTypedString();
|
||||
_sourceString = chunk.readTypedString();
|
||||
}
|
||||
|
||||
void MediaStationEngine::readContextReferencesFromStream(Chunk &chunk) {
|
||||
uint flag = chunk.readTypedUint16();
|
||||
while (flag != 0) {
|
||||
ContextReference contextReference(chunk);
|
||||
_contextReferences.setVal(contextReference._contextId, contextReference);
|
||||
flag = chunk.readTypedUint16();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readScreenReferencesFromStream(Chunk &chunk) {
|
||||
uint flag = chunk.readTypedUint16();
|
||||
while (flag != 0) {
|
||||
ScreenReference screenDeclaration(chunk);
|
||||
_screenReferences.setVal(screenDeclaration._screenActorId, screenDeclaration);
|
||||
flag = chunk.readTypedUint16();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readAndAddFileMaps(Chunk &chunk) {
|
||||
uint flag = chunk.readTypedUint16();
|
||||
while (flag != 0) {
|
||||
FileInfo fileDeclaration(chunk);
|
||||
_fileMap.setVal(fileDeclaration._id, fileDeclaration);
|
||||
flag = chunk.readTypedUint16();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readAndAddStreamMaps(Chunk &chunk) {
|
||||
uint flag = chunk.readTypedUint16();
|
||||
while (flag != 0) {
|
||||
StreamInfo subfileDeclaration(chunk);
|
||||
_streamMap.setVal(subfileDeclaration._actorId, subfileDeclaration);
|
||||
flag = chunk.readTypedUint16();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
} // End of namespace MediaStation
|
||||
161
engines/mediastation/boot.h
Normal file
161
engines/mediastation/boot.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_BOOT_H
|
||||
#define MEDIASTATION_BOOT_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/str.h"
|
||||
#include "common/array.h"
|
||||
#include "common/hashmap.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum ContextReferenceSectionType {
|
||||
kContextReferencePlaceholder = 0x0003,
|
||||
kContextReferenceContextId = 0x0004,
|
||||
kContextReferenceStreamId = 0x0005,
|
||||
kContextReferenceParentContextId = 0x0006,
|
||||
kContextReferenceName = 0x0bb8
|
||||
};
|
||||
|
||||
class ContextReference {
|
||||
public:
|
||||
ContextReference(Chunk &chunk);
|
||||
ContextReference() {};
|
||||
|
||||
uint _contextId = 0;
|
||||
uint _streamId = 0;
|
||||
Common::String _name;
|
||||
Common::Array<uint> _parentContextIds;
|
||||
|
||||
private:
|
||||
ContextReferenceSectionType getSectionType(Chunk &chunk);
|
||||
};
|
||||
|
||||
enum ScreenReferenceSectionType {
|
||||
kScreenReferenceScreenId = 0x0009,
|
||||
kScreenReferenceContextId = 0x0004
|
||||
};
|
||||
|
||||
class ScreenReference {
|
||||
public:
|
||||
ScreenReference(Chunk &chunk);
|
||||
ScreenReference() {};
|
||||
|
||||
uint _screenActorId = 0;
|
||||
uint _contextId = 0;
|
||||
|
||||
private:
|
||||
ScreenReferenceSectionType getSectionType(Chunk &chunk);
|
||||
};
|
||||
|
||||
enum FileInfoSectionType {
|
||||
kFileInfoEmptySection = 0x0000,
|
||||
kFileInfoFileId = 0x002b,
|
||||
kFileInfoFileNameAndType = 0x002d
|
||||
};
|
||||
|
||||
// Indicates where a file is intended to be stored.
|
||||
// NOTE: This might not be correct and this might be a more general "file type".
|
||||
enum IntendedFileLocation {
|
||||
kFileLocationEmpty = 0x0000,
|
||||
// Usually all files that have numbers remain on the CD-ROM.
|
||||
kFileIntendedOnCdRom = 0x0007,
|
||||
// These UNKs only appear in George Shrinks.
|
||||
kFileIntendedForUnk1 = 0x0008,
|
||||
kFileIntendedForUnk2 = 0x0009,
|
||||
// Usually only INSTALL.CXT is copied to the hard disk.
|
||||
kFileIntendedOnHardDisk = 0x000b
|
||||
};
|
||||
|
||||
class FileInfo {
|
||||
public:
|
||||
FileInfo(Chunk &chunk);
|
||||
FileInfo() {};
|
||||
|
||||
uint _id = 0;
|
||||
IntendedFileLocation _intendedLocation = kFileLocationEmpty;
|
||||
Common::String _name;
|
||||
|
||||
private:
|
||||
FileInfoSectionType getSectionType(Chunk &chunk);
|
||||
};
|
||||
|
||||
enum StreamInfoSectionType {
|
||||
kStreamInfoEmptySection = 0x0000,
|
||||
kStreamInfoActorId = 0x002a,
|
||||
kStreamInfoFileId = 0x002b,
|
||||
kStreamInfoStartOffset = 0x002c
|
||||
};
|
||||
|
||||
class StreamInfo {
|
||||
public:
|
||||
StreamInfo(Chunk &chunk);
|
||||
StreamInfo() {};
|
||||
|
||||
uint _actorId = 0;
|
||||
uint _fileId = 0;
|
||||
uint _startOffsetInFile = 0;
|
||||
|
||||
private:
|
||||
StreamInfoSectionType getSectionType(Chunk &chunk);
|
||||
};
|
||||
|
||||
// Declares a cursor, which is stored as a cursor resource in the game executable.
|
||||
class CursorDeclaration {
|
||||
public:
|
||||
CursorDeclaration(Chunk &chunk);
|
||||
CursorDeclaration() {};
|
||||
|
||||
uint _id = 0;
|
||||
uint _unk = 0;
|
||||
Common::String _name;
|
||||
};
|
||||
|
||||
class EngineResourceDeclaration {
|
||||
public:
|
||||
EngineResourceDeclaration(Common::String resourceName, int resourceId) : _name(resourceName), _id(resourceId) {};
|
||||
EngineResourceDeclaration() {};
|
||||
|
||||
Common::String _name;
|
||||
int _id = 0;
|
||||
};
|
||||
|
||||
enum BootSectionType {
|
||||
kBootLastSection = 0x0000,
|
||||
kBootContextReference = 0x0002,
|
||||
kBootVersionInformation = 0x0190,
|
||||
kBootUnk1 = 0x0191,
|
||||
kBootFunctionTableSize = 0x0192,
|
||||
kBootUnk3 = 0x0193,
|
||||
kBootEngineResource = 0x0bba,
|
||||
kBootEngineResourceId = 0x0bbb,
|
||||
kBootScreenReference = 0x0007,
|
||||
kBootFileInfo = 0x000a,
|
||||
kBootStreamInfo = 0x000b,
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
306
engines/mediastation/clients.cpp
Normal file
306
engines/mediastation/clients.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/* 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 "mediastation/actors/screen.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/clients.h"
|
||||
#include "mediastation/context.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
bool DeviceOwner::attemptToReadFromStream(Chunk &chunk, uint sectionType) {
|
||||
bool handledParam = true;
|
||||
switch (sectionType) {
|
||||
case kDeviceOwnerAllowMultipleSounds:
|
||||
_allowMultipleSounds = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
case kDeviceOwnerAllowMultipleStreams:
|
||||
_allowMultipleStreams = chunk.readTypedByte();
|
||||
break;
|
||||
|
||||
default:
|
||||
handledParam = false;
|
||||
}
|
||||
|
||||
return handledParam;
|
||||
}
|
||||
|
||||
bool Document::attemptToReadFromStream(Chunk &chunk, uint sectionType) {
|
||||
bool handledParam = true;
|
||||
switch (sectionType) {
|
||||
case kDocumentContextLoadComplete:
|
||||
readContextLoadComplete(chunk);
|
||||
break;
|
||||
|
||||
case kDocumentStartupInformation:
|
||||
readStartupInformation(chunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
handledParam = false;
|
||||
}
|
||||
|
||||
return handledParam;
|
||||
}
|
||||
|
||||
void Document::readStartupInformation(Chunk &chunk) {
|
||||
DocumentSectionType sectionType = static_cast<DocumentSectionType>(chunk.readTypedUint16());
|
||||
debugC(5, kDebugLoading, "%s: sectionType = 0x%x", __func__, static_cast<uint>(sectionType));
|
||||
switch (sectionType) {
|
||||
case kDocumentEntryScreen: {
|
||||
uint entryPointScreenId = chunk.readTypedUint16();
|
||||
if (_entryPointScreenId == 0) {
|
||||
// We don't want to reset the overridden screen entry point.
|
||||
_entryPointScreenId = entryPointScreenId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Unhandled section type 0x%x", __func__, static_cast<uint>(sectionType));
|
||||
}
|
||||
}
|
||||
|
||||
void Document::readContextLoadComplete(Chunk &chunk) {
|
||||
uint contextId = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "%s: Context %d", __func__, contextId);
|
||||
if (contextId == _loadingContextId) {
|
||||
contextLoadDidComplete();
|
||||
}
|
||||
|
||||
if (_loadingScreenActorId != 0) {
|
||||
uint loadingScreenActorContextId = contextIdForScreenActorId(_loadingScreenActorId);
|
||||
if (contextId == loadingScreenActorContextId) {
|
||||
screenLoadDidComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Document::beginTitle(uint overriddenEntryPointScreenId) {
|
||||
_entryPointStreamId = MediaStationEngine::BOOT_STREAM_ID;
|
||||
if (overriddenEntryPointScreenId != 0) {
|
||||
// This lets us override the default entry screen for development purposes.
|
||||
_entryPointScreenId = overriddenEntryPointScreenId;
|
||||
_entryPointScreenIdWasOverridden = true;
|
||||
}
|
||||
startFeed(_entryPointStreamId);
|
||||
}
|
||||
|
||||
|
||||
void Document::startContextLoad(uint contextId) {
|
||||
debugC(5, kDebugLoading, "%s: Loading context %d", __func__, contextId);
|
||||
Context *existingContext = g_engine->_loadedContexts.getValOrDefault(contextId);
|
||||
if (existingContext == nullptr) {
|
||||
if (_loadingContextId == 0) {
|
||||
const ContextReference &contextRef = g_engine->contextRefWithId(contextId);
|
||||
if (contextRef._contextId != 0) {
|
||||
_loadingContextId = contextId;
|
||||
startFeed(contextRef._streamId);
|
||||
}
|
||||
} else {
|
||||
addToContextLoadQueue(contextId);
|
||||
}
|
||||
} else {
|
||||
if (_currentScreenActorId != 0 && contextId != _loadingContextId) {
|
||||
Actor *currentScreen = g_engine->getActorById(_currentScreenActorId);
|
||||
ScriptValue arg;
|
||||
arg.setToActorId(contextId);
|
||||
currentScreen->runEventHandlerIfExists(kContextLoadCompleteEvent2, arg);
|
||||
}
|
||||
|
||||
if (_loadingContextId == 0) {
|
||||
checkQueuedContextLoads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Document::isContextLoadInProgress(uint contextId) {
|
||||
if (contextId == 0) {
|
||||
// If we don't have a valid context ID, just check if we are loading any context.
|
||||
return _loadingContextId != 0;
|
||||
} else {
|
||||
// If the context ID is valid, check if we are loading specifically that context.
|
||||
return contextId == _loadingContextId;
|
||||
}
|
||||
}
|
||||
|
||||
void Document::branchToScreen() {
|
||||
if (_loadingScreenActorId == 0) {
|
||||
_loadingScreenActorId = _requestedScreenBranchId;
|
||||
_requestedScreenBranchId = 0;
|
||||
uint contextId = contextIdForScreenActorId(_loadingScreenActorId);
|
||||
|
||||
blowAwayCurrentScreen();
|
||||
preloadParentContexts(contextId);
|
||||
addToContextLoadQueue(contextId);
|
||||
|
||||
if (_loadingContextId == 0) {
|
||||
checkQueuedContextLoads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Document::scheduleScreenBranch(uint screenActorId) {
|
||||
// This is to support not immediately branching to the wrong screen
|
||||
// when we are starting at a user-defined context. This is because the click
|
||||
// handler usually points to the main menu screen rather than the screen
|
||||
// we're starting at. It would be way too complicated to find the right variable
|
||||
// and change it at runtime, so we will just branch to the screen we are already on.
|
||||
// (We have to branch to something because by this point we have already faded out the screen and such,
|
||||
// so we need to run another screen entry event to bring things back in again.)
|
||||
if (_entryPointScreenIdWasOverridden) {
|
||||
_entryPointScreenIdWasOverridden = false;
|
||||
screenActorId = _currentScreenActorId;
|
||||
}
|
||||
|
||||
_requestedScreenBranchId = screenActorId;
|
||||
}
|
||||
|
||||
void Document::scheduleContextRelease(uint contextId) {
|
||||
if (!g_engine->contextIsLocked(contextId)) {
|
||||
_requestedContextReleaseId.push_back(contextId);
|
||||
}
|
||||
}
|
||||
|
||||
void Document::streamDidClose(uint streamId) {
|
||||
bool currentStreamIsTargetStream = _currentStreamFeed != nullptr && streamId == _currentStreamFeed->_id;
|
||||
if (!currentStreamIsTargetStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
_currentStreamFeed = nullptr;
|
||||
}
|
||||
|
||||
void Document::streamDidFinish(uint streamId) {
|
||||
bool currentStreamIsTargetStream = _currentStreamFeed != nullptr && streamId == _currentStreamFeed->_id;
|
||||
if (currentStreamIsTargetStream) {
|
||||
stopFeed();
|
||||
if (streamId == _entryPointStreamId) {
|
||||
_requestedScreenBranchId = _entryPointScreenId;
|
||||
branchToScreen();
|
||||
} else {
|
||||
checkQueuedContextLoads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Document::contextLoadDidComplete() {
|
||||
if (_currentScreenActorId != 0) {
|
||||
ScriptValue arg;
|
||||
arg.setToActorId(_loadingContextId);
|
||||
Actor *currentScreen = g_engine->getActorById(_currentScreenActorId);
|
||||
if (currentScreen != nullptr) {
|
||||
currentScreen->runEventHandlerIfExists(kContextLoadCompleteEvent, arg);
|
||||
}
|
||||
}
|
||||
_loadingContextId = 0;
|
||||
}
|
||||
|
||||
void Document::screenLoadDidComplete() {
|
||||
_currentScreenActorId = _loadingScreenActorId;
|
||||
Actor *currentScreen = g_engine->getActorById(_loadingScreenActorId);
|
||||
currentScreen->runEventHandlerIfExists(kScreenEntryEvent);
|
||||
_loadingScreenActorId = 0;
|
||||
}
|
||||
|
||||
void Document::process() {
|
||||
if (!_requestedContextReleaseId.empty()) {
|
||||
for (uint contextId : _requestedContextReleaseId) {
|
||||
g_engine->destroyContext(contextId);
|
||||
}
|
||||
_requestedContextReleaseId.clear();
|
||||
}
|
||||
|
||||
if (_requestedScreenBranchId != 0) {
|
||||
branchToScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void Document::blowAwayCurrentScreen() {
|
||||
if (_currentScreenActorId != 0) {
|
||||
uint contextId = contextIdForScreenActorId(_currentScreenActorId);
|
||||
if (contextId != 0) {
|
||||
Actor *currentScreen = g_engine->getActorById(_currentScreenActorId);
|
||||
currentScreen->runEventHandlerIfExists(kScreenExitEvent);
|
||||
g_engine->destroyContext(contextId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint Document::contextIdForScreenActorId(uint screenActorId) {
|
||||
ScreenReference screenRef = g_engine->screenRefWithId(screenActorId);
|
||||
return screenRef._contextId;
|
||||
}
|
||||
|
||||
void Document::startFeed(uint streamId) {
|
||||
// The original had some more stuff here, including cache management and device ownership,
|
||||
// but since we don't need these things right now, this function is rather empty.
|
||||
_currentStreamFeed = g_engine->getStreamFeedManager()->openStreamFeed(streamId);
|
||||
_currentStreamFeed->readData();
|
||||
}
|
||||
|
||||
void Document::stopFeed() {
|
||||
_currentStreamFeed->stopFeed();
|
||||
g_engine->getStreamFeedManager()->closeStreamFeed(_currentStreamFeed);
|
||||
_currentStreamFeed = nullptr;
|
||||
}
|
||||
|
||||
void Document::preloadParentContexts(uint contextId) {
|
||||
ContextReference contextReference = g_engine->contextRefWithId(contextId);
|
||||
for (uint parentContextId : contextReference._parentContextIds) {
|
||||
if (parentContextId != 0) {
|
||||
Context *existingContext = g_engine->_loadedContexts.getValOrDefault(parentContextId);
|
||||
if (existingContext == nullptr && parentContextId != contextId) {
|
||||
debugC(5, kDebugLoading, "%s: Loading parent context %d", __func__, parentContextId);
|
||||
addToContextLoadQueue(parentContextId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Document::addToContextLoadQueue(uint contextId) {
|
||||
if (!isContextLoadQueued(contextId)) {
|
||||
_contextLoadQueue.push_back(contextId);
|
||||
} else {
|
||||
warning("%s: Context %d already queued for load", __func__, contextId);
|
||||
}
|
||||
}
|
||||
|
||||
bool Document::isContextLoadQueued(uint contextId) {
|
||||
for (uint queuedContextId : _contextLoadQueue) {
|
||||
if (queuedContextId == contextId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Document::checkQueuedContextLoads() {
|
||||
while (!_contextLoadQueue.empty()) {
|
||||
uint contextId = _contextLoadQueue.front();
|
||||
_contextLoadQueue.erase(_contextLoadQueue.begin());
|
||||
startContextLoad(contextId);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
108
engines/mediastation/clients.h
Normal file
108
engines/mediastation/clients.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_CLIENTS_H
|
||||
#define MEDIASTATION_CLIENTS_H
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class ParameterClient {
|
||||
public:
|
||||
ParameterClient() {};
|
||||
virtual ~ParameterClient() {};
|
||||
|
||||
virtual bool attemptToReadFromStream(Chunk &chunk, uint sectionType) = 0;
|
||||
};
|
||||
|
||||
enum DeviceOwnerSectionType {
|
||||
kDeviceOwnerAllowMultipleSounds = 0x35,
|
||||
kDeviceOwnerAllowMultipleStreams = 0x36,
|
||||
};
|
||||
|
||||
class DeviceOwner : public ParameterClient {
|
||||
public:
|
||||
virtual bool attemptToReadFromStream(Chunk &chunk, uint sectionType) override;
|
||||
|
||||
bool _allowMultipleSounds = false;
|
||||
bool _allowMultipleStreams = false;
|
||||
};
|
||||
|
||||
enum DocumentSectionType {
|
||||
kDocumentContextLoadComplete = 0x10,
|
||||
kDocumentStartupInformation = 0x2e,
|
||||
kDocumentEntryScreen = 0x2f,
|
||||
};
|
||||
|
||||
class Document : public ParameterClient {
|
||||
public:
|
||||
virtual bool attemptToReadFromStream(Chunk &chunk, uint sectionType) override;
|
||||
void readStartupInformation(Chunk &chunk);
|
||||
void readContextLoadComplete(Chunk &chunk);
|
||||
|
||||
void beginTitle(uint overriddenEntryPointScreenId = 0);
|
||||
void startContextLoad(uint contextId);
|
||||
bool isContextLoadInProgress(uint contextId);
|
||||
void branchToScreen();
|
||||
void scheduleScreenBranch(uint screenActorId);
|
||||
void scheduleContextRelease(uint contextId);
|
||||
|
||||
void streamDidClose(uint streamId);
|
||||
void streamDidFinish(uint streamId);
|
||||
// These implementations are left empty because they are empty in the original,
|
||||
// but they are kept because they are technically still defined in the original.
|
||||
void streamDidOpen(uint streamId) {};
|
||||
void streamWillRead(uint streamId) {};
|
||||
|
||||
void process();
|
||||
uint contextIdForScreenActorId(uint screenActorId);
|
||||
|
||||
private:
|
||||
uint _currentScreenActorId = 0;
|
||||
StreamFeed *_currentStreamFeed = nullptr;
|
||||
Common::Array<uint> _requestedContextReleaseId;
|
||||
Common::Array<uint> _contextLoadQueue;
|
||||
uint _requestedScreenBranchId = 0;
|
||||
bool _entryPointScreenIdWasOverridden = false;
|
||||
uint _entryPointScreenId = 0;
|
||||
uint _entryPointStreamId = 0;
|
||||
uint _loadingContextId = 0;
|
||||
uint _loadingScreenActorId = 0;
|
||||
|
||||
void contextLoadDidComplete();
|
||||
void screenLoadDidComplete();
|
||||
void startFeed(uint streamId);
|
||||
// This is named stopFeed in the original, but it is a bit of a misnomer
|
||||
// because it also closes the stream feed. In the lower-level stream feed manager
|
||||
// and stream feeds themselves, stopping the stream feed and closing it is
|
||||
// two separate operations.
|
||||
void stopFeed();
|
||||
void blowAwayCurrentScreen();
|
||||
void preloadParentContexts(uint contextId);
|
||||
void addToContextLoadQueue(uint contextId);
|
||||
bool isContextLoadQueued(uint contextId);
|
||||
void checkQueuedContextLoads();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
3
engines/mediastation/configure.engine
Normal file
3
engines/mediastation/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
|
||||
add_engine mediastation "Media Station" no "" "" "highres"
|
||||
250
engines/mediastation/context.cpp
Normal file
250
engines/mediastation/context.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
/* 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 "mediastation/mediastation.h"
|
||||
#include "mediastation/context.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
#include "mediastation/bitmap.h"
|
||||
#include "mediastation/mediascript/collection.h"
|
||||
#include "mediastation/mediascript/function.h"
|
||||
#include "mediastation/actors/camera.h"
|
||||
#include "mediastation/actors/canvas.h"
|
||||
#include "mediastation/actors/palette.h"
|
||||
#include "mediastation/actors/image.h"
|
||||
#include "mediastation/actors/path.h"
|
||||
#include "mediastation/actors/sound.h"
|
||||
#include "mediastation/actors/movie.h"
|
||||
#include "mediastation/actors/sprite.h"
|
||||
#include "mediastation/actors/stage.h"
|
||||
#include "mediastation/actors/hotspot.h"
|
||||
#include "mediastation/actors/timer.h"
|
||||
#include "mediastation/actors/screen.h"
|
||||
#include "mediastation/actors/font.h"
|
||||
#include "mediastation/actors/text.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
Context::~Context() {
|
||||
for (auto it = _variables.begin(); it != _variables.end(); ++it) {
|
||||
delete it->_value;
|
||||
}
|
||||
_variables.clear();
|
||||
}
|
||||
|
||||
void MediaStationEngine::readControlCommands(Chunk &chunk) {
|
||||
ContextSectionType sectionType = kContextEndOfSection;
|
||||
do {
|
||||
sectionType = static_cast<ContextSectionType>(chunk.readTypedUint16());
|
||||
debugC(5, kDebugLoading, "%s: sectionType = 0x%x (@0x%llx)", __func__, static_cast<uint>(sectionType), static_cast<long long int>(chunk.pos()));
|
||||
if (sectionType != kContextEndOfSection) {
|
||||
readCommandFromStream(chunk, sectionType);
|
||||
}
|
||||
} while (sectionType != kContextEndOfSection);
|
||||
}
|
||||
|
||||
void MediaStationEngine::readCreateContextData(Chunk &chunk) {
|
||||
uint contextId = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "%s: Context %d", __func__, contextId);
|
||||
Context *context = _loadedContexts.getValOrDefault(contextId);
|
||||
if (context == nullptr) {
|
||||
context = new Context();
|
||||
context->_id = contextId;
|
||||
_loadedContexts.setVal(contextId, context);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readDestroyContextData(Chunk &chunk) {
|
||||
uint contextId = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "%s: Context %d", __func__, contextId);
|
||||
destroyContext(contextId);
|
||||
}
|
||||
|
||||
void MediaStationEngine::readDestroyActorData(Chunk &chunk) {
|
||||
uint actorId = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "%s: Actor %d", __func__, actorId);
|
||||
destroyActor(actorId);
|
||||
}
|
||||
|
||||
void MediaStationEngine::readActorLoadComplete(Chunk &chunk) {
|
||||
uint actorId = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "%s: Actor %d", __func__, actorId);
|
||||
Actor *actor = g_engine->getActorById(actorId);
|
||||
actor->loadIsComplete();
|
||||
}
|
||||
|
||||
void MediaStationEngine::readCreateActorData(Chunk &chunk) {
|
||||
uint contextId = chunk.readTypedUint16();
|
||||
ActorType type = static_cast<ActorType>(chunk.readTypedUint16());
|
||||
uint id = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "%s: Actor %d, type 0x%x", __func__, id, static_cast<uint>(type));
|
||||
|
||||
Actor *actor = nullptr;
|
||||
switch (type) {
|
||||
case kActorTypeImage:
|
||||
actor = new ImageActor();
|
||||
break;
|
||||
|
||||
case kActorTypeMovie:
|
||||
actor = new StreamMovieActor();
|
||||
break;
|
||||
|
||||
case kActorTypeSound:
|
||||
actor = new SoundActor();
|
||||
break;
|
||||
|
||||
case kActorTypePalette:
|
||||
actor = new PaletteActor();
|
||||
break;
|
||||
|
||||
case kActorTypePath:
|
||||
actor = new PathActor();
|
||||
break;
|
||||
|
||||
case kActorTypeTimer:
|
||||
actor = new TimerActor();
|
||||
break;
|
||||
|
||||
case kActorTypeHotspot:
|
||||
actor = new HotspotActor();
|
||||
break;
|
||||
|
||||
case kActorTypeSprite:
|
||||
actor = new SpriteMovieActor();
|
||||
break;
|
||||
|
||||
case kActorTypeCanvas:
|
||||
actor = new CanvasActor();
|
||||
break;
|
||||
|
||||
case kActorTypeCamera:
|
||||
actor = new CameraActor();
|
||||
break;
|
||||
|
||||
case kActorTypeStage:
|
||||
actor = new StageActor();
|
||||
break;
|
||||
|
||||
case kActorTypeScreen:
|
||||
actor = new ScreenActor();
|
||||
break;
|
||||
|
||||
case kActorTypeFont:
|
||||
actor = new FontActor();
|
||||
break;
|
||||
|
||||
case kActorTypeText:
|
||||
actor = new TextActor();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: No class for actor type 0x%x (@0x%llx)", __func__, static_cast<uint>(type), static_cast<long long int>(chunk.pos()));
|
||||
}
|
||||
actor->setId(id);
|
||||
actor->setContextId(contextId);
|
||||
actor->initFromParameterStream(chunk);
|
||||
g_engine->registerActor(actor);
|
||||
}
|
||||
|
||||
void MediaStationEngine::readCreateVariableData(Chunk &chunk) {
|
||||
uint contextId = chunk.readTypedUint16();
|
||||
uint id = chunk.readTypedUint16();
|
||||
if (g_engine->getVariable(id) != nullptr) {
|
||||
error("%s: Global variable %d already exists", __func__, id);
|
||||
}
|
||||
|
||||
ScriptValue *value = new ScriptValue(&chunk);
|
||||
Context *context = _loadedContexts.getValOrDefault(contextId);
|
||||
if (context == nullptr) {
|
||||
error("%s: Context %d does not exist or has not been loaded yet in this title", __func__, contextId);
|
||||
}
|
||||
|
||||
context->_variables.setVal(id, value);
|
||||
debugC(5, kDebugScript, "%s: %d (type: %s)", __func__, id, scriptValueTypeToStr(value->getType()));
|
||||
}
|
||||
|
||||
void MediaStationEngine::readHeaderSections(Subfile &subfile, Chunk &chunk) {
|
||||
do {
|
||||
ChannelClient *actor = g_engine->getChannelClientByChannelIdent(chunk._id);
|
||||
if (actor == nullptr) {
|
||||
error("%s: Client \"%s\" (0x%x) does not exist or has not been read yet in this title. (@0x%llx)", __func__, tag2str(chunk._id), chunk._id, static_cast<long long int>(chunk.pos()));
|
||||
}
|
||||
if (chunk.bytesRemaining() > 0) {
|
||||
actor->readChunk(chunk);
|
||||
}
|
||||
|
||||
if (chunk.bytesRemaining() != 0) {
|
||||
warning("%s: %d bytes remaining at end of chunk", __func__, chunk.bytesRemaining());
|
||||
}
|
||||
|
||||
if (!subfile.atEnd()) {
|
||||
chunk = subfile.nextChunk();
|
||||
}
|
||||
} while (!subfile.atEnd());
|
||||
}
|
||||
|
||||
void MediaStationEngine::readContextNameData(Chunk &chunk) {
|
||||
uint contextId = chunk.readTypedUint16();
|
||||
debugC(5, kDebugLoading, "%s: Context %d", __func__, contextId);
|
||||
Context *context = _loadedContexts.getValOrDefault(contextId);
|
||||
if (context == nullptr) {
|
||||
error("%s: Context %d does not exist or has not been loaded yet in this title", __func__, contextId);
|
||||
}
|
||||
context->_name = chunk.readTypedString();
|
||||
}
|
||||
|
||||
void MediaStationEngine::readCommandFromStream(Chunk &chunk, ContextSectionType sectionType) {
|
||||
switch (sectionType) {
|
||||
case kContextCreateData:
|
||||
readCreateContextData(chunk);
|
||||
break;
|
||||
|
||||
case kContextDestroyData:
|
||||
readDestroyContextData(chunk);
|
||||
break;
|
||||
|
||||
case kContextCreateActorData:
|
||||
readCreateActorData(chunk);
|
||||
break;
|
||||
|
||||
case kContextDestroyActorData:
|
||||
readDestroyActorData(chunk);
|
||||
break;
|
||||
|
||||
case kContextActorLoadComplete:
|
||||
readActorLoadComplete(chunk);
|
||||
break;
|
||||
|
||||
case kContextCreateVariableData:
|
||||
readCreateVariableData(chunk);
|
||||
break;
|
||||
|
||||
case kContextNameData:
|
||||
readContextNameData(chunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
readUnrecognizedFromStream(chunk, static_cast<uint>(sectionType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
69
engines/mediastation/context.h
Normal file
69
engines/mediastation/context.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_CONTEXT_H
|
||||
#define MEDIASTATION_CONTEXT_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/path.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "graphics/palette.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/actor.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum StreamType {
|
||||
kDocumentDefStream = 0x01,
|
||||
kControlCommandsStream = 0x0D,
|
||||
};
|
||||
|
||||
enum ContextSectionType {
|
||||
kContextEndOfSection = 0x00,
|
||||
kContextControlCommands = 0x0d,
|
||||
kContextCreateData = 0x0e,
|
||||
kContextDestroyData = 0x0f,
|
||||
kContextLoadCompleteSection = 0x10,
|
||||
kContextCreateActorData = 0x11,
|
||||
kContextDestroyActorData = 0x12,
|
||||
kContextActorLoadComplete = 0x13,
|
||||
kContextCreateVariableData = 0x14,
|
||||
kContextFunctionSection = 0x31,
|
||||
kContextNameData = 0xbb8
|
||||
};
|
||||
|
||||
class Context {
|
||||
public:
|
||||
~Context();
|
||||
|
||||
Common::String _name;
|
||||
Common::HashMap<uint, ScriptValue *> _variables;
|
||||
|
||||
// This is not an internal file ID, but the number of the file
|
||||
// as it appears in the filename. For instance, the context in
|
||||
// "100.cxt" would have file number 100.
|
||||
uint _id = 0;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
3
engines/mediastation/credits.pl
Normal file
3
engines/mediastation/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("Media Station");
|
||||
add_person("Nathanael Gentry", "npjg", "");
|
||||
end_section();
|
||||
272
engines/mediastation/cursors.cpp
Normal file
272
engines/mediastation/cursors.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/* 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 "mediastation/cursors.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/file.h"
|
||||
#include "common/formats/winexe_ne.h"
|
||||
#include "common/formats/winexe_pe.h"
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
CursorManager::~CursorManager() {
|
||||
// It is up to the platform-specific cursor managers
|
||||
// to actually delete their resources.
|
||||
_cursors.clear();
|
||||
}
|
||||
|
||||
bool CursorManager::attemptToReadFromStream(Chunk &chunk, uint param) {
|
||||
bool handledParam = true;
|
||||
switch (param) {
|
||||
case kCursorManagerInit:
|
||||
init(chunk);
|
||||
break;
|
||||
|
||||
case kCursorManagerNewCursor:
|
||||
newCursor(chunk);
|
||||
break;
|
||||
|
||||
case kCursorManagerDisposeCursor:
|
||||
disposeCursor(chunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
handledParam = false;
|
||||
}
|
||||
|
||||
return handledParam;
|
||||
}
|
||||
|
||||
void CursorManager::init(Chunk &chunk) {
|
||||
_baseCursorId = chunk.readTypedUint16();
|
||||
_maxCursorId = chunk.readTypedUint16();
|
||||
|
||||
if (_maxCursorId < _baseCursorId || _baseCursorId == 0) {
|
||||
error("%s: Got invalid cursor IDs", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void CursorManager::newCursor(Chunk &chunk) {
|
||||
CursorType cursorType = static_cast<CursorType>(chunk.readTypedUint16());
|
||||
uint16 cursorId = chunk.readTypedUint16();
|
||||
switch (cursorType) {
|
||||
case kPlatformCursor: {
|
||||
uint16 platformCursorId = chunk.readTypedUint16();
|
||||
newPlatformCursor(cursorId, platformCursorId);
|
||||
break;
|
||||
}
|
||||
|
||||
case kResourceCursor: {
|
||||
// This first value isn't actually used.
|
||||
chunk.readTypedUint16();
|
||||
Common::String resourceName = chunk.readTypedFilename();
|
||||
newResourceCursor(cursorId, resourceName);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Got unknown cursor type %d", __func__, static_cast<uint>(cursorType));
|
||||
}
|
||||
}
|
||||
|
||||
void CursorManager::disposeCursor(Chunk &chunk) {
|
||||
uint16 cursorId = chunk.readTypedUint16();
|
||||
_cursors.erase(cursorId);
|
||||
// We don't actually delete the underlying platform-specific
|
||||
// cursor, just remove it from the hashmap. Otherwise, we'd
|
||||
// mess up the platform-specific storage.
|
||||
}
|
||||
|
||||
void CursorManager::newPlatformCursor(uint16 platformCursorId, uint16 cursorId) {
|
||||
if (cursorId < _baseCursorId || cursorId > _maxCursorId || cursorId == 0) {
|
||||
error("%s: Got invalid cursor ID %d", __func__, static_cast<uint>(cursorId));
|
||||
}
|
||||
|
||||
warning("STUB: %s: Platform cursor %d, internal cursor %d", __func__, platformCursorId, cursorId);
|
||||
// TODO: To implement this, we need have the default platform cursors for Windows and Mac.
|
||||
}
|
||||
|
||||
void CursorManager::newResourceCursor(uint16 cursorId, const Common::String &resourceName) {
|
||||
if (cursorId < _baseCursorId || cursorId > _maxCursorId || cursorId == 0) {
|
||||
error("%s: Got invalid cursor ID %d", __func__, static_cast<uint>(cursorId));
|
||||
}
|
||||
|
||||
Graphics::Cursor *cursor = loadResourceCursor(resourceName);
|
||||
_cursors.setVal(cursorId, cursor);
|
||||
}
|
||||
|
||||
void CursorManager::showCursor() {
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
void CursorManager::hideCursor() {
|
||||
CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
void CursorManager::registerAsPermanent(uint16 id) {
|
||||
if (id != 0) {
|
||||
_permanentCursorId = id;
|
||||
}
|
||||
}
|
||||
|
||||
void CursorManager::setAsPermanent(uint16 id) {
|
||||
bool cursorAlreadySet = _currentCursorId == id && _permanentCursorId == id;
|
||||
bool cursorIsEmpty = id == 0;
|
||||
if (cursorAlreadySet || cursorIsEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
_permanentCursorId = id;
|
||||
_currentCursorId = id;
|
||||
resetCurrent();
|
||||
}
|
||||
|
||||
void CursorManager::setAsTemporary(uint16 id) {
|
||||
bool cursorAlreadySet = _currentCursorId == id;
|
||||
bool cursorIsEmpty = id == 0;
|
||||
if (cursorAlreadySet || cursorIsEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
_currentCursorId = id;
|
||||
resetCurrent();
|
||||
}
|
||||
|
||||
void CursorManager::unsetPermanent() {
|
||||
_permanentCursorId = 0;
|
||||
_currentCursorId = 0;
|
||||
}
|
||||
|
||||
void CursorManager::unsetTemporary() {
|
||||
if (_currentCursorId != _permanentCursorId) {
|
||||
_currentCursorId = _permanentCursorId;
|
||||
resetCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
void CursorManager::resetCurrent() {
|
||||
if (_currentCursorId != 0) {
|
||||
Graphics::Cursor *cursor = _cursors.getVal(_currentCursorId);
|
||||
CursorMan.replaceCursor(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
void CursorManager::setDefaultCursor() {
|
||||
Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor();
|
||||
CursorMan.replaceCursor(cursor);
|
||||
delete cursor;
|
||||
}
|
||||
|
||||
WindowsCursorManager::WindowsCursorManager(const Common::Path &appName) : CursorManager(appName) {
|
||||
if (appName.empty()) {
|
||||
error("%s: No executable to load cursors from", __func__);
|
||||
} else if (!Common::File::exists(appName)) {
|
||||
error("%s: Executable %s doesn't exist", __func__, appName.toString().c_str());
|
||||
}
|
||||
|
||||
Common::WinResources *exe = Common::WinResources::createFromEXE(appName);
|
||||
if (exe == nullptr || !exe->loadFromEXE(appName)) {
|
||||
error("%s: Could not load resources from executable %s", __func__, appName.toString().c_str());
|
||||
}
|
||||
|
||||
const Common::Array<Common::WinResourceID> cursorGroups = exe->getIDList(Common::kWinGroupCursor);
|
||||
for (Common::WinResourceID cursorGroup : cursorGroups) {
|
||||
Common::String resourceString = cursorGroup.getString();
|
||||
if (resourceString.empty()) {
|
||||
warning("%s: Got Windows cursor group with no string ID", __func__);
|
||||
continue;
|
||||
}
|
||||
Graphics::WinCursorGroup *group = Graphics::WinCursorGroup::createCursorGroup(exe, cursorGroup);
|
||||
_cursorGroups.setVal(resourceString, group);
|
||||
}
|
||||
delete exe;
|
||||
}
|
||||
|
||||
WindowsCursorManager::~WindowsCursorManager() {
|
||||
for (auto it = _cursorGroups.begin(); it != _cursorGroups.end(); ++it) {
|
||||
delete it->_value;
|
||||
}
|
||||
_cursorGroups.clear();
|
||||
|
||||
// We don't need to delete items in _cursors itself,
|
||||
// because those cursors are part of _cursorGroups.
|
||||
}
|
||||
|
||||
Graphics::Cursor *WindowsCursorManager::loadResourceCursor(const Common::String &name) {
|
||||
// Search for case-insensitive match since resource names are expected to be case-insensitive.
|
||||
for (auto it = _cursorGroups.begin(); it != _cursorGroups.end(); ++it) {
|
||||
if (it->_key.equalsIgnoreCase(name)) {
|
||||
Graphics::Cursor *cursor = it->_value->cursors[0].cursor;
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
error("%s: Reqested Windows cursor %s not found", __func__, name.c_str());
|
||||
}
|
||||
|
||||
MacCursorManager::MacCursorManager(const Common::Path &appName) : CursorManager(appName) {
|
||||
if (appName.empty()) {
|
||||
error("%s: No file to load cursors from", __func__);
|
||||
} else if (!Common::File::exists(appName)) {
|
||||
error("%s: File %s doesn't exist", __func__, appName.toString().c_str());
|
||||
}
|
||||
|
||||
_resFork = new Common::MacResManager();
|
||||
if (!_resFork->open(appName) || !_resFork->hasResFork()) {
|
||||
error("%s: Could not load resource fork from %s", __func__, appName.toString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
MacCursorManager::~MacCursorManager() {
|
||||
for (auto it = _cursors.begin(); it != _cursors.end(); ++it) {
|
||||
delete it->_value;
|
||||
}
|
||||
|
||||
delete _resFork;
|
||||
_resFork = nullptr;
|
||||
}
|
||||
|
||||
Graphics::Cursor *MacCursorManager::loadResourceCursor(const Common::String &name) {
|
||||
// Try to load a color cursor first.
|
||||
Common::SeekableReadStream *stream = _resFork->getResource(MKTAG('c', 'r', 's', 'r'), name);
|
||||
if (stream == nullptr) {
|
||||
// Fall back to attempting to load a mnochrome cursor.
|
||||
stream = _resFork->getResource(MKTAG('C', 'U', 'R', 'S'), name);
|
||||
}
|
||||
|
||||
// Make sure we got a resource.
|
||||
if (stream == nullptr) {
|
||||
error("%s: Reqested Mac cursor %s not found", __func__, name.c_str());
|
||||
}
|
||||
|
||||
Graphics::MacCursor *macCursor = new Graphics::MacCursor();
|
||||
if (!macCursor->readFromStream(*stream)) {
|
||||
error("%s: Error parsing cursor %s from stream", __func__, name.c_str());
|
||||
}
|
||||
delete stream;
|
||||
return macCursor;
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
114
engines/mediastation/cursors.h
Normal file
114
engines/mediastation/cursors.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_CURSORS_H
|
||||
#define MEDIASTATION_CURSORS_H
|
||||
|
||||
#include "common/platform.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/str.h"
|
||||
#include "common/macresman.h"
|
||||
#include "common/formats/winexe.h"
|
||||
#include "graphics/wincursor.h"
|
||||
#include "graphics/maccursor.h"
|
||||
|
||||
#include "mediastation/clients.h"
|
||||
#include "mediastation/datafile.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum CursorManagerCommandType {
|
||||
kCursorManagerInit = 0x0c,
|
||||
kCursorManagerNewCursor = 0x15,
|
||||
kCursorManagerDisposeCursor = 0x16,
|
||||
};
|
||||
|
||||
enum CursorType {
|
||||
kPlatformCursor = 0,
|
||||
kResourceCursor = 1,
|
||||
};
|
||||
|
||||
// Media Station stores cursors in the executable as named resources.
|
||||
class CursorManager : public ParameterClient {
|
||||
public:
|
||||
CursorManager(const Common::Path &appName) : _appName(appName) {}
|
||||
virtual ~CursorManager();
|
||||
|
||||
virtual bool attemptToReadFromStream(Chunk &chunk, uint param) override;
|
||||
void init(Chunk &chunk);
|
||||
void newCursor(Chunk &chunk);
|
||||
void disposeCursor(Chunk &chunk);
|
||||
|
||||
void newPlatformCursor(uint16 platformCursorId, uint16 cursorId);
|
||||
void newResourceCursor(uint16 cursorId, const Common::String &resourceName);
|
||||
// Some engine versions also have newBufferCursor that seems to be unused.
|
||||
|
||||
void showCursor();
|
||||
void hideCursor();
|
||||
|
||||
virtual void resetCurrent();
|
||||
void registerAsPermanent(uint16 id);
|
||||
void setAsPermanent(uint16 id);
|
||||
void setAsTemporary(uint16 id);
|
||||
void unsetPermanent();
|
||||
void unsetTemporary();
|
||||
|
||||
protected:
|
||||
Common::Path _appName;
|
||||
|
||||
uint16 _baseCursorId = 0;
|
||||
uint16 _maxCursorId = 0;
|
||||
uint16 _currentCursorId = 0;
|
||||
uint16 _permanentCursorId = 0;
|
||||
|
||||
// The original used an array with computed indices, but we use a hashmap for simplicity.
|
||||
Common::HashMap<uint16, Graphics::Cursor *> _cursors;
|
||||
|
||||
virtual Graphics::Cursor *loadResourceCursor(const Common::String &name) = 0;
|
||||
void setDefaultCursor();
|
||||
};
|
||||
|
||||
class WindowsCursorManager : public CursorManager {
|
||||
public:
|
||||
WindowsCursorManager(const Common::Path &appName);
|
||||
~WindowsCursorManager() override;
|
||||
|
||||
virtual Graphics::Cursor *loadResourceCursor(const Common::String &name) override;
|
||||
|
||||
private:
|
||||
Common::HashMap<Common::String, Graphics::WinCursorGroup *> _cursorGroups;
|
||||
};
|
||||
|
||||
class MacCursorManager : public CursorManager {
|
||||
public:
|
||||
explicit MacCursorManager(const Common::Path &appName);
|
||||
~MacCursorManager() override;
|
||||
|
||||
virtual Graphics::Cursor *loadResourceCursor(const Common::String &name) override;
|
||||
|
||||
private:
|
||||
Common::MacResManager *_resFork;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
331
engines/mediastation/datafile.cpp
Normal file
331
engines/mediastation/datafile.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
/* 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 "mediastation/datafile.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
void ParameterReadStream::readAndVerifyType(DatumType type) {
|
||||
DatumType actualType = static_cast<DatumType>(readUint16LE());
|
||||
if (actualType != type) {
|
||||
error("%s: Expected datum type %d, got %d (@0x%llx)", __func__, type, actualType, static_cast<long long int>(pos()));
|
||||
}
|
||||
}
|
||||
|
||||
byte ParameterReadStream::readTypedByte() {
|
||||
readAndVerifyType(kDatumTypeUint8);
|
||||
return readByte();
|
||||
}
|
||||
|
||||
uint16 ParameterReadStream::readTypedUint16() {
|
||||
readAndVerifyType(kDatumTypeUint16);
|
||||
return readUint16LE();
|
||||
}
|
||||
|
||||
uint32 ParameterReadStream::readTypedUint32() {
|
||||
readAndVerifyType(kDatumTypeUint32);
|
||||
return readUint32LE();
|
||||
}
|
||||
|
||||
int8 ParameterReadStream::readTypedSByte() {
|
||||
readAndVerifyType(kDatumTypeInt8);
|
||||
return readSByte();
|
||||
}
|
||||
|
||||
int16 ParameterReadStream::readTypedSint16() {
|
||||
readAndVerifyType(kDatumTypeInt16);
|
||||
return readSint16LE();
|
||||
}
|
||||
|
||||
int32 ParameterReadStream::readTypedSint32() {
|
||||
readAndVerifyType(kDatumTypeInt32);
|
||||
return readSint32LE();
|
||||
}
|
||||
|
||||
float ParameterReadStream::readTypedFloat() {
|
||||
readAndVerifyType(kDatumTypeFloat);
|
||||
return readFloatLE();
|
||||
}
|
||||
|
||||
double ParameterReadStream::readTypedDouble() {
|
||||
readAndVerifyType(kDatumTypeDouble);
|
||||
return readDoubleLE();
|
||||
}
|
||||
|
||||
Common::String ParameterReadStream::readTypedFilename() {
|
||||
readAndVerifyType(kDatumTypeFilename);
|
||||
uint size = readTypedUint32();
|
||||
return readString('\0', size);
|
||||
}
|
||||
|
||||
Common::Rect ParameterReadStream::readTypedRect() {
|
||||
readAndVerifyType(kDatumTypeRect);
|
||||
Common::Point leftTop = readTypedPoint();
|
||||
Common::Point dimensions = readTypedGraphicSize();
|
||||
return Common::Rect(leftTop, dimensions.x, dimensions.y);
|
||||
}
|
||||
|
||||
Common::Point ParameterReadStream::readTypedPoint() {
|
||||
readAndVerifyType(kDatumTypePoint);
|
||||
int16 x = readTypedGraphicUnit();
|
||||
int16 y = readTypedGraphicUnit();
|
||||
return Common::Point(x, y);
|
||||
}
|
||||
|
||||
Common::Point ParameterReadStream::readTypedGraphicSize() {
|
||||
readAndVerifyType(kDatumTypeGraphicSize);
|
||||
int16 width = readTypedGraphicUnit();
|
||||
int16 height = readTypedGraphicUnit();
|
||||
return Common::Point(width, height);
|
||||
}
|
||||
|
||||
int16 ParameterReadStream::readTypedGraphicUnit() {
|
||||
readAndVerifyType(kDatumTypeGraphicUnit);
|
||||
return readSint16LE();
|
||||
}
|
||||
|
||||
double ParameterReadStream::readTypedTime() {
|
||||
readAndVerifyType(kDatumTypeTime);
|
||||
return readDoubleLE();
|
||||
}
|
||||
|
||||
Common::String ParameterReadStream::readTypedString() {
|
||||
readAndVerifyType(kDatumTypeString);
|
||||
uint size = readTypedUint32();
|
||||
return readString('\0', size);
|
||||
}
|
||||
|
||||
VersionInfo ParameterReadStream::readTypedVersion() {
|
||||
readAndVerifyType(kDatumTypeVersion);
|
||||
VersionInfo version;
|
||||
version.major = readTypedUint16();
|
||||
version.minor = readTypedUint16();
|
||||
version.patch = readTypedUint16();
|
||||
return version;
|
||||
}
|
||||
|
||||
ChannelIdent ParameterReadStream::readTypedChannelIdent() {
|
||||
readAndVerifyType(kDatumTypeChannelIdent);
|
||||
// This one is always BE.
|
||||
return readUint32BE();
|
||||
}
|
||||
|
||||
Polygon ParameterReadStream::readTypedPolygon() {
|
||||
Polygon polygon;
|
||||
uint totalPoints = readTypedUint16();
|
||||
for (uint i = 0; i < totalPoints; ++i) {
|
||||
Common::Point point = readTypedGraphicSize();
|
||||
polygon.push_back(point);
|
||||
}
|
||||
return polygon;
|
||||
}
|
||||
|
||||
Chunk::Chunk(Common::SeekableReadStream *stream) : _parentStream(stream) {
|
||||
_id = _parentStream->readUint32BE();
|
||||
_length = _parentStream->readUint32LE();
|
||||
_dataStartOffset = pos();
|
||||
_dataEndOffset = _dataStartOffset + _length;
|
||||
debugC(5, kDebugLoading, "Chunk::Chunk(): Got chunk with ID \"%s\" and size 0x%x", tag2str(_id), _length);
|
||||
}
|
||||
|
||||
uint32 Chunk::bytesRemaining() {
|
||||
return _dataEndOffset - pos();
|
||||
}
|
||||
|
||||
uint32 Chunk::read(void *dataPtr, uint32 dataSize) {
|
||||
if (pos() > _dataEndOffset) {
|
||||
uint overrun = pos() - _dataEndOffset;
|
||||
error("%s: Attempted to read 0x%x bytes at a location 0x%x bytes past end of chunk (@0x%llx)", __func__, dataSize, overrun, static_cast<long long int>(pos()));
|
||||
} else {
|
||||
return _parentStream->read(dataPtr, dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
bool Chunk::seek(int64 offset, int whence) {
|
||||
bool result = _parentStream->seek(offset, whence);
|
||||
if (result == false)
|
||||
return false;
|
||||
|
||||
if (pos() < _dataStartOffset) {
|
||||
uint overrun = _dataStartOffset - offset;
|
||||
error("Attempted to seek 0x%x bytes before start of chunk (@0x%llx)", overrun, static_cast<long long int>(pos()));
|
||||
} else if (pos() > _dataEndOffset) {
|
||||
uint overrun = offset - _dataEndOffset;
|
||||
error("Attempted to seek 0x%x bytes past end of chunk (@0x%llx)", overrun, static_cast<long long int>(pos()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Subfile::Subfile(Common::SeekableReadStream *stream) : _stream(stream) {
|
||||
// Verify file signature.
|
||||
debugC(5, kDebugLoading, "\n*** Subfile::Subfile(): Got new subfile (@0x%llx) ***", static_cast<long long int>(_stream->pos()));
|
||||
_rootChunk = nextChunk();
|
||||
if (_rootChunk._id != MKTAG('R', 'I', 'F', 'F'))
|
||||
error("%s: Expected \"RIFF\" chunk, got %s (@0x%llx)", __func__, tag2str(_rootChunk._id), static_cast<long long int>(_stream->pos()));
|
||||
_stream->skip(4); // IMTS
|
||||
|
||||
// Read the RATE chunk.
|
||||
// This chunk should always contain just one piece of data,
|
||||
// the "rate" (whatever that is). Usually it is zero.
|
||||
// TODO: Figure out what this actually is.
|
||||
Chunk rateChunk = nextChunk();
|
||||
if (rateChunk._id != MKTAG('r', 'a', 't', 'e'))
|
||||
error("%s: Expected \"rate\" chunk, got %s (@0x%llx)", __func__, tag2str(_rootChunk._id), static_cast<long long int>(_stream->pos()));
|
||||
_rate = _stream->readUint32LE();
|
||||
|
||||
// Queue up the first data chunk.
|
||||
// First, we need to read past the LIST chunk.
|
||||
nextChunk();
|
||||
if (_stream->readUint32BE() != MKTAG('d', 'a', 't', 'a'))
|
||||
error("%s: Expected \"data\" as first bytes of subfile, got %s @0x%llx)", __func__, tag2str(rateChunk._id), static_cast<long long int>(_stream->pos()));
|
||||
}
|
||||
|
||||
Chunk Subfile::nextChunk() {
|
||||
// Chunks always start on even-indexed bytes.
|
||||
if (_stream->pos() & 1)
|
||||
_stream->skip(1);
|
||||
|
||||
_currentChunk = Chunk(_stream);
|
||||
return _currentChunk;
|
||||
}
|
||||
|
||||
bool Subfile::atEnd() {
|
||||
// There might be a padding byte at the end of the subfile, so
|
||||
// we need to check for that.
|
||||
if (_rootChunk.pos() % 2 == 0) {
|
||||
return _rootChunk.bytesRemaining() == 0;
|
||||
} else {
|
||||
return _rootChunk.bytesRemaining() == 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CdRomStream::openStream(uint streamId) {
|
||||
const StreamInfo &streamInfo = g_engine->streamInfoForIdent(streamId);
|
||||
if (streamInfo._fileId == 0) {
|
||||
error("%s: Stream %d not found in current title", __func__, streamId);
|
||||
}
|
||||
|
||||
const FileInfo &fileInfo = g_engine->fileInfoForIdent(streamInfo._fileId);
|
||||
if (fileInfo._id == 0) {
|
||||
error("%s: File %d for stream %d not found in current title", __func__, streamInfo._fileId, streamId);
|
||||
}
|
||||
|
||||
bool requestedStreamAlreadyOpen = isOpen() && _fileId == streamInfo._fileId;
|
||||
if (requestedStreamAlreadyOpen) {
|
||||
seek(streamInfo._startOffsetInFile);
|
||||
} else {
|
||||
if (isOpen()) {
|
||||
close();
|
||||
}
|
||||
|
||||
Common::Path filename(fileInfo._name);
|
||||
if (!open(filename)) {
|
||||
error("%s: Failed to open %s", __func__, filename.toString().c_str());
|
||||
}
|
||||
seek(streamInfo._startOffsetInFile);
|
||||
_fileId = streamInfo._fileId;
|
||||
}
|
||||
}
|
||||
|
||||
Subfile CdRomStream::getNextSubfile() {
|
||||
return Subfile(_handle);
|
||||
}
|
||||
|
||||
void ChannelClient::registerWithStreamManager() {
|
||||
g_engine->getStreamFeedManager()->registerChannelClient(this);
|
||||
}
|
||||
|
||||
void ChannelClient::unregisterWithStreamManager() {
|
||||
g_engine->getStreamFeedManager()->unregisterChannelClient(this);
|
||||
}
|
||||
|
||||
ImtStreamFeed::ImtStreamFeed(uint actorId) : StreamFeed(actorId) {
|
||||
_stream = new CdRomStream();
|
||||
}
|
||||
|
||||
ImtStreamFeed::~ImtStreamFeed() {
|
||||
delete _stream;
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
void ImtStreamFeed::closeFeed() {
|
||||
_stream->closeStream();
|
||||
g_engine->getDocument()->streamDidClose(_id);
|
||||
}
|
||||
|
||||
void ImtStreamFeed::openFeed(uint streamId, uint startOffset) {
|
||||
// For CXT files, there is a 0x10-byte header before the first stream, but this header
|
||||
// isn't actually used by the engine. This header is not present in BOOT.STM.
|
||||
// [0x00-0x04] Byte order - either II\0\0 for Intel byte order or MM\0\0 for Motorola byte order.
|
||||
// Motorola byte order never actually seems to be used for data files, even on big-endian
|
||||
// platforms. Other parts of the engine perform the byte swapping on the fly.
|
||||
// [0x05-0x08] Unknown.
|
||||
// [0x09-0x0c] Stream (subfile) count in this file, uint32le.
|
||||
// [0x0d-0x10] Total file size, uint32le.
|
||||
|
||||
// The original had an intermediary StreamProgress class here, with a StreamProgressClient
|
||||
// class, but there as only
|
||||
g_engine->getDocument()->streamDidOpen(streamId);
|
||||
_stream->openStream(streamId);
|
||||
}
|
||||
|
||||
void ImtStreamFeed::readData() {
|
||||
Subfile subfile = _stream->getNextSubfile();
|
||||
Chunk chunk = subfile.nextChunk();
|
||||
g_engine->getDocument()->streamWillRead(_id);
|
||||
g_engine->readHeaderSections(subfile, chunk);
|
||||
g_engine->getDocument()->streamDidFinish(_id);
|
||||
}
|
||||
|
||||
StreamFeedManager::~StreamFeedManager() {
|
||||
for (auto it = _streamFeeds.begin(); it != _streamFeeds.end(); ++it) {
|
||||
delete it->_value;
|
||||
}
|
||||
_streamFeeds.clear();
|
||||
}
|
||||
|
||||
void StreamFeedManager::closeStreamFeed(StreamFeed *streamFeed) {
|
||||
streamFeed->closeFeed();
|
||||
_streamFeeds.erase(streamFeed->_id);
|
||||
delete streamFeed;
|
||||
}
|
||||
|
||||
void StreamFeedManager::registerChannelClient(ChannelClient *client) {
|
||||
if (_channelClients.getValOrDefault(client->channelIdent()) != nullptr) {
|
||||
error("%s: Channel ident %d already has a client", __func__, client->channelIdent());
|
||||
}
|
||||
_channelClients.setVal(client->channelIdent(), client);
|
||||
}
|
||||
|
||||
void StreamFeedManager::unregisterChannelClient(ChannelClient *client) {
|
||||
_channelClients.erase(client->channelIdent());
|
||||
}
|
||||
|
||||
ImtStreamFeed *StreamFeedManager::openStreamFeed(uint actorId, uint offsetInStream, uint maxBytesToRead) {
|
||||
ImtStreamFeed *streamFeed = new ImtStreamFeed(actorId);
|
||||
streamFeed->openFeed(actorId, offsetInStream);
|
||||
_streamFeeds.setVal(actorId, streamFeed);
|
||||
return streamFeed;
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
228
engines/mediastation/datafile.h
Normal file
228
engines/mediastation/datafile.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_DATAFILE_H
|
||||
#define MEDIASTATION_DATAFILE_H
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/path.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
// The version number of this engine,
|
||||
// in the form 4.0r8 (major . minor r revision).
|
||||
struct VersionInfo {
|
||||
uint16 major = 0;
|
||||
uint16 minor = 0;
|
||||
uint16 patch = 0;
|
||||
};
|
||||
|
||||
typedef Common::Array<Common::Point> Polygon;
|
||||
|
||||
// A Media Station datafile consists of one or more RIFF-style "subfiles". Aside
|
||||
// from some oddness at the start of the subfile, each subfile is basically
|
||||
// standard sequence of chunks inside a LIST chunk, like you'd see in any RIFF
|
||||
// file. These chunks have special IDs:
|
||||
// - igod: Indicates a chunk that contains metadata about actor(s) in metadata sections.
|
||||
// - a000, where 000 is a string that represents a 3-digit hexadecimal number.
|
||||
// Indicates a chunk that contains actor data (sounds and bitmaps).
|
||||
|
||||
enum DatumType {
|
||||
kDatumTypeEmpty = 0x00,
|
||||
kDatumTypeUint8 = 0x02,
|
||||
kDatumTypeUint16 = 0x03,
|
||||
kDatumTypeUint32 = 0x04,
|
||||
kDatumTypeInt8 = 0x05,
|
||||
kDatumTypeInt16 = 0x06,
|
||||
kDatumTypeInt32 = 0x07,
|
||||
kDatumTypeFloat = 0x08,
|
||||
kDatumTypeDouble = 0x09,
|
||||
kDatumTypeFilename = 0x0a,
|
||||
kDatumTypeRect = 0x0d,
|
||||
kDatumTypePoint = 0x0e,
|
||||
kDatumTypeGraphicSize = 0x0f,
|
||||
kDatumTypeGraphicUnit = 0x10,
|
||||
kDatumTypeTime = 0x11,
|
||||
kDatumTypeString = 0x12,
|
||||
kDatumTypeVersion = 0x13,
|
||||
kDatumTypeChannelIdent = 0x1b,
|
||||
kDatumTypePolygon = 0x1d,
|
||||
};
|
||||
|
||||
class ParameterReadStream : public Common::SeekableReadStream {
|
||||
public:
|
||||
// Data files are internally little-endian, even on game versions targeting
|
||||
// big-endian systems. The original engine has code for swapping byte order
|
||||
// at runtime when needed. All of these internally assume the data files are
|
||||
// stored little-endian on disk.
|
||||
byte readTypedByte();
|
||||
uint16 readTypedUint16();
|
||||
uint32 readTypedUint32();
|
||||
int8 readTypedSByte();
|
||||
int16 readTypedSint16();
|
||||
int32 readTypedSint32();
|
||||
float readTypedFloat();
|
||||
double readTypedDouble();
|
||||
Common::String readTypedFilename();
|
||||
Common::Rect readTypedRect();
|
||||
Common::Point readTypedPoint();
|
||||
Common::Point readTypedGraphicSize();
|
||||
int16 readTypedGraphicUnit();
|
||||
double readTypedTime();
|
||||
Common::String readTypedString();
|
||||
VersionInfo readTypedVersion();
|
||||
uint32 readTypedChannelIdent();
|
||||
Polygon readTypedPolygon();
|
||||
|
||||
private:
|
||||
void readAndVerifyType(DatumType type);
|
||||
};
|
||||
|
||||
class Chunk : public ParameterReadStream {
|
||||
public:
|
||||
Chunk() = default;
|
||||
Chunk(Common::SeekableReadStream *stream);
|
||||
|
||||
uint32 bytesRemaining();
|
||||
|
||||
uint32 _id = 0;
|
||||
uint32 _length = 0;
|
||||
|
||||
// ReadStream implementation
|
||||
virtual bool eos() const { return _parentStream->eos(); };
|
||||
virtual bool err() const { return _parentStream->err(); };
|
||||
virtual void clearErr() { _parentStream->clearErr(); };
|
||||
virtual uint32 read(void *dataPtr, uint32 dataSize);
|
||||
virtual int64 pos() const { return _parentStream->pos(); };
|
||||
virtual int64 size() const { return _parentStream->size(); };
|
||||
virtual bool skip(uint32 offset) { return seek(offset, SEEK_CUR); };
|
||||
virtual bool seek(int64 offset, int whence = SEEK_SET);
|
||||
|
||||
private:
|
||||
Common::SeekableReadStream *_parentStream = nullptr;
|
||||
uint32 _dataStartOffset = 0;
|
||||
uint32 _dataEndOffset = 0;
|
||||
};
|
||||
|
||||
class Subfile {
|
||||
public:
|
||||
Subfile() = default;
|
||||
Subfile(Common::SeekableReadStream *stream);
|
||||
|
||||
Chunk nextChunk();
|
||||
bool atEnd();
|
||||
|
||||
Chunk _currentChunk;
|
||||
uint32 _rate;
|
||||
|
||||
private:
|
||||
Common::SeekableReadStream *_stream = nullptr;
|
||||
Chunk _rootChunk;
|
||||
};
|
||||
|
||||
// The stream loading class hierarchy presented below is a bit complex for reading directly
|
||||
// from streams, like we can do on modern computers, without needing to worry about
|
||||
// buffering from CD-ROM. But we are staying close to the original logic and class
|
||||
// hierarchy where possible, so some of that original architecture is reflected here.
|
||||
typedef uint32 ChannelIdent;
|
||||
|
||||
class CdRomStream : public Common::File {
|
||||
public:
|
||||
CdRomStream() {};
|
||||
void openStream(uint streamId);
|
||||
void closeStream() { close(); }
|
||||
|
||||
Subfile getNextSubfile();
|
||||
|
||||
private:
|
||||
uint _fileId = 0;
|
||||
};
|
||||
|
||||
class ChannelClient {
|
||||
public:
|
||||
virtual ~ChannelClient() {};
|
||||
|
||||
void setChannelIdent(ChannelIdent channelIdent) { _channelIdent = channelIdent; }
|
||||
ChannelIdent channelIdent() const { return _channelIdent; }
|
||||
|
||||
virtual void readChunk(Chunk &chunk) {};
|
||||
|
||||
void registerWithStreamManager();
|
||||
void unregisterWithStreamManager();
|
||||
|
||||
protected:
|
||||
ChannelIdent _channelIdent = 0;
|
||||
};
|
||||
|
||||
class StreamFeed {
|
||||
public:
|
||||
StreamFeed(uint streamId) : _id(streamId) {};
|
||||
virtual ~StreamFeed() {};
|
||||
|
||||
virtual void openFeed(uint streamId, uint startOffset) = 0;
|
||||
|
||||
// The original also has forceCloseFeed, which doesn't do some other cleanup
|
||||
// that the regular closeFeed does. However, since we are not doing caching and
|
||||
// some other functionality in the original, we don't need this.
|
||||
virtual void closeFeed() = 0;
|
||||
virtual void stopFeed() = 0;
|
||||
virtual void readData() = 0;
|
||||
|
||||
uint _id = 0;
|
||||
|
||||
protected:
|
||||
CdRomStream *_stream = nullptr;
|
||||
};
|
||||
|
||||
class ImtStreamFeed : public StreamFeed {
|
||||
public:
|
||||
ImtStreamFeed(uint streamId);
|
||||
~ImtStreamFeed();
|
||||
|
||||
virtual void openFeed(uint streamId, uint startOffset) override;
|
||||
virtual void closeFeed() override;
|
||||
// This implementation is currently empty because all this has to do with read timing.
|
||||
virtual void stopFeed() override {};
|
||||
virtual void readData() override;
|
||||
};
|
||||
|
||||
class StreamFeedManager {
|
||||
public:
|
||||
~StreamFeedManager();
|
||||
|
||||
void registerChannelClient(ChannelClient *client);
|
||||
void unregisterChannelClient(ChannelClient *client);
|
||||
ChannelClient *channelClientForChannel(uint clientId) { return _channelClients.getValOrDefault(clientId); }
|
||||
|
||||
ImtStreamFeed *openStreamFeed(uint streamId, uint offsetInStream = 0, uint maxBytesToRead = 0);
|
||||
void closeStreamFeed(StreamFeed *streamFeed);
|
||||
|
||||
private:
|
||||
Common::HashMap<uint, StreamFeed *> _streamFeeds;
|
||||
Common::HashMap<ChannelIdent, ChannelClient *> _channelClients;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
45
engines/mediastation/debugchannels.h
Normal file
45
engines/mediastation/debugchannels.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_DEBUG_CHANNELS_H
|
||||
#define MEDIASTATION_DEBUG_CHANNELS_H
|
||||
|
||||
// This is a convenience so we don't have to include
|
||||
// two files in every translation unit where we want
|
||||
// debugging support.
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
// TODO: Finish comments that describe the various debug levels.
|
||||
enum DebugChannels {
|
||||
kDebugGraphics = 1,
|
||||
kDebugCamera,
|
||||
kDebugPath,
|
||||
kDebugScan,
|
||||
kDebugScript,
|
||||
kDebugEvents,
|
||||
kDebugLoading,
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
52
engines/mediastation/detection.cpp
Normal file
52
engines/mediastation/detection.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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 "base/plugins.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
#include "common/md5.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "mediastation/detection.h"
|
||||
#include "mediastation/detection_tables.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
const DebugChannelDef MediaStationMetaEngineDetection::debugFlagList[] = {
|
||||
{ MediaStation::kDebugGraphics, "graphics", "Graphics debug level" },
|
||||
{ MediaStation::kDebugCamera, "camera", "Camera panning debug level" },
|
||||
{ MediaStation::kDebugPath, "path", "Pathfinding debug level" },
|
||||
{ MediaStation::kDebugScan, "scan", "Scan for unrecognised games" },
|
||||
{ MediaStation::kDebugScript, "script", "Enable debug script dump" },
|
||||
{ MediaStation::kDebugEvents, "events", "Events processing" },
|
||||
{ MediaStation::kDebugLoading, "loading", "File loading" },
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
MediaStationMetaEngineDetection::MediaStationMetaEngineDetection() : AdvancedMetaEngineDetection(
|
||||
MediaStation::gameDescriptions, MediaStation::mediastationGames) {
|
||||
_maxScanDepth = 3;
|
||||
_directoryGlobs = MediaStation::directoryGlobs;
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(MEDIASTATION_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, MediaStationMetaEngineDetection);
|
||||
61
engines/mediastation/detection.h
Normal file
61
engines/mediastation/detection.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_DETECTION_H
|
||||
#define MEDIASTATION_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
extern const PlainGameDescriptor mediastationGames[];
|
||||
|
||||
extern const ADGameDescription gameDescriptions[];
|
||||
|
||||
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
class MediaStationMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
static const DebugChannelDef debugFlagList[];
|
||||
|
||||
public:
|
||||
MediaStationMetaEngineDetection();
|
||||
~MediaStationMetaEngineDetection() override {}
|
||||
|
||||
const char *getName() const override {
|
||||
return "mediastation";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Media Station";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "(C) 1994 - 1999 Media Station, Inc.";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MEDIASTATION_DETECTION_H
|
||||
730
engines/mediastation/detection_tables.h
Normal file
730
engines/mediastation/detection_tables.h
Normal file
@@ -0,0 +1,730 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
const PlainGameDescriptor mediastationGames[] = {
|
||||
{ "georgeshrinks", "George Shrinks Interactive Storybook" },
|
||||
{ "mousecookie", "If You Give a Mouse a Cookie Interactive Storybook" },
|
||||
{ "lionking", "Disney's Animated Storybook: The Lion King" },
|
||||
{ "janpienkowski", "Jan Pieńkowski Haunted House" },
|
||||
{ "lambchop", "Lamb Chop Loves Music" },
|
||||
{ "frogprince", "Fractured Fairy Tales: The Frog Prince" },
|
||||
{ "honeytree", "Disney's Animated Storybook: Winnie the Pooh and the Honey Tree" },
|
||||
{ "notredame", "Disney's Animated Storybook: The Hunchback of Notre Dame" },
|
||||
{ "puzzlecastle", "Puzzle Castle" },
|
||||
{ "ibmcrayola", "IBM/Crayola Print Factory" },
|
||||
{ "ibmcrayolaholiday", "IBM/Crayola Print Factory Holiday Activity" },
|
||||
{ "101dalmatians", "Disney's Animated Storybook: 101 Dalmatians" },
|
||||
{ "herculesasb", "Disney's Animated Storybook: Hercules" },
|
||||
{ "pocahontas", "Disney's Animated Storybook: Pocahontas"},
|
||||
{ "barbieasrapunzel", "Magic Fairy Tales: Barbie as Rapunzel" },
|
||||
{ "tonkasearchandrescue", "Tonka Search and Rescue" },
|
||||
{ "arielstorystudio", "Disney presents Ariel's Story Studio" },
|
||||
{ "tonkagarage", "Tonka Garage" },
|
||||
{ "dwpickyeater", "D.W. the Picky Eater" },
|
||||
{ "tonkaworkshop", "Tonka Workshop" },
|
||||
{ "tonkaraceway", "Tonka Raceway" },
|
||||
{ "stuartlittlebigcity", "Stuart Little: Big City Adventures"},
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
// In these entries, the executable must always be listed first.
|
||||
// The title version can be obtained by pressing Ctrl-V while running
|
||||
// the original interpreter. Some titles include a built-in language code
|
||||
// (e.g. "v1.0/DE" or "v1.0/US") but others do not (e.g. "v1.1").
|
||||
const ADGameDescription gameDescriptions[] = {
|
||||
// George Shrinks Interactive Storybook
|
||||
// This title seems to be Windows-only.
|
||||
{
|
||||
"georgeshrinks",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"GEORGE.EX_", "ae70a2efbe5fbe66ad7bb9f269ea0a2f", 139674, // Packed executable
|
||||
"BOOT.STM", "5b7c08398fe6ae016db9d94ad9240241", 6744,
|
||||
"103.CXT", "e7d563ff79f1b1416e5f1e0c803f78ec", 1474802
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// If You Give a Mouse a Cookie Interactive Storybook
|
||||
{
|
||||
"mousecookie",
|
||||
"v2.0",
|
||||
AD_ENTRY3s(
|
||||
"MOUSECKE.EXE", "58350e268ec0cdf4fa21281a9d83fd80", 329568,
|
||||
"BOOT.STM", "11d11b2067519d8368175cc8e8caa94f", 59454,
|
||||
"100.CXT", "cac48b9bb5f327d035a831cd15f1688c", 1762032
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"mousecookie",
|
||||
"v2.0",
|
||||
AD_ENTRY3s(
|
||||
"If You Give a Mouse a Cookie", "r:d23bc24ab6da4d97547a6f2c35946f12", 265297,
|
||||
"BOOT.STM", "11d11b2067519d8368175cc8e8caa94f", 59454,
|
||||
"100.CXT", "cac48b9bb5f327d035a831cd15f1688c", 1762032
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Disney's Animated Storybook: The Lion King
|
||||
{
|
||||
"lionking",
|
||||
"v2.0/GB",
|
||||
AD_ENTRY3s(
|
||||
"LIONKING.EXE", "3239451c477eaa16015110502be031a5", 363232,
|
||||
"BOOT.STM", "dd83fd1fb899b680f00c586404cc7b7c", 23610,
|
||||
"100.CXT", "d5dc4d49df2ea6f2ff0aa33a3f385506", 1455740
|
||||
),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"lionking",
|
||||
"v2.0/GB",
|
||||
AD_ENTRY3s(
|
||||
"The Lion King", "r:24a4a5f56188c78d2ef16cd1646379f6", 311245,
|
||||
"BOOT.STM", "dd83fd1fb899b680f00c586404cc7b7c", 23610,
|
||||
"100.CXT", "d5dc4d49df2ea6f2ff0aa33a3f385506", 1455740
|
||||
),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Jan Pieńkowski Haunted House
|
||||
{
|
||||
"janpienkowski",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"HAUNTED.EXE", "869bcbae21bcfd87a63474f9efb042df", 330336,
|
||||
"BOOT.STM", "d01f338d6a3912056aff8f9022867bba", 137830,
|
||||
"100.CXT", "6154f6efef3a8e54476c10d522dcec20", 1164800
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"janpienkowski",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"Haunted House", "r:9d4e1623d86d0474d3813e2a9ddf51e0", 266166,
|
||||
"BOOT.STM", "d01f338d6a3912056aff8f9022867bba", 137830,
|
||||
"100.CXT", "6154f6efef3a8e54476c10d522dcec20", 1164800
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Lamb Chop Loves Music
|
||||
{
|
||||
"lambchop",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"LCMUSIC.EXE", "1830080b410abd103c5064f583bdca1e", 329504,
|
||||
"BOOT.STM", "c90200e52bcaad52524520d461caef2b", 29884,
|
||||
"100.CXT", "ce40843604b8c52701694cd543072a88", 3253600
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"lambchop",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"Lamb Chop Loves Music", "r:5ae7f4d1c5c74470c8f09ca37238c33b", 265388,
|
||||
"BOOT.STM", "c90200e52bcaad52524520d461caef2b", 29884,
|
||||
"100.CXT", "ce40843604b8c52701694cd543072a88", 3253600
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Fractured Fairy Tales: The Frog Prince
|
||||
{
|
||||
"frogprince",
|
||||
"v1.1",
|
||||
AD_ENTRY3s(
|
||||
"FPRINCE.EXE", "cd7aff763bb4879cc3a11def90dd7cb7", 513984,
|
||||
"BOOT.STM", "1c6d14c87790d009702be8ba4e4e5906", 13652,
|
||||
"100.CXT", "a5ec9a32c3741a20b82e1793e76234b2", 1630762
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"frogprince",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"FPRINCE.EXE", "a8f3a63ef2032de300f46397cea625df", 518400,
|
||||
"BOOT.STM", "1c6d14c87790d009702be8ba4e4e5906", 13652,
|
||||
"100.CXT", "a5ec9a32c3741a20b82e1793e76234b2", 1630762
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"frogprince",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"The Frog Prince", "r:d77fd2a5dfb81a7fde03d175f93244bd", 1005600,
|
||||
"BOOT.STM", "1c6d14c87790d009702be8ba4e4e5906", 13652,
|
||||
"100.CXT", "a5ec9a32c3741a20b82e1793e76234b2", 1630762
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Disney's Animated Storybook: Winnie the Pooh and the Honey Tree
|
||||
{
|
||||
"honeytree",
|
||||
"v2.0/US", // Also includes Spanish as an in-game language option.
|
||||
AD_ENTRY3s(
|
||||
"WPHTASB.EXE", "916666c49efeeaeae61eb669405fc66f", 433024,
|
||||
"BOOT.STM", "9b9f528bf9c9b8ebe194b0c47dbe485e", 55422,
|
||||
"100.CXT", "30f010077fd0489933989a562db81ad6", 1971940
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"honeytree",
|
||||
"v2.0/US", // Also includes Spanish as an in-game language option.
|
||||
AD_ENTRY3s(
|
||||
"Pooh and the Honey Tree", "r:3f0077774418305ccd4c20cb6fa4c765", 764753,
|
||||
"BOOT.STM", "9b9f528bf9c9b8ebe194b0c47dbe485e", 55422,
|
||||
"100.CXT", "30f010077fd0489933989a562db81ad6", 1971940
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"honeytree",
|
||||
"v2.0/SE", // Also includes English as an in-game language option.
|
||||
AD_ENTRY3s(
|
||||
"WPHTASB.EXE", "8cbb2b365a1073ca5c8c1fde301094ea", 443008,
|
||||
"BOOT.STM", "448efdc32f4ce36b5e4f91b34f44437a", 55284,
|
||||
"100.CXT", "76bd87d2692b6ab7b034bbc50957156b", 1966658
|
||||
),
|
||||
Common::SV_SWE,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"honeytree",
|
||||
"v2.0/SE", // Also includes English as an in-game language option.
|
||||
AD_ENTRY3s(
|
||||
"Nalle Puh", "r:3c061bff404de99c69a0b0187018a7da", 765688,
|
||||
"BOOT.STM", "448efdc32f4ce36b5e4f91b34f44437a", 55284,
|
||||
"100.CXT", "00239a03730b8e1c3c730050b8872d33", 2267499
|
||||
),
|
||||
Common::SV_SWE,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Disney's Animated Storybook: The Hunchback of Notre Dame
|
||||
{
|
||||
"notredame",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"HB_ASB.EXE", "f3f2e83562d7941a99d299ae31600f07", 533120,
|
||||
"BOOT.STM", "7949e1253a62531e53963a2fffe57211", 55300,
|
||||
"100.CXT", "54c11a94888a1b747e1c8935b7315889", 4766278
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"notredame",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"Hunchback Animated StoryBook", "r:711b5eba6477f801177cd9095a51e1a5", 1044920,
|
||||
"BOOT.STM", "7949e1253a62531e53963a2fffe57211", 55300,
|
||||
"100.CXT", "54c11a94888a1b747e1c8935b7315889", 4766278
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Puzzle Castle
|
||||
{
|
||||
"puzzlecastle",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"PZCASTLE.EXE", "ce44597dcbad42f2396d4963c06714d5", 528224,
|
||||
"BOOT.STM", "7b0faf38da2d76df40b4085eed6f4fc8", 22080,
|
||||
"100.CXT", "ebc4b6247b742733c81456dfd299aa55", 3346944
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"puzzlecastle",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"Puzzle Castle", "r:aa2c5c12ec9e0d3cba54efcbd143f8e0", 959690,
|
||||
"BOOT.STM", "7b0faf38da2d76df40b4085eed6f4fc8", 22080,
|
||||
"100.CXT", "ebc4b6247b742733c81456dfd299aa55", 3346944
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"puzzlecastle",
|
||||
"v1.0 Demo",
|
||||
AD_ENTRY3s(
|
||||
"DEMO.EXE", "63dedc1e2cdf8a39725ef9ca99273cc4", 514496,
|
||||
"BOOT.STM", "b7ce005e0d67021f792ebb73e7fbe34c", 5960,
|
||||
"100.CXT", "cc64a6fcb3af2736d622658cff3ef2b5", 1262
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE | ADGF_DEMO,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"puzzlecastle",
|
||||
"v1.0 Demo",
|
||||
AD_ENTRY3s(
|
||||
"Puzzle Castle Demo", "r:f9f4715f39e084ac80e6b222cb69b20e", 959563,
|
||||
"BOOT.STM", "b7ce005e0d67021f792ebb73e7fbe34c", 5960,
|
||||
"100.CXT", "cc64a6fcb3af2736d622658cff3ef2b5", 1262
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE | ADGF_DEMO,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// IBM/Crayola Print Factory
|
||||
{
|
||||
"ibmcrayola",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"PRINTFAC.EXE", "2571746dcb8b8d386f2ef07255e715ba", 721248,
|
||||
"BOOT.STM", "359542015c6665c70252cf21a8467cdb", 11044,
|
||||
"100.CXT", "42bffe4165640dd1e64a6e8565f48af3", 5125226
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"ibmcrayola",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"IBM and Crayola Print Factory", "r:f30fbc530b26feb0ed23164e632c1a88", 1583870,
|
||||
"BOOT.STM", "359542015c6665c70252cf21a8467cdb", 11044,
|
||||
"100.CXT", "42bffe4165640dd1e64a6e8565f48af3", 5125226
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// IBM/Crayola Print Factory Holiday Activity Pack
|
||||
{
|
||||
"ibmcrayolaholiday",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"HOLIDAY.EXE", "10b70a2cb94f92295d26f43540129f14", 742048,
|
||||
"BOOT.STM", "50f30298bf700f357d98c4390f75cb7a", 10932,
|
||||
"100.CXT", "8110f70f1d01d0f42cac9b1bb6d2de12", 4967390
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"ibmcrayolaholiday",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"HOLIDAY.EXE", "r:bf5345cf76a4ee24823634b420739771", 1576023,
|
||||
"BOOT.STM", "50f30298bf700f357d98c4390f75cb7a", 10932,
|
||||
"100.CXT", "8110f70f1d01d0f42cac9b1bb6d2de12", 4967390
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Disney's Animated Storybook: 101 Dalmatians
|
||||
{
|
||||
"101dalmatians",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"101_ASB.EXE", "42d7d258652bdc7ecd0e39e8b326bc38", 528736,
|
||||
"BOOT.STM", "ee6725a718cbce640d02acec2b84825f", 47970,
|
||||
"100.CXT", "2df853283a3fd2d079b06bc27b50527f", 6784502
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"101dalmatians",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"101 Dalmatians StoryBook", "r:9ec3f0b3fd6c28650e00475b6bf08615", 1042456,
|
||||
"BOOT.STM", "ee6725a718cbce640d02acec2b84825f", 47970,
|
||||
"100.CXT", "2df853283a3fd2d079b06bc27b50527f", 6784502
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Disney's Animated Storybook: Hercules
|
||||
{
|
||||
"herculesasb",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"HERC_ASB.EXE", "23663fabde2db43a2e8f6a23e7495e01", 543040,
|
||||
"BOOT.STM", "afc773416e46e30873f743e234794957", 26924,
|
||||
"100.CXT", "56875e1640320909e9697f11b5a8c9a6", 4895998
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"herculesasb",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"Hercules Animated Storybook", "r:d870f6a3ab564f25428c7a7179cc1e53", 1173749,
|
||||
"BOOT.STM", "afc773416e46e30873f743e234794957", 26924,
|
||||
"100.CXT", "56875e1640320909e9697f11b5a8c9a6", 4895998
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Disney's Animated Storybook: Pocahontas
|
||||
{
|
||||
"pocahontas",
|
||||
"v1.0/SE", // Also includes English as an in-game language option
|
||||
AD_ENTRY3s(
|
||||
"POCA_ASB.EXE", "b5dc94c806c1122a69b19a2ef9113d3c", 389440,
|
||||
"BOOT.STM", "dfb9353599cf8ca0f95095353041ef54", 337944,
|
||||
"100.CXT", "7f9fae41a07e8e1cc467d1b2be37ef9d", 1117144
|
||||
),
|
||||
Common::SV_SWE,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"pocahontas",
|
||||
"v1.0/SE", // Also includes English as an in-game language option
|
||||
AD_ENTRY3s(
|
||||
"Pocahontas", "r:6b0d52f286954d7dbb5fd703ff696b40", 326402,
|
||||
"BOOT.STM", "dfb9353599cf8ca0f95095353041ef54", 337944,
|
||||
"100.CXT", "7f9fae41a07e8e1cc467d1b2be37ef9d", 1117144
|
||||
),
|
||||
Common::SV_SWE,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"pocahontas",
|
||||
"v1.1.01 English",
|
||||
AD_ENTRY3s(
|
||||
"POCA_ASB.EXE", "0287ca22a971d305e9a67fc4fc87239d", 367552,
|
||||
"BOOT.STM", "d35338f9f014b73a8471523f3b141f2d", 324138,
|
||||
"100.CXT", "8d7b65d4c50515c8b28a91980017d327", 1107900
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"pocahontas",
|
||||
"v1.1.01 English",
|
||||
AD_ENTRY3s(
|
||||
"Pocahontas", "r:6b0d52f286954d7dbb5fd703ff696b40", 319909,
|
||||
"BOOT.STM", "d35338f9f014b73a8471523f3b141f2d", 324138,
|
||||
"100.CXT", "8d7b65d4c50515c8b28a91980017d327", 1107900
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Magic Fairy Tales: Barbie as Rapunzel
|
||||
{
|
||||
"barbieasrapunzel",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"RAPUNZEL.EXE", "e47a752fe748258ebc0f5ee6f31b385b", 535840,
|
||||
"BOOT.STM", "eef6bdf54d2ae25af0ec29361fd4c126", 17530,
|
||||
"100.CXT", "f0bcc27b61bfb33328db2dd537b2b6e3", 1688902
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"barbieasrapunzel",
|
||||
"v1.0",
|
||||
AD_ENTRY3s(
|
||||
"Rapunzel", "r:b8b5fc7def85c07ed4c673e8a80ed338", 1043127,
|
||||
"BOOT.STM", "eef6bdf54d2ae25af0ec29361fd4c126", 17530,
|
||||
"100.CXT", "f0bcc27b61bfb33328db2dd537b2b6e3", 1688902
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Tonka Search and Rescue
|
||||
{
|
||||
"tonkasearchandrescue",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"TONKA_SR.EXE", "46037a28e0cbf6df9ed3218e58ee1ae2", 561984, // 32-bit (PE)
|
||||
"BOOT.STM", "90c5f17734219c3a442316d21e6833f8", 25362,
|
||||
"100.CXT", "85a05487b6c499ba3ce86d043305ddfd", 6410562
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"tonkasearchandrescue",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"Tonka Search and Rescue", "r:432c202bcc7b259c2927e0f6fb1bbd64", 567011,
|
||||
"BOOT.STM", "90c5f17734219c3a442316d21e6833f8", 25362,
|
||||
"100.CXT", "85a05487b6c499ba3ce86d043305ddfd", 6410562
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Disney presents Ariel's Story Studio
|
||||
{
|
||||
"arielstorystudio",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"ARIEL_SS.EXE", "bb2afc5205a852e59d77631c454fde5d", 606720,
|
||||
"BOOT.STM", "297670b908f887ed6c97b364406575d0", 65480,
|
||||
"100.CXT", "c12c5b784ad931eca293a9816c11043b", 6532022
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"arielstorystudio",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"Ariel's Story Studio", "r:7a21e3080828b50c43e4b7805617db9c", 1523037,
|
||||
"BOOT.STM", "297670b908f887ed6c97b364406575d0", 65480,
|
||||
"100.CXT", "c12c5b784ad931eca293a9816c11043b", 6532022
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"arielstorystudio",
|
||||
"v1.1/US",
|
||||
AD_ENTRY3s(
|
||||
"MERMAID.EXE", "2eabe2910cf5a2df32dcc889ebd90cea", 634240,
|
||||
"BOOT.STM", "7d53a551efde620fe5b332d7b1f009ab", 65450,
|
||||
"100.CXT", "993252bca0aa6791ca3da30b1ae6f5f8", 6532022
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Tonka Garage
|
||||
// This title seems to be Windows-only.
|
||||
{
|
||||
"tonkagarage",
|
||||
"v1.1/US",
|
||||
AD_ENTRY3s(
|
||||
"TONKA_GR.EXE", "4e7e75ac11c996454b334f9add38c691", 1297408, // 32-bit (PE)
|
||||
"BOOT.STM", "fc8863bb302e94d3b778b3a97556601b", 25208,
|
||||
"100.CXT", "13683c2a06275920181d9dda5b2b69e7", 2691398
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// D.W. the Picky Eater (Living Books)
|
||||
{
|
||||
"dwpickyeater",
|
||||
"v1.0/US (32-bit)",
|
||||
AD_ENTRY3s(
|
||||
"DW_32.EXE", "3612aa19a2809f9cb6ee48046e5d7068", 1079296, // 32-bit (PE)
|
||||
"BOOT.STM", "80cc94e3e894ee8c5a22a9c07a33d891", 26402,
|
||||
"100.CXT", "e65e359ab25d7a639cf369a01b9a21c0", 2163750
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"dwpickyeater",
|
||||
"v1.0/US (16-bit)",
|
||||
AD_ENTRY3s(
|
||||
"DW_16.EXE", "56553be9eee6130b4458fe9dfa2bcacf", 1007184,
|
||||
"BOOT.STM", "80cc94e3e894ee8c5a22a9c07a33d891", 26402,
|
||||
"100.CXT", "e65e359ab25d7a639cf369a01b9a21c0", 2163750
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
{
|
||||
"dwpickyeater",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"D.W. the Picky Eater", "r:4f85d13c1d241ffd37787884d0da2aef", 2502801,
|
||||
"BOOT.STM", "80cc94e3e894ee8c5a22a9c07a33d891", 26402,
|
||||
"100.CXT", "e65e359ab25d7a639cf369a01b9a21c0", 2163750
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Tonka Workshop
|
||||
// This title seems to be Windows-only.
|
||||
{
|
||||
"tonkaworkshop",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"TONKA_W.EXE", "f3e480c57967093b87db68cb8f3f3a18", 1097728, // 32-bit (PE)
|
||||
"BOOT.STM", "15e6d32925f557f3196fd0bb79b25375", 38190,
|
||||
"100.CXT", "1cb35998f2e044eee59a96120b3bda6c", 2691398
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Tonka Raceway
|
||||
// This title seems to be Windows-only.
|
||||
{
|
||||
"tonkaraceway",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"TONKA_RACEWAY.EXE", "cccd33d4d9e824bada6a1ca115794226", 1735680, // 32-bit (PE)
|
||||
"BOOT.STM", "da512cb9bcd18465294e544ed790881c", 12272,
|
||||
"100.CXT", "30802327b29fbfa722a707c3d3b0f8f8", 2691398
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
|
||||
// Stuart Little: Big City Adventures
|
||||
// This title seems to be Windows-only.
|
||||
{
|
||||
"stuartlittlebigcity",
|
||||
"v1.0/US",
|
||||
AD_ENTRY3s(
|
||||
"STUARTCD.EXE", "8aaa593c9a1a17a0e41f424d046b3de8", 1191936, // 32-bit (PE)
|
||||
"BOOT.STM", "992787bf30104a4b7aa2ead64dda21ff", 10974,
|
||||
"100.CXT", "21f44a1d1de6abf8bd67341c155dfead", 2691398
|
||||
),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOASPECT)
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
763
engines/mediastation/dissolvepatterns.h
Normal file
763
engines/mediastation/dissolvepatterns.h
Normal file
@@ -0,0 +1,763 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_DISSOLVE_PATTERNS_H
|
||||
#define MEDIASTATION_DISSOLVE_PATTERNS_H
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
static const byte DISSOLVE_PATTERN_00[] = {
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_01[] = {
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_02[] = {
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_03[] = {
|
||||
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_04[] = {
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_05[] = {
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_06[] = {
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_07[] = {
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_08[] = {
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_09[] = {
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_0a[] = {
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_0b[] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_0c[] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_0d[] = {
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_0e[] = {
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_0f[] = {
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_10[] = {
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_11[] = {
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
|
||||
1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_12[] = {
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_13[] = {
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_14[] = {
|
||||
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_15[] = {
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_16[] = {
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_17[] = {
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_18[] = {
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
struct DissolvePattern {
|
||||
uint16 widthHeight;
|
||||
uint16 threshold;
|
||||
const byte *data;
|
||||
};
|
||||
|
||||
static const byte DISSOLVE_PATTERN_COUNT = 0x19;
|
||||
static const DissolvePattern DISSOLVE_PATTERNS[] = {
|
||||
{0x19, 1, DISSOLVE_PATTERN_00},
|
||||
{0x19, 1, DISSOLVE_PATTERN_01},
|
||||
{0x19, 1, DISSOLVE_PATTERN_02},
|
||||
{0x19, 1, DISSOLVE_PATTERN_03},
|
||||
{0x19, 1, DISSOLVE_PATTERN_04},
|
||||
{0x19, 1, DISSOLVE_PATTERN_05},
|
||||
{0x19, 1, DISSOLVE_PATTERN_06},
|
||||
{0x19, 1, DISSOLVE_PATTERN_07},
|
||||
{0x19, 1, DISSOLVE_PATTERN_08},
|
||||
{0x19, 1, DISSOLVE_PATTERN_09},
|
||||
{0x19, 1, DISSOLVE_PATTERN_0a},
|
||||
{0x19, 1, DISSOLVE_PATTERN_0b},
|
||||
{0x19, 0, DISSOLVE_PATTERN_0c},
|
||||
{0x19, 0, DISSOLVE_PATTERN_0d},
|
||||
{0x19, 0, DISSOLVE_PATTERN_0e},
|
||||
{0x19, 0, DISSOLVE_PATTERN_0f},
|
||||
{0x19, 0, DISSOLVE_PATTERN_10},
|
||||
{0x19, 0, DISSOLVE_PATTERN_11},
|
||||
{0x19, 0, DISSOLVE_PATTERN_12},
|
||||
{0x19, 0, DISSOLVE_PATTERN_13},
|
||||
{0x19, 0, DISSOLVE_PATTERN_14},
|
||||
{0x19, 0, DISSOLVE_PATTERN_15},
|
||||
{0x19, 0, DISSOLVE_PATTERN_16},
|
||||
{0x19, 0, DISSOLVE_PATTERN_17},
|
||||
{0x18, 1, DISSOLVE_PATTERN_18},
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
1176
engines/mediastation/graphics.cpp
Normal file
1176
engines/mediastation/graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
engines/mediastation/graphics.h
Normal file
269
engines/mediastation/graphics.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_GRAPHICS_H
|
||||
#define MEDIASTATION_GRAPHICS_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/array.h"
|
||||
#include "common/stack.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "graphics/screen.h"
|
||||
|
||||
#include "mediastation/clients.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class MediaStationEngine;
|
||||
struct DissolvePattern;
|
||||
class Bitmap;
|
||||
|
||||
enum BlitMode {
|
||||
kUncompressedBlit = 0x00,
|
||||
kRle8Blit = 0x01,
|
||||
kClipEnabled = 0x04,
|
||||
kUncompressedTransparentBlit = 0x08,
|
||||
kPartialDissolve = 0x10,
|
||||
kFullDissolve = 0x20,
|
||||
kCccBlit = 0x40,
|
||||
kCccTransparentBlit = 0x80
|
||||
};
|
||||
|
||||
enum TransitionType {
|
||||
kTransitionFadeToBlack = 300,
|
||||
kTransitionFadeToPalette = 301,
|
||||
kTransitionSetToPalette = 302,
|
||||
kTransitionSetToBlack = 303,
|
||||
kTransitionFadeToColor = 304,
|
||||
kTransitionSetToColor = 305,
|
||||
kTransitionSetToPercentOfPalette = 306,
|
||||
kTransitionFadeToPaletteObject = 307,
|
||||
kTransitionSetToPaletteObject = 308,
|
||||
kTransitionSetToPercentOfPaletteObject = 309,
|
||||
kTransitionColorShiftCurrentPalette = 310,
|
||||
kTransitionCircleOut = 328
|
||||
};
|
||||
|
||||
enum VideoDisplayManagerSectionType {
|
||||
kVideoDisplayManagerUpdateDirty = 0x578,
|
||||
kVideoDisplayManagerUpdateAll = 0x579,
|
||||
kVideoDisplayManagerEffectTransition = 0x57a,
|
||||
kVideoDisplayManagerSetTime = 0x57b,
|
||||
kVideoDisplayManagerLoadPalette = 0x5aa,
|
||||
};
|
||||
|
||||
class Region {
|
||||
public:
|
||||
void addRect(const Common::Rect &rect);
|
||||
bool intersects(const Common::Rect &rect);
|
||||
void operator&=(const Common::Rect &rect);
|
||||
void operator+=(const Common::Point &point);
|
||||
|
||||
Common::Array<Common::Rect> _rects;
|
||||
Common::Rect _bounds;
|
||||
};
|
||||
|
||||
class Clip {
|
||||
public:
|
||||
Clip() {}
|
||||
Clip(const Common::Rect &rect);
|
||||
|
||||
void addToRegion(const Region ®ion);
|
||||
void addToRegion(const Common::Rect &rect);
|
||||
bool clipIntersectsRect(const Common::Rect &rect);
|
||||
void intersectWithRegion(const Common::Rect &rect);
|
||||
void makeEmpty();
|
||||
|
||||
Region _region;
|
||||
Common::Rect _bounds;
|
||||
};
|
||||
|
||||
class DisplayContext {
|
||||
public:
|
||||
bool clipIsEmpty();
|
||||
void intersectClipWith(const Common::Rect &rect);
|
||||
bool rectIsInClip(const Common::Rect &rect);
|
||||
void setClipTo(Region region);
|
||||
void emptyCurrentClip();
|
||||
|
||||
void addClip();
|
||||
Clip *currentClip();
|
||||
Clip *previousClip();
|
||||
void verifyClipSize();
|
||||
|
||||
// These are not named as such in the original, but are helper functions
|
||||
// for things that likely were macros or something similar in the original.
|
||||
void pushOrigin();
|
||||
void popOrigin();
|
||||
|
||||
Common::Point _origin;
|
||||
Graphics::ManagedSurface *_destImage = nullptr;
|
||||
|
||||
private:
|
||||
Common::Stack<Common::Point> _origins;
|
||||
Common::Stack<Clip> _clips;
|
||||
};
|
||||
|
||||
class VideoDisplayManager : public ParameterClient {
|
||||
public:
|
||||
VideoDisplayManager(MediaStationEngine *vm);
|
||||
~VideoDisplayManager();
|
||||
|
||||
virtual bool attemptToReadFromStream(Chunk &chunk, uint sectionType) override;
|
||||
|
||||
void updateScreen() { _screen->update(); }
|
||||
Graphics::Palette *getRegisteredPalette() { return _registeredPalette; }
|
||||
void setRegisteredPalette(Graphics::Palette *palette) { _registeredPalette = palette; }
|
||||
|
||||
void imageBlit(
|
||||
Common::Point destinationPoint,
|
||||
const Bitmap *image,
|
||||
double dissolveFactor,
|
||||
DisplayContext *displayContext,
|
||||
Graphics::ManagedSurface *destinationImage = nullptr);
|
||||
|
||||
void imageDeltaBlit(
|
||||
Common::Point deltaFramePos,
|
||||
const Common::Point &keyFrameOffset,
|
||||
const Bitmap *deltaFrame,
|
||||
const Bitmap *keyFrame,
|
||||
const double dissolveFactor,
|
||||
DisplayContext *displayContext);
|
||||
|
||||
void effectTransition(Common::Array<ScriptValue> &args);
|
||||
void setTransitionOnSync(Common::Array<ScriptValue> &args) { _scheduledTransitionOnSync = args; }
|
||||
void doTransitionOnSync();
|
||||
|
||||
void performUpdateDirty();
|
||||
void performUpdateAll();
|
||||
|
||||
void setGammaValues(double red, double green, double blue);
|
||||
void getDefaultGammaValues(double &red, double &green, double &blue);
|
||||
void getGammaValues(double &red, double &green, double &blue);
|
||||
|
||||
DisplayContext _displayContext;
|
||||
|
||||
private:
|
||||
MediaStationEngine *_vm = nullptr;
|
||||
Graphics::Screen *_screen = nullptr;
|
||||
Graphics::Palette *_registeredPalette = nullptr;
|
||||
Common::Array<ScriptValue> _scheduledTransitionOnSync;
|
||||
double _defaultTransitionTime = 0.0;
|
||||
|
||||
const double DEFAULT_GAMMA_VALUE = 1.0;
|
||||
double _redGamma = 1.0;
|
||||
double _greenGamma = 1.0;
|
||||
double _blueGamma = 1.0;
|
||||
|
||||
void readAndEffectTransition(Chunk &chunk);
|
||||
void readAndRegisterPalette(Chunk &chunk);
|
||||
|
||||
// Blitting methods.
|
||||
// blitRectsClip encompasses the functionality of both opaqueBlitRectsClip
|
||||
// and transparentBlitRectsClip in the disasm.
|
||||
void blitRectsClip(
|
||||
Graphics::ManagedSurface *dest,
|
||||
const Common::Point &destLocation,
|
||||
const Graphics::ManagedSurface &source,
|
||||
const Common::Array<Common::Rect> &dirtyRegion);
|
||||
void rleBlitRectsClip(
|
||||
Graphics::ManagedSurface *dest,
|
||||
const Common::Point &destLocation,
|
||||
const Bitmap *source,
|
||||
const Common::Array<Common::Rect> &dirtyRegion);
|
||||
Graphics::ManagedSurface decompressRle8Bitmap(
|
||||
const Bitmap *source,
|
||||
const Graphics::ManagedSurface *keyFrame = nullptr,
|
||||
const Common::Point *keyFrameOffset = nullptr);
|
||||
void dissolveBlitRectsClip(
|
||||
Graphics::ManagedSurface *dest,
|
||||
const Common::Point &destPos,
|
||||
const Bitmap *source,
|
||||
const Common::Array<Common::Rect> &dirtyRegion,
|
||||
const uint dissolveFactor);
|
||||
void dissolveBlit1Rect(
|
||||
Graphics::ManagedSurface *dest,
|
||||
const Common::Rect &areaToRedraw,
|
||||
const Common::Point &originOnScreen,
|
||||
const Bitmap *source,
|
||||
const Common::Rect &dirtyRegion,
|
||||
const DissolvePattern &pattern);
|
||||
void fullDeltaRleBlitRectsClip(
|
||||
Graphics::ManagedSurface *destinationImage,
|
||||
const Common::Point &deltaFramePos,
|
||||
const Common::Point &keyFrameOffset,
|
||||
const Bitmap *deltaFrame,
|
||||
const Bitmap *keyFrame,
|
||||
const Common::Array<Common::Rect> &dirtyRegion);
|
||||
void deltaRleBlitRectsClip(
|
||||
Graphics::ManagedSurface *destinationImage,
|
||||
const Common::Point &deltaFramePos,
|
||||
const Bitmap *deltaFrame,
|
||||
const Bitmap *keyFrame,
|
||||
const Common::Array<Common::Rect> &dirtyRegion);
|
||||
void deltaRleBlit1Rect(
|
||||
Graphics::ManagedSurface *destinationImage,
|
||||
const Common::Point &destinationPoint,
|
||||
const Bitmap *sourceImage,
|
||||
const Bitmap *deltaImage,
|
||||
const Common::Rect &dirtyRect);
|
||||
|
||||
// Transition methods.
|
||||
const double DEFAULT_FADE_TRANSITION_TIME_IN_SECONDS = 0.5;
|
||||
const byte DEFAULT_PALETTE_TRANSITION_START_INDEX = 0x01;
|
||||
const byte DEFAULT_PALETTE_TRANSITION_COLOR_COUNT = 0xFE;
|
||||
void fadeToBlack(Common::Array<ScriptValue> &args);
|
||||
void fadeToRegisteredPalette(Common::Array<ScriptValue> &args);
|
||||
void setToRegisteredPalette(Common::Array<ScriptValue> &args);
|
||||
void setToBlack(Common::Array<ScriptValue> &args);
|
||||
void fadeToColor(Common::Array<ScriptValue> &args);
|
||||
void setToColor(Common::Array<ScriptValue> &args);
|
||||
void setToPercentOfPalette(Common::Array<ScriptValue> &args);
|
||||
void fadeToPaletteObject(Common::Array<ScriptValue> &args);
|
||||
void setToPaletteObject(Common::Array<ScriptValue> &args);
|
||||
void setToPercentOfPaletteObject(Common::Array<ScriptValue> &args);
|
||||
void colorShiftCurrentPalette(Common::Array<ScriptValue> &args);
|
||||
void circleOut(Common::Array<ScriptValue> &args);
|
||||
|
||||
void _setPalette(Graphics::Palette &palette, uint startIndex, uint colorCount);
|
||||
void _setPaletteToColor(Graphics::Palette &targetPalette, byte r, byte g, byte b);
|
||||
uint _limitColorRange(uint &startIndex, uint &colorCount);
|
||||
byte _interpolateColorComponent(byte source, byte target, double progress);
|
||||
|
||||
void _fadeToColor(byte r, byte g, byte b, double fadeTime, uint startIndex, uint colorCount);
|
||||
void _setToColor(byte r, byte g, byte b, uint startIndex, uint colorCount);
|
||||
void _setPercentToColor(double percent, byte r, byte g, byte b, uint startIndex, uint colorCount);
|
||||
|
||||
void _fadeToPalette(double fadeTime, Graphics::Palette &targetPalette, uint startIndex, uint colorCount);
|
||||
void _setToPercentPalette(double percent, Graphics::Palette ¤tPalette, Graphics::Palette &targetPalette,
|
||||
uint startIndex, uint colorCount);
|
||||
void _fadeToRegisteredPalette(double fadeTime, uint startIndex, uint colorCount);
|
||||
void _setToRegisteredPalette(uint startIndex, uint colorCount);
|
||||
void _colorShiftCurrentPalette(uint startIndex, uint shiftAmount, uint colorCount);
|
||||
void _fadeToPaletteObject(uint paletteId, double fadeTime, uint startIndex, uint colorCount);
|
||||
void _setToPaletteObject(uint paletteId, uint startIndex, uint colorCount);
|
||||
void _setPercentToPaletteObject(double percent, uint paletteId, uint startIndex, uint colorCount);
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
598
engines/mediastation/mediascript/codechunk.cpp
Normal file
598
engines/mediastation/mediascript/codechunk.cpp
Normal file
@@ -0,0 +1,598 @@
|
||||
/* 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 "common/ptr.h"
|
||||
|
||||
#include "mediastation/mediastation.h"
|
||||
#include "mediastation/mediascript/codechunk.h"
|
||||
#include "mediastation/mediascript/collection.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
CodeChunk::CodeChunk(Chunk &chunk) {
|
||||
uint lengthInBytes = chunk.readTypedUint32();
|
||||
debugC(5, kDebugLoading, "CodeChunk::CodeChunk(): Length 0x%x (@0x%llx)", lengthInBytes, static_cast<long long int>(chunk.pos()));
|
||||
_bytecode = static_cast<ParameterReadStream *>(chunk.readStream(lengthInBytes));
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::executeNextBlock() {
|
||||
uint blockSize = _bytecode->readTypedUint32();
|
||||
int64 startingPos = _bytecode->pos();
|
||||
debugC(7, kDebugScript, "%s: Entering new block (blockSize: %d, startingPos: %lld)",
|
||||
__func__, blockSize, static_cast<long long int>(startingPos));
|
||||
|
||||
ScriptValue returnValue;
|
||||
ExpressionType expressionType = static_cast<ExpressionType>(_bytecode->readTypedUint16());
|
||||
while (expressionType != kExpressionTypeEmpty && !_returnImmediately) {
|
||||
returnValue = evaluateExpression(expressionType);
|
||||
expressionType = static_cast<ExpressionType>(_bytecode->readTypedUint16());
|
||||
|
||||
if (expressionType == kExpressionTypeEmpty) {
|
||||
debugC(7, kDebugScript, "%s: Done executing block due to end of chunk", __func__);
|
||||
}
|
||||
if (_returnImmediately) {
|
||||
debugC(7, kDebugScript, "%s: Done executing block due to script requesting immediate return", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we consumed the right number of script bytes.
|
||||
if (!_returnImmediately) {
|
||||
uint bytesRead = _bytecode->pos() - startingPos;
|
||||
if (bytesRead != blockSize) {
|
||||
error("%s: Expected to have read %d script bytes, actually read %d", __func__, blockSize, bytesRead);
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void CodeChunk::skipNextBlock() {
|
||||
uint lengthInBytes = _bytecode->readTypedUint32();
|
||||
_bytecode->skip(lengthInBytes);
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::execute(Common::Array<ScriptValue> *args) {
|
||||
_args = args;
|
||||
ScriptValue returnValue = executeNextBlock();
|
||||
|
||||
// Rewind the stream once we're finished, in case we need to execute
|
||||
// this code again!
|
||||
_bytecode->seek(0);
|
||||
_returnImmediately = false;
|
||||
_locals.clear();
|
||||
// We don't own the args, so we will prevent a potentially out-of-scope
|
||||
// variable from being re-accessed.
|
||||
_args = nullptr;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateExpression() {
|
||||
ExpressionType expressionType = static_cast<ExpressionType>(_bytecode->readTypedUint16());
|
||||
ScriptValue returnValue = evaluateExpression(expressionType);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateExpression(ExpressionType expressionType) {
|
||||
debugCN(5, kDebugScript, "(%s) ", expressionTypeToStr(expressionType));
|
||||
|
||||
ScriptValue returnValue;
|
||||
switch (expressionType) {
|
||||
case kExpressionTypeEmpty:
|
||||
break;
|
||||
|
||||
case kExpressionTypeOperation:
|
||||
returnValue = evaluateOperation();
|
||||
break;
|
||||
|
||||
case kExpressionTypeValue:
|
||||
returnValue = evaluateValue();
|
||||
break;
|
||||
|
||||
case kExpressionTypeVariable:
|
||||
returnValue = evaluateVariable();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Got unimplemented expression type %s (%d)", __func__,
|
||||
expressionTypeToStr(expressionType), static_cast<uint>(expressionType));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateOperation() {
|
||||
Opcode opcode = static_cast<Opcode>(_bytecode->readTypedUint16());
|
||||
debugCN(5, kDebugScript, "%s ", opcodeToStr(opcode));
|
||||
|
||||
ScriptValue returnValue;
|
||||
switch (opcode) {
|
||||
case kOpcodeIf:
|
||||
evaluateIf();
|
||||
break;
|
||||
|
||||
case kOpcodeIfElse:
|
||||
evaluateIfElse();
|
||||
break;
|
||||
|
||||
case kOpcodeAssignVariable:
|
||||
evaluateAssign();
|
||||
break;
|
||||
|
||||
case kOpcodeOr:
|
||||
case kOpcodeXor:
|
||||
case kOpcodeAnd:
|
||||
case kOpcodeEquals:
|
||||
case kOpcodeNotEquals:
|
||||
case kOpcodeLessThan:
|
||||
case kOpcodeGreaterThan:
|
||||
case kOpcodeLessThanOrEqualTo:
|
||||
case kOpcodeGreaterThanOrEqualTo:
|
||||
case kOpcodeAdd:
|
||||
case kOpcodeSubtract:
|
||||
case kOpcodeMultiply:
|
||||
case kOpcodeDivide:
|
||||
case kOpcodeModulo:
|
||||
returnValue = evaluateBinaryOperation(opcode);
|
||||
break;
|
||||
|
||||
case kOpcodeNegate:
|
||||
returnValue = evaluateUnaryOperation();
|
||||
break;
|
||||
|
||||
case kOpcodeCallFunction:
|
||||
returnValue = evaluateFunctionCall();
|
||||
break;
|
||||
|
||||
case kOpcodeCallMethod:
|
||||
returnValue = evaluateMethodCall();
|
||||
break;
|
||||
|
||||
case kOpcodeDeclareLocals:
|
||||
evaluateDeclareLocals();
|
||||
break;
|
||||
|
||||
case kOpcodeReturn:
|
||||
returnValue = evaluateReturn();
|
||||
break;
|
||||
|
||||
case kOpcodeReturnNoValue:
|
||||
evaluateReturnNoValue();
|
||||
break;
|
||||
|
||||
case kOpcodeWhile:
|
||||
evaluateWhileLoop();
|
||||
break;
|
||||
|
||||
case kOpcodeCallFunctionInVariable:
|
||||
returnValue = evaluateFunctionCall(true);
|
||||
break;
|
||||
|
||||
case kOpcodeCallMethodInVariable:
|
||||
returnValue = evaluateMethodCall(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Got unimplemented opcode %s (%d)", __func__, opcodeToStr(opcode), static_cast<uint>(opcode));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateValue() {
|
||||
OperandType operandType = static_cast<OperandType>(_bytecode->readTypedUint16());
|
||||
debugCN(5, kDebugScript, "%s ", operandTypeToStr(operandType));
|
||||
|
||||
ScriptValue returnValue;
|
||||
switch (operandType) {
|
||||
case kOperandTypeBool: {
|
||||
int b = _bytecode->readTypedByte();
|
||||
if (b != 0 && b != 1) {
|
||||
error("%s: Got invalid literal bool value %d", __func__, b);
|
||||
}
|
||||
debugC(5, kDebugScript, "%d ", b);
|
||||
returnValue.setToBool(b == 1 ? true : false);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeFloat: {
|
||||
double f = _bytecode->readTypedDouble();
|
||||
debugC(5, kDebugScript, "%f ", f);
|
||||
returnValue.setToFloat(f);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeInt: {
|
||||
int i = _bytecode->readTypedSint32();
|
||||
debugC(5, kDebugScript, "%d ", i);
|
||||
// Ints are stored internally as doubles.
|
||||
returnValue.setToFloat(static_cast<double>(i));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeString: {
|
||||
// This is indeed a raw string, not a string wrapped in a datum!
|
||||
uint size = _bytecode->readTypedUint16();
|
||||
Common::String string = _bytecode->readString('\0', size);
|
||||
debugC(5, kDebugScript, "%s ", string.c_str());
|
||||
returnValue.setToString(string);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeParamToken: {
|
||||
uint literal = _bytecode->readTypedUint16();
|
||||
debugC(5, kDebugScript, "%d ", literal);
|
||||
returnValue.setToParamToken(literal);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeActorId: {
|
||||
uint actorId = _bytecode->readTypedUint16();
|
||||
debugC(5, kDebugScript, "%d ", actorId);
|
||||
returnValue.setToActorId(actorId);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeTime: {
|
||||
double d = _bytecode->readTypedTime();
|
||||
debugC(5, kDebugScript, "%f ", d);
|
||||
returnValue.setToTime(d);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeVariable: {
|
||||
returnValue = ScriptValue(_bytecode);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeFunctionId: {
|
||||
uint functionId = _bytecode->readTypedUint16();
|
||||
debugC(5, kDebugScript, "%d ", functionId);
|
||||
returnValue.setToFunctionId(functionId);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
case kOperandTypeMethodId: {
|
||||
BuiltInMethod methodId = static_cast<BuiltInMethod>(_bytecode->readTypedUint16());
|
||||
debugC(5, kDebugScript, "%s ", builtInMethodToStr(methodId));
|
||||
returnValue.setToMethodId(methodId);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Got unknown ScriptValue type %s (%d)", __func__, operandTypeToStr(operandType), static_cast<uint>(operandType));
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateVariable() {
|
||||
ScriptValue *variable = readAndReturnVariable();
|
||||
return *variable;
|
||||
}
|
||||
|
||||
ScriptValue *CodeChunk::readAndReturnVariable() {
|
||||
uint id = _bytecode->readTypedUint16();
|
||||
VariableScope scope = static_cast<VariableScope>(_bytecode->readTypedUint16());
|
||||
debugC(5, kDebugScript, "%d (%s)", id, variableScopeToStr(scope));
|
||||
|
||||
ScriptValue returnValue;
|
||||
switch (scope) {
|
||||
case kVariableScopeGlobal: {
|
||||
ScriptValue *variable = g_engine->getVariable(id);
|
||||
if (variable == nullptr) {
|
||||
error("%s: Global variable %d doesn't exist", __func__, id);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
case kVariableScopeLocal: {
|
||||
uint index = id - 1;
|
||||
return &_locals.operator[](index);
|
||||
}
|
||||
|
||||
case kVariableScopeIndirectParameter: {
|
||||
ScriptValue indexValue = evaluateExpression();
|
||||
uint index = static_cast<uint>(indexValue.asFloat() + id);
|
||||
return &_args->operator[](index);
|
||||
}
|
||||
|
||||
case kVariableScopeParameter: {
|
||||
uint index = id - 1;
|
||||
if (_args == nullptr) {
|
||||
error("%s: Requested a parameter in a code chunk that has no parameters", __func__);
|
||||
}
|
||||
return &_args->operator[](index);
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Got unknown variable scope %s (%d)", __func__, variableScopeToStr(scope), static_cast<uint>(scope));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeChunk::evaluateIf() {
|
||||
debugCN(5, kDebugScript, "\n condition: ");
|
||||
ScriptValue condition = evaluateExpression();
|
||||
if (condition.getType() != kScriptValueTypeBool) {
|
||||
error("%s: Expected bool condition, got %s", __func__, scriptValueTypeToStr(condition.getType()));
|
||||
}
|
||||
|
||||
if (condition.asBool()) {
|
||||
executeNextBlock();
|
||||
} else {
|
||||
skipNextBlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeChunk::evaluateIfElse() {
|
||||
debugCN(5, kDebugScript, "\n condition: ");
|
||||
ScriptValue condition = evaluateExpression();
|
||||
if (condition.getType() != kScriptValueTypeBool) {
|
||||
error("%s: Expected bool condition, got %s", __func__, scriptValueTypeToStr(condition.getType()));
|
||||
}
|
||||
|
||||
if (condition.asBool()) {
|
||||
executeNextBlock();
|
||||
skipNextBlock();
|
||||
} else {
|
||||
skipNextBlock();
|
||||
executeNextBlock();
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateAssign() {
|
||||
debugCN(5, kDebugScript, "Variable ");
|
||||
ScriptValue *targetVariable = readAndReturnVariable();
|
||||
|
||||
debugC(5, kDebugScript, " Value: ");
|
||||
ScriptValue value = evaluateExpression();
|
||||
|
||||
if (value.getType() == kScriptValueTypeEmpty) {
|
||||
error("%s: Attempt to assign an empty value to a variable", __func__);
|
||||
}
|
||||
|
||||
if (targetVariable != nullptr) {
|
||||
*targetVariable = value;
|
||||
return value;
|
||||
} else {
|
||||
error("%s: Attempt to assign to null variable", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateBinaryOperation(Opcode op) {
|
||||
debugCN(5, kDebugScript, "\n lhs: ");
|
||||
ScriptValue value1 = evaluateExpression();
|
||||
debugCN(5, kDebugScript, " rhs: ");
|
||||
ScriptValue value2 = evaluateExpression();
|
||||
|
||||
ScriptValue returnValue;
|
||||
switch (op) {
|
||||
case kOpcodeOr:
|
||||
returnValue.setToBool(value1 || value2);
|
||||
break;
|
||||
|
||||
case kOpcodeXor:
|
||||
returnValue.setToBool(value1 ^ value2);
|
||||
break;
|
||||
|
||||
case kOpcodeAnd:
|
||||
returnValue.setToBool(value1 && value2);
|
||||
break;
|
||||
|
||||
case kOpcodeEquals:
|
||||
returnValue.setToBool(value1 == value2);
|
||||
break;
|
||||
|
||||
case kOpcodeNotEquals:
|
||||
returnValue.setToBool(value1 != value2);
|
||||
break;
|
||||
|
||||
case kOpcodeLessThan:
|
||||
returnValue.setToBool(value1 < value2);
|
||||
break;
|
||||
|
||||
case kOpcodeGreaterThan:
|
||||
returnValue.setToBool(value1 > value2);
|
||||
break;
|
||||
|
||||
case kOpcodeLessThanOrEqualTo:
|
||||
returnValue.setToBool(value1 <= value2);
|
||||
break;
|
||||
|
||||
case kOpcodeGreaterThanOrEqualTo:
|
||||
returnValue.setToBool(value1 >= value2);
|
||||
break;
|
||||
|
||||
case kOpcodeAdd:
|
||||
returnValue = value1 + value2;
|
||||
break;
|
||||
|
||||
case kOpcodeSubtract:
|
||||
returnValue = value1 - value2;
|
||||
break;
|
||||
|
||||
case kOpcodeMultiply:
|
||||
returnValue = value1 * value2;
|
||||
break;
|
||||
|
||||
case kOpcodeDivide:
|
||||
returnValue = value1 / value2;
|
||||
break;
|
||||
|
||||
case kOpcodeModulo:
|
||||
returnValue = value1 % value2;
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Got unknown binary operation opcode %s", __func__, opcodeToStr(op));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateUnaryOperation() {
|
||||
// The only supported unary operation seems to be negation.
|
||||
ScriptValue value = evaluateExpression();
|
||||
debugCN(5, kDebugScript, " value: ");
|
||||
return -value;
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateFunctionCall(bool isIndirect) {
|
||||
uint functionId, paramCount = 0;
|
||||
if (isIndirect) {
|
||||
paramCount = _bytecode->readTypedUint16();
|
||||
ScriptValue value = evaluateExpression();
|
||||
functionId = value.asFunctionId();
|
||||
} else {
|
||||
functionId = _bytecode->readTypedUint16();
|
||||
paramCount = _bytecode->readTypedUint16();
|
||||
}
|
||||
|
||||
return evaluateFunctionCall(functionId, paramCount);
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateFunctionCall(uint functionId, uint paramCount) {
|
||||
debugC(5, kDebugScript, "%d (%d params)", functionId, paramCount);
|
||||
|
||||
Common::Array<ScriptValue> args;
|
||||
for (uint i = 0; i < paramCount; i++) {
|
||||
debugCN(5, kDebugScript, " Param %d: ", i);
|
||||
ScriptValue arg = evaluateExpression();
|
||||
args.push_back(arg);
|
||||
}
|
||||
|
||||
ScriptValue returnValue = g_engine->getFunctionManager()->call(functionId, args);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateMethodCall(bool isIndirect) {
|
||||
BuiltInMethod method;
|
||||
uint paramCount = 0;
|
||||
if (isIndirect) {
|
||||
paramCount = _bytecode->readTypedUint16();
|
||||
ScriptValue value = evaluateExpression();
|
||||
method = value.asMethodId();
|
||||
} else {
|
||||
method = static_cast<BuiltInMethod>(_bytecode->readTypedUint16());
|
||||
paramCount = _bytecode->readTypedUint16();
|
||||
}
|
||||
|
||||
return evaluateMethodCall(method, paramCount);
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateMethodCall(BuiltInMethod method, uint paramCount) {
|
||||
// In Media Station, all methods are built-in - there aren't
|
||||
// custom objects or methods individual titles can
|
||||
// define. Functions, however, CAN be title-defined.
|
||||
// But here, we're only looking for built-in methods.
|
||||
debugC(5, kDebugScript, "%s (%d params)", builtInMethodToStr(method), paramCount);
|
||||
debugCN(5, kDebugScript, " Self: ");
|
||||
|
||||
ScriptValue target = evaluateExpression();
|
||||
Common::Array<ScriptValue> args;
|
||||
for (uint i = 0; i < paramCount; i++) {
|
||||
debugCN(5, kDebugScript, " Param %d: ", i);
|
||||
ScriptValue arg = evaluateExpression();
|
||||
args.push_back(arg);
|
||||
}
|
||||
|
||||
ScriptValue returnValue;
|
||||
switch (target.getType()) {
|
||||
case kScriptValueTypeActorId: {
|
||||
if (target.asActorId() == 0) {
|
||||
// It seems to be valid to call a method on a null actor ID, in
|
||||
// which case nothing happens. Still issue warning for traceability.
|
||||
warning("%s: Attempt to call method on a null actor ID", __func__);
|
||||
return returnValue;
|
||||
} else {
|
||||
// This is a regular actor that we can process directly.
|
||||
uint actorId = target.asActorId();
|
||||
Actor *targetActor = g_engine->getActorById(actorId);
|
||||
if (targetActor == nullptr) {
|
||||
error("%s: Attempt to call method on actor ID %d, which isn't loaded", __func__, target.asActorId());
|
||||
}
|
||||
returnValue = targetActor->callMethod(method, args);
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
case kScriptValueTypeCollection: {
|
||||
Common::SharedPtr<Collection> collection = target.asCollection();
|
||||
returnValue = collection->callMethod(method, args);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
default:
|
||||
error("Attempt to call method on unimplemented value type %s (%d)",
|
||||
scriptValueTypeToStr(target.getType()), static_cast<uint>(target.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeChunk::evaluateDeclareLocals() {
|
||||
uint localVariableCount = _bytecode->readTypedUint16();
|
||||
if (localVariableCount <= 0) {
|
||||
error("Got non-positive local variable count");
|
||||
}
|
||||
debugC(5, kDebugScript, "%d", localVariableCount);
|
||||
_locals = Common::Array<ScriptValue>(localVariableCount);
|
||||
}
|
||||
|
||||
ScriptValue CodeChunk::evaluateReturn() {
|
||||
ScriptValue returnValue = evaluateExpression();
|
||||
_returnImmediately = true;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void CodeChunk::evaluateReturnNoValue() {
|
||||
_returnImmediately = true;
|
||||
}
|
||||
|
||||
void CodeChunk::evaluateWhileLoop() {
|
||||
uint loopStartPosition = _bytecode->pos();
|
||||
uint iterationCount = 0;
|
||||
|
||||
while (true) {
|
||||
// Seek to the top of the loop bytecode.
|
||||
_bytecode->seek(loopStartPosition);
|
||||
ScriptValue condition = evaluateExpression();
|
||||
if (condition.getType() != kScriptValueTypeBool) {
|
||||
error("Expected loop condition to be bool, not %s", scriptValueTypeToStr(condition.getType()));
|
||||
}
|
||||
|
||||
if (++iterationCount >= MAX_LOOP_ITERATION_COUNT) {
|
||||
error("Exceeded max loop iteration count");
|
||||
}
|
||||
|
||||
if (condition.asBool()) {
|
||||
executeNextBlock();
|
||||
} else {
|
||||
skipNextBlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CodeChunk::~CodeChunk() {
|
||||
_locals.clear();
|
||||
|
||||
// We don't own the args, so we don't need to delete it.
|
||||
_args = nullptr;
|
||||
|
||||
delete _bytecode;
|
||||
_bytecode = nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
75
engines/mediastation/mediascript/codechunk.h
Normal file
75
engines/mediastation/mediascript/codechunk.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_MEDIASCRIPT_CODECHUNK_H
|
||||
#define MEDIASTATION_MEDIASCRIPT_CODECHUNK_H
|
||||
|
||||
#include "common/array.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class CodeChunk {
|
||||
public:
|
||||
CodeChunk(Chunk &chunk);
|
||||
~CodeChunk();
|
||||
|
||||
ScriptValue executeNextBlock();
|
||||
ScriptValue execute(Common::Array<ScriptValue> *args = nullptr);
|
||||
|
||||
private:
|
||||
void skipNextBlock();
|
||||
|
||||
ScriptValue evaluateExpression();
|
||||
ScriptValue evaluateExpression(ExpressionType expressionType);
|
||||
ScriptValue evaluateOperation();
|
||||
ScriptValue evaluateValue();
|
||||
ScriptValue evaluateVariable();
|
||||
|
||||
ScriptValue *readAndReturnVariable();
|
||||
|
||||
void evaluateIf();
|
||||
void evaluateIfElse();
|
||||
ScriptValue evaluateAssign();
|
||||
ScriptValue evaluateBinaryOperation(Opcode op);
|
||||
ScriptValue evaluateUnaryOperation();
|
||||
ScriptValue evaluateFunctionCall(bool isIndirect = false);
|
||||
ScriptValue evaluateFunctionCall(uint functionId, uint paramCount);
|
||||
ScriptValue evaluateMethodCall(bool isIndirect = false);
|
||||
ScriptValue evaluateMethodCall(BuiltInMethod method, uint paramCount);
|
||||
void evaluateDeclareLocals();
|
||||
ScriptValue evaluateReturn();
|
||||
void evaluateReturnNoValue();
|
||||
void evaluateWhileLoop();
|
||||
|
||||
static const uint MAX_LOOP_ITERATION_COUNT = 1000;
|
||||
bool _returnImmediately = false;
|
||||
Common::Array<ScriptValue> _locals;
|
||||
Common::Array<ScriptValue> *_args = nullptr;
|
||||
ParameterReadStream *_bytecode = nullptr;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
173
engines/mediastation/mediascript/collection.cpp
Normal file
173
engines/mediastation/mediascript/collection.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/* 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 "mediastation/mediastation.h"
|
||||
#include "mediastation/mediascript/collection.h"
|
||||
#include "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/codechunk.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
ScriptValue Collection::callMethod(BuiltInMethod method, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
switch (method) {
|
||||
case kAppendMethod:
|
||||
for (ScriptValue value : args) {
|
||||
push_back(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case kApplyMethod:
|
||||
apply(args);
|
||||
break;
|
||||
|
||||
case kCountMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToFloat(size());
|
||||
break;
|
||||
|
||||
case kDeleteFirstMethod:
|
||||
assert(args.empty());
|
||||
returnValue = remove_at(0);
|
||||
break;
|
||||
|
||||
case kDeleteLastMethod:
|
||||
assert(args.empty());
|
||||
returnValue = remove_at(size() - 1);
|
||||
break;
|
||||
|
||||
case kEmptyMethod:
|
||||
assert(args.empty());
|
||||
clear();
|
||||
break;
|
||||
|
||||
case kGetAtMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint index = static_cast<uint>(args[0].asFloat());
|
||||
returnValue = operator[](index);
|
||||
break;
|
||||
}
|
||||
|
||||
case kIsEmptyMethod:
|
||||
assert(args.empty());
|
||||
returnValue.setToBool(empty());
|
||||
break;
|
||||
|
||||
case kJumbleMethod:
|
||||
assert(args.empty());
|
||||
jumble();
|
||||
break;
|
||||
|
||||
case kSeekMethod: {
|
||||
assert(args.size() == 1);
|
||||
int index = seek(args[0]);
|
||||
returnValue.setToFloat(index);
|
||||
break;
|
||||
}
|
||||
|
||||
case kSendMethod:
|
||||
send(args);
|
||||
break;
|
||||
|
||||
case kDeleteAtMethod: {
|
||||
assert(args.size() == 1);
|
||||
uint index = static_cast<uint>(args[0].asFloat());
|
||||
returnValue = remove_at(index);
|
||||
break;
|
||||
}
|
||||
|
||||
case kInsertAtMethod: {
|
||||
assert(args.size() == 2);
|
||||
uint index = static_cast<uint>(args[1].asFloat());
|
||||
insert_at(index, args[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case kReplaceAtMethod: {
|
||||
assert(args.size() == 2);
|
||||
uint index = static_cast<uint>(args[1].asFloat());
|
||||
operator[](index) = args[0];
|
||||
break;
|
||||
}
|
||||
|
||||
case kPrependListMethod:
|
||||
insert_at(0, args);
|
||||
break;
|
||||
|
||||
case kSortMethod:
|
||||
assert(args.empty());
|
||||
Common::sort(begin(), end());
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Attempt to call unimplemented method %s (%d)", __func__, builtInMethodToStr(method), static_cast<uint>(method));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void Collection::apply(const Common::Array<ScriptValue> &args) {
|
||||
// Calls a function with each element of the collection as the first arg.
|
||||
Common::Array<ScriptValue> argsToApply = args;
|
||||
uint functionId = args[0].asFunctionId();
|
||||
for (const ScriptValue &item : *this) {
|
||||
argsToApply[0] = item;
|
||||
g_engine->getFunctionManager()->call(functionId, argsToApply);
|
||||
}
|
||||
}
|
||||
|
||||
void Collection::send(const Common::Array<ScriptValue> &args) {
|
||||
Common::Array<ScriptValue> argsToSend(args.size() - 1);
|
||||
if (argsToSend.size() > 0) {
|
||||
for (uint i = 1; i < args.size(); i++) {
|
||||
argsToSend[i - 1] = args[i];
|
||||
}
|
||||
}
|
||||
|
||||
BuiltInMethod methodToSend = static_cast<BuiltInMethod>(args[0].asMethodId());
|
||||
Common::Array<ScriptValue> sendArgs;
|
||||
for (const ScriptValue &item : *this) {
|
||||
uint actorId = item.asActorId();
|
||||
Actor *targetActor = g_engine->getActorById(actorId);
|
||||
if (targetActor != nullptr) {
|
||||
targetActor->callMethod(methodToSend, argsToSend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Collection::seek(const ScriptValue &item) {
|
||||
// Search from back to front.
|
||||
for (int i = size() - 1; i >= 0; i--) {
|
||||
if (item == operator[](i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Collection::jumble() {
|
||||
for (uint i = size() - 1; i > 0; --i) {
|
||||
uint j = g_engine->_randomSource.getRandomNumber(size() - 1);
|
||||
SWAP(operator[](i), operator[](j));
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
49
engines/mediastation/mediascript/collection.h
Normal file
49
engines/mediastation/mediascript/collection.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_MEDIASCRIPT_COLLECTION_H
|
||||
#define MEDIASTATION_MEDIASCRIPT_COLLECTION_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "common/str.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class ScriptValue;
|
||||
|
||||
class Collection : public Common::Array<ScriptValue> {
|
||||
public:
|
||||
ScriptValue callMethod(BuiltInMethod method, Common::Array<ScriptValue> &args);
|
||||
|
||||
private:
|
||||
void apply(const Common::Array<ScriptValue> &values);
|
||||
void send(const Common::Array<ScriptValue> &values);
|
||||
int seek(const ScriptValue &itemToFind);
|
||||
void jumble();
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
56
engines/mediastation/mediascript/eventhandler.cpp
Normal file
56
engines/mediastation/mediascript/eventhandler.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/* 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 "mediastation/mediascript/eventhandler.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
EventHandler::EventHandler(Chunk &chunk) {
|
||||
_type = static_cast<EventType>(chunk.readTypedUint16());
|
||||
debugC(5, kDebugLoading, "EventHandler::EventHandler(): Type %s (%d) (@0x%llx)",
|
||||
eventTypeToStr(_type), static_cast<uint>(_type), static_cast<long long int>(chunk.pos()));
|
||||
|
||||
_argumentValue = ScriptValue(&chunk);
|
||||
_code = new CodeChunk(chunk);
|
||||
}
|
||||
|
||||
ScriptValue EventHandler::execute(uint actorId) {
|
||||
// TODO: The actorId is only passed in for debug visibility, there should be
|
||||
// a better way to handle that.
|
||||
Common::String actorAndType = Common::String::format("(actor %d) (type = %s)", actorId, eventTypeToStr(_type));
|
||||
Common::String argValue = Common::String::format("(%s)", _argumentValue.getDebugString().c_str());
|
||||
debugC(5, kDebugScript, "\n********** EVENT HANDLER %s %s **********", actorAndType.c_str(), argValue.c_str());
|
||||
|
||||
// The only argument that can be provided to an
|
||||
// event handler is the _argumentValue.
|
||||
ScriptValue returnValue = _code->execute();
|
||||
|
||||
debugC(5, kDebugScript, "********** END EVENT HANDLER %s %s **********", actorAndType.c_str(), argValue.c_str());
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
EventHandler::~EventHandler() {
|
||||
delete _code;
|
||||
_code = nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
48
engines/mediastation/mediascript/eventhandler.h
Normal file
48
engines/mediastation/mediascript/eventhandler.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_MEDIASCRIPT_EVENTHANDLER_H
|
||||
#define MEDIASTATION_MEDIASCRIPT_EVENTHANDLER_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/codechunk.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class EventHandler {
|
||||
public:
|
||||
EventHandler(Chunk &chunk);
|
||||
~EventHandler();
|
||||
|
||||
ScriptValue execute(uint actorId);
|
||||
EventType _type;
|
||||
ScriptValue _argumentValue;
|
||||
|
||||
private:
|
||||
CodeChunk *_code = nullptr;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
567
engines/mediastation/mediascript/function.cpp
Normal file
567
engines/mediastation/mediascript/function.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
/* 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 "mediastation/mediascript/function.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
ScriptFunction::ScriptFunction(Chunk &chunk) {
|
||||
_contextId = chunk.readTypedUint16();
|
||||
// In PROFILE._ST (only present in some titles), the function ID is reported
|
||||
// with 19900 added, so function 100 would be reported as 20000. But in
|
||||
// bytecode, the zero-based ID is used, so that's what we'll store here.
|
||||
_id = chunk.readTypedUint16();
|
||||
_code = new CodeChunk(chunk);
|
||||
}
|
||||
|
||||
ScriptFunction::~ScriptFunction() {
|
||||
delete _code;
|
||||
_code = nullptr;
|
||||
}
|
||||
|
||||
ScriptValue ScriptFunction::execute(Common::Array<ScriptValue> &args) {
|
||||
debugC(5, kDebugScript, "\n********** SCRIPT FUNCTION %d **********", _id);
|
||||
ScriptValue returnValue = _code->execute(&args);
|
||||
debugC(5, kDebugScript, "********** END SCRIPT FUNCTION **********");
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
FunctionManager::~FunctionManager() {
|
||||
for (auto it = _functions.begin(); it != _functions.end(); ++it) {
|
||||
delete it->_value;
|
||||
}
|
||||
_functions.clear();
|
||||
}
|
||||
|
||||
bool FunctionManager::attemptToReadFromStream(Chunk &chunk, uint sectionType) {
|
||||
bool handledParam = true;
|
||||
switch (sectionType) {
|
||||
case 0x31: {
|
||||
ScriptFunction *function = new ScriptFunction(chunk);
|
||||
_functions.setVal(function->_id, function);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
handledParam = false;
|
||||
}
|
||||
|
||||
return handledParam;
|
||||
}
|
||||
|
||||
ScriptValue FunctionManager::call(uint functionId, Common::Array<ScriptValue> &args) {
|
||||
ScriptValue returnValue;
|
||||
|
||||
// The original had a complex function registration system that I deemed too uselessly complex to
|
||||
// reimplement. First, we try executing the title-defined function. We try this first because
|
||||
// later engine versions used some functions IDs that previously mapped to built-in functions in
|
||||
// earlier engine versions. So we will try executing the title-defined function first and only then
|
||||
// fall back to the built-in functions.
|
||||
ScriptFunction *scriptFunction = _functions.getValOrDefault(functionId);
|
||||
if (scriptFunction != nullptr) {
|
||||
returnValue = scriptFunction->execute(args);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
// If there was no title-defined function, next check for built-in functions.
|
||||
switch (functionId) {
|
||||
case kRandomFunction:
|
||||
case kLegacy_RandomFunction:
|
||||
assert(args.size() == 2);
|
||||
script_Random(args, returnValue);
|
||||
break;
|
||||
|
||||
case kTimeOfDayFunction:
|
||||
case kLegacy_TimeOfDayFunction:
|
||||
script_TimeOfDay(args, returnValue);
|
||||
break;
|
||||
|
||||
case kEffectTransitionFunction:
|
||||
case kLegacy_EffectTransitionFunction:
|
||||
g_engine->getDisplayManager()->effectTransition(args);
|
||||
break;
|
||||
|
||||
case kEffectTransitionOnSyncFunction:
|
||||
case kLegacy_EffectTransitionOnSyncFunction:
|
||||
g_engine->getDisplayManager()->setTransitionOnSync(args);
|
||||
break;
|
||||
|
||||
case kPlatformFunction:
|
||||
case kLegacy_PlatformFunction:
|
||||
assert(args.empty());
|
||||
script_GetPlatform(args, returnValue);
|
||||
break;
|
||||
|
||||
case kSquareRootFunction:
|
||||
case kLegacy_SquareRootFunction:
|
||||
assert(args.size() == 1);
|
||||
script_SquareRoot(args, returnValue);
|
||||
break;
|
||||
|
||||
case kGetUniqueRandomFunction:
|
||||
case kLegacy_GetUniqueRandomFunction:
|
||||
assert(args.size() >= 2);
|
||||
script_GetUniqueRandom(args, returnValue);
|
||||
break;
|
||||
|
||||
case kCurrentRunTimeFunction:
|
||||
script_CurrentRunTime(args, returnValue);
|
||||
break;
|
||||
|
||||
case kSetGammaCorrectionFunction:
|
||||
script_SetGammaCorrection(args, returnValue);
|
||||
break;
|
||||
|
||||
case kGetDefaultGammaCorrectionFunction:
|
||||
script_GetDefaultGammaCorrection(args, returnValue);
|
||||
break;
|
||||
|
||||
case kGetCurrentGammaCorrectionFunction:
|
||||
script_GetCurrentGammaCorrection(args, returnValue);
|
||||
break;
|
||||
|
||||
case kSetAudioVolumeFunction:
|
||||
assert(args.size() == 1);
|
||||
script_SetAudioVolume(args, returnValue);
|
||||
break;
|
||||
|
||||
case kGetAudioVolumeFunction:
|
||||
assert(args.empty());
|
||||
script_GetAudioVolume(args, returnValue);
|
||||
break;
|
||||
|
||||
case kSystemLanguagePreferenceFunction:
|
||||
case kLegacy_SystemLanguagePreferenceFunction:
|
||||
script_SystemLanguagePreference(args, returnValue);
|
||||
break;
|
||||
|
||||
case kSetRegistryFunction:
|
||||
script_SetRegistry(args, returnValue);
|
||||
break;
|
||||
|
||||
case kGetRegistryFunction:
|
||||
script_GetRegistry(args, returnValue);
|
||||
break;
|
||||
|
||||
case kSetProfileFunction:
|
||||
script_SetProfile(args, returnValue);
|
||||
break;
|
||||
|
||||
case kMazeGenerateFunction:
|
||||
script_MazeGenerate(args, returnValue);
|
||||
break;
|
||||
|
||||
case kMazeApplyMoveMaskFunction:
|
||||
script_MazeApplyMoveMask(args, returnValue);
|
||||
break;
|
||||
|
||||
case kMazeSolveFunction:
|
||||
script_MazeSolve(args, returnValue);
|
||||
break;
|
||||
|
||||
case kBeginTimedIntervalFunction:
|
||||
script_BeginTimedInterval(args, returnValue);
|
||||
break;
|
||||
|
||||
case kEndTimedIntervalFunction:
|
||||
script_EndTimedInterval(args, returnValue);
|
||||
break;
|
||||
|
||||
case kDrawingFunction:
|
||||
script_Drawing(args, returnValue);
|
||||
break;
|
||||
|
||||
case kLegacy_DebugPrintFunction:
|
||||
script_DebugPrint(args, returnValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
// If we got here, that means there was neither a title-defined nor a built-in function
|
||||
// for this ID, so we can now declare it unimplemented. This is a warning instead of an error
|
||||
// so execution can continue, but if the function is expected to return anything, there will
|
||||
// likely be an error about attempting to assign a null value to a variable.
|
||||
warning("%s: Unimplemented function 0x%02x", __func__, functionId);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void FunctionManager::script_GetPlatform(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
Common::Platform platform = g_engine->getPlatform();
|
||||
switch (platform) {
|
||||
case Common::Platform::kPlatformWindows:
|
||||
returnValue.setToParamToken(kPlatformParamTokenWindows);
|
||||
break;
|
||||
|
||||
case Common::Platform::kPlatformMacintosh:
|
||||
returnValue.setToParamToken(kPlatformParamTokenWindows);
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("%s: Unknown platform %d", __func__, static_cast<int>(platform));
|
||||
returnValue.setToParamToken(kPlatformParamTokenUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionManager::script_Random(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
// This function takes in a range, and then generates a random value within that range.
|
||||
ScriptValue bottomArg = args[0];
|
||||
ScriptValue topArg = args[1];
|
||||
if (bottomArg.getType() != topArg.getType()) {
|
||||
error("%s: Both arguments must be of same type", __func__);
|
||||
}
|
||||
|
||||
ScriptValueType type = args[0].getType();
|
||||
double bottom = 0.0;
|
||||
double top = 0.0;
|
||||
bool treatAsInteger = false;
|
||||
switch (type) {
|
||||
case kScriptValueTypeFloat: {
|
||||
// For numeric values, treat them as integers (floor values).
|
||||
bottom = floor(bottomArg.asFloat());
|
||||
top = floor(topArg.asFloat());
|
||||
treatAsInteger = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeBool: {
|
||||
// Convert boolean values to numbers.
|
||||
bottom = bottomArg.asBool() ? 1.0 : 0.0;
|
||||
top = topArg.asBool() ? 1.0 : 0.0;
|
||||
treatAsInteger = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeTime: {
|
||||
// Treat time values as capable of having fractional seconds.
|
||||
bottom = bottomArg.asTime();
|
||||
top = topArg.asTime();
|
||||
treatAsInteger = false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Invalid argument type: %s", __func__, scriptValueTypeToStr(type));
|
||||
}
|
||||
|
||||
// Ensure proper inclusive ordering of bottom and top.
|
||||
if (top < bottom) {
|
||||
SWAP(top, bottom);
|
||||
}
|
||||
|
||||
// Calculate random value in range.
|
||||
double range = top - bottom;
|
||||
uint randomValue = g_engine->_randomSource.getRandomNumber(UINT32_MAX);
|
||||
double randomFloat = (static_cast<double>(randomValue) * range) / static_cast<double>(UINT32_MAX) + bottom;
|
||||
if (treatAsInteger) {
|
||||
randomFloat = floor(randomFloat);
|
||||
}
|
||||
|
||||
// Set result based on original argument type.
|
||||
switch (type) {
|
||||
case kScriptValueTypeFloat:
|
||||
returnValue.setToFloat(randomFloat);
|
||||
break;
|
||||
|
||||
case kScriptValueTypeBool: {
|
||||
bool boolResult = (randomFloat != 0.0);
|
||||
returnValue.setToBool(boolResult);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeTime:
|
||||
returnValue.setToTime(randomFloat);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Invalid argument type: %s", __func__, scriptValueTypeToStr(type));
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionManager::script_TimeOfDay(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: TimeOfDay");
|
||||
}
|
||||
|
||||
void FunctionManager::script_SquareRoot(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
if (args[0].getType() != kScriptValueTypeFloat) {
|
||||
error("%s: Numeric value required", __func__);
|
||||
}
|
||||
|
||||
double value = args[0].asFloat();
|
||||
if (value < 0.0) {
|
||||
error("%s: Argument must be nonnegative", __func__);
|
||||
}
|
||||
|
||||
double result = sqrt(value);
|
||||
returnValue.setToFloat(result);
|
||||
}
|
||||
|
||||
void FunctionManager::script_GetUniqueRandom(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
// Unlike the regular Random which simply returns any random number in a range, GetUniqueRandom allows the caller
|
||||
// to specify numbers that should NOT be returned (the third arg and onward), making it useful for generating random
|
||||
// values that haven't been used before or avoiding specific unwanted values.
|
||||
for (ScriptValue arg : args) {
|
||||
if (arg.getType() != kScriptValueTypeFloat) {
|
||||
error("%s: All arguments must be numeric", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
// The original forces that the list of excluded numbers (and the range to choose from)
|
||||
// can be at max 100 numbers. With the two args for the range, the max is thus 102.
|
||||
const uint MAX_ARGS_SIZE = 102;
|
||||
if (args.size() > MAX_ARGS_SIZE) {
|
||||
args.resize(MAX_ARGS_SIZE);
|
||||
}
|
||||
|
||||
// Ensure that the range is properly constructed.
|
||||
double bottom = floor(args[0].asFloat());
|
||||
double top = floor(args[1].asFloat());
|
||||
if (top < bottom) {
|
||||
SWAP(top, bottom);
|
||||
}
|
||||
|
||||
// Build list of unused (non-excluded) numbers in the range. For this numeric type,
|
||||
// everything is treated as an integer (even though it's stored as a double).
|
||||
Common::Array<double> unusedNumbers;
|
||||
for (double currentValue = bottom; currentValue < top; currentValue += 1.0) {
|
||||
// Check if this value appears in the exclusion list (args 2 onwards).
|
||||
bool isExcluded = false;
|
||||
for (uint i = 2; i < args.size(); i++) {
|
||||
if (args[i].asFloat() == currentValue) {
|
||||
isExcluded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExcluded) {
|
||||
unusedNumbers.push_back(currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (unusedNumbers.size() > 0) {
|
||||
uint randomIndex = g_engine->_randomSource.getRandomNumberRng(0, unusedNumbers.size());
|
||||
returnValue.setToFloat(unusedNumbers[randomIndex]);
|
||||
} else {
|
||||
warning("%s: No unused numbers to choose from", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionManager::script_CurrentRunTime(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
// The current runtime is expected to be returned in seconds.
|
||||
const uint MILLISECONDS_IN_ONE_SECOND = 1000;
|
||||
double runtimeInSeconds = g_system->getMillis() / MILLISECONDS_IN_ONE_SECOND;
|
||||
returnValue.setToFloat(runtimeInSeconds);
|
||||
}
|
||||
|
||||
void FunctionManager::script_SetGammaCorrection(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
if (args.size() != 1 && args.size() != 3) {
|
||||
warning("%s: Expected 1 or 3 arguments, got %u", __func__, args.size());
|
||||
return;
|
||||
}
|
||||
|
||||
double red = 1.0;
|
||||
double green = 1.0;
|
||||
double blue = 1.0;
|
||||
if (args.size() >= 3) {
|
||||
if (args[0].getType() != kScriptValueTypeFloat ||
|
||||
args[1].getType() != kScriptValueTypeFloat ||
|
||||
args[2].getType() != kScriptValueTypeFloat) {
|
||||
warning("%s: Expected float arguments", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
red = args[0].asFloat();
|
||||
green = args[1].asFloat();
|
||||
blue = args[2].asFloat();
|
||||
|
||||
} else if (args.size() >= 1) {
|
||||
if (args[0].getType() != kScriptValueTypeCollection) {
|
||||
warning("%s: Expected collection argument", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
Common::SharedPtr<Collection> collection = args[0].asCollection();
|
||||
if (collection->size() != 3) {
|
||||
warning("%s: Collection must contain exactly 3 elements, got %u", __func__, collection->size());
|
||||
return;
|
||||
}
|
||||
|
||||
if (collection->operator[](0).getType() != kScriptValueTypeFloat ||
|
||||
collection->operator[](1).getType() != kScriptValueTypeFloat ||
|
||||
collection->operator[](2).getType() != kScriptValueTypeFloat) {
|
||||
warning("%s: Expected float arguments", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
red = collection->operator[](0).asFloat();
|
||||
green = collection->operator[](1).asFloat();
|
||||
blue = collection->operator[](2).asFloat();
|
||||
}
|
||||
|
||||
g_engine->getDisplayManager()->setGammaValues(red, green, blue);
|
||||
}
|
||||
|
||||
void FunctionManager::script_GetDefaultGammaCorrection(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
if (args.size() != 0) {
|
||||
warning("%s: Expected 0 arguments, got %u", __func__, args.size());
|
||||
return;
|
||||
}
|
||||
|
||||
double red, green, blue;
|
||||
g_engine->getDisplayManager()->getDefaultGammaValues(red, green, blue);
|
||||
|
||||
Common::SharedPtr<Collection> collection = Common::SharedPtr<Collection>(new Collection());
|
||||
ScriptValue redValue;
|
||||
redValue.setToFloat(red);
|
||||
collection->push_back(redValue);
|
||||
|
||||
ScriptValue greenValue;
|
||||
greenValue.setToFloat(green);
|
||||
collection->push_back(greenValue);
|
||||
|
||||
ScriptValue blueValue;
|
||||
blueValue.setToFloat(blue);
|
||||
collection->push_back(blueValue);
|
||||
|
||||
returnValue.setToCollection(collection);
|
||||
}
|
||||
|
||||
void FunctionManager::script_GetCurrentGammaCorrection(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
if (args.size() != 0) {
|
||||
warning("%s: Expected 0 arguments, got %u", __func__, args.size());
|
||||
return;
|
||||
}
|
||||
|
||||
double red, green, blue;
|
||||
g_engine->getDisplayManager()->getGammaValues(red, green, blue);
|
||||
Common::SharedPtr<Collection> collection = Common::SharedPtr<Collection>(new Collection());
|
||||
|
||||
ScriptValue redValue;
|
||||
redValue.setToFloat(red);
|
||||
collection->push_back(redValue);
|
||||
|
||||
ScriptValue greenValue;
|
||||
greenValue.setToFloat(green);
|
||||
collection->push_back(greenValue);
|
||||
|
||||
ScriptValue blueValue;
|
||||
blueValue.setToFloat(blue);
|
||||
collection->push_back(blueValue);
|
||||
|
||||
returnValue.setToCollection(collection);
|
||||
}
|
||||
|
||||
void FunctionManager::script_SetAudioVolume(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
if (args[0].getType() != kScriptValueTypeFloat) {
|
||||
warning("%s: Expected float argument", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert from 0.0 - 1.0 to ScummVM's mixer range.
|
||||
double volume = args[0].asFloat();
|
||||
volume = CLIP(volume, 0.0, 1.0);
|
||||
int mixerVolume = static_cast<int>(volume * Audio::Mixer::kMaxMixerVolume);
|
||||
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, mixerVolume);
|
||||
}
|
||||
|
||||
void FunctionManager::script_GetAudioVolume(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
// Convert from ScummVM's mixer range to 0.0 - 1.0.
|
||||
int mixerVolume = g_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
|
||||
double volume = static_cast<double>(mixerVolume) / static_cast<double>(Audio::Mixer::kMaxMixerVolume);
|
||||
CLIP(volume, 0.0, 1.0);
|
||||
returnValue.setToFloat(volume);
|
||||
}
|
||||
|
||||
void FunctionManager::script_SystemLanguagePreference(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: SystemLanguagePreference");
|
||||
}
|
||||
|
||||
void FunctionManager::script_SetRegistry(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: SetRegistry");
|
||||
}
|
||||
|
||||
void FunctionManager::script_GetRegistry(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: GetRegistry");
|
||||
}
|
||||
|
||||
void FunctionManager::script_SetProfile(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: SetProfile");
|
||||
}
|
||||
|
||||
void FunctionManager::script_DebugPrint(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
// The original reports time in seconds, but milliseconds is fine.
|
||||
// The "IMT @ clock ..." format is from the original's debug printing style.
|
||||
Common::String output = Common::String::format("IMT @ clock %d", g_system->getMillis());
|
||||
for (uint i = 0; i < args.size(); i++) {
|
||||
// Append all provided arguments.
|
||||
if (i != 0) {
|
||||
output += ", ";
|
||||
} else {
|
||||
output += " ";
|
||||
}
|
||||
output += args[i].getDebugString();
|
||||
}
|
||||
debug("%s", output.c_str());
|
||||
}
|
||||
|
||||
void FunctionManager::script_MazeGenerate(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: MazeGenerate");
|
||||
}
|
||||
|
||||
void FunctionManager::script_MazeApplyMoveMask(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: MazeApplyMoveMask");
|
||||
}
|
||||
|
||||
void FunctionManager::script_MazeSolve(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: MazeSolve");
|
||||
}
|
||||
|
||||
void FunctionManager::script_BeginTimedInterval(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: BeginTimedInterval");
|
||||
}
|
||||
|
||||
void FunctionManager::script_EndTimedInterval(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: EndTimedInterval");
|
||||
}
|
||||
|
||||
void FunctionManager::script_Drawing(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
|
||||
warning("STUB: Drawing");
|
||||
}
|
||||
|
||||
void FunctionManager::deleteFunctionsForContext(uint contextId) {
|
||||
// Collect function IDs to delete first.
|
||||
Common::Array<ScriptFunction *> functionsToDelete;
|
||||
for (auto it = _functions.begin(); it != _functions.end(); ++it) {
|
||||
ScriptFunction *scriptFunction = it->_value;
|
||||
if (scriptFunction->_contextId == contextId) {
|
||||
functionsToDelete.push_back(scriptFunction);
|
||||
}
|
||||
}
|
||||
|
||||
// Now delete them.
|
||||
for (ScriptFunction *scriptFunction : functionsToDelete) {
|
||||
_functions.erase(scriptFunction->_id);
|
||||
delete scriptFunction;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
96
engines/mediastation/mediascript/function.h
Normal file
96
engines/mediastation/mediascript/function.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_MEDIASCRIPT_FUNCTION_H
|
||||
#define MEDIASTATION_MEDIASCRIPT_FUNCTION_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/hashmap.h"
|
||||
|
||||
#include "mediastation/clients.h"
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/codechunk.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum Platform {
|
||||
kPlatformParamTokenUnknown = 0,
|
||||
kPlatformParamTokenWindows = 0x76D,
|
||||
kPlatformParakTokenMacintosh = 0x76E
|
||||
};
|
||||
|
||||
class ScriptFunction {
|
||||
public:
|
||||
ScriptFunction(Chunk &chunk);
|
||||
~ScriptFunction();
|
||||
|
||||
ScriptValue execute(Common::Array<ScriptValue> &args);
|
||||
|
||||
uint _contextId = 0;
|
||||
uint _id = 0;
|
||||
|
||||
private:
|
||||
CodeChunk *_code = nullptr;
|
||||
};
|
||||
|
||||
class FunctionManager : public ParameterClient {
|
||||
public:
|
||||
FunctionManager() {};
|
||||
virtual ~FunctionManager();
|
||||
|
||||
virtual bool attemptToReadFromStream(Chunk &chunk, uint sectionType) override;
|
||||
ScriptValue call(uint functionId, Common::Array<ScriptValue> &args);
|
||||
void deleteFunctionsForContext(uint contextId);
|
||||
|
||||
private:
|
||||
Common::HashMap<uint, ScriptFunction *> _functions;
|
||||
|
||||
void script_GetPlatform(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_Random(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_TimeOfDay(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_SquareRoot(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_GetUniqueRandom(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_CurrentRunTime(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_SetGammaCorrection(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_GetDefaultGammaCorrection(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_GetCurrentGammaCorrection(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_SetAudioVolume(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_GetAudioVolume(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_SystemLanguagePreference(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_SetRegistry(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_GetRegistry(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_SetProfile(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_DebugPrint(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
|
||||
// 101 Dalmatians.
|
||||
void script_MazeGenerate(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_MazeApplyMoveMask(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_MazeSolve(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_BeginTimedInterval(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
void script_EndTimedInterval(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
|
||||
// IBM/Crayola.
|
||||
void script_Drawing(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
491
engines/mediastation/mediascript/scriptconstants.cpp
Normal file
491
engines/mediastation/mediascript/scriptconstants.cpp
Normal file
@@ -0,0 +1,491 @@
|
||||
/* 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 "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
const char *expressionTypeToStr(ExpressionType type) {
|
||||
switch (type) {
|
||||
case kExpressionTypeEmpty:
|
||||
return "Empty";
|
||||
case kExpressionTypeVariable:
|
||||
return "Variable";
|
||||
case kExpressionTypeValue:
|
||||
return "Value";
|
||||
case kExpressionTypeOperation:
|
||||
return "Operation";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *opcodeToStr(Opcode opcode) {
|
||||
switch (opcode) {
|
||||
case kOpcodeIf:
|
||||
return "If";
|
||||
case kOpcodeIfElse:
|
||||
return "IfElse";
|
||||
case kOpcodeAssignVariable:
|
||||
return "AssignVariable";
|
||||
case kOpcodeOr:
|
||||
return "Or";
|
||||
case kOpcodeXor:
|
||||
return "Xor";
|
||||
case kOpcodeAnd:
|
||||
return "And";
|
||||
case kOpcodeEquals:
|
||||
return "==";
|
||||
case kOpcodeNotEquals:
|
||||
return "!=";
|
||||
case kOpcodeLessThan:
|
||||
return "<";
|
||||
case kOpcodeGreaterThan:
|
||||
return ">";
|
||||
case kOpcodeLessThanOrEqualTo:
|
||||
return "<=";
|
||||
case kOpcodeGreaterThanOrEqualTo:
|
||||
return ">=";
|
||||
case kOpcodeAdd:
|
||||
return "+";
|
||||
case kOpcodeSubtract:
|
||||
return "-";
|
||||
case kOpcodeMultiply:
|
||||
return "*";
|
||||
case kOpcodeDivide:
|
||||
return "/";
|
||||
case kOpcodeModulo:
|
||||
return "%";
|
||||
case kOpcodeNegate:
|
||||
return "-";
|
||||
case kOpcodeCallFunction:
|
||||
return "CallFunction";
|
||||
case kOpcodeCallMethod:
|
||||
return "CallMethod";
|
||||
case kOpcodeDeclareLocals:
|
||||
return "DeclareLocals";
|
||||
case kOpcodeReturn:
|
||||
return "Return";
|
||||
case kOpcodeReturnNoValue:
|
||||
return "ReturnNoValue";
|
||||
case kOpcodeWhile:
|
||||
return "While";
|
||||
case kOpcodeCallFunctionInVariable:
|
||||
return "CallFunctionInVariable";
|
||||
case kOpcodeCallMethodInVariable:
|
||||
return "CallMethodInVariable";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *variableScopeToStr(VariableScope scope) {
|
||||
switch (scope) {
|
||||
case kVariableScopeLocal:
|
||||
return "Local";
|
||||
case kVariableScopeParameter:
|
||||
return "Parameter";
|
||||
case kVariableScopeIndirectParameter:
|
||||
return "IndirectParameter";
|
||||
case kVariableScopeGlobal:
|
||||
return "Global";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *builtInFunctionToStr(BuiltInFunction function) {
|
||||
switch (function) {
|
||||
case kRandomFunction:
|
||||
return "Random";
|
||||
case kTimeOfDayFunction:
|
||||
return "TimeOfDay";
|
||||
case kEffectTransitionFunction:
|
||||
return "EffectTransition";
|
||||
case kEffectTransitionOnSyncFunction:
|
||||
return "EffectTransitionOnSync";
|
||||
case kPlatformFunction:
|
||||
return "Platform";
|
||||
case kSquareRootFunction:
|
||||
return "SquareRoot";
|
||||
case kGetUniqueRandomFunction:
|
||||
return "GetUniqueRandom";
|
||||
case kCurrentRunTimeFunction:
|
||||
return "CurrentRunTime";
|
||||
case kSetGammaCorrectionFunction:
|
||||
return "SetGammaCorrection";
|
||||
case kGetDefaultGammaCorrectionFunction:
|
||||
return "GetDefaultGammaCorrection";
|
||||
case kGetCurrentGammaCorrectionFunction:
|
||||
return "GetCurrentGammaCorrection";
|
||||
case kSetAudioVolumeFunction:
|
||||
return "SetAudioVolume";
|
||||
case kGetAudioVolumeFunction:
|
||||
return "GetAudioVolume";
|
||||
case kSystemLanguagePreferenceFunction:
|
||||
return "SystemLanguagePreference";
|
||||
case kSetRegistryFunction:
|
||||
return "SetRegistry";
|
||||
case kGetRegistryFunction:
|
||||
return "GetRegistry";
|
||||
case kSetProfileFunction:
|
||||
return "SetProfile";
|
||||
case kMazeGenerateFunction:
|
||||
return "MazeGenerate";
|
||||
case kMazeApplyMoveMaskFunction:
|
||||
return "MazeApplyMoveMask";
|
||||
case kMazeSolveFunction:
|
||||
return "MazeSolve";
|
||||
case kBeginTimedIntervalFunction:
|
||||
return "BeginTimedInterval";
|
||||
case kEndTimedIntervalFunction:
|
||||
return "EndTimedInterval";
|
||||
case kDrawingFunction:
|
||||
return "Drawing";
|
||||
case kLegacy_RandomFunction:
|
||||
return "Legacy Random";
|
||||
case kLegacy_TimeOfDayFunction:
|
||||
return "Legacy TimeOfDay";
|
||||
case kLegacy_EffectTransitionFunction:
|
||||
return "Legacy EffectTransition";
|
||||
case kLegacy_EffectTransitionOnSyncFunction:
|
||||
return "Legacy EffectTransitionOnSync";
|
||||
case kLegacy_PlatformFunction:
|
||||
return "Legacy Platform";
|
||||
case kLegacy_SquareRootFunction:
|
||||
return "Legacy SquareRoot";
|
||||
case kLegacy_GetUniqueRandomFunction:
|
||||
return "Legacy GetUniqueRandom";
|
||||
case kLegacy_DebugPrintFunction:
|
||||
return "DebugPrint";
|
||||
case kLegacy_SystemLanguagePreferenceFunction:
|
||||
return "Legacy SystemLanguagePreference";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *builtInMethodToStr(BuiltInMethod method) {
|
||||
switch (method) {
|
||||
case kCursorSetMethod:
|
||||
return "CursorSet";
|
||||
case kSpatialHideMethod:
|
||||
return "SpatialHide";
|
||||
case kSpatialMoveToMethod:
|
||||
return "SpatialMoveTo";
|
||||
case kSpatialMoveToByOffsetMethod:
|
||||
return "SpatialMoveToByOffset";
|
||||
case kSpatialZMoveToMethod:
|
||||
return "SpatialZMoveTo";
|
||||
case kSpatialCenterMoveToMethod:
|
||||
return "SpatialCenterMoveTo";
|
||||
case kSpatialShowMethod:
|
||||
return "SpatialShow";
|
||||
case kTimePlayMethod:
|
||||
return "TimePlay";
|
||||
case kTimeStopMethod:
|
||||
return "TimeStop";
|
||||
case kIsPlayingMethod:
|
||||
return "IsPlaying/SetMultipleStreams";
|
||||
case kSetDissolveFactorMethod:
|
||||
return "SetDissolveFactor";
|
||||
case kMouseActivateMethod:
|
||||
return "MouseActivate";
|
||||
case kMouseDeactivateMethod:
|
||||
return "MouseDeactivate";
|
||||
case kGetLeftXMethod:
|
||||
return "GetLeftX";
|
||||
case kGetTopYMethod:
|
||||
return "GetTopY";
|
||||
case kTriggerAbsXPositionMethod:
|
||||
return "TriggerAbsXPosition";
|
||||
case kTriggerAbsYPositionMethod:
|
||||
return "TriggerAbsYPosition";
|
||||
case kIsActiveMethod:
|
||||
return "IsActive";
|
||||
case kGetWidthMethod:
|
||||
return "GetWidth";
|
||||
case kGetHeightMethod:
|
||||
return "GetHeight";
|
||||
case kGetCenterXMethod:
|
||||
return "GetCenterX";
|
||||
case kGetCenterYMethod:
|
||||
return "GetCenterY";
|
||||
case kGetZCoordinateMethod:
|
||||
return "GetZCoordinate";
|
||||
case kIsPointInsideMethod:
|
||||
return "IsPointInside";
|
||||
case kGetMouseXOffsetMethod:
|
||||
return "GetMouseXOffset";
|
||||
case kGetMouseYOffsetMethod:
|
||||
return "GetMouseYOffset";
|
||||
case kIsVisibleMethod:
|
||||
return "IsVisible";
|
||||
case kSetMousePositionMethod:
|
||||
return "SetMousePosition";
|
||||
case kGetXScaleMethod1:
|
||||
case kGetXScaleMethod2:
|
||||
return "GetXScale";
|
||||
case kSetScaleMethod:
|
||||
return "SetScale";
|
||||
case kSetXScaleMethod:
|
||||
return "SetXScale";
|
||||
case kGetYScaleMethod:
|
||||
return "GetYScale";
|
||||
case kSetYScaleMethod:
|
||||
return "SetYScale";
|
||||
case kMovieResetMethod:
|
||||
return "MovieReset";
|
||||
case kSetCurrentClipMethod:
|
||||
return "SetCurrentClip";
|
||||
case kIncrementFrameMethod:
|
||||
return "IncrementFrame";
|
||||
case kDecrementFrameMethod:
|
||||
return "DecrementFrame";
|
||||
case kGetCurrentClipIdMethod:
|
||||
return "GetCurrentClipId";
|
||||
case kSetWorldSpaceExtentMethod:
|
||||
return "SetWorldSpaceExtent";
|
||||
case kSetBoundsMethod:
|
||||
return "SetBounds";
|
||||
case kStageGetWidthMethod:
|
||||
return "StageGetWidth";
|
||||
case kStageGetHeightMethod:
|
||||
return "StageGetHeight";
|
||||
case kAddToStageMethod:
|
||||
return "AddToStage\\OpenLens";
|
||||
case kRemoveFromStageMethod:
|
||||
return "RemoveFromStage\\CloseLens";
|
||||
case kAddedToStageMethod:
|
||||
return "AddedToStage";
|
||||
case kStartPanMethod:
|
||||
return "StartPan";
|
||||
case kStopPanMethod:
|
||||
return "StopPan";
|
||||
case kIsPanningMethod:
|
||||
return "IsPanning";
|
||||
case kViewportMoveToMethod:
|
||||
return "ViewportMoveTo";
|
||||
case kAdjustCameraViewportMethod:
|
||||
return "AdjustCameraViewport";
|
||||
case kAdjustCameraViewportSpatialCenterMethod:
|
||||
return "AdjustCameraViewportSpatialCenter";
|
||||
case kSetCameraBoundsMethod:
|
||||
return "SetCameraBounds";
|
||||
case kXViewportPositionMethod:
|
||||
return "XViewportPosition";
|
||||
case kYViewportPositionMethod:
|
||||
return "YViewportPosition";
|
||||
case kPanToMethod:
|
||||
return "PanTo";
|
||||
case kClearToPaletteMethod:
|
||||
return "ClearToPalette";
|
||||
case kDocumentLoadContextMethod:
|
||||
return "LoadContext";
|
||||
case kDocumentReleaseContextMethod:
|
||||
return "ReleaseContext";
|
||||
case kDocumentBranchToScreenMethod:
|
||||
return "BranchToScreen";
|
||||
case kDocumentQuitMethod:
|
||||
return "Quit";
|
||||
case kDocumentContextLoadInProgressMethod:
|
||||
return "ContextLoadInProgress";
|
||||
case kDocumentSetMultipleSoundsMethod:
|
||||
return "SetMultipleSounds";
|
||||
case kDocumentContextIsLoadedMethod:
|
||||
return "IsLoaded";
|
||||
case kSetDurationMethod:
|
||||
return "SetDuration";
|
||||
case kPercentCompleteMethod:
|
||||
return "PercentComplete";
|
||||
case kTextMethod:
|
||||
return "Text";
|
||||
case kSetTextMethod:
|
||||
return "SetText";
|
||||
case kSetMaximumTextLengthMethod:
|
||||
return "SetMaximumTextLength";
|
||||
case kAppendMethod:
|
||||
return "Append";
|
||||
case kApplyMethod:
|
||||
return "Apply";
|
||||
case kCountMethod:
|
||||
return "Count";
|
||||
case kDeleteFirstMethod:
|
||||
return "DeleteFirst";
|
||||
case kDeleteLastMethod:
|
||||
return "DeleteLast";
|
||||
case kEmptyMethod:
|
||||
return "Empty";
|
||||
case kGetAtMethod:
|
||||
return "GetAt";
|
||||
case kIsEmptyMethod:
|
||||
return "IsEmpty";
|
||||
case kJumbleMethod:
|
||||
return "Jumble";
|
||||
case kSeekMethod:
|
||||
return "Seek";
|
||||
case kSendMethod:
|
||||
return "Send";
|
||||
case kDeleteAtMethod:
|
||||
return "DeleteAt";
|
||||
case kInsertAtMethod:
|
||||
return "InsertAt";
|
||||
case kReplaceAtMethod:
|
||||
return "ReplaceAt";
|
||||
case kPrependListMethod:
|
||||
return "PrependList";
|
||||
case kSortMethod:
|
||||
return "Sort";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *eventTypeToStr(EventType type) {
|
||||
switch (type) {
|
||||
case kTimerEvent:
|
||||
return "Timer";
|
||||
case kMouseDownEvent:
|
||||
return "MouseDown";
|
||||
case kMouseUpEvent:
|
||||
return "MouseUp";
|
||||
case kMouseMovedEvent:
|
||||
return "MouseMoved";
|
||||
case kMouseEnteredEvent:
|
||||
return "MouseEntered";
|
||||
case kMouseExitedEvent:
|
||||
return "MouseExited";
|
||||
case kKeyDownEvent:
|
||||
return "KeyDown";
|
||||
case kSoundEndEvent:
|
||||
return "SoundEnd";
|
||||
case kSoundAbortEvent:
|
||||
return "SoundAbort";
|
||||
case kSoundFailureEvent:
|
||||
return "SoundFailure";
|
||||
case kSoundStoppedEvent:
|
||||
return "SoundStopped";
|
||||
case kSoundBeginEvent:
|
||||
return "SoundBegin";
|
||||
case kMovieEndEvent:
|
||||
return "MovieEnd";
|
||||
case kMovieAbortEvent:
|
||||
return "MovieAbort";
|
||||
case kMovieFailureEvent:
|
||||
return "MovieFailure";
|
||||
case kMovieStoppedEvent:
|
||||
return "MovieStopped";
|
||||
case kMovieBeginEvent:
|
||||
return "MovieBegin";
|
||||
case kSpriteMovieEndEvent:
|
||||
return "SpriteMovieEnd";
|
||||
case kScreenEntryEvent:
|
||||
return "ScreenEntry";
|
||||
case kScreenExitEvent:
|
||||
return "ScreenExit";
|
||||
case kContextLoadCompleteEvent:
|
||||
return "ContextLoadComplete";
|
||||
case kContextLoadCompleteEvent2:
|
||||
return "ContextLoadComplete2";
|
||||
case kContextLoadAbortEvent:
|
||||
return "ContextLoadAbort";
|
||||
case kContextLoadFailureEvent:
|
||||
return "ContextLoadFailure";
|
||||
case kTextInputEvent:
|
||||
return "TextInput";
|
||||
case kTextErrorEvent:
|
||||
return "TextError";
|
||||
case kCameraPanStepEvent:
|
||||
return "CameraPanStep";
|
||||
case kCameraPanAbortEvent:
|
||||
return "CameraPanAbort";
|
||||
case kCameraPanEndEvent:
|
||||
return "CameraPanEnd";
|
||||
case kPathStepEvent:
|
||||
return "PathStep";
|
||||
case kPathStoppedEvent:
|
||||
return "PathStopped";
|
||||
case kPathEndEvent:
|
||||
return "PathEnd";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *operandTypeToStr(OperandType type) {
|
||||
switch (type) {
|
||||
case kOperandTypeEmpty:
|
||||
return "Empty";
|
||||
case kOperandTypeBool:
|
||||
return "Bool";
|
||||
case kOperandTypeFloat:
|
||||
return "Float";
|
||||
case kOperandTypeInt:
|
||||
return "Int";
|
||||
case kOperandTypeString:
|
||||
return "String";
|
||||
case kOperandTypeParamToken:
|
||||
return "DollarSignVariable";
|
||||
case kOperandTypeActorId:
|
||||
return "ActorId";
|
||||
case kOperandTypeTime:
|
||||
return "Time";
|
||||
case kOperandTypeVariable:
|
||||
return "Variable";
|
||||
case kOperandTypeFunctionId:
|
||||
return "FunctionId";
|
||||
case kOperandTypeMethodId:
|
||||
return "MethodId";
|
||||
case kOperandTypeCollection:
|
||||
return "Collection";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *scriptValueTypeToStr(ScriptValueType type) {
|
||||
switch (type) {
|
||||
case kScriptValueTypeEmpty:
|
||||
return "Empty";
|
||||
case kScriptValueTypeFloat:
|
||||
return "Float";
|
||||
case kScriptValueTypeBool:
|
||||
return "Bool";
|
||||
case kScriptValueTypeTime:
|
||||
return "Time";
|
||||
case kScriptValueTypeParamToken:
|
||||
return "Int";
|
||||
case kScriptValueTypeActorId:
|
||||
return "ActorId";
|
||||
case kScriptValueTypeString:
|
||||
return "String";
|
||||
case kScriptValueTypeCollection:
|
||||
return "Collection";
|
||||
case kScriptValueTypeFunctionId:
|
||||
return "FunctionId";
|
||||
case kScriptValueTypeMethodId:
|
||||
return "MethodId";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
315
engines/mediastation/mediascript/scriptconstants.h
Normal file
315
engines/mediastation/mediascript/scriptconstants.h
Normal file
@@ -0,0 +1,315 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_MEDIASCRIPT_BUILTINS_H
|
||||
#define MEDIASTATION_MEDIASCRIPT_BUILTINS_H
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
enum ExpressionType {
|
||||
kExpressionTypeEmpty = 0x0000,
|
||||
kExpressionTypeVariable = 0x0065,
|
||||
kExpressionTypeValue = 0x0066,
|
||||
kExpressionTypeOperation = 0x0067,
|
||||
};
|
||||
const char *expressionTypeToStr(ExpressionType type);
|
||||
|
||||
enum Opcode {
|
||||
kOpcodeIf = 0xC9,
|
||||
kOpcodeIfElse = 0xCA,
|
||||
kOpcodeAssignVariable = 0xCB,
|
||||
kOpcodeOr = 0xCC,
|
||||
kOpcodeXor = 0xCD,
|
||||
kOpcodeAnd = 0xCE,
|
||||
kOpcodeEquals = 0xCF,
|
||||
kOpcodeNotEquals = 0xD0,
|
||||
kOpcodeLessThan = 0xD1,
|
||||
kOpcodeGreaterThan = 0xD2,
|
||||
kOpcodeLessThanOrEqualTo = 0xD3,
|
||||
kOpcodeGreaterThanOrEqualTo = 0xD4,
|
||||
kOpcodeAdd = 0xD5,
|
||||
kOpcodeSubtract = 0xD6,
|
||||
kOpcodeMultiply = 0xD7,
|
||||
kOpcodeDivide = 0xD8,
|
||||
kOpcodeModulo = 0xD9,
|
||||
kOpcodeNegate = 0xDA,
|
||||
kOpcodeCallFunction = 0xDB,
|
||||
kOpcodeCallMethod = 0xDC,
|
||||
kOpcodeDeclareLocals = 0xDD,
|
||||
kOpcodeReturn = 0xDE,
|
||||
kOpcodeReturnNoValue = 0xDF,
|
||||
kOpcodeWhile = 0xE0,
|
||||
kOpcodeCallFunctionInVariable = 0xE1, // IndirectCall
|
||||
kOpcodeCallMethodInVariable = 0xE2 // IndirectMsg
|
||||
};
|
||||
const char *opcodeToStr(Opcode opcode);
|
||||
|
||||
enum VariableScope {
|
||||
kVariableScopeLocal = 0x1,
|
||||
kVariableScopeParameter = 0x2,
|
||||
kVariableScopeIndirectParameter = 0x3,
|
||||
kVariableScopeGlobal = 0x4
|
||||
};
|
||||
const char *variableScopeToStr(VariableScope scope);
|
||||
|
||||
enum BuiltInFunction {
|
||||
kRandomFunction = 0x0A,
|
||||
kTimeOfDayFunction = 0x0B,
|
||||
kEffectTransitionFunction = 0x0C,
|
||||
kEffectTransitionOnSyncFunction = 0x0D,
|
||||
kPlatformFunction = 0x0E,
|
||||
kSquareRootFunction = 0x0F,
|
||||
kGetUniqueRandomFunction = 0x10,
|
||||
kCurrentRunTimeFunction = 0x11,
|
||||
kSetGammaCorrectionFunction = 0x12,
|
||||
kGetDefaultGammaCorrectionFunction = 0x13,
|
||||
kGetCurrentGammaCorrectionFunction = 0x14,
|
||||
kSetAudioVolumeFunction = 0x17,
|
||||
kGetAudioVolumeFunction = 0x18,
|
||||
kSystemLanguagePreferenceFunction = 0x19,
|
||||
kSetRegistryFunction = 0x1A,
|
||||
kGetRegistryFunction = 0x1B,
|
||||
kSetProfileFunction = 0x1C,
|
||||
kMazeGenerateFunction = 0x1F,
|
||||
kMazeApplyMoveMaskFunction = 0x20,
|
||||
kMazeSolveFunction = 0x21,
|
||||
kBeginTimedIntervalFunction = 0x22,
|
||||
kEndTimedIntervalFunction = 0x23,
|
||||
kDrawingFunction = 0x25,
|
||||
|
||||
// Early engine versions (like for Lion King and such), had different opcodes
|
||||
// for some functions, even though the functions were the same. So those are
|
||||
// defined here.
|
||||
kLegacy_RandomFunction = 0x64,
|
||||
kLegacy_TimeOfDayFunction = 0x65,
|
||||
kLegacy_EffectTransitionFunction = 0x66,
|
||||
kLegacy_EffectTransitionOnSyncFunction = 0x67,
|
||||
kLegacy_PlatformFunction = 0x68,
|
||||
kLegacy_SquareRootFunction = 0x69,
|
||||
kLegacy_GetUniqueRandomFunction = 0x6A,
|
||||
kLegacy_DebugPrintFunction = 0xB4,
|
||||
kLegacy_SystemLanguagePreferenceFunction = 0xC8,
|
||||
};
|
||||
const char *builtInFunctionToStr(BuiltInFunction function);
|
||||
|
||||
enum BuiltInMethod {
|
||||
kInvalidMethod = 0,
|
||||
// TODO: What object types does CursorSet apply to?
|
||||
// Currently it's only in var_7be1_cursor_currentTool in
|
||||
// IBM/Crayola.
|
||||
kCursorSetMethod = 0xC8,
|
||||
|
||||
// SPATIAL ENTITY METHODS.
|
||||
kSpatialHideMethod = 0xCB,
|
||||
kSpatialMoveToMethod = 0xCC,
|
||||
kSpatialMoveToByOffsetMethod = 0xCD,
|
||||
kSpatialZMoveToMethod = 0xD8,
|
||||
kSpatialShowMethod = 0xCA,
|
||||
kTimePlayMethod = 0xCE,
|
||||
kTimeStopMethod = 0xCF,
|
||||
kIsPlayingMethod = 0x174,
|
||||
kSetDissolveFactorMethod = 0xF1,
|
||||
kSpatialCenterMoveToMethod = 0xE6,
|
||||
kGetLeftXMethod = 0xE9,
|
||||
kGetTopYMethod = 0xEA,
|
||||
kGetWidthMethod = 0xEB,
|
||||
kGetHeightMethod = 0xEC,
|
||||
kGetCenterXMethod = 0xED,
|
||||
kGetCenterYMethod = 0xEE,
|
||||
kGetZCoordinateMethod = 0xEF,
|
||||
kIsPointInsideMethod = 0xF6,
|
||||
kGetMouseXOffsetMethod = 0x108,
|
||||
kGetMouseYOffsetMethod = 0x109,
|
||||
kIsVisibleMethod = 0x10D,
|
||||
kSetMousePositionMethod = 0x129,
|
||||
// It isn't clear what the difference is meant to be
|
||||
// between these two, as the code looks the same for both.
|
||||
kGetXScaleMethod1 = 0x16E,
|
||||
kGetXScaleMethod2 = 0x17E,
|
||||
kSetScaleMethod = 0x16F,
|
||||
kSetXScaleMethod = 0x17F,
|
||||
kGetYScaleMethod = 0x180,
|
||||
kSetYScaleMethod = 0x181,
|
||||
|
||||
// HOTSPOT METHODS.
|
||||
// NOTE: IDs 0xD2 and 0xD3 seem to be double-assigned
|
||||
// between two hotspot methods and two stage methods.
|
||||
kMouseActivateMethod = 0xD2,
|
||||
kMouseDeactivateMethod = 0xD3,
|
||||
kTriggerAbsXPositionMethod = 0x141,
|
||||
kTriggerAbsYPositionMethod = 0x142,
|
||||
kIsActiveMethod = 0x173,
|
||||
|
||||
// SPRITE METHODS.
|
||||
kMovieResetMethod = 0xDB,
|
||||
kSetCurrentClipMethod = 0xDC,
|
||||
kIncrementFrameMethod = 0xDD,
|
||||
kDecrementFrameMethod = 0xDE,
|
||||
kGetCurrentClipIdMethod = 0xF0,
|
||||
|
||||
// STAGE METHODS.
|
||||
// NOTE: IDs 0xD2 and 0xD3 seem to be double-assigned
|
||||
// between two hotspot methods and two stage methods.
|
||||
kAddActorToStageMethod = 0xD2,
|
||||
kRemoveActorFromStageMethod = 0xD3,
|
||||
kSetWorldSpaceExtentMethod = 0x16B,
|
||||
kSetBoundsMethod = 0x11F,
|
||||
kStageSetSizeMethod = 0x16B,
|
||||
kStageGetWidthMethod = 0x16C,
|
||||
kStageGetHeightMethod = 0x16D,
|
||||
|
||||
// CAMERA METHODS.
|
||||
// NOTE: IDs 0x15A and 0x15B seem to be double-assigned
|
||||
// between two camera methods and two printer methods.
|
||||
kAddToStageMethod = 0x15A,
|
||||
kRemoveFromStageMethod = 0x15B,
|
||||
kAddedToStageMethod = 0x15C,
|
||||
kStartPanMethod = 0x15D,
|
||||
kStopPanMethod = 0x15E,
|
||||
kIsPanningMethod = 0x15F,
|
||||
kViewportMoveToMethod = 0x160,
|
||||
kAdjustCameraViewportMethod = 0x161,
|
||||
kAdjustCameraViewportSpatialCenterMethod = 0x162,
|
||||
kSetCameraBoundsMethod = 0x163,
|
||||
kXViewportPositionMethod = 0x164,
|
||||
kYViewportPositionMethod = 0x165,
|
||||
kPanToMethod = 0x172,
|
||||
|
||||
// CANVAS METHODS.
|
||||
kClearToPaletteMethod = 0x17B,
|
||||
|
||||
// DOCUMENT METHODS.
|
||||
kDocumentBranchToScreenMethod = 0xC9,
|
||||
kDocumentQuitMethod = 0xD9,
|
||||
kDocumentContextLoadInProgressMethod = 0x169,
|
||||
kDocumentSetMultipleStreamsMethod = 0x174,
|
||||
kDocumentSetMultipleSoundsMethod = 0x175,
|
||||
kDocumentLoadContextMethod = 0x176,
|
||||
kDocumentReleaseContextMethod = 0x177,
|
||||
kDocumentContextIsLoadedMethod = 0x178,
|
||||
|
||||
// PATH METHODS.
|
||||
kSetDurationMethod = 0x106,
|
||||
kPercentCompleteMethod = 0x107,
|
||||
|
||||
// TEXT METHODS.
|
||||
kTextMethod = 0x122,
|
||||
kSetTextMethod = 0x123,
|
||||
kSetMaximumTextLengthMethod = 0x125,
|
||||
|
||||
// COLLECTION METHODS.
|
||||
// These are arrays used in Media Script.
|
||||
kAppendMethod = 0xF7,
|
||||
kApplyMethod = 0xF8,
|
||||
kCountMethod = 0xF9,
|
||||
kDeleteFirstMethod = 0xFA,
|
||||
kDeleteLastMethod = 0xFB,
|
||||
kEmptyMethod = 0xFC,
|
||||
kGetAtMethod = 0xFD,
|
||||
kIsEmptyMethod = 0xFE,
|
||||
kJumbleMethod = 0xFF,
|
||||
kSeekMethod = 0x100,
|
||||
kSendMethod = 0x101,
|
||||
kDeleteAtMethod = 0x102,
|
||||
kInsertAtMethod = 0x103,
|
||||
kReplaceAtMethod = 0x104,
|
||||
kPrependListMethod = 0x105,
|
||||
kSortMethod = 0x10A,
|
||||
|
||||
// PRINTER METHODS.
|
||||
// NOTE: IDs 0x15A and 0x15B seem to be double-assigned
|
||||
// between two camera methods and two printer methods.
|
||||
kOpenLensMethod = 0x15A,
|
||||
kCloseLensMethod = 0x15B,
|
||||
};
|
||||
const char *builtInMethodToStr(BuiltInMethod method);
|
||||
|
||||
enum EventType {
|
||||
kTimerEvent = 0x05,
|
||||
kMouseDownEvent = 0x06,
|
||||
kMouseUpEvent = 0x07,
|
||||
kMouseMovedEvent = 0x08,
|
||||
kMouseEnteredEvent = 0x09,
|
||||
kMouseExitedEvent = 0x0A,
|
||||
kKeyDownEvent = 0x0D,
|
||||
kSoundEndEvent = 0x0E,
|
||||
kMovieEndEvent = 0x0F,
|
||||
kPathEndEvent = 0x10,
|
||||
kScreenEntryEvent = 0x11,
|
||||
kSoundAbortEvent = 0x13,
|
||||
kSoundFailureEvent = 0x14,
|
||||
kMovieAbortEvent = 0x15,
|
||||
kMovieFailureEvent = 0x16,
|
||||
kSpriteMovieEndEvent = 0x17,
|
||||
kScreenExitEvent = 0x1B,
|
||||
kPathStepEvent = 0x1C,
|
||||
kSoundStoppedEvent = 0x1D,
|
||||
kSoundBeginEvent = 0x1E,
|
||||
kMovieStoppedEvent = 0x1F,
|
||||
kMovieBeginEvent = 0x20,
|
||||
kPathStoppedEvent = 0x21,
|
||||
kTextInputEvent = 0x25,
|
||||
kTextErrorEvent = 0x26,
|
||||
kCameraPanStepEvent = 0x29,
|
||||
kCameraPanEndEvent = 0x2A,
|
||||
kCameraPanAbortEvent = 0x2B,
|
||||
kContextLoadCompleteEvent = 0x2C,
|
||||
// TODO: These last 3 events appear as valid event types, but I haven't found
|
||||
// scripts that actually use them. So the names might be wrong.
|
||||
kContextLoadCompleteEvent2 = 0x2D,
|
||||
kContextLoadAbortEvent = 0x2E,
|
||||
kContextLoadFailureEvent = 0x2F,
|
||||
};
|
||||
const char *eventTypeToStr(EventType type);
|
||||
|
||||
enum OperandType {
|
||||
kOperandTypeEmpty = 0x0,
|
||||
kOperandTypeBool = 0x97,
|
||||
kOperandTypeFloat = 0x98,
|
||||
kOperandTypeInt = 0x99,
|
||||
kOperandTypeString = 0x9A,
|
||||
kOperandTypeParamToken = 0x9B,
|
||||
kOperandTypeActorId = 0x9C,
|
||||
kOperandTypeTime = 0x9D,
|
||||
kOperandTypeVariable = 0x9E,
|
||||
kOperandTypeFunctionId = 0x9F,
|
||||
kOperandTypeMethodId = 0xA0,
|
||||
kOperandTypeCollection = 0xA1
|
||||
};
|
||||
const char *operandTypeToStr(OperandType type);
|
||||
|
||||
enum ScriptValueType {
|
||||
kScriptValueTypeEmpty = 0x0,
|
||||
kScriptValueTypeFloat = 0x1,
|
||||
kScriptValueTypeBool = 0x2,
|
||||
kScriptValueTypeTime = 0x3,
|
||||
kScriptValueTypeParamToken = 0x4,
|
||||
kScriptValueTypeActorId = 0x5,
|
||||
kScriptValueTypeString = 0x6,
|
||||
kScriptValueTypeCollection = 0x7,
|
||||
kScriptValueTypeFunctionId = 0x8,
|
||||
kScriptValueTypeMethodId = 0x9
|
||||
};
|
||||
const char *scriptValueTypeToStr(ScriptValueType type);
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
574
engines/mediastation/mediascript/scriptvalue.cpp
Normal file
574
engines/mediastation/mediascript/scriptvalue.cpp
Normal file
@@ -0,0 +1,574 @@
|
||||
/* 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 "mediastation/mediascript/scriptvalue.h"
|
||||
#include "mediastation/mediascript/function.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
ScriptValue::ScriptValue(ParameterReadStream *stream) {
|
||||
_type = static_cast<ScriptValueType>(stream->readTypedByte());
|
||||
|
||||
switch (_type) {
|
||||
case kScriptValueTypeEmpty:
|
||||
break;
|
||||
|
||||
case kScriptValueTypeFloat: {
|
||||
double d = stream->readTypedDouble();
|
||||
setToFloat(d);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeBool: {
|
||||
uint rawValue = stream->readTypedByte();
|
||||
if (rawValue != 0 && rawValue != 1) {
|
||||
error("%s: Got invalid literal bool value %d", __func__, rawValue);
|
||||
}
|
||||
setToBool(rawValue);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeTime: {
|
||||
double d = stream->readTypedTime();
|
||||
setToFloat(d);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeParamToken: {
|
||||
uint paramToken = stream->readTypedUint16();
|
||||
setToParamToken(paramToken);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeActorId: {
|
||||
uint actorId = stream->readTypedUint16();
|
||||
setToActorId(actorId);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeString: {
|
||||
uint size = stream->readTypedUint16();
|
||||
Common::String string = stream->readString('\0', size);
|
||||
setToString(string);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeCollection: {
|
||||
uint totalItems = stream->readTypedUint16();
|
||||
Common::SharedPtr<Collection> collection(new Collection);
|
||||
for (uint i = 0; i < totalItems; i++) {
|
||||
ScriptValue collectionValue = ScriptValue(stream);
|
||||
collection->push_back(collectionValue);
|
||||
}
|
||||
setToCollection(collection);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeFunctionId: {
|
||||
uint functionId = stream->readTypedUint16();
|
||||
setToFunctionId(functionId);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeMethodId: {
|
||||
BuiltInMethod methodId = static_cast<BuiltInMethod>(stream->readTypedUint16());
|
||||
setToMethodId(methodId);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Got unknown script value type %s", __func__, scriptValueTypeToStr(_type));
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToFloat(uint i) {
|
||||
setToFloat(static_cast<double>(i));
|
||||
}
|
||||
|
||||
void ScriptValue::setToFloat(int i) {
|
||||
setToFloat(static_cast<double>(i));
|
||||
}
|
||||
|
||||
void ScriptValue::setToFloat(double d) {
|
||||
_type = kScriptValueTypeFloat;
|
||||
_u.d = d;
|
||||
}
|
||||
|
||||
double ScriptValue::asFloat() const {
|
||||
if (_type == kScriptValueTypeFloat) {
|
||||
return _u.d;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeFloat);
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToBool(bool b) {
|
||||
_type = kScriptValueTypeBool;
|
||||
_u.b = b;
|
||||
}
|
||||
|
||||
bool ScriptValue::asBool() const {
|
||||
if (_type == kScriptValueTypeBool) {
|
||||
return _u.b;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeBool);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToTime(double d) {
|
||||
_type = kScriptValueTypeTime;
|
||||
_u.d = d;
|
||||
}
|
||||
|
||||
double ScriptValue::asTime() const {
|
||||
if (_type == kScriptValueTypeTime) {
|
||||
return _u.d;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeTime);
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToParamToken(uint paramToken) {
|
||||
_type = kScriptValueTypeParamToken;
|
||||
_u.paramToken = paramToken;
|
||||
}
|
||||
|
||||
uint ScriptValue::asParamToken() const {
|
||||
if (_type == kScriptValueTypeParamToken) {
|
||||
return _u.paramToken;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeParamToken);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToActorId(uint actorId) {
|
||||
_type = kScriptValueTypeActorId;
|
||||
_u.actorId = actorId;
|
||||
}
|
||||
|
||||
uint ScriptValue::asActorId() const {
|
||||
if (_type == kScriptValueTypeActorId) {
|
||||
return _u.actorId;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeActorId);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToString(const Common::String &string) {
|
||||
_type = kScriptValueTypeString;
|
||||
_string = string;
|
||||
}
|
||||
|
||||
Common::String ScriptValue::asString() const {
|
||||
if (_type == kScriptValueTypeString) {
|
||||
return _string;
|
||||
} else {
|
||||
return Common::String("");
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToCollection(Common::SharedPtr<Collection> collection) {
|
||||
_type = kScriptValueTypeCollection;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
Common::SharedPtr<Collection> ScriptValue::asCollection() const {
|
||||
if (_type == kScriptValueTypeCollection) {
|
||||
return _collection;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeCollection);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToFunctionId(uint functionId) {
|
||||
_type = kScriptValueTypeFunctionId;
|
||||
_u.functionId = functionId;
|
||||
}
|
||||
|
||||
uint ScriptValue::asFunctionId() const {
|
||||
if (_type == kScriptValueTypeFunctionId) {
|
||||
return _u.functionId;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeFunctionId);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptValue::setToMethodId(BuiltInMethod methodId) {
|
||||
_type = kScriptValueTypeMethodId;
|
||||
_u.methodId = methodId;
|
||||
}
|
||||
|
||||
BuiltInMethod ScriptValue::asMethodId() const {
|
||||
if (_type == kScriptValueTypeMethodId) {
|
||||
return _u.methodId;
|
||||
} else {
|
||||
issueValueMismatchWarning(kScriptValueTypeMethodId);
|
||||
return kInvalidMethod;
|
||||
}
|
||||
}
|
||||
|
||||
Common::String ScriptValue::getDebugString() {
|
||||
switch (getType()) {
|
||||
case kScriptValueTypeEmpty:
|
||||
return "empty";
|
||||
|
||||
case kScriptValueTypeFloat:
|
||||
return Common::String::format("float: %f", asFloat());
|
||||
|
||||
case kScriptValueTypeActorId:
|
||||
return Common::String::format("actor: %d", asActorId());
|
||||
|
||||
case kScriptValueTypeTime:
|
||||
return Common::String::format("time: %f", asTime());
|
||||
|
||||
case kScriptValueTypeParamToken:
|
||||
return Common::String::format("token: %d", asParamToken());
|
||||
|
||||
default:
|
||||
return Common::String::format("arg type %s", scriptValueTypeToStr(getType()));
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::compare(Opcode op, const ScriptValue &lhs, const ScriptValue &rhs) {
|
||||
if (lhs.getType() != rhs.getType()) {
|
||||
warning("%s: Attempt to compare mismatched types %s and %s", __func__, scriptValueTypeToStr(lhs.getType()), scriptValueTypeToStr(rhs.getType()));
|
||||
}
|
||||
|
||||
switch (lhs.getType()) {
|
||||
case kScriptValueTypeEmpty:
|
||||
return compareEmptyValues(op);
|
||||
|
||||
case kScriptValueTypeFloat:
|
||||
return compare(op, lhs.asFloat(), rhs.asFloat());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeBool:
|
||||
return compare(op, lhs.asBool(), rhs.asBool());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeTime:
|
||||
return compare(op, lhs.asTime(), rhs.asTime());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeParamToken:
|
||||
return compare(op, lhs.asParamToken(), rhs.asParamToken());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeActorId:
|
||||
return compare(op, lhs.asActorId(), rhs.asActorId());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeString:
|
||||
return compareStrings(op, lhs.asString(), rhs.asString());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeCollection:
|
||||
return compare(op, lhs.asCollection(), rhs.asCollection());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeFunctionId:
|
||||
return compare(op, lhs.asFunctionId(), rhs.asFunctionId());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeMethodId:
|
||||
return compare(op, static_cast<uint>(lhs.asMethodId()), static_cast<uint>(rhs.asMethodId()));
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Got unknown script value type %d", __func__, lhs.getType());
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::compareEmptyValues(Opcode op) {
|
||||
// Empty values are considered equal.
|
||||
switch (op) {
|
||||
case kOpcodeEquals:
|
||||
return true;
|
||||
|
||||
case kOpcodeNotEquals:
|
||||
return false;
|
||||
|
||||
default:
|
||||
warning("%s: Got invalid empty value operation %s", __func__, opcodeToStr(op));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::compareStrings(Opcode op, const Common::String &left, const Common::String &right) {
|
||||
switch (op) {
|
||||
case kOpcodeEquals:
|
||||
return (left == right);
|
||||
|
||||
case kOpcodeNotEquals:
|
||||
return (left != right);
|
||||
|
||||
case kOpcodeLessThan:
|
||||
return (left < right);
|
||||
|
||||
case kOpcodeGreaterThan:
|
||||
return (left > right);
|
||||
|
||||
case kOpcodeLessThanOrEqualTo:
|
||||
return (left <= right);
|
||||
|
||||
case kOpcodeGreaterThanOrEqualTo:
|
||||
return (left >= right);
|
||||
|
||||
default:
|
||||
error("%s: Got invalid string operation %s", __func__, opcodeToStr(op));
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::compare(Opcode op, uint left, uint right) {
|
||||
switch (op) {
|
||||
case kOpcodeEquals:
|
||||
return (left == right);
|
||||
|
||||
case kOpcodeNotEquals:
|
||||
return (left != right);
|
||||
|
||||
default:
|
||||
error("%s: Got invalid param token operation %s", __func__, opcodeToStr(op));
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::compare(Opcode op, bool left, bool right) {
|
||||
switch (op) {
|
||||
case kOpcodeEquals:
|
||||
return (left == right);
|
||||
|
||||
case kOpcodeNotEquals:
|
||||
return (left != right);
|
||||
|
||||
default:
|
||||
error("%s: Got invalid bool operation %s", __func__, opcodeToStr(op));
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::compare(Opcode op, double left, double right) {
|
||||
switch (op) {
|
||||
case kOpcodeEquals:
|
||||
return (left == right);
|
||||
|
||||
case kOpcodeNotEquals:
|
||||
return (left != right);
|
||||
|
||||
case kOpcodeLessThan:
|
||||
return (left < right);
|
||||
|
||||
case kOpcodeGreaterThan:
|
||||
return (left > right);
|
||||
|
||||
case kOpcodeLessThanOrEqualTo:
|
||||
return (left <= right);
|
||||
|
||||
case kOpcodeGreaterThanOrEqualTo:
|
||||
return (left >= right);
|
||||
|
||||
default:
|
||||
error("%s: Got invalid float operation %s", __func__, opcodeToStr(op));
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::compare(Opcode op, Common::SharedPtr<Collection> left, Common::SharedPtr<Collection> right) {
|
||||
switch (op) {
|
||||
case kOpcodeEquals:
|
||||
return (left == right);
|
||||
|
||||
case kOpcodeNotEquals:
|
||||
return (left != right);
|
||||
|
||||
default:
|
||||
error("%s: Got invalid collection operation %s", __func__, opcodeToStr(op));
|
||||
}
|
||||
}
|
||||
|
||||
ScriptValue ScriptValue::evalMathOperation(Opcode op, const ScriptValue &left, const ScriptValue &right) {
|
||||
ScriptValue returnValue;
|
||||
double result = 0.0;
|
||||
|
||||
switch (left.getType()) {
|
||||
case kScriptValueTypeFloat: {
|
||||
if (right.getType() == kScriptValueTypeTime) {
|
||||
result = binaryMathOperation(op, left.asFloat(), right.asTime());
|
||||
} else if (right.getType() == kScriptValueTypeFloat) {
|
||||
result = binaryMathOperation(op, left.asFloat(), right.asFloat());
|
||||
} else {
|
||||
error("%s: Attempted to do math operation on unsupported value type %s", __func__, scriptValueTypeToStr(right.getType()));
|
||||
}
|
||||
returnValue.setToFloat(result);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeTime: {
|
||||
if (right.getType() == kScriptValueTypeTime) {
|
||||
result = binaryMathOperation(op, left.asTime(), right.asTime());
|
||||
} else if (right.getType() == kScriptValueTypeFloat) {
|
||||
result = binaryMathOperation(op, left.asTime(), right.asFloat());
|
||||
} else {
|
||||
error("%s: Attempted to do math operation on unsupported value type %s", __func__, scriptValueTypeToStr(right.getType()));
|
||||
}
|
||||
returnValue.setToFloat(result);
|
||||
break;
|
||||
}
|
||||
|
||||
case kScriptValueTypeString: {
|
||||
returnValue.setToString(left.asString() + right.asString());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Attempted to do math operation on unsupported value type %s", __func__, scriptValueTypeToStr(right.getType()));
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
double ScriptValue::binaryMathOperation(Opcode op, double left, double right) {
|
||||
switch (op) {
|
||||
case kOpcodeAdd:
|
||||
return left + right;
|
||||
|
||||
case kOpcodeSubtract:
|
||||
return left - right;
|
||||
|
||||
case kOpcodeMultiply:
|
||||
return left * right;
|
||||
|
||||
case kOpcodeDivide:
|
||||
if (right != 0.0) {
|
||||
return left / right;
|
||||
} else {
|
||||
error("%s: Division by zero", __func__);
|
||||
}
|
||||
|
||||
case kOpcodeModulo:
|
||||
if (right != 0.0) {
|
||||
return fmod(left, right);
|
||||
} else {
|
||||
error("%s: Division by zero", __func__);
|
||||
}
|
||||
|
||||
default:
|
||||
error("%s: Got unvalid binary math operation %s", __func__, opcodeToStr(op));
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptValue::operator==(const ScriptValue &other) const {
|
||||
return compare(kOpcodeEquals, *this, other);
|
||||
}
|
||||
|
||||
bool ScriptValue::operator!=(const ScriptValue &other) const {
|
||||
return compare(kOpcodeNotEquals, *this, other);
|
||||
}
|
||||
|
||||
bool ScriptValue::operator<(const ScriptValue &other) const {
|
||||
return compare(kOpcodeLessThan, *this, other);
|
||||
}
|
||||
|
||||
bool ScriptValue::operator>(const ScriptValue &other) const {
|
||||
return compare(kOpcodeGreaterThan, *this, other);
|
||||
}
|
||||
|
||||
bool ScriptValue::operator<=(const ScriptValue &other) const {
|
||||
return compare(kOpcodeLessThanOrEqualTo, *this, other);
|
||||
}
|
||||
|
||||
bool ScriptValue::operator>=(const ScriptValue &other) const {
|
||||
return compare(kOpcodeGreaterThanOrEqualTo, *this, other);
|
||||
}
|
||||
|
||||
bool ScriptValue::operator||(const ScriptValue &other) const {
|
||||
if (getType() != kScriptValueTypeBool || other.getType() != kScriptValueTypeBool) {
|
||||
error("%s: Expected bools for binary comparison, got %s and %s", __func__, scriptValueTypeToStr(getType()), scriptValueTypeToStr(other.getType()));
|
||||
}
|
||||
|
||||
return asBool() || other.asBool();
|
||||
}
|
||||
|
||||
bool ScriptValue::operator^(const ScriptValue &other) const {
|
||||
if (getType() != kScriptValueTypeBool || other.getType() != kScriptValueTypeBool) {
|
||||
error("%s: Expected bools for binary comparison, got %s and %s", __func__, scriptValueTypeToStr(getType()), scriptValueTypeToStr(other.getType()));
|
||||
}
|
||||
|
||||
return asBool() ^ other.asBool();
|
||||
}
|
||||
|
||||
bool ScriptValue::operator&&(const ScriptValue &other) const {
|
||||
if (getType() != kScriptValueTypeBool || other.getType() != kScriptValueTypeBool) {
|
||||
error("%s: Expected bools for binary comparison, got %s and %s", __func__, scriptValueTypeToStr(getType()), scriptValueTypeToStr(other.getType()));
|
||||
}
|
||||
|
||||
return asBool() && other.asBool();
|
||||
}
|
||||
|
||||
ScriptValue ScriptValue::operator+(const ScriptValue &other) const {
|
||||
return evalMathOperation(kOpcodeAdd, *this, other);
|
||||
}
|
||||
|
||||
ScriptValue ScriptValue::operator-(const ScriptValue &other) const {
|
||||
return evalMathOperation(kOpcodeSubtract, *this, other);
|
||||
}
|
||||
|
||||
ScriptValue ScriptValue::operator*(const ScriptValue &other) const {
|
||||
return evalMathOperation(kOpcodeMultiply, *this, other);
|
||||
}
|
||||
|
||||
ScriptValue ScriptValue::operator/(const ScriptValue &other) const {
|
||||
return evalMathOperation(kOpcodeDivide, *this, other);
|
||||
}
|
||||
|
||||
ScriptValue ScriptValue::operator%(const ScriptValue &other) const {
|
||||
return evalMathOperation(kOpcodeModulo, *this, other);
|
||||
}
|
||||
|
||||
ScriptValue ScriptValue::operator-() const {
|
||||
ScriptValue returnValue;
|
||||
switch (getType()) {
|
||||
case kScriptValueTypeFloat:
|
||||
returnValue.setToFloat(-asFloat());
|
||||
break;
|
||||
|
||||
case kScriptValueTypeTime:
|
||||
returnValue.setToTime(-asTime());
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Attempted to negate type %s", __func__, scriptValueTypeToStr(getType()));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void ScriptValue::issueValueMismatchWarning(ScriptValueType expectedType) const {
|
||||
// The original just blithely returns 0 (or equivalent) when you call a
|
||||
// getter for the wrong type (for instance, calling asFloat() on a bool),
|
||||
// but for debugging purposes we'll issue a warning.
|
||||
warning("%s: Script value type mismatch: Expected %s, got %s", __func__, scriptValueTypeToStr(expectedType), scriptValueTypeToStr(_type));
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
122
engines/mediastation/mediascript/scriptvalue.h
Normal file
122
engines/mediastation/mediascript/scriptvalue.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_MEDIASCRIPT_SCRIPTVALUE_H
|
||||
#define MEDIASTATION_MEDIASCRIPT_SCRIPTVALUE_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
#include "mediastation/mediascript/collection.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
class Actor;
|
||||
|
||||
class ScriptValue {
|
||||
public:
|
||||
ScriptValue() : _type(kScriptValueTypeEmpty) {}
|
||||
ScriptValue(ParameterReadStream *stream);
|
||||
|
||||
ScriptValueType getType() const { return _type; }
|
||||
|
||||
void setToFloat(uint i);
|
||||
void setToFloat(int i);
|
||||
void setToFloat(double d);
|
||||
double asFloat() const;
|
||||
int asIntFromFloat() const;
|
||||
|
||||
void setToBool(bool b);
|
||||
bool asBool() const;
|
||||
|
||||
void setToTime(double d);
|
||||
double asTime() const;
|
||||
|
||||
void setToParamToken(uint paramToken);
|
||||
uint asParamToken() const;
|
||||
|
||||
void setToActorId(uint actorId);
|
||||
uint asActorId() const;
|
||||
|
||||
void setToString(const Common::String &string);
|
||||
Common::String asString() const;
|
||||
|
||||
void setToCollection(Common::SharedPtr<Collection> collection);
|
||||
Common::SharedPtr<Collection> asCollection() const;
|
||||
|
||||
void setToFunctionId(uint functionId);
|
||||
uint asFunctionId() const;
|
||||
|
||||
void setToMethodId(BuiltInMethod methodId);
|
||||
BuiltInMethod asMethodId() const;
|
||||
|
||||
Common::String getDebugString();
|
||||
|
||||
bool operator==(const ScriptValue &other) const;
|
||||
bool operator!=(const ScriptValue &other) const;
|
||||
bool operator<(const ScriptValue &other) const;
|
||||
bool operator>(const ScriptValue &other) const;
|
||||
bool operator<=(const ScriptValue &other) const;
|
||||
bool operator>=(const ScriptValue &other) const;
|
||||
|
||||
bool operator||(const ScriptValue &other) const;
|
||||
bool operator^(const ScriptValue &other) const;
|
||||
bool operator&&(const ScriptValue &other) const;
|
||||
|
||||
ScriptValue operator+(const ScriptValue &other) const;
|
||||
ScriptValue operator-(const ScriptValue &other) const;
|
||||
ScriptValue operator*(const ScriptValue &other) const;
|
||||
ScriptValue operator/(const ScriptValue &other) const;
|
||||
ScriptValue operator%(const ScriptValue &other) const;
|
||||
ScriptValue operator-() const;
|
||||
|
||||
private:
|
||||
ScriptValueType _type = kScriptValueTypeEmpty;
|
||||
union {
|
||||
double d = 0;
|
||||
bool b;
|
||||
uint paramToken;
|
||||
uint actorId;
|
||||
uint functionId;
|
||||
BuiltInMethod methodId;
|
||||
} _u;
|
||||
Common::String _string;
|
||||
Common::SharedPtr<Collection> _collection;
|
||||
|
||||
static bool compare(Opcode op, const ScriptValue &left, const ScriptValue &right);
|
||||
static bool compareEmptyValues(Opcode op);
|
||||
static bool compareStrings(Opcode op, const Common::String &left, const Common::String &right);
|
||||
static bool compare(Opcode op, uint left, uint right);
|
||||
static bool compare(Opcode op, bool left, bool right);
|
||||
static bool compare(Opcode op, double left, double right);
|
||||
static bool compare(Opcode op, Common::SharedPtr<Collection> left, Common::SharedPtr<Collection> right);
|
||||
|
||||
static ScriptValue evalMathOperation(Opcode op, const ScriptValue &left, const ScriptValue &right);
|
||||
static double binaryMathOperation(Opcode op, double left, double right);
|
||||
|
||||
void issueValueMismatchWarning(ScriptValueType actualType) const;
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif
|
||||
397
engines/mediastation/mediastation.cpp
Normal file
397
engines/mediastation/mediastation.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
/* 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 "common/config-manager.h"
|
||||
|
||||
#include "mediastation/mediastation.h"
|
||||
#include "mediastation/debugchannels.h"
|
||||
#include "mediastation/detection.h"
|
||||
#include "mediastation/boot.h"
|
||||
#include "mediastation/context.h"
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/actors/document.h"
|
||||
#include "mediastation/actors/movie.h"
|
||||
#include "mediastation/actors/screen.h"
|
||||
#include "mediastation/actors/palette.h"
|
||||
#include "mediastation/actors/hotspot.h"
|
||||
#include "mediastation/actors/stage.h"
|
||||
#include "mediastation/mediascript/scriptconstants.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
MediaStationEngine *g_engine;
|
||||
|
||||
MediaStationEngine::MediaStationEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
|
||||
_gameDescription(gameDesc),
|
||||
_randomSource("MediaStation") {
|
||||
g_engine = this;
|
||||
|
||||
_gameDataDir = Common::FSNode(ConfMan.getPath("path"));
|
||||
SearchMan.addDirectory(_gameDataDir, 0, 3);
|
||||
for (uint i = 0; MediaStation::directoryGlobs[i]; i++) {
|
||||
Common::String directoryGlob = directoryGlobs[i];
|
||||
SearchMan.addSubDirectoryMatching(_gameDataDir, directoryGlob, 0, 5);
|
||||
}
|
||||
|
||||
_channelIdent = MKTAG('i', 'g', 'o', 'd'); // ImtGod
|
||||
}
|
||||
|
||||
MediaStationEngine::~MediaStationEngine() {
|
||||
for (auto it = _loadedContexts.begin(); it != _loadedContexts.end(); ++it) {
|
||||
destroyContext(it->_value->_id, false);
|
||||
}
|
||||
_loadedContexts.clear();
|
||||
|
||||
// Only delete the document actor.
|
||||
// The root stage is deleted from stage director, and
|
||||
// the other actors are deleted from their contexts.
|
||||
destroyActor(DocumentActor::DOCUMENT_ACTOR_ID);
|
||||
|
||||
delete _displayManager;
|
||||
_displayManager = nullptr;
|
||||
|
||||
delete _cursorManager;
|
||||
_cursorManager = nullptr;
|
||||
|
||||
delete _functionManager;
|
||||
_functionManager = nullptr;
|
||||
|
||||
delete _document;
|
||||
_document = nullptr;
|
||||
|
||||
delete _deviceOwner;
|
||||
_deviceOwner = nullptr;
|
||||
|
||||
delete _stageDirector;
|
||||
_stageDirector = nullptr;
|
||||
|
||||
unregisterWithStreamManager();
|
||||
delete _streamFeedManager;
|
||||
_streamFeedManager = nullptr;
|
||||
|
||||
_contextReferences.clear();
|
||||
_streamMap.clear();
|
||||
_engineResourceDeclarations.clear();
|
||||
_screenReferences.clear();
|
||||
_fileMap.clear();
|
||||
_actors.clear();
|
||||
}
|
||||
|
||||
Actor *MediaStationEngine::getActorById(uint actorId) {
|
||||
return _actors.getValOrDefault(actorId);
|
||||
}
|
||||
|
||||
SpatialEntity *MediaStationEngine::getSpatialEntityById(uint spatialEntityId) {
|
||||
Actor *actor = getActorById(spatialEntityId);
|
||||
if (actor != nullptr) {
|
||||
if (!actor->isSpatialActor()) {
|
||||
error("%s: Actor %d is not a spatial actor", __func__, spatialEntityId);
|
||||
}
|
||||
return static_cast<SpatialEntity *>(actor);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ChannelClient *MediaStationEngine::getChannelClientByChannelIdent(uint channelIdent) {
|
||||
return _streamFeedManager->channelClientForChannel(channelIdent);
|
||||
}
|
||||
|
||||
ScriptValue *MediaStationEngine::getVariable(uint variableId) {
|
||||
for (auto it = _loadedContexts.begin(); it != _loadedContexts.end(); ++it) {
|
||||
ScriptValue *variable = it->_value->_variables.getValOrDefault(variableId);
|
||||
if (variable != nullptr) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 MediaStationEngine::getFeatures() const {
|
||||
return _gameDescription->flags;
|
||||
}
|
||||
|
||||
Common::String MediaStationEngine::getGameId() const {
|
||||
return _gameDescription->gameId;
|
||||
}
|
||||
|
||||
Common::Platform MediaStationEngine::getPlatform() const {
|
||||
return _gameDescription->platform;
|
||||
}
|
||||
|
||||
const char *MediaStationEngine::getAppName() const {
|
||||
return _gameDescription->filesDescriptions[0].fileName;
|
||||
}
|
||||
|
||||
bool MediaStationEngine::isFirstGenerationEngine() {
|
||||
return _versionInfo.major == 0;
|
||||
}
|
||||
|
||||
Common::Error MediaStationEngine::run() {
|
||||
initDisplayManager();
|
||||
initCursorManager();
|
||||
initFunctionManager();
|
||||
initDocument();
|
||||
initDeviceOwner();
|
||||
initStageDirector();
|
||||
initStreamFeedManager();
|
||||
setupInitialStreamMap();
|
||||
|
||||
if (ConfMan.hasKey("entry_context")) {
|
||||
// For development purposes, we can choose to start at an arbitrary context
|
||||
// in this title. This might not work in all cases.
|
||||
uint entryContextId = ConfMan.get("entry_context").asUint64();
|
||||
warning("%s: Starting at user-requested context %d", __func__, entryContextId);
|
||||
_document->beginTitle(entryContextId);
|
||||
} else {
|
||||
_document->beginTitle();
|
||||
}
|
||||
|
||||
runEventLoop();
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void MediaStationEngine::runEventLoop() {
|
||||
while (true) {
|
||||
dispatchSystemEvents();
|
||||
if (shouldQuit()) {
|
||||
break;
|
||||
}
|
||||
_document->process();
|
||||
|
||||
debugC(5, kDebugGraphics, "***** START SCREEN UPDATE ***");
|
||||
for (auto it = _actors.begin(); it != _actors.end(); ++it) {
|
||||
it->_value->process();
|
||||
}
|
||||
draw();
|
||||
debugC(5, kDebugGraphics, "***** END SCREEN UPDATE ***");
|
||||
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::initDisplayManager() {
|
||||
_displayManager = new VideoDisplayManager(this);
|
||||
_parameterClients.push_back(_displayManager);
|
||||
}
|
||||
|
||||
void MediaStationEngine::initCursorManager() {
|
||||
if (getPlatform() == Common::kPlatformWindows) {
|
||||
_cursorManager = new WindowsCursorManager(getAppName());
|
||||
} else if (getPlatform() == Common::kPlatformMacintosh) {
|
||||
_cursorManager = new MacCursorManager(getAppName());
|
||||
} else {
|
||||
error("%s: Attempted to use unsupported platform %s", __func__, Common::getPlatformDescription(getPlatform()));
|
||||
}
|
||||
_parameterClients.push_back(_cursorManager);
|
||||
_cursorManager->showCursor();
|
||||
}
|
||||
|
||||
void MediaStationEngine::initFunctionManager() {
|
||||
_functionManager = new FunctionManager();
|
||||
_parameterClients.push_back(_functionManager);
|
||||
}
|
||||
|
||||
void MediaStationEngine::initDocument() {
|
||||
_document = new Document();
|
||||
_parameterClients.push_back(_document);
|
||||
|
||||
DocumentActor *documentActor = new DocumentActor;
|
||||
registerActor(documentActor);
|
||||
}
|
||||
|
||||
void MediaStationEngine::initDeviceOwner() {
|
||||
_deviceOwner = new DeviceOwner();
|
||||
_parameterClients.push_back(_deviceOwner);
|
||||
}
|
||||
|
||||
void MediaStationEngine::initStageDirector() {
|
||||
_stageDirector = new StageDirector;
|
||||
}
|
||||
|
||||
void MediaStationEngine::initStreamFeedManager() {
|
||||
_streamFeedManager = new StreamFeedManager;
|
||||
registerWithStreamManager();
|
||||
}
|
||||
|
||||
void MediaStationEngine::setupInitialStreamMap() {
|
||||
StreamInfo streamInfo;
|
||||
streamInfo._actorId = 0;
|
||||
streamInfo._fileId = MediaStationEngine::BOOT_STREAM_ID;
|
||||
streamInfo._startOffsetInFile = 0;
|
||||
_streamMap.setVal(streamInfo._fileId, streamInfo);
|
||||
|
||||
const Common::String BOOT_STM_FILENAME("BOOT.STM");
|
||||
FileInfo fileInfo;
|
||||
fileInfo._id = MediaStationEngine::BOOT_STREAM_ID;
|
||||
fileInfo._name = BOOT_STM_FILENAME;
|
||||
_fileMap.setVal(fileInfo._id, fileInfo);
|
||||
}
|
||||
|
||||
void MediaStationEngine::dispatchSystemEvents() {
|
||||
while (g_system->getEventManager()->pollEvent(_event)) {
|
||||
debugC(9, kDebugEvents, "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
debugC(9, kDebugEvents, "@@@@ Dispatching system events");
|
||||
debugC(9, kDebugEvents, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
||||
|
||||
switch (_event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
_stageDirector->handleMouseMovedEvent(_event);
|
||||
break;
|
||||
|
||||
case Common::EVENT_KEYDOWN:
|
||||
_stageDirector->handleKeyboardEvent(_event);
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
_stageDirector->handleMouseDownEvent(_event);
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
_stageDirector->handleMouseUpEvent(_event);
|
||||
break;
|
||||
|
||||
case Common::EVENT_FOCUS_LOST:
|
||||
_stageDirector->handleMouseOutOfFocusEvent(_event);
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
// We are using the right button as a quick exit since the Media
|
||||
// Station engine doesn't seem to use the right button itself.
|
||||
warning("%s: EVENT_RBUTTONDOWN: Quitting for development purposes", __func__);
|
||||
quitGame();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Avoid warnings about unimplemented cases by having an explicit
|
||||
// default case.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::draw(bool dirtyOnly) {
|
||||
if (dirtyOnly) {
|
||||
_stageDirector->drawDirtyRegion();
|
||||
} else {
|
||||
_stageDirector->drawAll();
|
||||
}
|
||||
_displayManager->updateScreen();
|
||||
_displayManager->doTransitionOnSync();
|
||||
}
|
||||
|
||||
void MediaStationEngine::registerActor(Actor *actorToAdd) {
|
||||
if (getActorById(actorToAdd->id())) {
|
||||
error("%s: Actor with ID 0x%d was already defined in this title", __func__, actorToAdd->id());
|
||||
}
|
||||
_actors.setVal(actorToAdd->id(), actorToAdd);
|
||||
}
|
||||
|
||||
void MediaStationEngine::destroyActor(uint actorId) {
|
||||
Actor *actorToDestroy = getActorById(actorId);
|
||||
if (actorToDestroy) {
|
||||
delete _actors[actorId];
|
||||
_actors.erase(actorId);
|
||||
} else {
|
||||
warning("%s: Actor %d is not currently loaded", __func__, actorId);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::destroyContext(uint contextId, bool eraseFromLoadedContexts) {
|
||||
debugC(5, kDebugScript, "%s: Destroying context %d", __func__, contextId);
|
||||
Context *context = _loadedContexts.getValOrDefault(contextId);
|
||||
if (context == nullptr) {
|
||||
error("%s: Attempted to unload context %d that is not currently loaded", __func__, contextId);
|
||||
}
|
||||
|
||||
getRootStage()->deleteChildrenFromContextId(contextId);
|
||||
destroyActorsInContext(contextId);
|
||||
_functionManager->deleteFunctionsForContext(contextId);
|
||||
|
||||
delete context;
|
||||
if (eraseFromLoadedContexts) {
|
||||
// If we are deleting all contexts at once, we don't want to actually do this,
|
||||
// as it will mess up our iterators - the whole structure should be cleared after this.
|
||||
_loadedContexts.erase(contextId);
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaStationEngine::contextIsLocked(uint contextId) {
|
||||
for (auto it = _loadedContexts.begin(); it != _loadedContexts.end(); ++it) {
|
||||
uint id = it->_key;
|
||||
ContextReference contextReference = _contextReferences.getVal(id);
|
||||
for (uint childContextId : contextReference._parentContextIds) {
|
||||
if (childContextId == contextId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MediaStationEngine::destroyActorsInContext(uint contextId) {
|
||||
// Collect actors to remove first, then delete them.
|
||||
// This is necessary because calling erase on a hashmap invalidates
|
||||
// the iterators, so collecting them all first makes more sense.
|
||||
Common::Array<uint> actorsToRemove;
|
||||
for (auto it = _actors.begin(); it != _actors.end(); ++it) {
|
||||
uint actorContextId = it->_value->contextId();
|
||||
if (actorContextId == contextId) {
|
||||
actorsToRemove.push_back(it->_key);
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove the collected actors.
|
||||
for (uint actorId : actorsToRemove) {
|
||||
destroyActor(actorId);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readUnrecognizedFromStream(Chunk &chunk, uint sectionType) {
|
||||
bool paramHandled = false;
|
||||
for (ParameterClient *client : g_engine->_parameterClients) {
|
||||
if (client->attemptToReadFromStream(chunk, sectionType)) {
|
||||
paramHandled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!paramHandled) {
|
||||
warning("%s: Parameter %d not handled", __func__, sectionType);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStationEngine::readChunk(Chunk &chunk) {
|
||||
StreamType streamType = static_cast<StreamType>(chunk.readTypedUint16());
|
||||
switch (streamType) {
|
||||
case kDocumentDefStream:
|
||||
readDocumentDef(chunk);
|
||||
break;
|
||||
|
||||
case kControlCommandsStream:
|
||||
readControlCommands(chunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("%s: Unhandled section type 0x%x", __func__, static_cast<uint>(streamType));
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace MediaStation
|
||||
203
engines/mediastation/mediastation.h
Normal file
203
engines/mediastation/mediastation.h
Normal file
@@ -0,0 +1,203 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_H
|
||||
#define MEDIASTATION_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "common/error.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/random.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/events.h"
|
||||
#include "common/util.h"
|
||||
#include "engines/engine.h"
|
||||
#include "engines/savestate.h"
|
||||
|
||||
#include "mediastation/clients.h"
|
||||
#include "mediastation/detection.h"
|
||||
#include "mediastation/datafile.h"
|
||||
#include "mediastation/boot.h"
|
||||
#include "mediastation/context.h"
|
||||
#include "mediastation/actor.h"
|
||||
#include "mediastation/cursors.h"
|
||||
#include "mediastation/graphics.h"
|
||||
#include "mediastation/mediascript/function.h"
|
||||
#include "mediastation/actors/stage.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
struct MediaStationGameDescription;
|
||||
class HotspotActor;
|
||||
class RootStage;
|
||||
class Bitmap;
|
||||
|
||||
// Most Media Station titles follow this file structure from the root directory
|
||||
// of the CD-ROM:
|
||||
// - [TITLE].EXE (main game executable, name vares based on game)
|
||||
// - DATA/ (subdirectory that holds actual game data including bytecode)
|
||||
// - 100.CXT
|
||||
// - ... other CXTs, varies per title
|
||||
static const char *const directoryGlobs[] = {
|
||||
"DATA", // For most titles
|
||||
"program", // For D.W. the Picky Eater
|
||||
"PZDATA", // For Puzzle Castle demo
|
||||
nullptr
|
||||
};
|
||||
|
||||
// As this is currently structured, some of the methods in the main engine class are from
|
||||
// the RT_ImtGod class in the original, and others are from the RT_App class in the original.
|
||||
// In the interest of avoiding more indirection than is already present in the original, we will
|
||||
// just keep these together for now.
|
||||
class MediaStationEngine : public Engine, public ChannelClient {
|
||||
public:
|
||||
MediaStationEngine(OSystem *syst, const ADGameDescription *gameDesc);
|
||||
~MediaStationEngine() override;
|
||||
|
||||
uint32 getFeatures() const;
|
||||
Common::String getGameId() const;
|
||||
Common::Platform getPlatform() const;
|
||||
const char *getAppName() const;
|
||||
bool hasFeature(EngineFeature f) const override {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher);
|
||||
};
|
||||
|
||||
bool isFirstGenerationEngine();
|
||||
void dispatchSystemEvents();
|
||||
void draw(bool dirtyOnly = true);
|
||||
|
||||
void registerActor(Actor *actorToAdd);
|
||||
void destroyActor(uint actorId);
|
||||
void destroyContext(uint contextId, bool eraseFromLoadedContexts = true);
|
||||
bool contextIsLocked(uint contextId);
|
||||
|
||||
void readUnrecognizedFromStream(Chunk &chunk, uint sectionType);
|
||||
void readHeaderSections(Subfile &subfile, Chunk &chunk);
|
||||
|
||||
Actor *getActorById(uint actorId);
|
||||
SpatialEntity *getSpatialEntityById(uint spatialEntityId);
|
||||
ChannelClient *getChannelClientByChannelIdent(uint channelIdent);
|
||||
ScriptValue *getVariable(uint variableId);
|
||||
VideoDisplayManager *getDisplayManager() { return _displayManager; }
|
||||
CursorManager *getCursorManager() { return _cursorManager; }
|
||||
FunctionManager *getFunctionManager() { return _functionManager; }
|
||||
RootStage *getRootStage() { return _stageDirector->getRootStage(); }
|
||||
StreamFeedManager *getStreamFeedManager() { return _streamFeedManager; }
|
||||
Document *getDocument() { return _document; }
|
||||
|
||||
const FileInfo &fileInfoForIdent(uint fileId) { return _fileMap.getValOrDefault(fileId); }
|
||||
const StreamInfo &streamInfoForIdent(uint streamId) { return _streamMap.getValOrDefault(streamId); }
|
||||
const ScreenReference &screenRefWithId(uint screenActorId) { return _screenReferences.getValOrDefault(screenActorId); }
|
||||
const ContextReference &contextRefWithId(uint contextId) { return _contextReferences.getValOrDefault(contextId); }
|
||||
|
||||
Common::Array<ParameterClient *> _parameterClients;
|
||||
Common::HashMap<uint, Context *> _loadedContexts;
|
||||
|
||||
SpatialEntity *getMouseInsideHotspot() { return _mouseInsideHotspot; }
|
||||
void setMouseInsideHotspot(SpatialEntity *entity) { _mouseInsideHotspot = entity; }
|
||||
void clearMouseInsideHotspot() { _mouseInsideHotspot = nullptr; }
|
||||
|
||||
SpatialEntity *getMouseDownHotspot() { return _mouseDownHotspot; }
|
||||
void setMouseDownHotspot(SpatialEntity *entity) { _mouseDownHotspot = entity; }
|
||||
void clearMouseDownHotspot() { _mouseDownHotspot = nullptr; }
|
||||
|
||||
Common::RandomSource _randomSource;
|
||||
|
||||
static const uint SCREEN_WIDTH = 640;
|
||||
static const uint SCREEN_HEIGHT = 480;
|
||||
static const uint BOOT_STREAM_ID = 1;
|
||||
|
||||
protected:
|
||||
Common::Error run() override;
|
||||
|
||||
private:
|
||||
Common::Event _event;
|
||||
Common::FSNode _gameDataDir;
|
||||
const ADGameDescription *_gameDescription;
|
||||
|
||||
VideoDisplayManager *_displayManager = nullptr;
|
||||
CursorManager *_cursorManager = nullptr;
|
||||
FunctionManager *_functionManager = nullptr;
|
||||
Document *_document = nullptr;
|
||||
DeviceOwner *_deviceOwner = nullptr;
|
||||
StageDirector *_stageDirector = nullptr;
|
||||
StreamFeedManager *_streamFeedManager = nullptr;
|
||||
|
||||
Common::HashMap<uint, Actor *> _actors;
|
||||
SpatialEntity *_mouseInsideHotspot = nullptr;
|
||||
SpatialEntity *_mouseDownHotspot = nullptr;
|
||||
|
||||
Common::String _gameTitle;
|
||||
VersionInfo _versionInfo;
|
||||
Common::String _engineInfo;
|
||||
Common::String _sourceString;
|
||||
Common::HashMap<uint, ContextReference> _contextReferences;
|
||||
Common::HashMap<uint, ScreenReference> _screenReferences;
|
||||
Common::HashMap<uint, FileInfo> _fileMap;
|
||||
Common::HashMap<uint, StreamInfo> _streamMap;
|
||||
Common::HashMap<uint, EngineResourceDeclaration> _engineResourceDeclarations;
|
||||
uint _unk1 = 0;
|
||||
uint _functionTableSize = 0;
|
||||
uint _unk3 = 0;
|
||||
|
||||
void initDisplayManager();
|
||||
void initCursorManager();
|
||||
void initFunctionManager();
|
||||
void initDocument();
|
||||
void initDeviceOwner();
|
||||
void initStageDirector();
|
||||
void initStreamFeedManager();
|
||||
void setupInitialStreamMap();
|
||||
|
||||
void runEventLoop();
|
||||
|
||||
virtual void readChunk(Chunk &chunk) override;
|
||||
void readDocumentDef(Chunk &chunk);
|
||||
void readDocumentInfoFromStream(Chunk &chunk, BootSectionType sectionType);
|
||||
void readVersionInfoFromStream(Chunk &chunk);
|
||||
void readContextReferencesFromStream(Chunk &chunk);
|
||||
void readScreenReferencesFromStream(Chunk &chunk);
|
||||
void readAndAddFileMaps(Chunk &chunk);
|
||||
void readAndAddStreamMaps(Chunk &chunk);
|
||||
|
||||
void readControlCommands(Chunk &chunk);
|
||||
void readCommandFromStream(Chunk &chunk, ContextSectionType sectionType);
|
||||
void readCreateContextData(Chunk &chunk);
|
||||
void readDestroyContextData(Chunk &chunk);
|
||||
void readCreateActorData(Chunk &chunk);
|
||||
void readDestroyActorData(Chunk &chunk);
|
||||
void readActorLoadComplete(Chunk &chunk);
|
||||
void readCreateVariableData(Chunk &chunk);
|
||||
void readContextNameData(Chunk &chunk);
|
||||
|
||||
void destroyActorsInContext(uint contextId);
|
||||
};
|
||||
|
||||
extern MediaStationEngine *g_engine;
|
||||
#define SHOULD_QUIT ::MediaStation::g_engine->shouldQuit()
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
#endif // MEDIASTATION_H
|
||||
58
engines/mediastation/metaengine.cpp
Normal file
58
engines/mediastation/metaengine.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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 "common/translation.h"
|
||||
|
||||
#include "mediastation/metaengine.h"
|
||||
#include "mediastation/detection.h"
|
||||
#include "mediastation/mediastation.h"
|
||||
|
||||
namespace MediaStation {
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
} // End of namespace MediaStation
|
||||
|
||||
const char *MediaStationMetaEngine::getName() const {
|
||||
return "mediastation";
|
||||
}
|
||||
|
||||
const ADExtraGuiOptionsMap *MediaStationMetaEngine::getAdvancedExtraGuiOptions() const {
|
||||
return MediaStation::optionsList;
|
||||
}
|
||||
|
||||
Common::Error MediaStationMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
|
||||
*engine = new MediaStation::MediaStationEngine(syst, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool MediaStationMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return checkExtendedSaves(f) ||
|
||||
(f == kSupportsLoadingDuringStartup);
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(MEDIASTATION)
|
||||
REGISTER_PLUGIN_DYNAMIC(MEDIASTATION, PLUGIN_TYPE_ENGINE, MediaStationMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(MEDIASTATION, PLUGIN_TYPE_ENGINE, MediaStationMetaEngine);
|
||||
#endif
|
||||
43
engines/mediastation/metaengine.h
Normal file
43
engines/mediastation/metaengine.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEDIASTATION_METAENGINE_H
|
||||
#define MEDIASTATION_METAENGINE_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
class MediaStationMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override;
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
|
||||
|
||||
/**
|
||||
* Determine whether the engine supports the specified MetaEngine feature.
|
||||
*
|
||||
* Used by e.g. the launcher to determine whether to enable the Load button.
|
||||
*/
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override;
|
||||
};
|
||||
|
||||
#endif // MEDIASTATION_METAENGINE_H
|
||||
46
engines/mediastation/module.mk
Normal file
46
engines/mediastation/module.mk
Normal file
@@ -0,0 +1,46 @@
|
||||
MODULE := engines/mediastation
|
||||
|
||||
MODULE_OBJS = \
|
||||
actor.o \
|
||||
actors/camera.o \
|
||||
actors/canvas.o \
|
||||
actors/document.o \
|
||||
actors/font.o \
|
||||
actors/hotspot.o \
|
||||
actors/image.o \
|
||||
actors/movie.o \
|
||||
actors/palette.o \
|
||||
actors/path.o \
|
||||
actors/screen.o \
|
||||
actors/sound.o \
|
||||
actors/sprite.o \
|
||||
actors/stage.o \
|
||||
actors/text.o \
|
||||
actors/timer.o \
|
||||
audio.o \
|
||||
bitmap.o \
|
||||
boot.o \
|
||||
clients.o \
|
||||
context.o \
|
||||
cursors.o \
|
||||
datafile.o \
|
||||
graphics.o \
|
||||
mediascript/codechunk.o \
|
||||
mediascript/collection.o \
|
||||
mediascript/eventhandler.o \
|
||||
mediascript/function.o \
|
||||
mediascript/scriptconstants.o \
|
||||
mediascript/scriptvalue.o \
|
||||
mediastation.o \
|
||||
metaengine.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_MEDIASTATION), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
Reference in New Issue
Block a user