[Scummvm-git-logs] scummvm master -> aad959004fbf123a5baf7a94c4f9ae92c2eaaf54
npjg
noreply at scummvm.org
Sat Aug 2 15:47:08 UTC 2025
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
1b6e3ba916 MEDIASTATION: Create separate Document actor
aad959004f MEDIASTATION: Implement video display manager functions
Commit: 1b6e3ba916e23d313535c4b6e53326514c69d2f6
https://github.com/scummvm/scummvm/commit/1b6e3ba916e23d313535c4b6e53326514c69d2f6
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-08-02T11:37:10-04:00
Commit Message:
MEDIASTATION: Create separate Document actor
To get this functionality out of the main engine object.
Changed paths:
A engines/mediastation/assets/document.cpp
A engines/mediastation/assets/document.h
engines/mediastation/asset.h
engines/mediastation/mediascript/codechunk.cpp
engines/mediastation/mediastation.cpp
engines/mediastation/mediastation.h
engines/mediastation/module.mk
diff --git a/engines/mediastation/asset.h b/engines/mediastation/asset.h
index d322aa2519e..036f6679983 100644
--- a/engines/mediastation/asset.h
+++ b/engines/mediastation/asset.h
@@ -43,6 +43,7 @@ enum AssetType {
kAssetTypeSprite = 0x000e, // SPR
kAssetTypeLKZazu = 0x000f,
kAssetTypeLKConstellations = 0x0010,
+ kAssetTypeDocument = 0x0011,
kAssetTypeImageSet = 0x001d,
kAssetTypeCursor = 0x000c, // CSR
kAssetTypePrinter = 0x0019, // PRT
diff --git a/engines/mediastation/assets/document.cpp b/engines/mediastation/assets/document.cpp
new file mode 100644
index 00000000000..897826e73a0
--- /dev/null
+++ b/engines/mediastation/assets/document.cpp
@@ -0,0 +1,54 @@
+/* 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/assets/document.h"
+
+namespace MediaStation {
+
+ScriptValue Document::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
+ ScriptValue returnValue;
+
+ switch (methodId) {
+ case kBranchToScreenMethod: {
+ assert(args.size() >= 1);
+ if (args.size() > 1) {
+ // TODO: Figure out what the rest of the args can be.
+ warning("branchToScreen got more than one arg");
+ }
+ uint32 contextId = args[0].asAssetId();
+ g_engine->scheduleScreenBranch(contextId);
+ return returnValue;
+ }
+
+ case kReleaseContextMethod: {
+ assert(args.size() == 1);
+ uint32 contextId = args[0].asAssetId();
+ g_engine->scheduleContextRelease(contextId);
+ return returnValue;
+ }
+
+ default:
+ return Asset::callMethod(methodId, args);
+ }
+}
+
+} // End of namespace MediaStation
diff --git a/engines/mediastation/assets/document.h b/engines/mediastation/assets/document.h
new file mode 100644
index 00000000000..8129a10c4c4
--- /dev/null
+++ b/engines/mediastation/assets/document.h
@@ -0,0 +1,40 @@
+/* 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/asset.h"
+#include "mediastation/mediascript/scriptvalue.h"
+#include "mediastation/mediascript/scriptconstants.h"
+
+namespace MediaStation {
+
+class Document : public Asset {
+public:
+ Document() : Asset(kAssetTypeDocument) { _id = 1; };
+
+ virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
+};
+
+} // End of namespace MediaStation
+
+#endif
\ No newline at end of file
diff --git a/engines/mediastation/mediascript/codechunk.cpp b/engines/mediastation/mediascript/codechunk.cpp
index 08ae09347ad..3806b7ab0a8 100644
--- a/engines/mediastation/mediascript/codechunk.cpp
+++ b/engines/mediastation/mediascript/codechunk.cpp
@@ -513,15 +513,7 @@ ScriptValue CodeChunk::evaluateMethodCall(BuiltInMethod method, uint paramCount)
ScriptValue returnValue;
switch (target.getType()) {
case kScriptValueTypeAssetId: {
- if (target.asAssetId() == 1) {
- // This is a "document" method that we need to handle specially.
- // The document (@doc) accepts engine-level methods like changing the
- // active screen.
- // HACK: This is so we don't have to implement a separate document class
- // just to house these methods. Rather, we just call in the engine.
- returnValue = g_engine->callMethod(method, args);
- return returnValue;
- } else if (target.asAssetId() == 0) {
+ if (target.asAssetId() == 0) {
// It seems to be valid to call a method on a null asset ID, in
// which case nothing happens. Still issue warning for traceability.
warning("Attempt to call method on a null asset ID");
diff --git a/engines/mediastation/mediastation.cpp b/engines/mediastation/mediastation.cpp
index 649733a3e20..d14216fc5ab 100644
--- a/engines/mediastation/mediastation.cpp
+++ b/engines/mediastation/mediastation.cpp
@@ -28,6 +28,7 @@
#include "mediastation/boot.h"
#include "mediastation/context.h"
#include "mediastation/asset.h"
+#include "mediastation/assets/document.h"
#include "mediastation/assets/movie.h"
#include "mediastation/assets/screen.h"
#include "mediastation/assets/palette.h"
@@ -66,6 +67,9 @@ MediaStationEngine::~MediaStationEngine() {
delete it->_value;
}
_loadedContexts.clear();
+
+ // Delete the document actor. The rest are deleted from their contexts.
+ delete _assets[0];
}
Asset *MediaStationEngine::getAssetById(uint assetId) {
@@ -149,6 +153,9 @@ Common::Error MediaStationEngine::run() {
}
_cursor->showCursor();
+ Document *document = new Document;
+ _assets.push_back(document);
+
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.
@@ -389,31 +396,12 @@ void MediaStationEngine::registerAsset(Asset *assetToAdd) {
}
}
-ScriptValue MediaStationEngine::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) {
- ScriptValue returnValue;
-
- switch (methodId) {
- case kBranchToScreenMethod: {
- assert(args.size() >= 1);
- if (args.size() > 1) {
- // TODO: Figure out what the rest of the args can be.
- warning("MediaStationEngine::callMethod(): branchToScreen got more than one arg");
- }
- uint32 contextId = args[0].asAssetId();
- _requestedScreenBranchId = contextId;
- return returnValue;
- }
-
- case kReleaseContextMethod: {
- assert(args.size() == 1);
- uint32 contextId = args[0].asAssetId();
- _requestedContextReleaseId.push_back(contextId);
- return returnValue;
- }
+void MediaStationEngine::scheduleScreenBranch(uint screenId) {
+ _requestedScreenBranchId = screenId;
+}
- default:
- error("MediaStationEngine::callMethod(): Got unimplemented method ID %s (%d)", builtInMethodToStr(methodId), static_cast<uint>(methodId));
- }
+void MediaStationEngine::scheduleContextRelease(uint contextId) {
+ _requestedContextReleaseId.push_back(contextId);
}
void MediaStationEngine::doBranchToScreen() {
diff --git a/engines/mediastation/mediastation.h b/engines/mediastation/mediastation.h
index 85e83ba43cc..8189da60b5e 100644
--- a/engines/mediastation/mediastation.h
+++ b/engines/mediastation/mediastation.h
@@ -82,13 +82,14 @@ public:
void setPalette(Asset *palette);
void registerAsset(Asset *assetToAdd);
+ void scheduleScreenBranch(uint screenId);
+ void scheduleContextRelease(uint contextId);
Asset *getAssetById(uint assetId);
Asset *getAssetByChunkReference(uint chunkReference);
Function *getFunctionById(uint functionId);
ScriptValue *getVariable(uint variableId);
- ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args);
ScriptValue callBuiltInFunction(BuiltInFunction function, Common::Array<ScriptValue> &args);
Common::RandomSource _randomSource;
diff --git a/engines/mediastation/module.mk b/engines/mediastation/module.mk
index abd4880133c..a32a467c3f3 100644
--- a/engines/mediastation/module.mk
+++ b/engines/mediastation/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/mediastation
MODULE_OBJS = \
asset.o \
assets/canvas.o \
+ assets/document.o \
assets/font.o \
assets/hotspot.o \
assets/image.o \
Commit: aad959004fbf123a5baf7a94c4f9ae92c2eaaf54
https://github.com/scummvm/scummvm/commit/aad959004fbf123a5baf7a94c4f9ae92c2eaaf54
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-08-02T11:46:00-04:00
Commit Message:
MEDIASTATION: Implement video display manager functions
Both blitting and basic transitions should now be working properly.
More advanced transitions from later in the engine's development
will be reversed separately.
Changed paths:
A engines/mediastation/dissolvepatterns.h
A engines/mediastation/graphics.cpp
A engines/mediastation/graphics.h
R engines/mediastation/transitions.cpp
engines/mediastation/asset.cpp
engines/mediastation/asset.h
engines/mediastation/assets/canvas.cpp
engines/mediastation/assets/canvas.h
engines/mediastation/assets/document.cpp
engines/mediastation/assets/document.h
engines/mediastation/assets/image.cpp
engines/mediastation/assets/image.h
engines/mediastation/assets/movie.cpp
engines/mediastation/assets/movie.h
engines/mediastation/assets/palette.cpp
engines/mediastation/assets/palette.h
engines/mediastation/assets/path.cpp
engines/mediastation/assets/sprite.cpp
engines/mediastation/assets/sprite.h
engines/mediastation/assets/text.cpp
engines/mediastation/assets/text.h
engines/mediastation/bitmap.cpp
engines/mediastation/bitmap.h
engines/mediastation/context.cpp
engines/mediastation/datafile.h
engines/mediastation/debugchannels.h
engines/mediastation/mediastation.cpp
engines/mediastation/mediastation.h
engines/mediastation/module.mk
diff --git a/engines/mediastation/asset.cpp b/engines/mediastation/asset.cpp
index d2be6c294fb..ab92d7b3b22 100644
--- a/engines/mediastation/asset.cpp
+++ b/engines/mediastation/asset.cpp
@@ -19,6 +19,8 @@
*
*/
+#include "common/util.h"
+
#include "mediastation/asset.h"
#include "mediastation/debugchannels.h"
#include "mediastation/mediascript/scriptconstants.h"
@@ -199,6 +201,13 @@ ScriptValue SpatialEntity::callMethod(BuiltInMethod methodId, Common::Array<Scri
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());
@@ -216,6 +225,10 @@ void SpatialEntity::readParameter(Chunk &chunk, AssetHeaderSectionType paramType
_boundingBox = chunk.readTypedRect();
break;
+ case kAssetHeaderDissolveFactor:
+ _dissolveFactor = chunk.readTypedDouble();
+ break;
+
case kAssetHeaderZIndex:
_zIndex = chunk.readTypedGraphicUnit();
break;
@@ -284,8 +297,16 @@ void SpatialEntity::setZIndex(int zIndex) {
invalidateLocalZIndex();
}
+void SpatialEntity::setDissolveFactor(double dissolveFactor) {
+ CLIP(dissolveFactor, 0.0, 1.0);
+ if (dissolveFactor != _dissolveFactor) {
+ _dissolveFactor = dissolveFactor;
+ invalidateLocalBounds();
+ }
+}
+
void SpatialEntity::invalidateLocalBounds() {
- g_engine->_dirtyRects.push_back(_boundingBox);
+ g_engine->addDirtyRect(getBbox());
}
void SpatialEntity::invalidateLocalZIndex() {
diff --git a/engines/mediastation/asset.h b/engines/mediastation/asset.h
index 036f6679983..cbd934e147c 100644
--- a/engines/mediastation/asset.h
+++ b/engines/mediastation/asset.h
@@ -168,20 +168,19 @@ class SpatialEntity : public Asset {
public:
SpatialEntity(AssetType type) : Asset(type) {};
- virtual void redraw(Common::Rect &rect) { return; }
+ virtual void draw(const Common::Array<Common::Rect> &dirtyRegion) { return; }
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
+ virtual void readParameter(Chunk &chunk, AssetHeaderSectionType paramType) override;
virtual bool isSpatialActor() const override { return true; }
virtual bool isVisible() const { return _isVisible; }
-
- virtual void readParameter(Chunk &chunk, AssetHeaderSectionType paramType) override;
-
- Common::Rect getBbox() const { return _boundingBox; }
+ virtual Common::Rect getBbox() const { return _boundingBox; }
int zIndex() const { return _zIndex; }
protected:
uint _stageId = 0;
int _zIndex = 0;
+ double _dissolveFactor = 0.0;
Common::Rect _boundingBox;
bool _isVisible = false;
bool _hasTransparency = false;
@@ -192,6 +191,7 @@ protected:
void setBounds(const Common::Rect &bounds);
void setZIndex(int zIndex);
+ virtual void setDissolveFactor(double dissolveFactor);
virtual void invalidateLocalBounds();
virtual void invalidateLocalZIndex();
};
diff --git a/engines/mediastation/assets/canvas.cpp b/engines/mediastation/assets/canvas.cpp
index cb9ead43def..d5096f6f075 100644
--- a/engines/mediastation/assets/canvas.cpp
+++ b/engines/mediastation/assets/canvas.cpp
@@ -29,10 +29,6 @@ void Canvas::readParameter(Chunk &chunk, AssetHeaderSectionType paramType) {
_isVisible = static_cast<bool>(chunk.readTypedByte());
break;
- case kAssetHeaderDissolveFactor:
- _dissolveFactor = chunk.readTypedDouble();
- break;
-
default:
SpatialEntity::readParameter(chunk, paramType);
}
diff --git a/engines/mediastation/assets/canvas.h b/engines/mediastation/assets/canvas.h
index 76e121d092a..4210d95ac58 100644
--- a/engines/mediastation/assets/canvas.h
+++ b/engines/mediastation/assets/canvas.h
@@ -34,9 +34,6 @@ public:
virtual void readParameter(Chunk &chunk, AssetHeaderSectionType paramType) override;
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
-
-private:
- double _dissolveFactor = 0.0;
};
} // End of namespace MediaStation
diff --git a/engines/mediastation/assets/document.cpp b/engines/mediastation/assets/document.cpp
index 897826e73a0..8c09e95138c 100644
--- a/engines/mediastation/assets/document.cpp
+++ b/engines/mediastation/assets/document.cpp
@@ -28,16 +28,9 @@ ScriptValue Document::callMethod(BuiltInMethod methodId, Common::Array<ScriptVal
ScriptValue returnValue;
switch (methodId) {
- case kBranchToScreenMethod: {
- assert(args.size() >= 1);
- if (args.size() > 1) {
- // TODO: Figure out what the rest of the args can be.
- warning("branchToScreen got more than one arg");
- }
- uint32 contextId = args[0].asAssetId();
- g_engine->scheduleScreenBranch(contextId);
+ case kBranchToScreenMethod:
+ processBranch(args);
return returnValue;
- }
case kReleaseContextMethod: {
assert(args.size() == 1);
@@ -51,4 +44,16 @@ ScriptValue Document::callMethod(BuiltInMethod methodId, Common::Array<ScriptVal
}
}
+void Document::processBranch(Common::Array<ScriptValue> &args) {
+ assert(args.size() >= 1);
+ uint contextId = args[0].asAssetId();
+ if (args.size() > 1) {
+ bool disableUpdates = static_cast<bool>(args[1].asParamToken());
+ if (disableUpdates)
+ warning("processBranch: disableUpdates parameter not handled yet");
+ }
+
+ g_engine->scheduleScreenBranch(contextId);
+}
+
} // End of namespace MediaStation
diff --git a/engines/mediastation/assets/document.h b/engines/mediastation/assets/document.h
index 8129a10c4c4..dadb1e8b0ef 100644
--- a/engines/mediastation/assets/document.h
+++ b/engines/mediastation/assets/document.h
@@ -33,6 +33,9 @@ public:
Document() : Asset(kAssetTypeDocument) { _id = 1; };
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
+
+private:
+ void processBranch(Common::Array<ScriptValue> &args);
};
} // End of namespace MediaStation
diff --git a/engines/mediastation/assets/image.cpp b/engines/mediastation/assets/image.cpp
index a3b1fb91e7a..8b4a029de3c 100644
--- a/engines/mediastation/assets/image.cpp
+++ b/engines/mediastation/assets/image.cpp
@@ -48,10 +48,6 @@ void Image::readParameter(Chunk &chunk, AssetHeaderSectionType paramType) {
_loadType = chunk.readTypedByte();
break;
- case kAssetHeaderDissolveFactor:
- _dissolveFactor = chunk.readTypedDouble();
- break;
-
case kAssetHeaderX:
_xOffset = chunk.readTypedUint16();
break;
@@ -80,48 +76,36 @@ ScriptValue Image::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue>
return returnValue;
}
- case kSetDissolveFactorMethod: {
- warning("STUB: setDissolveFactor");
- assert(args.size() == 1);
- _dissolveFactor = args[0].asFloat();
- return returnValue;
- }
-
default:
return SpatialEntity::callMethod(methodId, args);
}
}
-void Image::redraw(Common::Rect &rect) {
- if (!_isVisible) {
- return;
+void Image::draw(const Common::Array<Common::Rect> &dirtyRegion) {
+ if (_isVisible) {
+ Common::Point origin = getBbox().origin();
+ g_engine->getDisplayManager()->imageBlit(origin, _bitmap, _dissolveFactor, dirtyRegion);
}
+}
- Common::Point leftTop = getLeftTop();
- Common::Rect bbox(leftTop, _bitmap->width(), _bitmap->height());
- Common::Rect areaToRedraw = bbox.findIntersectingRect(rect);
- if (!areaToRedraw.isEmpty()) {
- Common::Point originOnScreen(areaToRedraw.left, areaToRedraw.top);
- areaToRedraw.translate(-leftTop.x, -leftTop.y);
- areaToRedraw.clip(Common::Rect(0, 0, _bitmap->width(), _bitmap->height()));
- g_engine->_screen->simpleBlitFrom(_bitmap->_surface, areaToRedraw, originOnScreen);
- }
+void Image::invalidateLocalBounds() {
+ g_engine->addDirtyRect(getBbox());
}
void Image::spatialShow() {
_isVisible = true;
- Common::Rect bbox(getLeftTop(), _bitmap->width(), _bitmap->height());
- g_engine->_dirtyRects.push_back(bbox);
+ invalidateLocalBounds();
}
void Image::spatialHide() {
_isVisible = false;
- Common::Rect bbox(getLeftTop(), _bitmap->width(), _bitmap->height());
- g_engine->_dirtyRects.push_back(bbox);
+ invalidateLocalBounds();
}
-Common::Point Image::getLeftTop() {
- return Common::Point(_xOffset + _boundingBox.left, _yOffset + _boundingBox.top);
+Common::Rect Image::getBbox() const {
+ Common::Point origin(_xOffset + _boundingBox.left, _yOffset + _boundingBox.top);
+ Common::Rect bbox(origin, _bitmap->width(), _bitmap->height());
+ return bbox;
}
void Image::readChunk(Chunk &chunk) {
diff --git a/engines/mediastation/assets/image.h b/engines/mediastation/assets/image.h
index a729504c0be..23c708f32af 100644
--- a/engines/mediastation/assets/image.h
+++ b/engines/mediastation/assets/image.h
@@ -40,20 +40,19 @@ public:
virtual void readChunk(Chunk &chunk) override;
virtual void readParameter(Chunk &chunk, AssetHeaderSectionType paramType) override;
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
- virtual void redraw(Common::Rect &rect) override;
+ virtual void draw(const Common::Array<Common::Rect> &dirtyRegion) override;
+ virtual void invalidateLocalBounds() override;
+ virtual Common::Rect getBbox() const override;
private:
Bitmap *_bitmap = nullptr;
uint _loadType = 0;
- double _dissolveFactor = 0.0;
int _xOffset = 0;
int _yOffset = 0;
// Script method implementations.
void spatialShow();
void spatialHide();
-
- Common::Point getLeftTop();
};
} // End of namespace MediaStation
diff --git a/engines/mediastation/assets/movie.cpp b/engines/mediastation/assets/movie.cpp
index d71928ba0db..e515d694c93 100644
--- a/engines/mediastation/assets/movie.cpp
+++ b/engines/mediastation/assets/movie.cpp
@@ -43,7 +43,7 @@ MovieFrame::MovieFrame(Chunk &chunk) {
unk4 = chunk.readTypedUint16();
index = chunk.readTypedUint16();
} else {
- blitType = chunk.readTypedUint16();
+ blitType = static_cast<MovieBlitType>(chunk.readTypedUint16());
startInMilliseconds = chunk.readTypedUint32();
endInMilliseconds = chunk.readTypedUint32();
// These are unsigned in the data files but ScummVM expects signed.
@@ -119,10 +119,6 @@ void Movie::readParameter(Chunk &chunk, AssetHeaderSectionType paramType) {
_isVisible = static_cast<bool>(chunk.readTypedByte());
break;
- case kAssetHeaderDissolveFactor:
- _dissolveFactor = chunk.readTypedDouble();
- break;
-
case kAssetHeaderMovieAudioChunkReference:
_audioChunkReference = chunk.readTypedChunkReference();
break;
@@ -190,13 +186,6 @@ ScriptValue Movie::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue>
return returnValue;
}
- case kSetDissolveFactorMethod: {
- warning("STUB: setDissolveFactor");
- assert(args.size() == 1);
- _dissolveFactor = args[0].asFloat();
- return returnValue;
- }
-
default:
return SpatialEntity::callMethod(methodId, args);
}
@@ -318,15 +307,28 @@ void Movie::updateFrameState() {
}
}
-void Movie::redraw(Common::Rect &rect) {
+void Movie::draw(const Common::Array<Common::Rect> &dirtyRegion) {
for (MovieFrame *frame : _framesOnScreen) {
Common::Rect bbox = getFrameBoundingBox(frame);
- Common::Rect areaToRedraw = bbox.findIntersectingRect(rect);
- if (!areaToRedraw.isEmpty()) {
- Common::Point originOnScreen(areaToRedraw.left, areaToRedraw.top);
- areaToRedraw.translate(-frame->leftTop.x - _boundingBox.left, -frame->leftTop.y - _boundingBox.top);
- areaToRedraw.clip(Common::Rect(0, 0, frame->image->width(), frame->image->height()));
- g_engine->_screen->simpleBlitFrom(frame->image->_surface, areaToRedraw, originOnScreen);
+
+ switch (frame->blitType) {
+ case kUncompressedMovieBlit:
+ g_engine->getDisplayManager()->imageBlit(bbox.origin(), frame->image, _dissolveFactor, dirtyRegion);
+ break;
+
+ case kUncompressedDeltaMovieBlit:
+ g_engine->getDisplayManager()->imageDeltaBlit(bbox.origin(), frame->diffBetweenKeyframeAndFrame, frame->image, frame->keyframeImage, _dissolveFactor, dirtyRegion);
+ break;
+
+ case kCompressedDeltaMovieBlit:
+ if (frame->keyframeImage->isCompressed()) {
+ decompressIntoAuxImage(frame);
+ }
+ g_engine->getDisplayManager()->imageDeltaBlit(bbox.origin(), frame->diffBetweenKeyframeAndFrame, frame->image, frame->keyframeImage, _dissolveFactor, dirtyRegion);
+ break;
+
+ default:
+ error("Got unknown movie frame blit type: %d", frame->blitType);
}
}
}
@@ -437,7 +439,17 @@ void Movie::readSubfile(Subfile &subfile, Chunk &chunk) {
}
void Movie::invalidateRect(const Common::Rect &rect) {
- g_engine->_dirtyRects.push_back(rect);
+ g_engine->addDirtyRect(rect);
+}
+
+void Movie::decompressIntoAuxImage(MovieFrame *frame) {
+ const Common::Point origin(0, 0);
+ Common::Rect test = Common::Rect(frame->keyframeImage->width(), frame->keyframeImage->height());
+ Common::Array<Common::Rect> allDirty(1);
+ allDirty.push_back(test);
+ 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, allDirty, &frame->keyframeImage->_image);
}
void Movie::readImageData(Chunk &chunk) {
diff --git a/engines/mediastation/assets/movie.h b/engines/mediastation/assets/movie.h
index 896a0311836..d82e0e310bb 100644
--- a/engines/mediastation/assets/movie.h
+++ b/engines/mediastation/assets/movie.h
@@ -32,6 +32,13 @@
namespace MediaStation {
+enum MovieBlitType {
+ kInvalidMovieBlit = 0,
+ kUncompressedMovieBlit = 1,
+ kUncompressedDeltaMovieBlit = 2,
+ kCompressedDeltaMovieBlit = 3,
+};
+
class MovieFrameHeader : public BitmapHeader {
public:
MovieFrameHeader(Chunk &chunk);
@@ -66,7 +73,7 @@ struct MovieFrame {
uint endInMilliseconds = 0;
Common::Point leftTop;
Common::Point diffBetweenKeyframeAndFrame;
- uint blitType = 0;
+ MovieBlitType blitType = kInvalidMovieBlit;
int16 zIndex = 0;
uint keyframeIndex = 0;
bool keepAfterEnd = false;
@@ -87,7 +94,7 @@ public:
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
virtual void process() override;
- virtual void redraw(Common::Rect &rect) override;
+ virtual void draw(const Common::Array<Common::Rect> &dirtyRegion) override;
virtual bool isVisible() const override { return _isVisible; }
@@ -100,7 +107,6 @@ private:
uint _fullTime = 0;
uint _loadType = 0;
- double _dissolveFactor = 0.0;
bool _isPlaying = false;
bool _hasStill = false;
@@ -117,6 +123,7 @@ private:
void setVisibility(bool visibility);
void updateFrameState();
void invalidateRect(const Common::Rect &rect);
+ void decompressIntoAuxImage(MovieFrame *frame);
void readImageData(Chunk &chunk);
void readFrameData(Chunk &chunk);
diff --git a/engines/mediastation/assets/palette.cpp b/engines/mediastation/assets/palette.cpp
index a82d4536e5b..1159686d224 100644
--- a/engines/mediastation/assets/palette.cpp
+++ b/engines/mediastation/assets/palette.cpp
@@ -33,11 +33,9 @@ Palette::~Palette() {
void Palette::readParameter(Chunk &chunk, AssetHeaderSectionType paramType) {
switch (paramType) {
case kAssetHeaderPalette: {
- const uint PALETTE_ENTRIES = 256;
- const uint PALETTE_BYTES = PALETTE_ENTRIES * 3;
- byte *buffer = new byte[PALETTE_BYTES];
- chunk.read(buffer, PALETTE_BYTES);
- _palette = new Graphics::Palette(buffer, PALETTE_ENTRIES, DisposeAfterUse::YES);
+ byte *buffer = new byte[Graphics::PALETTE_SIZE];
+ chunk.read(buffer, Graphics::PALETTE_SIZE);
+ _palette = new Graphics::Palette(buffer, Graphics::PALETTE_COUNT, DisposeAfterUse::YES);
break;
}
diff --git a/engines/mediastation/assets/palette.h b/engines/mediastation/assets/palette.h
index b54dc21fe8b..5345e24facd 100644
--- a/engines/mediastation/assets/palette.h
+++ b/engines/mediastation/assets/palette.h
@@ -22,6 +22,8 @@
#ifndef MEDIASTATION_PALETTE_H
#define MEDIASTATION_PALETTE_H
+#include "graphics/palette.h"
+
#include "mediastation/asset.h"
#include "mediastation/mediascript/scriptvalue.h"
#include "mediastation/mediascript/scriptconstants.h"
diff --git a/engines/mediastation/assets/path.cpp b/engines/mediastation/assets/path.cpp
index e487eb6b0ed..6fdf2861491 100644
--- a/engines/mediastation/assets/path.cpp
+++ b/engines/mediastation/assets/path.cpp
@@ -70,7 +70,7 @@ ScriptValue Path::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue>
case kSetDurationMethod: {
assert(args.size() == 1);
- uint durationInMilliseconds = static_cast<uint>(args[0].asFloat() * 1000);
+ uint durationInMilliseconds = static_cast<uint>(args[0].asTime() * 1000);
setDuration(durationInMilliseconds);
return returnValue;
}
diff --git a/engines/mediastation/assets/sprite.cpp b/engines/mediastation/assets/sprite.cpp
index 45cf88de556..6554d4c5047 100644
--- a/engines/mediastation/assets/sprite.cpp
+++ b/engines/mediastation/assets/sprite.cpp
@@ -77,10 +77,6 @@ void Sprite::readParameter(Chunk &chunk, AssetHeaderSectionType paramType) {
_chunkReference = chunk.readTypedChunkReference();
break;
- case kAssetHeaderDissolveFactor:
- _dissolveFactor = chunk.readTypedDouble();
- break;
-
case kAssetHeaderFrameRate:
_frameRate = static_cast<uint32>(chunk.readTypedDouble());
break;
@@ -142,13 +138,6 @@ ScriptValue Sprite::callMethod(BuiltInMethod methodId, Common::Array<ScriptValue
return returnValue;
}
- case kSetDissolveFactorMethod: {
- warning("STUB: setDissolveFactor");
- assert(args.size() == 1);
- _dissolveFactor = args[0].asFloat();
- return returnValue;
- }
-
case kTimePlayMethod: {
assert(args.empty());
play();
@@ -373,20 +362,12 @@ void Sprite::postMovieEndEventIfNecessary() {
runEventHandlerIfExists(kSpriteMovieEndEvent, value);
}
-void Sprite::redraw(Common::Rect &rect) {
+void Sprite::draw(const Common::Array<Common::Rect> &dirtyRegion) {
SpriteFrame *activeFrame = _frames[_currentFrameIndex];
- if (activeFrame == nullptr || !_isVisible) {
- return;
- }
-
- Common::Rect bbox = activeFrame->boundingBox();
- bbox.translate(_boundingBox.left, _boundingBox.top);
- Common::Rect areaToRedraw = bbox.findIntersectingRect(rect);
- if (!areaToRedraw.isEmpty()) {
- Common::Point originOnScreen(areaToRedraw.left, areaToRedraw.top);
- areaToRedraw.translate(-activeFrame->left() - _boundingBox.left, -activeFrame->top() - _boundingBox.top);
- areaToRedraw.clip(Common::Rect(0, 0, activeFrame->width(), activeFrame->height()));
- g_engine->_screen->simpleBlitFrom(activeFrame->_surface, areaToRedraw, originOnScreen);
+ if (_isVisible) {
+ Common::Rect frameBbox = activeFrame->boundingBox();
+ frameBbox.translate(_boundingBox.left, _boundingBox.top);
+ g_engine->getDisplayManager()->imageBlit(frameBbox.origin(), activeFrame, _dissolveFactor, dirtyRegion);
}
}
diff --git a/engines/mediastation/assets/sprite.h b/engines/mediastation/assets/sprite.h
index 15d55001c8c..4c89bcc83d6 100644
--- a/engines/mediastation/assets/sprite.h
+++ b/engines/mediastation/assets/sprite.h
@@ -72,7 +72,7 @@ public:
~Sprite();
virtual void process() override;
- virtual void redraw(Common::Rect &rect) override;
+ virtual void draw(const Common::Array<Common::Rect> &dirtyRegion) override;
virtual void readParameter(Chunk &chunk, AssetHeaderSectionType paramType) override;
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
@@ -83,7 +83,6 @@ public:
private:
static const uint DEFAULT_CLIP_ID = 1200;
- double _dissolveFactor = 0.0;
uint _loadType = 0;
uint _frameRate = 0;
uint _frameCount = 0;
diff --git a/engines/mediastation/assets/text.cpp b/engines/mediastation/assets/text.cpp
index 154c3b78205..935897fbedb 100644
--- a/engines/mediastation/assets/text.cpp
+++ b/engines/mediastation/assets/text.cpp
@@ -65,10 +65,6 @@ void Text::readParameter(Chunk &chunk, AssetHeaderSectionType paramType) {
break;
}
- case kAssetHeaderDissolveFactor:
- _dissolveFactor = chunk.readTypedDouble();
- break;
-
default:
SpatialEntity::readParameter(chunk, paramType);
}
diff --git a/engines/mediastation/assets/text.h b/engines/mediastation/assets/text.h
index 0e186f82220..98d057dc17e 100644
--- a/engines/mediastation/assets/text.h
+++ b/engines/mediastation/assets/text.h
@@ -58,7 +58,6 @@ public:
private:
bool _editable = false;
uint _loadType = 0;
- double _dissolveFactor = 0.0;
bool _isVisible = false;
Common::String _text;
uint _maxTextLength = 0;
diff --git a/engines/mediastation/bitmap.cpp b/engines/mediastation/bitmap.cpp
index c0251d3a5a8..1143c2e5e0d 100644
--- a/engines/mediastation/bitmap.cpp
+++ b/engines/mediastation/bitmap.cpp
@@ -26,189 +26,43 @@ namespace MediaStation {
BitmapHeader::BitmapHeader(Chunk &chunk) {
uint headerSizeInBytes = chunk.readTypedUint16();
- debugC(5, kDebugLoading, "BitmapHeader::BitmapHeader(): headerSize = 0x%x", headerSizeInBytes);
_dimensions = chunk.readTypedGraphicSize();
_compressionType = static_cast<BitmapCompressionType>(chunk.readTypedUint16());
- debugC(5, kDebugLoading, "BitmapHeader::BitmapHeader(): _compressionType = 0x%x", static_cast<uint>(_compressionType));
- // TODO: Figure out what this is.
- // This has something to do with the width of the bitmap but is always
- // a few pixels off from the width. And in rare cases it seems to be
- // the true width!
- unk2 = chunk.readTypedUint16();
-}
-
-bool BitmapHeader::isCompressed() {
- return (_compressionType != kUncompressedBitmap1) && (_compressionType != kUncompressedBitmap2);
+ _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) {
- // The header must be constructed beforehand.
- int16 width = _bitmapHeader->_dimensions.x;
- int16 height = _bitmapHeader->_dimensions.y;
- _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
- _surface.setTransparentColor(0);
- uint8 *pixels = (uint8 *)_surface.getPixels();
- if (_bitmapHeader->isCompressed()) {
- // DECOMPRESS THE IMAGE.
- debugC(5, kDebugLoading, "Bitmap::Bitmap(): Decompressing bitmap (@0x%llx)", static_cast<long long int>(chunk.pos()));
- decompress(chunk);
- debugC(5, kDebugLoading, "Bitmap::Bitmap(): Finished decompressing bitmap (@0x%llx) [%d remaining bytes]", static_cast<long long int>(chunk.pos()), chunk.bytesRemaining());
- // TODO: Make sure there is nothing important in here. They are likely
- // just zeroes.
- chunk.skip(chunk.bytesRemaining());
- } else {
- // READ THE UNCOMPRESSED IMAGE DIRECTLY.
- // TODO: Understand why we need to ignore these 2 bytes.
- chunk.skip(2);
- chunk.read(pixels, chunk.bytesRemaining());
+ if (stride() < width()) {
+ warning("Bitmap: Got stride less than width");
+ }
+
+ _unk1 = chunk.readUint16LE();
+ if (chunk.bytesRemaining() > 0) {
+ if (isCompressed()) {
+ _compressedStream = chunk.readStream(chunk.bytesRemaining());
+ } else {
+ _image.create(width(), height(), Graphics::PixelFormat::createFormatCLUT8());
+ if (getCompressionType() == kUncompressedTransparentBitmap)
+ _image.setTransparentColor(0);
+ byte *pixels = static_cast<byte *>(_image.getPixels());
+ chunk.read(pixels, chunk.bytesRemaining());
+ }
}
}
Bitmap::~Bitmap() {
delete _bitmapHeader;
_bitmapHeader = nullptr;
-}
-
-int16 Bitmap::width() {
- return _bitmapHeader->_dimensions.x;
-}
-int16 Bitmap::height() {
- return _bitmapHeader->_dimensions.y;
+ delete _compressedStream;
+ _compressedStream = nullptr;
}
-void Bitmap::decompress(Chunk &chunk) {
- // MAKE SURE WE READ PAST THE FIRST 2 BYTES.
- uint unk1 = chunk.readByte();
- uint unk2 = chunk.readByte();
- if ((unk1 == 0) && (unk2 == 0)) {
- if (chunk.bytesRemaining() == 0) {
- // Sometimes there are compressed images that actually have no
- // contents! If we've hit this case, exit the decompression now.
- return;
- }
- } else {
- chunk.seek(chunk.pos() - 2);
- }
-
- // GET THE DECOMPRESSED PIXELS BUFFER.
- // Media Station has 8 bits per pixel, so the decompression buffer is
- // simple.
- char *decompressedImage = static_cast<char *>(_surface.getPixels());
-
- // DECOMPRESS THE RLE-COMPRESSED BITMAP STREAM.
- // TODO: Comemnted out becuase transparency runs not supported yet,
- // and there were compiler warnings about these variables not being used.
- // bool transparencyRunEverRead = false;
- // size_t transparencyRunTopYCoordinate = 0;
- // size_t transparencyRunLeftXCoordinate = 0;
- bool imageFullyRead = false;
- int16 currentYCoordinate = 0;
- while (currentYCoordinate < height()) {
- int16 currentXCoordinate = 0;
- bool readingTransparencyRun = false;
- while (true) {
- byte operation = chunk.readByte();
- if (operation == 0x00) {
- // ENTER CONTROL MODE.
- operation = chunk.readByte();
- if (operation == 0x00) {
- // MARK THE END OF THE LINE.
- // Also check if the image is finished being read.
- if (chunk.bytesRemaining() == 0) {
- imageFullyRead = true;
- }
- break;
- } else if (operation == 0x01) {
- // MARK THE END OF THE IMAGE.
- // TODO: When is this actually used?
- imageFullyRead = true;
- break;
- } else if (operation == 0x02) {
- // MARK THE START OF A KEYFRAME TRANSPARENCY REGION.
- // Until a color index other than 0x00 (usually white) is read on this line,
- // all pixels on this line will be marked transparent.
- // If no transparency regions are present in this image, all 0x00 color indices are treated
- // as transparent. Otherwise, only the 0x00 color indices within transparency regions
- // are considered transparent. Only intraframes (frames that are not keyframes) have been
- // observed to have transparency regions, and these intraframes have them so the keyframe
- // can extend outside the boundary of the intraframe and
- // still be removed.
- //
- // TODO: Comemnted out becuase transparency runs not
- // supported yet, and there were compiler warnings about
- // these variables being set but not used.
- // readingTransparencyRun = true;
- // transparencyRunTopYCoordinate = currentYCoordinate;
- // transparencyRunLeftXCoordinate = currentXCoordinate;
- // transparencyRunEverRead = true;
- } else if (operation == 0x03) {
- // ADJUST THE PIXEL POSITION.
- // This permits jumping to a different part of the same row without
- // needing a run of pixels in between. But the actual data consumed
- // seems to actually be higher this way, as you need the control byte
- // first.
- // So to skip 10 pixels using this approach, you would encode 00 03 0a 00.
- // But to "skip" 10 pixels by encoding them as blank (0xff), you would encode 0a ff.
- // What gives? I'm not sure.
- byte x_change = chunk.readByte();
- currentXCoordinate += x_change;
- byte y_change = chunk.readByte();
- currentYCoordinate += y_change;
- } else if (operation >= 0x04) {
- // READ A RUN OF UNCOMPRESSED PIXELS.
- size_t yOffset = currentYCoordinate * width();
- size_t runStartingOffset = yOffset + currentXCoordinate;
- char *runStartingPointer = decompressedImage + runStartingOffset;
- byte runLength = operation;
- // TODO: Is there a better way to do this than just copying?
- char *uncompressedPixels = new char[runLength];
- chunk.read(uncompressedPixels, runLength);
- memcpy(runStartingPointer, uncompressedPixels, runLength);
- delete[] uncompressedPixels;
-
- currentXCoordinate += operation;
- if (chunk.pos() % 2 == 1) {
- chunk.readByte();
- }
- }
- } else {
- // READ A RUN OF LENGTH ENCODED PIXELS.
- size_t yOffset = currentYCoordinate * width();
- size_t runStartingOffset = yOffset + currentXCoordinate;
- char *runStartingPointer = decompressedImage + runStartingOffset;
- byte colorIndexToRepeat = chunk.readByte();
- byte repetitionCount = operation;
- memset(runStartingPointer, colorIndexToRepeat, repetitionCount);
- currentXCoordinate += repetitionCount;
-
- if (readingTransparencyRun) {
- // TODO: This code is comemnted out becuase the engine
- // doesn't support the keyframes/transparency regions on
- // movies yet. However, only some movies have this to start with.
-
- // GET THE TRANSPARENCY RUN STARTING OFFSET.
- // size_t transparencyRunYOffset = transparencyRunTopYCoordinate * width();
- // size_t transparencyRunStartOffset = transparencyRunYOffset + transparencyRunLeftXCoordinate;
- // size_t transparencyRunEndingOffset = yOffset + currentXCoordinate;
- // size_t transparency_run_length = transparencyRunEndingOffset - transparencyRunStartOffset;
- // char *transparencyRunSrcPointer = keyframe_image + runStartingOffset;
- // char *transparencyRunDestPointer = decompressedImage + runStartingOffset;
-
- // COPY THE TRANSPARENT AREA FROM THE KEYFRAME.
- // The "interior" of transparency regions is always encoded by a single run of
- // pixels, usually 0x00 (white).
- // memcpy(transparencyRunDestPointer, transparencyRunSrcPointer, transparency_run_length);
- readingTransparencyRun = false;
- }
- }
- }
-
- currentYCoordinate++;
- if (imageFullyRead) {
- break;
- }
- }
+bool Bitmap::isCompressed() const {
+ return (getCompressionType() != kUncompressedBitmap) && \
+ (getCompressionType() != kUncompressedTransparentBitmap);
}
} // End of namespace MediaStation
diff --git a/engines/mediastation/bitmap.h b/engines/mediastation/bitmap.h
index 2c92728fcc9..16660887cfa 100644
--- a/engines/mediastation/bitmap.h
+++ b/engines/mediastation/bitmap.h
@@ -31,36 +31,39 @@
namespace MediaStation {
enum BitmapCompressionType {
- kUncompressedBitmap1 = 0,
- kRleCompressedBitmap = 1,
- kUnk1CompressedBitmap = 6,
- kUncompressedBitmap2 = 7,
+ kUncompressedBitmap = 0,
+ kRle8BitmapCompression = 1,
+ kCccBitmapCompression = 5,
+ kCccTransparentBitmapCompression = 6,
+ kUncompressedTransparentBitmap = 7,
};
class BitmapHeader {
public:
BitmapHeader(Chunk &chunk);
- bool isCompressed();
-
Common::Point _dimensions;
- BitmapCompressionType _compressionType;
- uint unk2;
+ BitmapCompressionType _compressionType = kUncompressedBitmap;
+ int16 _stride = 0;
};
class Bitmap {
public:
- BitmapHeader *_bitmapHeader = nullptr;
-
Bitmap(Chunk &chunk, BitmapHeader *bitmapHeader);
virtual ~Bitmap();
- int16 width();
- int16 height();
- Graphics::ManagedSurface _surface;
+ 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:
- void decompress(Chunk &chunk);
+ BitmapHeader *_bitmapHeader = nullptr;
+ uint _unk1 = 0;
};
} // End of namespace MediaStation
diff --git a/engines/mediastation/context.cpp b/engines/mediastation/context.cpp
index 02756b834ee..e9b4a64edcc 100644
--- a/engines/mediastation/context.cpp
+++ b/engines/mediastation/context.cpp
@@ -364,14 +364,12 @@ bool Context::readHeaderSection(Chunk &chunk) {
if (_palette != nullptr) {
error("Context::readHeaderSection(): Got multiple palettes (@0x%llx)", static_cast<long long int>(chunk.pos()));
}
- // TODO: Avoid the copying here!
- const uint PALETTE_ENTRIES = 256;
- const uint PALETTE_BYTES = PALETTE_ENTRIES * 3;
- byte *buffer = new byte[PALETTE_BYTES];
- chunk.read(buffer, PALETTE_BYTES);
- _palette = new Graphics::Palette(buffer, PALETTE_ENTRIES);
- delete[] buffer;
+
+ byte *buffer = new byte[Graphics::PALETTE_SIZE];
+ chunk.read(buffer, Graphics::PALETTE_SIZE);
+ _palette = new Graphics::Palette(buffer, Graphics::PALETTE_COUNT, DisposeAfterUse::YES);
debugC(5, kDebugLoading, "Context::readHeaderSection(): Read palette");
+
// This is likely just an ending flag that we expect to be zero.
uint endingFlag = chunk.readTypedUint16();
if (endingFlag != 0) {
diff --git a/engines/mediastation/datafile.h b/engines/mediastation/datafile.h
index 5a1b47e9519..ac656fea9a6 100644
--- a/engines/mediastation/datafile.h
+++ b/engines/mediastation/datafile.h
@@ -95,9 +95,6 @@ public:
VersionInfo readTypedVersion();
uint32 readTypedChunkReference();
Polygon readTypedPolygon();
- // PALETTE:
- // u.palette = new unsigned char[0x300];
- // chunk.read(u.palette, 0x300);
private:
void readAndVerifyType(DatumType type);
diff --git a/engines/mediastation/debugchannels.h b/engines/mediastation/debugchannels.h
index 4c77531dd95..3d2878464cc 100644
--- a/engines/mediastation/debugchannels.h
+++ b/engines/mediastation/debugchannels.h
@@ -36,7 +36,7 @@ enum DebugChannels {
kDebugScan,
kDebugScript,
kDebugEvents,
- kDebugLoading
+ kDebugLoading,
};
} // End of namespace MediaStation
diff --git a/engines/mediastation/dissolvepatterns.h b/engines/mediastation/dissolvepatterns.h
new file mode 100644
index 00000000000..d7f87b83897
--- /dev/null
+++ b/engines/mediastation/dissolvepatterns.h
@@ -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
diff --git a/engines/mediastation/graphics.cpp b/engines/mediastation/graphics.cpp
new file mode 100644
index 00000000000..83518727fe0
--- /dev/null
+++ b/engines/mediastation/graphics.cpp
@@ -0,0 +1,905 @@
+/* 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/system.h"
+#include "common/util.h"
+#include "engines/util.h"
+
+#include "mediastation/assets/palette.h"
+#include "mediastation/bitmap.h"
+#include "mediastation/debugchannels.h"
+#include "mediastation/dissolvepatterns.h"
+#include "mediastation/graphics.h"
+#include "mediastation/mediastation.h"
+
+namespace MediaStation {
+
+VideoDisplayManager::VideoDisplayManager(MediaStationEngine *vm) : _vm(vm) {
+ initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
+ _screen = new Graphics::Screen();
+}
+
+VideoDisplayManager::~VideoDisplayManager() {
+ delete _screen;
+ _screen = nullptr;
+ _vm = nullptr;
+}
+
+void VideoDisplayManager::effectTransition(Common::Array<ScriptValue> &args) {
+ if (args.empty()) {
+ warning("effectTransition: Script args cannot be empty");
+ return;
+ }
+
+ TransitionType transitionType = static_cast<TransitionType>(args[0].asParamToken());
+ switch (transitionType) {
+ case kTransitionFadeToBlack:
+ fadeToBlack(args);
+ break;
+
+ case kTransitionFadeToPalette:
+ fadeToRegisteredPalette(args);
+ break;
+
+ case kTransitionSetToPalette:
+ setToRegisteredPalette(args);
+ break;
+
+ case kTransitionSetToBlack:
+ setToBlack(args);
+ break;
+
+ case kTransitionFadeToColor:
+ fadeToColor(args);
+ break;
+
+ case kTransitionSetToColor:
+ setToColor(args);
+ break;
+
+ case kTransitionSetToPercentOfPalette:
+ setToPercentOfPalette(args);
+ break;
+
+ case kTransitionFadeToPaletteObject:
+ fadeToPaletteObject(args);
+ break;
+
+ case kTransitionSetToPaletteObject:
+ setToPaletteObject(args);
+ break;
+
+ case kTransitionSetToPercentOfPaletteObject:
+ setToPercentOfPaletteObject(args);
+ break;
+
+ case kTransitionColorShiftCurrentPalette:
+ colorShiftCurrentPalette(args);
+ break;
+
+ case kTransitionCircleOut:
+ circleOut(args);
+ break;
+
+ default:
+ warning("effectTransition: Got unknown transition type %d", static_cast<uint>(transitionType));
+ }
+}
+
+void VideoDisplayManager::doTransitionOnSync() {
+ if (!_scheduledTransitionOnSync.empty()) {
+ effectTransition(_scheduledTransitionOnSync);
+ _scheduledTransitionOnSync.clear();
+ }
+}
+
+void VideoDisplayManager::fadeToBlack(Common::Array<ScriptValue> &args) {
+ double fadeTime = DEFAULT_FADE_TRANSITION_TIME_IN_SECONDS;
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 2) {
+ fadeTime = args[1].asTime();
+ }
+ if (args.size() >= 4) {
+ startIndex = static_cast<uint>(args[2].asFloat());
+ colorCount = static_cast<uint>(args[3].asFloat());
+ }
+
+ _fadeToColor(0, 0, 0, fadeTime, startIndex, colorCount);
+}
+
+void VideoDisplayManager::fadeToRegisteredPalette(Common::Array<ScriptValue> &args) {
+ double fadeTime = DEFAULT_FADE_TRANSITION_TIME_IN_SECONDS;
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 2) {
+ fadeTime = args[1].asTime();
+ }
+ if (args.size() >= 4) {
+ startIndex = static_cast<uint>(args[2].asFloat());
+ colorCount = static_cast<uint>(args[3].asFloat());
+ }
+
+ _fadeToRegisteredPalette(fadeTime, startIndex, colorCount);
+}
+
+void VideoDisplayManager::setToRegisteredPalette(Common::Array<ScriptValue> &args) {
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 3) {
+ startIndex = static_cast<uint>(args[1].asFloat());
+ colorCount = static_cast<uint>(args[2].asFloat());
+ }
+
+ _setToRegisteredPalette(startIndex, colorCount);
+}
+
+void VideoDisplayManager::setToBlack(Common::Array<ScriptValue> &args) {
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 3) {
+ startIndex = static_cast<uint>(args[1].asFloat());
+ colorCount = static_cast<uint>(args[2].asFloat());
+ }
+
+ _setToColor(0, 0, 0, startIndex, colorCount);
+}
+
+void VideoDisplayManager::fadeToColor(Common::Array<ScriptValue> &args) {
+ byte r = 0, g = 0, b = 0;
+ double fadeTime = DEFAULT_FADE_TRANSITION_TIME_IN_SECONDS;
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 5) {
+ r = static_cast<byte>(args[1].asFloat());
+ g = static_cast<byte>(args[2].asFloat());
+ b = static_cast<byte>(args[3].asFloat());
+ fadeTime = args[4].asTime();
+ }
+ if (args.size() >= 7) {
+ fadeTime = args[5].asTime();
+ startIndex = static_cast<uint>(args[6].asFloat());
+ colorCount = static_cast<uint>(args[7].asFloat());
+ }
+
+ _fadeToColor(r, g, b, fadeTime, startIndex, colorCount);
+}
+
+void VideoDisplayManager::setToColor(Common::Array<ScriptValue> &args) {
+ if (args.size() < 6) {
+ error("setToColor: Too few script args");
+ }
+
+ byte r = static_cast<byte>(args[1].asFloat());
+ byte g = static_cast<byte>(args[2].asFloat());
+ byte b = static_cast<byte>(args[3].asFloat());
+ uint startIndex = static_cast<uint>(args[4].asFloat());
+ uint colorCount = static_cast<uint>(args[5].asFloat());
+
+ _setToColor(r, g, b, startIndex, colorCount);
+}
+
+void VideoDisplayManager::setToPercentOfPalette(Common::Array<ScriptValue> &args) {
+ if (args.size() < 7) {
+ error("setToPercentOfPalette: Too few script args");
+ }
+
+ double percent = args[1].asFloat();
+ byte r = static_cast<byte>(args[2].asFloat());
+ byte g = static_cast<byte>(args[3].asFloat());
+ byte b = static_cast<byte>(args[4].asFloat());
+ uint startIndex = static_cast<uint>(args[5].asFloat());
+ uint colorCount = static_cast<uint>(args[6].asFloat());
+
+ _setPercentToColor(percent, r, g, b, startIndex, colorCount);
+}
+
+void VideoDisplayManager::fadeToPaletteObject(Common::Array<ScriptValue> &args) {
+ uint paletteId = 0;
+ double fadeTime = DEFAULT_FADE_TRANSITION_TIME_IN_SECONDS;
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 2) {
+ paletteId = args[1].asAssetId();
+ } else {
+ warning("fadeToPaletteObject: Too few script args");
+ return;
+ }
+ if (args.size() >= 3) {
+ fadeTime = args[2].asFloat();
+ }
+ if (args.size() >= 5) {
+ startIndex = static_cast<uint>(args[3].asFloat());
+ colorCount = static_cast<uint>(args[4].asFloat());
+ }
+
+ _fadeToPaletteObject(paletteId, fadeTime, startIndex, colorCount);
+}
+
+void VideoDisplayManager::setToPaletteObject(Common::Array<ScriptValue> &args) {
+ uint paletteId = 0;
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 2) {
+ paletteId = args[1].asAssetId();
+ } else {
+ warning("fadeToPaletteObject: Too few script args");
+ return;
+ }
+ if (args.size() >= 4) {
+ startIndex = static_cast<uint>(args[2].asFloat());
+ colorCount = static_cast<uint>(args[3].asFloat());
+ }
+
+ _setToPaletteObject(paletteId, startIndex, colorCount);
+}
+
+void VideoDisplayManager::setToPercentOfPaletteObject(Common::Array<ScriptValue> &args) {
+ uint paletteId = 0;
+ double percent = 0.0;
+ uint startIndex = DEFAULT_PALETTE_TRANSITION_START_INDEX;
+ uint colorCount = DEFAULT_PALETTE_TRANSITION_COLOR_COUNT;
+
+ if (args.size() >= 3) {
+ percent = args[1].asFloat();
+ paletteId = args[2].asAssetId();
+ } else {
+ error("fadeToPaletteObject: Too few script args");
+ return;
+ }
+ if (args.size() >= 5) {
+ startIndex = static_cast<uint>(args[3].asFloat());
+ colorCount = static_cast<uint>(args[4].asFloat());
+ }
+
+ _setPercentToPaletteObject(percent, paletteId, startIndex, colorCount);
+}
+
+void VideoDisplayManager::colorShiftCurrentPalette(Common::Array<ScriptValue> &args) {
+ if (args.size() < 4) {
+ warning("colorShiftCurrentPalette: Too few script args");
+ return;
+ }
+
+ uint shift = static_cast<uint>(args[1].asFloat());
+ uint startIndex = static_cast<uint>(args[2].asFloat());
+ uint colorCount = static_cast<uint>(args[3].asFloat());
+
+ _colorShiftCurrentPalette(startIndex, shift, colorCount);
+}
+
+void VideoDisplayManager::circleOut(Common::Array<ScriptValue> &args) {
+ warning("STUB: circleOut");
+}
+
+void VideoDisplayManager::_setPalette(Graphics::Palette &palette, uint startIndex, uint colorCount) {
+ // We can't use the Palette::set method directly because it assumes the
+ // data we want to copy is at the start of the data pointer, but in this
+ // case we want to copy some range not necessarily right at the start. Thus,
+ // we need to calculate some pointers manually.
+ _limitColorRange(startIndex, colorCount);
+ uint startOffset = 3 * startIndex;
+ const byte *startPointer = palette.data() + startOffset;
+ _screen->setPalette(startPointer, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_setPaletteToColor(Graphics::Palette &targetPalette, byte r, byte g, byte b) {
+ for (uint colorIndex = 0; colorIndex < Graphics::PALETTE_COUNT; colorIndex++) {
+ targetPalette.set(colorIndex, r, g, b);
+ }
+}
+
+uint VideoDisplayManager::_limitColorRange(uint &startIndex, uint &colorCount) {
+ CLIP<uint>(startIndex, 0, Graphics::PALETTE_COUNT - 1);
+ uint endColorIndex = startIndex + colorCount;
+ CLIP<uint>(endColorIndex, 0, Graphics::PALETTE_COUNT);
+ colorCount = endColorIndex - startIndex;
+ return endColorIndex;
+}
+
+byte VideoDisplayManager::_interpolateColorComponent(byte source, byte target, double progress) {
+ // The original scaled to 1024 to convert to an integer, but we will just
+ // do floating-point interpolation.
+ double result = source + ((target - source) * progress);
+ return static_cast<byte>(CLIP<uint>(result, 0, Graphics::PALETTE_COUNT));
+}
+
+void VideoDisplayManager::_fadeToColor(byte r, byte g, byte b, double fadeTime, uint startIndex, uint colorCount) {
+ // Create a temporary palette that is all one color.
+ Graphics::Palette tempPalette(Graphics::PALETTE_COUNT);
+ _setPaletteToColor(tempPalette, r, g, b);
+ _fadeToPalette(fadeTime, tempPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_setToColor(byte r, byte g, byte b, uint startIndex, uint colorCount) {
+ Graphics::Palette tempPalette = _screen->getPalette();
+ uint endIndex = _limitColorRange(startIndex, colorCount);
+ for (uint colorIndex = startIndex; colorIndex < endIndex; colorIndex++) {
+ tempPalette.set(colorIndex, r, g, b);
+ }
+
+ _setPalette(tempPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_setPercentToColor(double percent, byte r, byte g, byte b, uint startIndex, uint colorCount) {
+ // Create a temporary palette that is all one color.
+ Graphics::Palette tempPalette(Graphics::PALETTE_COUNT);
+ _setPaletteToColor(tempPalette, r, g, b);
+
+ _setToPercentPalette(percent, *_registeredPalette, tempPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_setToPercentPalette(double percent, Graphics::Palette ¤tPalette, Graphics::Palette &targetPalette, uint startIndex, uint colorCount) {
+ if (percent < 0.0 || percent > 1.0) {
+ warning("_setToPercentPalette: Got invalid palette percent value %f", percent);
+ percent = CLIP<double>(percent, 0.0, 1.0);
+ }
+
+ uint endIndex = _limitColorRange(startIndex, colorCount);
+
+ Graphics::Palette blendedPalette = currentPalette;
+ for (uint colorIndex = startIndex; colorIndex < endIndex; colorIndex++) {
+ byte redSource, greenSource, blueSource, redTarget, greenTarget, blueTarget;
+ currentPalette.get(colorIndex, redSource, greenSource, blueSource);
+ targetPalette.get(colorIndex, redTarget, greenTarget, blueTarget);
+
+ byte newRed = _interpolateColorComponent(redSource, redTarget, percent);
+ byte newGreen = _interpolateColorComponent(greenSource, greenTarget, percent);
+ byte newBlue = _interpolateColorComponent(blueSource, blueTarget, percent);
+
+ blendedPalette.set(colorIndex, newRed, newGreen, newBlue);
+ }
+
+ _setPalette(blendedPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_fadeToPalette(double fadeTime, Graphics::Palette &targetPalette, uint startIndex, uint colorCount) {
+ if (fadeTime <= 0.0) {
+ // Set the fade time to something reasonable so we can continue.
+ warning("_fadeToPalette: Got invalid fade time %f", fadeTime);
+ fadeTime = 0.1;
+ }
+
+ // Gamma correction can be set via a script function, but I haven't seen
+ // that be set to anything other than 1 (the default), so it's not
+ // implemented for now.
+ Graphics::Palette currentPalette = _screen->getPalette();
+ Graphics::Palette intermediatePalette(Graphics::PALETTE_COUNT);
+ uint endIndex = _limitColorRange(startIndex, colorCount);
+ uint fadeTimeMillis = static_cast<uint>(fadeTime * 1000);
+ uint startTimeMillis = g_system->getMillis();
+ uint endTimeMillis = startTimeMillis + fadeTimeMillis;
+
+ while (g_system->getMillis() < endTimeMillis) {
+ uint currentTimeMillis = g_system->getMillis();
+ double progress = MIN<double>(static_cast<double>(currentTimeMillis - startTimeMillis) / fadeTimeMillis, 1.0);
+
+ for (uint colorIndex = startIndex; colorIndex < endIndex; colorIndex++) {
+ byte sourceR, sourceG, sourceB, targetR, targetG, targetB;
+
+ currentPalette.get(colorIndex, sourceR, sourceG, sourceB);
+ targetPalette.get(colorIndex, targetR, targetG, targetB);
+ byte newR = _interpolateColorComponent(sourceR, targetR, progress);
+ byte newG = _interpolateColorComponent(sourceG, targetG, progress);
+ byte newB = _interpolateColorComponent(sourceB, targetB, progress);
+
+ intermediatePalette.set(colorIndex, newR, newG, newB);
+ }
+
+ _setPalette(intermediatePalette, startIndex, colorCount);
+ g_system->updateScreen();
+ g_system->delayMillis(5);
+ }
+
+ // Ensure we end with exactly the target palette
+ _setPalette(targetPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_fadeToRegisteredPalette(double fadeTime, uint startIndex, uint colorCount) {
+ _fadeToPalette(fadeTime, *_registeredPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_setToRegisteredPalette(uint startIndex, uint colorCount) {
+ _setPalette(*_registeredPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_colorShiftCurrentPalette(uint startIndex, uint shiftAmount, uint colorCount) {
+ uint endIndex = _limitColorRange(startIndex, colorCount);
+ Graphics::Palette currentPalette = _screen->getPalette();
+ Graphics::Palette shiftedPalette = currentPalette;
+
+ for (uint i = startIndex; i < endIndex; i++) {
+ // Calculate target index with wraparound.
+ // We convert to a zero-based index, wrap that index to stay in bounds,
+ // and then convert back to the actual palette index range.
+ uint targetIndex = ((i + shiftAmount - startIndex) % colorCount) + startIndex;
+
+ byte r, g, b;
+ currentPalette.get(i, r, g, b);
+ shiftedPalette.set(targetIndex, r, g, b);
+ }
+
+ _setPalette(shiftedPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_fadeToPaletteObject(uint paletteId, double fadeTime, uint startIndex, uint colorCount) {
+ Asset *asset = _vm->getAssetById(paletteId);
+ if (asset == nullptr) {
+ error("Got null target palette");
+ } else if (asset->type() != kAssetTypePalette) {
+ error("Asset %d is not a palette", paletteId);
+ }
+
+ Graphics::Palette *palette = static_cast<Palette *>(asset)->_palette;
+ _fadeToPalette(fadeTime, *palette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_setToPaletteObject(uint paletteId, uint startIndex, uint colorCount) {
+ Asset *asset = _vm->getAssetById(paletteId);
+ if (asset == nullptr) {
+ error("Got null target palette");
+ } else if (asset->type() != kAssetTypePalette) {
+ error("Asset %d is not a palette", paletteId);
+ }
+
+ Graphics::Palette *palette = static_cast<Palette *>(asset)->_palette;
+ _setPalette(*palette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::_setPercentToPaletteObject(double percent, uint paletteId, uint startIndex, uint colorCount) {
+ Asset *asset = _vm->getAssetById(paletteId);
+ if (asset == nullptr) {
+ error("Got null target palette");
+ } else if (asset->type() != kAssetTypePalette) {
+ error("Asset %d is not a palette", paletteId);
+ }
+
+ Graphics::Palette *targetPalette = static_cast<Palette *>(asset)->_palette;
+ _setToPercentPalette(percent, *_registeredPalette, *targetPalette, startIndex, colorCount);
+}
+
+void VideoDisplayManager::imageBlit(
+ const Common::Point &destinationPoint,
+ const Bitmap *sourceImage,
+ const double dissolveFactor,
+ const Common::Array<Common::Rect> &dirtyRegion,
+ Graphics::ManagedSurface *targetImage) {
+
+ byte blitFlags = kClipEnabled;
+ switch (sourceImage->getCompressionType()) {
+ case kUncompressedBitmap:
+ break;
+
+ case kRle8BitmapCompression:
+ blitFlags |= kRle8Blit;
+ break;
+
+ case kCccBitmapCompression:
+ blitFlags |= kCccBlit;
+ break;
+
+ case kCccTransparentBitmapCompression:
+ blitFlags |= kCccTransparentBlit;
+ break;
+
+ case kUncompressedTransparentBitmap:
+ blitFlags |= kUncompressedTransparentBlit;
+ break;
+
+ default:
+ error("imageBlit: Got unknown bitmap compression type %d",
+ static_cast<uint>(sourceImage->getCompressionType()));
+ }
+
+ if (dissolveFactor > 1.0 || dissolveFactor < 0.0) {
+ warning("imageBlit: Got out-of-range dissolve factor: %f", dissolveFactor);
+ CLIP(dissolveFactor, 0.0, 1.0);
+ } else if (dissolveFactor == 0.0) {
+ // If the image is fully transparent, there is nothing to draw, so we can return now.
+ return;
+ } else if (dissolveFactor != 1.0) {
+ blitFlags |= kPartialDissolve;
+ }
+ uint integralDissolveFactor = static_cast<uint>(dissolveFactor * 100 + 0.5);
+
+ if (targetImage == nullptr) {
+ targetImage = _screen;
+ }
+
+ // In the disasm, this whole function has complex blit flag logic
+ // throughout, including a lot of switch cases in the statement below
+ // that were unreachable with the flags actually available, as defined above.
+ // The apparently unreachable switch cases are excluded from the statement below.
+ switch (blitFlags) {
+ case kClipEnabled:
+ case kUncompressedTransparentBlit | kClipEnabled:
+ // The original had two different methods for transparent versus
+ // non-transparent blitting, but we will just use simpleBlitFrom in both
+ // cases. It will pick the better method if there is no transparent
+ // color set.
+ blitRectsClip(targetImage, destinationPoint, sourceImage->_image, dirtyRegion);
+ break;
+
+ case kRle8Blit | kClipEnabled:
+ rleBlitRectsClip(targetImage, destinationPoint, sourceImage, dirtyRegion);
+ break;
+
+ case kCccBlit | kClipEnabled:
+ case kCccTransparentBlit | kClipEnabled:
+ // CCC blitting is unimplemented for now because few, if any, titles actually use it.
+ error("imageBlit: CCC blitting not implemented yet");
+ break;
+
+ case kPartialDissolve | kClipEnabled:
+ case kPartialDissolve | kUncompressedTransparentBlit | kClipEnabled:
+ case kPartialDissolve | kRle8Blit | kClipEnabled:
+ // The original had a separate function (rleDissolveBlitRectsClip) for decompressing the RLE and
+ // applying the dissolve at the same time that we are decompressing, but I thought that was too
+ // complex. Instead, we just check the compression type in the same
+ // method and decompress beforehand if necessary.
+ dissolveBlitRectsClip(targetImage, destinationPoint, sourceImage, dirtyRegion, integralDissolveFactor);
+ break;
+
+ default:
+ error("imageBlit: Got invalid blit mode: 0x%x", blitFlags);
+ }
+}
+
+void VideoDisplayManager::blitRectsClip(
+ Graphics::ManagedSurface *dest,
+ const Common::Point &destLocation,
+ const Graphics::ManagedSurface &source,
+ const Common::Array<Common::Rect> &dirtyRegion) {
+
+ for (const Common::Rect &dirtyRect : dirtyRegion) {
+ Common::Rect destRect(destLocation, source.w, source.h);
+ Common::Rect areaToRedraw = dirtyRect.findIntersectingRect(destRect);
+
+ if (!areaToRedraw.isEmpty()) {
+ // Calculate source coordinates (relative to source image).
+ Common::Point originOnScreen(areaToRedraw.origin());
+ areaToRedraw.translate(-destLocation.x, -destLocation.y);
+ dest->simpleBlitFrom(source, areaToRedraw, originOnScreen);
+ }
+ }
+}
+
+void VideoDisplayManager::rleBlitRectsClip(
+ Graphics::ManagedSurface *dest,
+ const Common::Point &destLocation,
+ const Bitmap *source,
+ const Common::Array<Common::Rect> &dirtyRegion) {
+
+ Graphics::ManagedSurface surface = decompressRle8Bitmap(source);
+ Common::Rect destRect(destLocation, source->width(), source->height());
+ for (const Common::Rect &dirtyRect : dirtyRegion) {
+ Common::Rect areaToRedraw = dirtyRect.findIntersectingRect(destRect);
+
+ if (!areaToRedraw.isEmpty()) {
+ // Calculate source coordinates (relative to source image).
+ Common::Point originOnScreen(areaToRedraw.origin());
+ areaToRedraw.translate(-destLocation.x, -destLocation.y);
+ dest->simpleBlitFrom(surface, areaToRedraw, originOnScreen);
+ }
+ }
+}
+
+void VideoDisplayManager::dissolveBlitRectsClip(
+ Graphics::ManagedSurface *dest,
+ const Common::Point &destPos,
+ const Bitmap *source,
+ const Common::Array<Common::Rect> &dirtyRegion,
+ const uint integralDissolveFactor) {
+
+ byte dissolveIndex = DISSOLVE_PATTERN_COUNT;
+ if (integralDissolveFactor != 50) {
+ dissolveIndex = ((integralDissolveFactor + 2) / 4) - 1;
+ CLIP<byte>(dissolveIndex, 0, (DISSOLVE_PATTERN_COUNT - 1));
+ }
+
+ Common::Rect destRect(Common::Rect(destPos, source->width(), source->height()));
+ for (const Common::Rect &dirtyRect : dirtyRegion) {
+ Common::Rect areaToRedraw = dirtyRect.findIntersectingRect(destRect);
+ if (!areaToRedraw.isEmpty()) {
+ // Calculate source coordinates (relative to source image).
+ Common::Point originOnScreen(areaToRedraw.origin());
+ areaToRedraw.translate(-destPos.x, -destPos.y);
+ dissolveBlit1Rect(dest, areaToRedraw, originOnScreen, source, dirtyRect, DISSOLVE_PATTERNS[dissolveIndex]);
+ }
+ }
+}
+
+void VideoDisplayManager::dissolveBlit1Rect(
+ Graphics::ManagedSurface *dest,
+ const Common::Rect &areaToRedraw,
+ const Common::Point &originOnScreen,
+ const Bitmap *source,
+ const Common::Rect &dirtyRegion,
+ const DissolvePattern &pattern) {
+
+ Graphics::ManagedSurface sourceSurface;
+ const Graphics::ManagedSurface *srcPtr = nullptr;
+ switch (source->getCompressionType()) {
+ case kRle8BitmapCompression:
+ sourceSurface = decompressRle8Bitmap(source);
+ srcPtr = &sourceSurface;
+ break;
+
+ case kUncompressedBitmap:
+ case kUncompressedTransparentBitmap:
+ srcPtr = &source->_image;
+ break;
+
+ default:
+ error("dissolveBlit1Rect: Unsupported compression type for dissolve blit: %d",
+ static_cast<uint>(source->getCompressionType()));
+ }
+
+ Common::Point patternStartPos(originOnScreen.x % pattern.widthHeight, originOnScreen.y % pattern.widthHeight);
+ Common::Point currentPatternPos;
+ for (int y = 0; y < areaToRedraw.height(); y++) {
+ currentPatternPos.y = (patternStartPos.y + y) % pattern.widthHeight;
+
+ for (int x = 0; x < areaToRedraw.width(); x++) {
+ currentPatternPos.x = (patternStartPos.x + x) % pattern.widthHeight;
+ uint patternIndex = currentPatternPos.y * pattern.widthHeight + currentPatternPos.x;
+
+ bool shouldDrawPixel = pattern.data[patternIndex] == pattern.threshold;
+ if (shouldDrawPixel) {
+ // Even if the pattern indicates we should draw here, only
+ // copy non-transparent source pixels (value != 0 for transparent bitmaps).
+ Common::Point sourcePos(areaToRedraw.left + x, areaToRedraw.top + y);
+
+ bool sourceXInBounds = sourcePos.x >= 0 && sourcePos.x < srcPtr->w;
+ bool sourceYInBounds = sourcePos.y >= 0 && sourcePos.y < srcPtr->h;
+ if (sourceXInBounds && sourceYInBounds) {
+ byte sourcePixel = srcPtr->getPixel(sourcePos.x, sourcePos.y);
+ if (sourcePixel != 0) {
+ Common::Point destPos(originOnScreen.x + x, originOnScreen.y + y);
+ bool destXInBounds = destPos.x >= 0 && destPos.x < dest->w;
+ bool destYInBounds = destPos.y >= 0 && destPos.y < dest->h;
+ if (destXInBounds && destYInBounds) {
+ dest->setPixel(destPos.x, destPos.y, sourcePixel);
+ } else {
+ warning("dissolveBlit1Rect: Dest out of bounds");
+ }
+ }
+ } else {
+ warning("dissolveBlit1Rect: Source out of bounds");
+ }
+ }
+ }
+ }
+}
+
+void VideoDisplayManager::imageDeltaBlit(
+ const Common::Point &deltaFramePos,
+ const Common::Point &keyFrameOffset,
+ const Bitmap *deltaFrame,
+ const Bitmap *keyFrame,
+ const double dissolveFactor,
+ const Common::Array<Common::Rect> &dirtyRegion) {
+
+ if (deltaFrame->getCompressionType() != kRle8BitmapCompression) {
+ error("imageDeltaBlit: Unsupported delta frame compression type for delta blit: %d",
+ static_cast<uint>(keyFrame->getCompressionType()));
+ } else if (dissolveFactor != 1.0) {
+ warning("imageDeltaBlit: Delta blit does not support dissolving");
+ }
+
+ switch (keyFrame->getCompressionType()) {
+ case kUncompressedBitmap:
+ case kUncompressedTransparentBitmap:
+ deltaRleBlitRectsClip(_screen, deltaFramePos, deltaFrame, keyFrame, dirtyRegion);
+ break;
+
+ case kRle8BitmapCompression:
+ fullDeltaRleBlitRectsClip(_screen, deltaFramePos, keyFrameOffset, deltaFrame, keyFrame, dirtyRegion);
+ break;
+
+ default:
+ error("imageDeltaBlit: Unsupported keyframe image type for delta blit: %d",
+ static_cast<uint>(deltaFrame->getCompressionType()));
+ }
+}
+
+void VideoDisplayManager::fullDeltaRleBlitRectsClip(
+ Graphics::ManagedSurface *destinationImage,
+ const Common::Point &deltaFramePos,
+ const Common::Point &keyFrameOffset,
+ const Bitmap *deltaFrame,
+ const Bitmap *keyFrame,
+ const Common::Array<Common::Rect> &dirtyRegion) {
+
+ Graphics::ManagedSurface surface = decompressRle8Bitmap(deltaFrame, &keyFrame->_image, &keyFrameOffset);
+ for (const Common::Rect &dirtyRect : dirtyRegion) {
+ // The original has a fullDeltaRleBlit1Rect function, but given that we do
+ // the delta application when we decompress the keyframe above, we really
+ // don't need a separate function for this.
+ Common::Rect destRect(deltaFramePos, deltaFrame->width(), deltaFrame->height());
+ Common::Rect areaToRedraw = dirtyRect.findIntersectingRect(destRect);
+
+ if (!areaToRedraw.isEmpty()) {
+ // Calculate source coordinates (relative to source image).
+ Common::Point originOnScreen(areaToRedraw.origin());
+ areaToRedraw.translate(-deltaFramePos.x, -deltaFramePos.y);
+ destinationImage->simpleBlitFrom(surface, areaToRedraw, originOnScreen);
+ }
+ }
+}
+
+void VideoDisplayManager::deltaRleBlitRectsClip(
+ Graphics::ManagedSurface *destinationImage,
+ const Common::Point &deltaFramePos,
+ const Bitmap *deltaFrame,
+ const Bitmap *keyFrame,
+ const Common::Array<Common::Rect> &dirtyRegion) {
+
+ Common::Rect deltaFrameBounds = Common::Rect(deltaFramePos, deltaFrame->width(), deltaFrame->height());
+ for (const Common::Rect &dirtyRect : dirtyRegion) {
+ if (deltaFrameBounds.intersects(dirtyRect)) {
+ deltaRleBlit1Rect(destinationImage, deltaFramePos, deltaFrame, keyFrame, dirtyRect);
+ }
+ }
+}
+
+void VideoDisplayManager::deltaRleBlit1Rect(
+ Graphics::ManagedSurface *destinationImage,
+ const Common::Point &destinationPoint,
+ const Bitmap *deltaFrame,
+ const Bitmap *keyFrame,
+ const Common::Rect &dirtyRect) {
+
+ // This is a very complex function that attempts to decompress the keyframe
+ // and delta frame at the same time, assuming the keyframe is also
+ // compressed. However, real titles don't seem to use it, instead
+ // decompressing the keyframe separately and then passng it in.
+ // So this is left unimplemented until it's actually needed.
+ warning("STUB: deltaRleBlit1Rect");
+}
+
+Graphics::ManagedSurface VideoDisplayManager::decompressRle8Bitmap(
+ const Bitmap *source,
+ const Graphics::ManagedSurface *keyFrame,
+ const Common::Point *keyFrameOffset) {
+
+ // Create a surface to hold the decompressed bitmap.
+ Graphics::ManagedSurface dest;
+ dest.create(source->width(), source->height(), Graphics::PixelFormat::createFormatCLUT8());
+ dest.setTransparentColor(0);
+ int destSizeInBytes = source->width() * source->height();
+
+ Common::SeekableReadStream *chunk = source->_compressedStream;
+ chunk->seek(0);
+
+ bool imageFullyRead = false;
+ Common::Point sourcePos;
+ while (sourcePos.y < source->height()) {
+ sourcePos.x = 0;
+ while (true) {
+ if (sourcePos.y >= source->height()) {
+ break;
+ }
+
+ byte operation = chunk->readByte();
+ if (operation == 0x00) {
+ operation = chunk->readByte();
+ if (operation == 0x00) {
+ // Mark the end of the line.
+ // Also check if the image is finished being read.
+ if (chunk->eos()) {
+ imageFullyRead = true;
+ }
+ break;
+
+ } else if (operation == 0x01) {
+ // Mark the end of the image.
+ imageFullyRead = true;
+ break;
+
+ } else if (operation == 0x02) {
+ // Copy from the keyframe region.
+ assert((keyFrame != nullptr) && (keyFrameOffset != nullptr));
+ byte xToCopy = chunk->readByte();
+ byte yToCopy = chunk->readByte();
+
+ // If we requested to copy multiple lines, do that first.
+ for (int lineOffset = 0; lineOffset < yToCopy; lineOffset++) {
+ Common::Point keyFramePos = sourcePos - *keyFrameOffset + Common::Point(0, lineOffset);
+ Common::Point destPos = sourcePos + Common::Point(0, lineOffset);
+
+ bool sourceXInBounds = (keyFramePos.x >= 0) && (keyFramePos.x + xToCopy <= keyFrame->w);
+ bool sourceYInBounds = (keyFramePos.y >= 0) && (keyFramePos.y < keyFrame->h);
+ bool destInBounds = (destPos.y * dest.w) + (destPos.x + xToCopy) <= destSizeInBytes;
+ if (sourceXInBounds && sourceYInBounds && destInBounds) {
+ const byte *srcPtr = static_cast<const byte *>(keyFrame->getBasePtr(keyFramePos.x, keyFramePos.y));
+ byte *destPtr = static_cast<byte *>(dest.getBasePtr(destPos.x, destPos.y));
+ memcpy(destPtr, srcPtr, xToCopy);
+ } else {
+ warning("decompressRle8Bitmap: Keyframe copy (multi-line) exceeds bounds");
+ }
+ }
+
+ // Then copy the pixels in the same line.
+ Common::Point keyFramePos = sourcePos - *keyFrameOffset;
+ bool sourceXInBounds = (keyFramePos.x >= 0) && (keyFramePos.x + xToCopy <= keyFrame->w);
+ bool sourceYInBounds = (keyFramePos.y >= 0) && (keyFramePos.y < keyFrame->h);
+ bool destInBounds = (sourcePos.y * dest.w) + (sourcePos.x + xToCopy) <= destSizeInBytes;
+ if (sourceXInBounds && sourceYInBounds && destInBounds) {
+ const byte *srcPtr = static_cast<const byte *>(keyFrame->getBasePtr(keyFramePos.x, keyFramePos.y));
+ byte *destPtr = static_cast<byte *>(dest.getBasePtr(sourcePos.x, sourcePos.y));
+ memcpy(destPtr, srcPtr, xToCopy);
+ } else {
+ warning("decompressRle8Bitmap: Keyframe copy (same line) exceeds bounds");
+ }
+
+ sourcePos += Common::Point(xToCopy, yToCopy);
+
+ } else if (operation == 0x03) {
+ // Adjust the pixel position.
+ sourcePos.x += chunk->readByte();
+ sourcePos.y += chunk->readByte();
+
+ } else if (operation >= 0x04) {
+ // Read a run of uncompressed pixels.
+ // The bounds check is structured this way because the run can extend across scanlines.
+ byte runLength = operation;
+ uint maxAllowedRun = destSizeInBytes - (sourcePos.y * dest.w + sourcePos.x);
+ CLIP<uint>(runLength, 0, maxAllowedRun);
+
+ byte *destPtr = static_cast<byte *>(dest.getBasePtr(sourcePos.x, sourcePos.y));
+ chunk->read(destPtr, runLength);
+ if (chunk->pos() % 2 == 1) {
+ chunk->readByte();
+ }
+
+ sourcePos.x += runLength;
+ }
+ } else {
+ // Read a run of length encoded pixels.
+ byte colorIndexToRepeat = chunk->readByte();
+ byte repetitionCount = operation;
+ uint maxAllowedCount = destSizeInBytes - (sourcePos.y * dest.w + sourcePos.x);
+ CLIP<uint>(repetitionCount, 0, maxAllowedCount);
+
+ byte *destPtr = static_cast<byte *>(dest.getBasePtr(sourcePos.x, sourcePos.y));
+ memset(destPtr, colorIndexToRepeat, repetitionCount);
+ sourcePos.x += repetitionCount;
+ }
+ }
+
+ sourcePos.y++;
+ if (imageFullyRead) {
+ break;
+ }
+ }
+
+ return dest;
+}
+
+} // End of namespace MediaStation
diff --git a/engines/mediastation/graphics.h b/engines/mediastation/graphics.h
new file mode 100644
index 00000000000..25466a14c25
--- /dev/null
+++ b/engines/mediastation/graphics.h
@@ -0,0 +1,190 @@
+/* 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 "graphics/managed_surface.h"
+#include "graphics/screen.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
+};
+
+class VideoDisplayManager {
+public:
+ VideoDisplayManager(MediaStationEngine *vm);
+ ~VideoDisplayManager();
+
+ void updateScreen() { _screen->update(); }
+ Graphics::Palette *getRegisteredPalette() { return _registeredPalette; }
+ void setRegisteredPalette(Graphics::Palette *palette) { _registeredPalette = palette; }
+
+ void imageBlit(
+ const Common::Point &destinationPoint,
+ const Bitmap *image,
+ const double dissolveFactor,
+ const Common::Array<Common::Rect> &dirtyRegion,
+ Graphics::ManagedSurface *destinationImage = nullptr);
+
+ void imageDeltaBlit(
+ const Common::Point &deltaFramePos,
+ const Common::Point &keyFrameOffset,
+ const Bitmap *deltaFrame,
+ const Bitmap *keyFrame,
+ const double dissolveFactor,
+ const Common::Array<Common::Rect> &dirtyRegion);
+
+ void effectTransition(Common::Array<ScriptValue> &args);
+ void setTransitionOnSync(Common::Array<ScriptValue> &args) { _scheduledTransitionOnSync = args; }
+ void doTransitionOnSync();
+
+private:
+ static const uint SCREEN_WIDTH = 640;
+ static const uint SCREEN_HEIGHT = 480;
+
+ MediaStationEngine *_vm = nullptr;
+ Graphics::Screen *_screen = nullptr;
+ Graphics::Palette *_registeredPalette = nullptr;
+ Common::Array<ScriptValue> _scheduledTransitionOnSync;
+
+ // 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
diff --git a/engines/mediastation/mediastation.cpp b/engines/mediastation/mediastation.cpp
index d14216fc5ab..9fa02af597e 100644
--- a/engines/mediastation/mediastation.cpp
+++ b/engines/mediastation/mediastation.cpp
@@ -20,7 +20,6 @@
*/
#include "common/config-manager.h"
-#include "engines/util.h"
#include "mediastation/mediastation.h"
#include "mediastation/debugchannels.h"
@@ -54,8 +53,8 @@ MediaStationEngine::MediaStationEngine(OSystem *syst, const ADGameDescription *g
}
MediaStationEngine::~MediaStationEngine() {
- delete _screen;
- _screen = nullptr;
+ delete _displayManager;
+ _displayManager = nullptr;
delete _cursor;
_cursor = nullptr;
@@ -136,10 +135,7 @@ bool MediaStationEngine::isFirstGenerationEngine() {
}
Common::Error MediaStationEngine::run() {
- initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
- _screen = new Graphics::Screen();
- // TODO: Determine if all titles blank the screen to 0xff.
- _screen->fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0xff);
+ _displayManager = new VideoDisplayManager(this);
Common::Path bootStmFilepath = Common::Path("BOOT.STM");
_boot = new Boot(bootStmFilepath);
@@ -180,25 +176,23 @@ Common::Error MediaStationEngine::run() {
_requestedContextReleaseId.clear();
}
+ if (_requestedScreenBranchId != 0) {
+ doBranchToScreen();
+ _requestedScreenBranchId = 0;
+ }
+
debugC(5, kDebugGraphics, "***** START SCREEN UPDATE ***");
for (Asset *asset : _assets) {
asset->process();
- if (_requestedScreenBranchId != 0) {
- doBranchToScreen();
- _requestedScreenBranchId = 0;
- break;
- }
-
if (_needsHotspotRefresh) {
refreshActiveHotspot();
_needsHotspotRefresh = false;
}
}
- redraw();
+ draw();
debugC(5, kDebugGraphics, "***** END SCREEN UPDATE ***");
- _screen->update();
g_system->delayMillis(10);
}
@@ -296,33 +290,21 @@ void MediaStationEngine::refreshActiveHotspot() {
}
}
-void MediaStationEngine::redraw() {
- if (_dirtyRects.empty()) {
- return;
- }
-
- for (Common::Rect dirtyRect : _dirtyRects) {
+void MediaStationEngine::draw() {
+ if (!_dirtyRects.empty()) {
for (Asset *asset : _spatialEntities) {
- if (!asset->isSpatialActor()) {
- continue;
- }
-
- SpatialEntity *entity = static_cast<SpatialEntity *>(asset);
- if (!entity->isVisible()) {
- continue;
- }
-
- Common::Rect bbox = entity->getBbox();
- if (!bbox.isEmpty()) {
- if (dirtyRect.intersects(bbox)) {
- entity->redraw(dirtyRect);
+ if (asset->isSpatialActor()) {
+ SpatialEntity *entity = static_cast<SpatialEntity *>(asset);
+ if (entity->isVisible()) {
+ entity->draw(_dirtyRects);
}
}
}
- }
- _screen->update();
- _dirtyRects.clear();
+ _dirtyRects.clear();
+ }
+ _displayManager->updateScreen();
+ _displayManager->doTransitionOnSync();
}
Context *MediaStationEngine::loadContext(uint32 contextId) {
@@ -363,28 +345,10 @@ Context *MediaStationEngine::loadContext(uint32 contextId) {
}
Context *context = new Context(entryCxtFilepath);
- // Some contexts have a built-in palette that becomes active when the
- // context is loaded, and some rely on scripts to set
- // the palette later.
- if (context->_palette != nullptr) {
- _screen->setPalette(*context->_palette);
- }
-
_loadedContexts.setVal(contextId, context);
return context;
}
-void MediaStationEngine::setPalette(Asset *asset) {
- if (asset == nullptr) {
- error("Requested palette not found");
- } else if (asset->type() != kAssetTypePalette) {
- error("Requested palette %d is not a palette", asset->id());
- } else {
- Palette *paletteAsset = static_cast<Palette *>(asset);
- _screen->setPalette(*paletteAsset->_palette);
- }
-}
-
void MediaStationEngine::registerAsset(Asset *assetToAdd) {
if (getAssetById(assetToAdd->id())) {
error("Asset with ID 0x%d was already defined in this title", assetToAdd->id());
@@ -410,13 +374,12 @@ void MediaStationEngine::doBranchToScreen() {
releaseContext(_currentContext->_screenAsset->id());
}
- Context *context = loadContext(_requestedScreenBranchId);
- _currentContext = context;
- _dirtyRects.push_back(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT));
+ _currentContext = loadContext(_requestedScreenBranchId);
_currentHotspot = nullptr;
+ _displayManager->setRegisteredPalette(_currentContext->_palette);
- if (context->_screenAsset != nullptr) {
- context->_screenAsset->runEventHandlerIfExists(kEntryEvent);
+ if (_currentContext->_screenAsset != nullptr) {
+ _currentContext->_screenAsset->runEventHandlerIfExists(kEntryEvent);
}
_requestedScreenBranchId = 0;
@@ -488,11 +451,12 @@ ScriptValue MediaStationEngine::callBuiltInFunction(BuiltInFunction function, Co
switch (function) {
case kEffectTransitionFunction:
- case kEffectTransitionOnSyncFunction: {
- // TODO: effectTransitionOnSync should be split out into its own function.
- effectTransition(args);
+ _displayManager->effectTransition(args);
+ return returnValue;
+
+ case kEffectTransitionOnSyncFunction:
+ _displayManager->setTransitionOnSync(args);
return returnValue;
- }
case kDrawingFunction: {
// Not entirely sure what this function does, but it seems like a way to
diff --git a/engines/mediastation/mediastation.h b/engines/mediastation/mediastation.h
index 8189da60b5e..609abb783c4 100644
--- a/engines/mediastation/mediastation.h
+++ b/engines/mediastation/mediastation.h
@@ -34,7 +34,6 @@
#include "common/util.h"
#include "engines/engine.h"
#include "engines/savestate.h"
-#include "graphics/screen.h"
#include "mediastation/detection.h"
#include "mediastation/datafile.h"
@@ -42,11 +41,13 @@
#include "mediastation/context.h"
#include "mediastation/asset.h"
#include "mediastation/cursors.h"
+#include "mediastation/graphics.h"
namespace MediaStation {
struct MediaStationGameDescription;
class Hotspot;
+class Bitmap;
// Most Media Station titles follow this file structure from the root directory
// of the CD-ROM:
@@ -78,9 +79,9 @@ public:
bool isFirstGenerationEngine();
void processEvents();
void refreshActiveHotspot();
- void redraw();
+ void addDirtyRect(const Common::Rect &rect) { _dirtyRects.push_back(rect); }
+ void draw();
- void setPalette(Asset *palette);
void registerAsset(Asset *assetToAdd);
void scheduleScreenBranch(uint screenId);
void scheduleContextRelease(uint contextId);
@@ -89,21 +90,16 @@ public:
Asset *getAssetByChunkReference(uint chunkReference);
Function *getFunctionById(uint functionId);
ScriptValue *getVariable(uint variableId);
+ VideoDisplayManager *getDisplayManager() { return _displayManager; }
ScriptValue callBuiltInFunction(BuiltInFunction function, Common::Array<ScriptValue> &args);
Common::RandomSource _randomSource;
- Graphics::Screen *_screen = nullptr;
Context *_currentContext = nullptr;
Common::Point _mousePos;
- Common::Array<Common::Rect> _dirtyRects;
bool _needsHotspotRefresh = false;
- // All Media Station titles run at 640x480.
- const uint16 SCREEN_WIDTH = 640;
- const uint16 SCREEN_HEIGHT = 480;
-
protected:
Common::Error run() override;
@@ -111,28 +107,28 @@ private:
Common::Event _event;
Common::FSNode _gameDataDir;
const ADGameDescription *_gameDescription;
+ Common::Array<Common::Rect> _dirtyRects;
// In Media Station, only the cursors are stored in the executable; everything
// else is in the Context (*.CXT) data files.
CursorManager *_cursor;
void setCursor(uint id);
+ VideoDisplayManager *_displayManager = nullptr;
+
Boot *_boot = nullptr;
Common::Array<Asset *> _assets;
Common::SortedArray<SpatialEntity *, const SpatialEntity *> _spatialEntities;
Common::HashMap<uint, Context *> _loadedContexts;
Asset *_currentHotspot = nullptr;
-
uint _requestedScreenBranchId = 0;
Common::Array<uint> _requestedContextReleaseId;
- void doBranchToScreen();
+ void doBranchToScreen();
Context *loadContext(uint32 contextId);
void releaseContext(uint32 contextId);
Asset *findAssetToAcceptMouseEvents();
- void effectTransition(Common::Array<ScriptValue> &args);
-
static int compareAssetByZIndex(const SpatialEntity *a, const SpatialEntity *b);
};
diff --git a/engines/mediastation/module.mk b/engines/mediastation/module.mk
index a32a467c3f3..b86556b3dcc 100644
--- a/engines/mediastation/module.mk
+++ b/engines/mediastation/module.mk
@@ -21,6 +21,7 @@ MODULE_OBJS = \
context.o \
cursors.o \
datafile.o \
+ graphics.o \
mediascript/codechunk.o \
mediascript/collection.o \
mediascript/eventhandler.o \
@@ -28,8 +29,7 @@ MODULE_OBJS = \
mediascript/scriptconstants.o \
mediascript/scriptvalue.o \
mediastation.o \
- metaengine.o \
- transitions.o
+ metaengine.o
# This module can be built as a plugin
ifeq ($(ENABLE_MEDIASTATION), DYNAMIC_PLUGIN)
diff --git a/engines/mediastation/transitions.cpp b/engines/mediastation/transitions.cpp
deleted file mode 100644
index 14b23e267ef..00000000000
--- a/engines/mediastation/transitions.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/* 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"
-
-namespace MediaStation {
-
-enum TransitionType {
- kTransitionFadeToBlack = 300,
- kTransitionFadeToPalette = 301,
- kTransitionSetToPalette = 302,
- kTransitionSetToBlack = 303,
- kTransitionFadeToColor = 304,
- kTransitionSetToColor = 305,
- kTransitionSetToPercentOfPalette = 306,
- kTransitionFadeToPaletteObject = 307,
- kTransitionSetToPaletteObject = 308,
- kTransitionSetToPercentOfPaletteObject = 309,
- kTransitionCircleOut = 328
-};
-
-void MediaStationEngine::effectTransition(Common::Array<ScriptValue> &args) {
- TransitionType transitionType = static_cast<TransitionType>(args[0].asParamToken());
- switch (transitionType) {
- case kTransitionFadeToBlack:
- case kTransitionSetToBlack: {
- // TODO: Implement transition.
- warning("MediaStationEngine::effectTransition(): Fading/setting to black not implemented");
- break;
- }
-
- case kTransitionFadeToPalette:
- case kTransitionSetToPalette: {
- // TODO: Implement transition by getting palette out of current context.
- warning("MediaStationEngine::effectTransition(): Fading/setting to palette not implemented, changing palette immediately");
- break;
- }
-
- case kTransitionFadeToColor:
- case kTransitionSetToColor: {
- // TODO: Implement transitions.
- warning("MediaStationEngine::effectTransition(): Fading/setting to color not implemented");
- break;
- }
-
- case kTransitionFadeToPaletteObject: {
- // TODO: Implement transition.
- warning("MediaStationEngine::effectTransition(): Fading to palette object not implemented, changing palette immediately");
- Asset *asset = g_engine->getAssetById(args[1].asAssetId());
- g_engine->setPalette(asset);
- break;
- }
-
- case kTransitionSetToPaletteObject: {
- Asset *asset = g_engine->getAssetById(args[1].asAssetId());
- g_engine->setPalette(asset);
- break;
- }
-
- case kTransitionSetToPercentOfPaletteObject: {
- double percentComplete = args[1].asFloat();
-
- // TODO: Implement percent of palette transition.
- warning("MediaStationEngine::effectTransition(): Setting to %f%% of palette not implemented, changing palette immediately", percentComplete);
- Asset *asset = g_engine->getAssetById(args[2].asAssetId());
- g_engine->setPalette(asset);
- break;
- }
-
- case kTransitionCircleOut: {
- warning("MediaStationEngine::effectTransition(): Circle out transition not implemented");
- break;
- }
-
- default:
- warning("MediaStationEngine::effectTransition(): Got unknown transition type %d", static_cast<uint>(transitionType));
- }
-}
-
-} // End of namespace MediaStation
\ No newline at end of file
More information about the Scummvm-git-logs
mailing list