aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mohawk/console.cpp2
-rw-r--r--engines/mohawk/cstime.h2
-rw-r--r--engines/mohawk/cstime_graphics.cpp64
-rw-r--r--engines/mohawk/cstime_graphics.h51
-rw-r--r--engines/mohawk/graphics.cpp1001
-rw-r--r--engines/mohawk/graphics.h195
-rw-r--r--engines/mohawk/livingbooks.h2
-rw-r--r--engines/mohawk/livingbooks_graphics.cpp102
-rw-r--r--engines/mohawk/livingbooks_graphics.h52
-rw-r--r--engines/mohawk/module.mk4
-rw-r--r--engines/mohawk/myst.cpp2
-rw-r--r--engines/mohawk/myst_areas.cpp2
-rw-r--r--engines/mohawk/myst_areas.h6
-rw-r--r--engines/mohawk/myst_graphics.cpp493
-rw-r--r--engines/mohawk/myst_graphics.h102
-rw-r--r--engines/mohawk/myst_scripts.cpp2
-rw-r--r--engines/mohawk/myst_stacks/channelwood.cpp2
-rw-r--r--engines/mohawk/myst_stacks/credits.cpp2
-rw-r--r--engines/mohawk/myst_stacks/demo.cpp2
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp2
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp2
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp2
-rw-r--r--engines/mohawk/myst_stacks/preview.cpp2
-rw-r--r--engines/mohawk/myst_stacks/slides.cpp2
-rw-r--r--engines/mohawk/myst_stacks/stoneship.cpp2
-rw-r--r--engines/mohawk/riven.cpp2
-rw-r--r--engines/mohawk/riven_external.cpp2
-rw-r--r--engines/mohawk/riven_graphics.cpp445
-rw-r--r--engines/mohawk/riven_graphics.h110
-rw-r--r--engines/mohawk/riven_scripts.cpp2
-rw-r--r--engines/mohawk/riven_scripts.h3
31 files changed, 1449 insertions, 1215 deletions
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index 0234c86c7e..a7a650d8ed 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -21,7 +21,6 @@
*/
#include "mohawk/console.h"
-#include "mohawk/graphics.h"
#include "mohawk/livingbooks.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
@@ -36,6 +35,7 @@
#ifdef ENABLE_MYST
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_scripts.h"
#endif
diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h
index 0bc236f930..db06b9791e 100644
--- a/engines/mohawk/cstime.h
+++ b/engines/mohawk/cstime.h
@@ -25,7 +25,7 @@
#include "mohawk/mohawk.h"
#include "mohawk/console.h"
-#include "mohawk/graphics.h"
+#include "mohawk/cstime_graphics.h"
#include "common/random.h"
#include "common/list.h"
diff --git a/engines/mohawk/cstime_graphics.cpp b/engines/mohawk/cstime_graphics.cpp
new file mode 100644
index 0000000000..3a1452e67c
--- /dev/null
+++ b/engines/mohawk/cstime_graphics.cpp
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mohawk/cstime.h"
+#include "mohawk/cstime_graphics.h"
+#include "mohawk/resource.h"
+
+#include "common/system.h"
+#include "engines/util.h"
+
+namespace Mohawk {
+
+CSTimeGraphics::CSTimeGraphics(MohawkEngine_CSTime *vm) : GraphicsManager(), _vm(vm) {
+ _bmpDecoder = new MohawkBitmap();
+
+ initGraphics(640, 480, true);
+}
+
+CSTimeGraphics::~CSTimeGraphics() {
+ delete _bmpDecoder;
+}
+
+void CSTimeGraphics::drawRect(Common::Rect rect, byte color) {
+ rect.clip(Common::Rect(640, 480));
+
+ // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active.
+ if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0)
+ return;
+
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+
+ screen->frameRect(rect, color);
+
+ _vm->_system->unlockScreen();
+}
+
+MohawkSurface *CSTimeGraphics::decodeImage(uint16 id) {
+ return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id));
+}
+
+Common::Array<MohawkSurface *> CSTimeGraphics::decodeImages(uint16 id) {
+ return _bmpDecoder->decodeImages(_vm->getResource(ID_TBMH, id));
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/cstime_graphics.h b/engines/mohawk/cstime_graphics.h
new file mode 100644
index 0000000000..5f034f47f4
--- /dev/null
+++ b/engines/mohawk/cstime_graphics.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MOHAWK_CSTIME_GRAPHICS_H
+#define MOHAWK_CSTIME_GRAPHICS_H
+
+#include "mohawk/graphics.h"
+
+namespace Mohawk {
+
+class MohawkEngine_CSTime;
+
+class CSTimeGraphics : public GraphicsManager {
+public:
+ CSTimeGraphics(MohawkEngine_CSTime *vm);
+ ~CSTimeGraphics();
+
+ void drawRect(Common::Rect rect, byte color);
+
+protected:
+ MohawkSurface *decodeImage(uint16 id);
+ Common::Array<MohawkSurface *> decodeImages(uint16 id);
+ MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
+
+private:
+ MohawkBitmap *_bmpDecoder;
+ MohawkEngine_CSTime *_vm;
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp
index 2ffabf1e8c..a08d034ef7 100644
--- a/engines/mohawk/graphics.cpp
+++ b/engines/mohawk/graphics.cpp
@@ -20,30 +20,13 @@
*
*/
+#include "mohawk/mohawk.h"
#include "mohawk/resource.h"
#include "mohawk/graphics.h"
-#include "mohawk/livingbooks.h"
-#include "common/substream.h"
#include "common/system.h"
-#include "common/textconsole.h"
#include "engines/util.h"
#include "graphics/palette.h"
-#include "graphics/primitives.h"
-#include "gui/message.h"
-
-#ifdef ENABLE_CSTIME
-#include "mohawk/cstime.h"
-#endif
-
-#ifdef ENABLE_MYST
-#include "mohawk/myst.h"
-#include "graphics/jpeg.h"
-#endif
-
-#ifdef ENABLE_RIVEN
-#include "mohawk/riven.h"
-#endif
namespace Mohawk {
@@ -262,986 +245,4 @@ void GraphicsManager::addImageToCache(uint16 id, MohawkSurface *surface) {
_cache[id] = surface;
}
-#ifdef ENABLE_MYST
-
-MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
- _bmpDecoder = new MystBitmap();
-
- _viewport = Common::Rect(544, 332);
-
- // The original version of Myst could run in 8bpp color too.
- // However, it dithered videos to 8bpp and they looked considerably
- // worse (than they already did :P). So we're not even going to
- // support 8bpp mode in Myst (Myst ME required >8bpp anyway).
- initGraphics(_viewport.width(), _viewport.height(), true, NULL); // What an odd screen size!
-
- _pixelFormat = _vm->_system->getScreenFormat();
-
- if (_pixelFormat.bytesPerPixel == 1)
- error("Myst requires greater than 256 colors to run");
-
- if (_vm->getFeatures() & GF_ME) {
- _jpegDecoder = new Graphics::JPEG();
- _pictDecoder = new Graphics::PictDecoder(_pixelFormat);
- } else {
- _jpegDecoder = NULL;
- _pictDecoder = NULL;
- }
-
- _pictureFile.entries = NULL;
-
- // Initialize our buffer
- _backBuffer = new Graphics::Surface();
- _backBuffer->create(_vm->_system->getWidth(), _vm->_system->getHeight(), _pixelFormat);
-
- _nextAllowedDrawTime = _vm->_system->getMillis();
- _enableDrawingTimeSimulation = 0;
-}
-
-MystGraphics::~MystGraphics() {
- delete _bmpDecoder;
- delete _jpegDecoder;
- delete _pictDecoder;
- delete[] _pictureFile.entries;
-
- _backBuffer->free();
- delete _backBuffer;
-}
-
-static const char *s_picFileNames[] = {
- "CHpics",
- "",
- "",
- "DUpics",
- "INpics",
- "",
- "MEpics",
- "MYpics",
- "SEpics",
- "",
- "",
- "STpics"
-};
-
-void MystGraphics::loadExternalPictureFile(uint16 stack) {
- if (_vm->getPlatform() != Common::kPlatformMacintosh)
- return;
-
- if (_pictureFile.picFile.isOpen())
- _pictureFile.picFile.close();
- delete[] _pictureFile.entries;
-
- if (!scumm_stricmp(s_picFileNames[stack], ""))
- return;
-
- if (!_pictureFile.picFile.open(s_picFileNames[stack]))
- error ("Could not open external picture file \'%s\'", s_picFileNames[stack]);
-
- _pictureFile.pictureCount = _pictureFile.picFile.readUint32BE();
- _pictureFile.entries = new PictureFile::PictureEntry[_pictureFile.pictureCount];
-
- for (uint32 i = 0; i < _pictureFile.pictureCount; i++) {
- _pictureFile.entries[i].offset = _pictureFile.picFile.readUint32BE();
- _pictureFile.entries[i].size = _pictureFile.picFile.readUint32BE();
- _pictureFile.entries[i].id = _pictureFile.picFile.readUint16BE();
- _pictureFile.entries[i].type = _pictureFile.picFile.readUint16BE();
- _pictureFile.entries[i].width = _pictureFile.picFile.readUint16BE();
- _pictureFile.entries[i].height = _pictureFile.picFile.readUint16BE();
- }
-}
-
-MohawkSurface *MystGraphics::decodeImage(uint16 id) {
- MohawkSurface *mhkSurface = 0;
-
- // Myst ME uses JPEG/PICT images instead of compressed Windows Bitmaps for room images,
- // though there are a few weird ones that use that format. For further nonsense with images,
- // the Macintosh version stores images in external "picture files." We check them before
- // going to check for a PICT resource.
- if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) {
- for (uint32 i = 0; i < _pictureFile.pictureCount; i++)
- if (_pictureFile.entries[i].id == id) {
- if (_pictureFile.entries[i].type == 0) {
- Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size);
-
- if (!_jpegDecoder->read(stream))
- error("Could not decode Myst ME Mac JPEG");
-
- mhkSurface = new MohawkSurface(_jpegDecoder->getSurface(_pixelFormat));
- delete stream;
- } else if (_pictureFile.entries[i].type == 1) {
- mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size)));
- } else
- error ("Unknown Picture File type %d", _pictureFile.entries[i].type);
- break;
- }
- }
-
- // We're not using the external Mac files, so it's time to delve into the main Mohawk
- // archives. However, we still don't know if it's a PICT or WDIB resource. If it's Myst
- // ME it's most likely a PICT, and if it's original it's definitely a WDIB. However,
- // Myst ME throws us another curve ball in that PICT resources can contain WDIB's instead
- // of PICT's.
- if (!mhkSurface) {
- bool isPict = false;
- Common::SeekableReadStream *dataStream = NULL;
-
- if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) {
- // The PICT resource exists. However, it could still contain a MystBitmap
- // instead of a PICT image...
- dataStream = _vm->getResource(ID_PICT, id);
- } else // No PICT, so the WDIB must exist. Let's go grab it.
- dataStream = _vm->getResource(ID_WDIB, id);
-
- if (_vm->getFeatures() & GF_ME) {
- // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap
- // would be compressed, there's no way to detect for the BM without a hack.
- // So, we search for the PICT version opcode for detection.
- dataStream->seek(512 + 10); // 512 byte pict header
- isPict = (dataStream->readUint32BE() == 0x001102FF);
- dataStream->seek(0);
- }
-
- if (isPict)
- mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(dataStream));
- else {
- mhkSurface = _bmpDecoder->decodeImage(dataStream);
- mhkSurface->convertToTrueColor();
- }
- }
-
- assert(mhkSurface);
- return mhkSurface;
-}
-
-void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest) {
- Graphics::Surface *surface = findImage(image)->getSurface();
-
- // Make sure the image is bottom aligned in the dest rect
- dest.top = dest.bottom - MIN<int>(surface->h, dest.height());
-
- // Convert from bitmap coordinates to surface coordinates
- uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height()));
-
- // Do not draw the top pixels if the image is too tall
- if (dest.height() > _viewport.height())
- top += dest.height() - _viewport.height();
-
- // Clip the destination rect to the screen
- if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight())
- dest.debugPrint(4, "Clipping destination rect to the screen");
- dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth());
- dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight());
-
- uint16 width = MIN<int>(surface->w, dest.width());
- uint16 height = MIN<int>(surface->h, dest.height());
-
- // Clamp Width and Height to within src surface dimensions
- if (src.left + width > surface->w)
- width = surface->w - src.left;
- if (src.top + height > surface->h)
- height = surface->h - src.top;
-
- debug(3, "MystGraphics::copyImageSectionToScreen()");
- debug(3, "\tImage: %d", image);
- debug(3, "\tsrc.left: %d", src.left);
- debug(3, "\tsrc.top: %d", src.top);
- debug(3, "\tdest.left: %d", dest.left);
- debug(3, "\tdest.top: %d", dest.top);
- debug(3, "\twidth: %d", width);
- debug(3, "\theight: %d", height);
-
- simulatePreviousDrawDelay(dest);
-
- _vm->_system->copyRectToScreen((byte *)surface->getBasePtr(src.left, top), surface->pitch, dest.left, dest.top, width, height);
-}
-
-void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest) {
- Graphics::Surface *surface = findImage(image)->getSurface();
-
- // Make sure the image is bottom aligned in the dest rect
- dest.top = dest.bottom - MIN<int>(surface->h, dest.height());
-
- // Convert from bitmap coordinates to surface coordinates
- uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height()));
-
- // Do not draw the top pixels if the image is too tall
- if (dest.height() > _viewport.height()) {
- top += dest.height() - _viewport.height();
- }
-
- // Clip the destination rect to the screen
- if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight())
- dest.debugPrint(4, "Clipping destination rect to the screen");
- dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth());
- dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight());
-
- uint16 width = MIN<int>(surface->w, dest.width());
- uint16 height = MIN<int>(surface->h, dest.height());
-
- // Clamp Width and Height to within src surface dimensions
- if (src.left + width > surface->w)
- width = surface->w - src.left;
- if (src.top + height > surface->h)
- height = surface->h - src.top;
-
- debug(3, "MystGraphics::copyImageSectionToBackBuffer()");
- debug(3, "\tImage: %d", image);
- debug(3, "\tsrc.left: %d", src.left);
- debug(3, "\tsrc.top: %d", src.top);
- debug(3, "\tdest.left: %d", dest.left);
- debug(3, "\tdest.top: %d", dest.top);
- debug(3, "\twidth: %d", width);
- debug(3, "\theight: %d", height);
-
- for (uint16 i = 0; i < height; i++)
- memcpy(_backBuffer->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->format.bytesPerPixel);
-}
-
-void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) {
- copyImageSectionToScreen(image, Common::Rect(544, 333), dest);
-}
-
-void MystGraphics::copyImageToBackBuffer(uint16 image, Common::Rect dest) {
- copyImageSectionToBackBuffer(image, Common::Rect(544, 333), dest);
-}
-
-void MystGraphics::copyBackBufferToScreen(Common::Rect r) {
- r.clip(_viewport);
-
- simulatePreviousDrawDelay(r);
-
- _vm->_system->copyRectToScreen((byte *)_backBuffer->getBasePtr(r.left, r.top), _backBuffer->pitch, r.left, r.top, r.width(), r.height());
-}
-
-void MystGraphics::runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay) {
-
- // Do not artificially delay during transitions
- int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation;
- _enableDrawingTimeSimulation = 0;
-
- switch (type) {
- case 0: {
- debugC(kDebugScript, "Left to Right");
-
- uint16 step = (rect.right - rect.left) / steps;
- Common::Rect area = rect;
- for (uint i = 0; i < steps; i++) {
- area.left = rect.left + step * i;
- area.right = area.left + step;
-
- _vm->_system->delayMillis(delay);
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- if (area.right < rect.right) {
- area.left = area.right;
- area.right = rect.right;
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- }
- break;
- case 1: {
- debugC(kDebugScript, "Right to Left");
-
- uint16 step = (rect.right - rect.left) / steps;
- Common::Rect area = rect;
- for (uint i = 0; i < steps; i++) {
- area.right = rect.right - step * i;
- area.left = area.right - step;
-
- _vm->_system->delayMillis(delay);
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- if (area.left > rect.left) {
- area.right = area.left;
- area.left = rect.left;
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- }
- break;
- case 5: {
- debugC(kDebugScript, "Top to Bottom");
-
- uint16 step = (rect.bottom - rect.top) / steps;
- Common::Rect area = rect;
- for (uint i = 0; i < steps; i++) {
- area.top = rect.top + step * i;
- area.bottom = area.top + step;
-
- _vm->_system->delayMillis(delay);
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- if (area.bottom < rect.bottom) {
- area.top = area.bottom;
- area.bottom = rect.bottom;
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- }
- break;
- case 6: {
- debugC(kDebugScript, "Bottom to Top");
-
- uint16 step = (rect.bottom - rect.top) / steps;
- Common::Rect area = rect;
- for (uint i = 0; i < steps; i++) {
- area.bottom = rect.bottom - step * i;
- area.top = area.bottom - step;
-
- _vm->_system->delayMillis(delay);
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- if (area.top > rect.top) {
- area.bottom = area.top;
- area.top = rect.top;
-
- copyBackBufferToScreen(area);
- _vm->_system->updateScreen();
- }
- }
- break;
- default:
- warning("Unknown Update Direction");
-
- //TODO: Replace minimal implementation
- copyBackBufferToScreen(rect);
- _vm->_system->updateScreen();
- break;
- }
-
- _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation;
-}
-
-void MystGraphics::drawRect(Common::Rect rect, RectState state) {
- rect.clip(_viewport);
-
- // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active.
- if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0)
- return;
-
- Graphics::Surface *screen = _vm->_system->lockScreen();
-
- if (state == kRectEnabled)
- screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0));
- else if (state == kRectUnreachable)
- screen->frameRect(rect, _pixelFormat.RGBToColor(0, 0, 255));
- else
- screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0));
-
- _vm->_system->unlockScreen();
-}
-
-void MystGraphics::drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color) {
- _backBuffer->drawLine(p1.x, p1.y, p2.x, p2.y, color);
-}
-
-void MystGraphics::enableDrawingTimeSimulation(bool enable) {
- if (enable)
- _enableDrawingTimeSimulation++;
- else
- _enableDrawingTimeSimulation--;
-
- if (_enableDrawingTimeSimulation < 0)
- _enableDrawingTimeSimulation = 0;
-}
-
-void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) {
- uint32 time = 0;
-
- if (_enableDrawingTimeSimulation) {
- time = _vm->_system->getMillis();
-
- // Do not draw anything new too quickly after the previous draw call
- // so that images stay at least a little while on screen
- // This is enabled only for scripted draw calls
- if (time < _nextAllowedDrawTime)
- _vm->_system->delayMillis(_nextAllowedDrawTime - time);
- }
-
- // Next draw call allowed at DELAY + AERA * COEFF milliseconds from now
- time = _vm->_system->getMillis();
- _nextAllowedDrawTime = time + _constantDrawDelay + dest.height() * dest.width() / _proportionalDrawDelay;
-}
-
-void MystGraphics::copyBackBufferToScreenWithSaturation(int16 saturation) {
- Graphics::Surface *screen = _vm->_system->lockScreen();
-
- for (uint16 y = 0; y < _viewport.height(); y++)
- for (uint16 x = 0; x < _viewport.width(); x++) {
- uint32 color;
- uint8 r, g, b;
-
- if (_pixelFormat.bytesPerPixel == 2)
- color = *(const uint16 *)_backBuffer->getBasePtr(x, y);
- else
- color = *(const uint32 *)_backBuffer->getBasePtr(x, y);
-
- _pixelFormat.colorToRGB(color, r, g, b);
-
- r = CLIP<int16>((int16)r - saturation, 0, 255);
- g = CLIP<int16>((int16)g - saturation, 0, 255);
- b = CLIP<int16>((int16)b - saturation, 0, 255);
-
- color = _pixelFormat.RGBToColor(r, g, b);
-
- if (_pixelFormat.bytesPerPixel == 2) {
- uint16 *dst = (uint16 *)screen->getBasePtr(x, y);
- *dst = color;
- } else {
- uint32 *dst = (uint32 *)screen->getBasePtr(x, y);
- *dst = color;
- }
- }
-
- _vm->_system->unlockScreen();
- _vm->_system->updateScreen();
-}
-
-void MystGraphics::fadeToBlack() {
- for (int16 i = 0; i < 256; i += 32) {
- copyBackBufferToScreenWithSaturation(i);
- }
-}
-
-void MystGraphics::fadeFromBlack() {
- for (int16 i = 256; i >= 0; i -= 32) {
- copyBackBufferToScreenWithSaturation(i);
- }
-}
-
-#endif // ENABLE_MYST
-
-#ifdef ENABLE_RIVEN
-
-RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm) {
- _bitmapDecoder = new MohawkBitmap();
-
- // Give me the best you've got!
- initGraphics(608, 436, true, NULL);
- _pixelFormat = _vm->_system->getScreenFormat();
-
- if (_pixelFormat.bytesPerPixel == 1)
- error("Riven requires greater than 256 colors to run");
-
- // The actual game graphics only take up the first 392 rows. The inventory
- // occupies the rest of the screen and we don't use the buffer to hold that.
- _mainScreen = new Graphics::Surface();
- _mainScreen->create(608, 392, _pixelFormat);
-
- _updatesEnabled = true;
- _scheduledTransition = -1; // no transition
- _dirtyScreen = false;
- _inventoryDrawn = false;
-
- _creditsImage = 302;
- _creditsPos = 0;
-}
-
-RivenGraphics::~RivenGraphics() {
- _mainScreen->free();
- delete _mainScreen;
- delete _bitmapDecoder;
-}
-
-MohawkSurface *RivenGraphics::decodeImage(uint16 id) {
- MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getResource(ID_TBMP, id));
- surface->convertToTrueColor();
- return surface;
-}
-
-void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uint32 right, uint32 bottom) {
- Graphics::Surface *surface = findImage(image)->getSurface();
-
- // Clip the width to fit on the screen. Fixes some images.
- if (left + surface->w > 608)
- surface->w = 608 - left;
-
- for (uint16 i = 0; i < surface->h; i++)
- memcpy(_mainScreen->getBasePtr(left, i + top), surface->getBasePtr(0, i), surface->w * surface->format.bytesPerPixel);
-
- _dirtyScreen = true;
-}
-
-void RivenGraphics::drawPLST(uint16 x) {
- Common::SeekableReadStream* plst = _vm->getResource(ID_PLST, _vm->getCurCard());
- uint16 recordCount = plst->readUint16BE();
-
- for (uint16 i = 0; i < recordCount; i++) {
- uint16 index = plst->readUint16BE();
- uint16 id = plst->readUint16BE();
- uint16 left = plst->readUint16BE();
- uint16 top = plst->readUint16BE();
- uint16 right = plst->readUint16BE();
- uint16 bottom = plst->readUint16BE();
-
- // We are also checking here to make sure we haven't drawn the image yet on screen.
- // This fixes problems with drawing PLST 1 twice and some other images twice. PLST
- // 1 is sometimes not called by the scripts, so some cards don't appear if we don't
- // draw PLST 1 each time. This "hack" is here to catch any PLST attempting to draw
- // twice. There should never be a problem with doing it this way.
- if (index == x && !(Common::find(_activatedPLSTs.begin(), _activatedPLSTs.end(), x) != _activatedPLSTs.end())) {
- debug(0, "Drawing image %d", id);
- copyImageToScreen(id, left, top, right, bottom);
- _activatedPLSTs.push_back(x);
- break;
- }
- }
-
- delete plst;
-}
-
-void RivenGraphics::updateScreen(Common::Rect updateRect) {
- if (_updatesEnabled) {
- _vm->runUpdateScreenScript();
-
- if (_dirtyScreen) {
- _activatedPLSTs.clear();
-
- // Copy to screen if there's no transition. Otherwise transition. ;)
- if (_scheduledTransition < 0)
- _vm->_system->copyRectToScreen((byte *)_mainScreen->getBasePtr(updateRect.left, updateRect.top), _mainScreen->pitch, updateRect.left, updateRect.top, updateRect.width(), updateRect.height());
- else
- runScheduledTransition();
-
- // Finally, update the screen.
- _vm->_system->updateScreen();
- _dirtyScreen = false;
- }
- }
-}
-
-void RivenGraphics::scheduleWaterEffect(uint16 sfxeID) {
- Common::SeekableReadStream *sfxeStream = _vm->getResource(ID_SFXE, sfxeID);
-
- if (sfxeStream->readUint16BE() != 'SL')
- error ("Unknown sfxe tag");
-
- // Read in header info
- SFXERecord sfxeRecord;
- sfxeRecord.frameCount = sfxeStream->readUint16BE();
- uint32 offsetTablePosition = sfxeStream->readUint32BE();
- sfxeRecord.rect.left = sfxeStream->readUint16BE();
- sfxeRecord.rect.top = sfxeStream->readUint16BE();
- sfxeRecord.rect.right = sfxeStream->readUint16BE();
- sfxeRecord.rect.bottom = sfxeStream->readUint16BE();
- sfxeRecord.speed = sfxeStream->readUint16BE();
- // Skip the rest of the fields...
-
- // Read in offsets
- sfxeStream->seek(offsetTablePosition);
- uint32 *frameOffsets = new uint32[sfxeRecord.frameCount];
- for (uint16 i = 0; i < sfxeRecord.frameCount; i++)
- frameOffsets[i] = sfxeStream->readUint32BE();
- sfxeStream->seek(frameOffsets[0]);
-
- // Read in the scripts
- for (uint16 i = 0; i < sfxeRecord.frameCount; i++)
- sfxeRecord.frameScripts.push_back(sfxeStream->readStream((i == sfxeRecord.frameCount - 1) ? sfxeStream->size() - frameOffsets[i] : frameOffsets[i + 1] - frameOffsets[i]));
-
- // Set it to the first frame
- sfxeRecord.curFrame = 0;
- sfxeRecord.lastFrameTime = 0;
-
- delete[] frameOffsets;
- delete sfxeStream;
- _waterEffects.push_back(sfxeRecord);
-}
-
-void RivenGraphics::clearWaterEffects() {
- _waterEffects.clear();
-}
-
-bool RivenGraphics::runScheduledWaterEffects() {
- // Don't run the effect if it's disabled
- if (_vm->_vars["waterenabled"] == 0)
- return false;
-
- Graphics::Surface *screen = NULL;
-
- for (uint16 i = 0; i < _waterEffects.size(); i++) {
- if (_vm->_system->getMillis() > _waterEffects[i].lastFrameTime + 1000 / _waterEffects[i].speed) {
- // Lock the screen!
- if (!screen)
- screen = _vm->_system->lockScreen();
-
- // Make sure the script is at the starting point
- Common::SeekableReadStream *script = _waterEffects[i].frameScripts[_waterEffects[i].curFrame];
- if (script->pos() != 0)
- script->seek(0);
-
- // Run script
- uint16 curRow = 0;
- for (uint16 op = script->readUint16BE(); op != 4; op = script->readUint16BE()) {
- if (op == 1) { // Increment Row
- curRow++;
- } else if (op == 3) { // Copy Pixels
- uint16 dstLeft = script->readUint16BE();
- uint16 srcLeft = script->readUint16BE();
- uint16 srcTop = script->readUint16BE();
- uint16 rowWidth = script->readUint16BE();
- memcpy ((byte *)screen->getBasePtr(dstLeft, curRow + _waterEffects[i].rect.top), (byte *)_mainScreen->getBasePtr(srcLeft, srcTop), rowWidth * _pixelFormat.bytesPerPixel);
- } else if (op != 4) { // End of Script
- error ("Unknown SFXE opcode %d", op);
- }
- }
-
- // Increment frame
- _waterEffects[i].curFrame++;
- if (_waterEffects[i].curFrame == _waterEffects[i].frameCount)
- _waterEffects[i].curFrame = 0;
-
- // Set the new time
- _waterEffects[i].lastFrameTime = _vm->_system->getMillis();
- }
- }
-
- // Unlock the screen if it has been locked and return true to update the screen
- if (screen) {
- _vm->_system->unlockScreen();
- return true;
- }
-
- return false;
-}
-
-void RivenGraphics::scheduleTransition(uint16 id, Common::Rect rect) {
- _scheduledTransition = id;
- _transitionRect = rect;
-}
-
-void RivenGraphics::runScheduledTransition() {
- if (_scheduledTransition < 0) // No transition is scheduled
- return;
-
- // TODO: There's a lot to be done here...
-
- // Note: Transitions 0-11 are actual transitions, but none are used in-game.
- // There's no point in implementing them if they're not used. These extra
- // transitions were found by hacking scripts.
-
- switch (_scheduledTransition) {
- case 0: // Swipe Left
- case 1: // Swipe Right
- case 2: // Swipe Up
- case 3: // Swipe Down
- case 12: // Pan Left
- case 13: // Pan Right
- case 14: // Pan Up
- case 15: // Pan Down
- case 16: // Dissolve
- case 17: // Dissolve (tspit CARD 155)
- break;
- default:
- if (_scheduledTransition >= 4 && _scheduledTransition <= 11)
- error("Found unused transition %d", _scheduledTransition);
- else
- error("Found unknown transition %d", _scheduledTransition);
- }
-
- // For now, just copy the image to screen without doing any transition.
- _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h);
- _vm->_system->updateScreen();
-
- _scheduledTransition = -1; // Clear scheduled transition
-}
-
-void RivenGraphics::clearMainScreen() {
- _mainScreen->fillRect(Common::Rect(0, 0, 608, 392), _pixelFormat.RGBToColor(0, 0, 0));
-}
-
-void RivenGraphics::fadeToBlack() {
- // The transition speed is forced to best here
- setTransitionSpeed(kRivenTransitionSpeedBest);
- scheduleTransition(16);
- clearMainScreen();
- runScheduledTransition();
-}
-
-void RivenGraphics::showInventory() {
- // Don't redraw the inventory
- if (_inventoryDrawn)
- return;
-
- // Clear the inventory area
- clearInventoryArea();
-
- // Draw the demo's exit button
- if (_vm->getFeatures() & GF_DEMO) {
- // extras.mhk tBMP 101 contains "EXIT" instead of Atrus' journal in the demo!
- // The demo's extras.mhk contains all the other inventory/marble/credits image
- // but has hacked tBMP 101 with "EXIT". *sigh*
- drawInventoryImage(101, g_demoExitRect);
- } else {
- // We don't want to show the inventory on setup screens or in other journals.
- if (_vm->getCurStack() == aspit)
- return;
-
- // There are three books and three vars. We have three different
- // combinations. At the start you have just Atrus' journal. Later,
- // you get Catherine's journal and the trap book. Near the end,
- // you lose the trap book and have just the two journals.
-
- bool hasCathBook = _vm->_vars["acathbook"] != 0;
- bool hasTrapBook = _vm->_vars["atrapbook"] != 0;
-
- if (!hasCathBook) {
- drawInventoryImage(101, g_atrusJournalRect1);
- } else if (!hasTrapBook) {
- drawInventoryImage(101, g_atrusJournalRect2);
- drawInventoryImage(102, g_cathJournalRect2);
- } else {
- drawInventoryImage(101, g_atrusJournalRect3);
- drawInventoryImage(102, g_cathJournalRect3);
- drawInventoryImage(100, g_trapBookRect3);
- }
- }
-
- _vm->_system->updateScreen();
- _inventoryDrawn = true;
-}
-
-void RivenGraphics::hideInventory() {
- // Don't hide the inventory twice
- if (!_inventoryDrawn)
- return;
-
- // Clear the area
- clearInventoryArea();
-
- _inventoryDrawn = false;
-}
-
-void RivenGraphics::clearInventoryArea() {
- // Clear the inventory area
- static const Common::Rect inventoryRect = Common::Rect(0, 392, 608, 436);
-
- // Lock the screen
- Graphics::Surface *screen = _vm->_system->lockScreen();
-
- // Fill the inventory area with black
- screen->fillRect(inventoryRect, _pixelFormat.RGBToColor(0, 0, 0));
-
- _vm->_system->unlockScreen();
-}
-
-void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) {
- MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id));
- mhkSurface->convertToTrueColor();
- Graphics::Surface *surface = mhkSurface->getSurface();
-
- _vm->_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h);
-
- delete mhkSurface;
-}
-
-void RivenGraphics::drawRect(Common::Rect rect, bool active) {
- // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active.
- Graphics::Surface *screen = _vm->_system->lockScreen();
-
- if (active)
- screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0));
- else
- screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0));
-
- _vm->_system->unlockScreen();
-}
-
-void RivenGraphics::drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect) {
- // Draw tBMP id from srcRect to dstRect
- Graphics::Surface *surface = findImage(id)->getSurface();
-
- assert(srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height());
-
- for (uint16 i = 0; i < srcRect.height(); i++)
- memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(srcRect.left, i + srcRect.top), srcRect.width() * surface->format.bytesPerPixel);
-
- _dirtyScreen = true;
-}
-
-void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) {
- MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id));
- mhkSurface->convertToTrueColor();
- Graphics::Surface *surface = mhkSurface->getSurface();
-
- assert(dstRect.width() == surface->w);
-
- for (uint16 i = 0; i < surface->h; i++)
- memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(0, i), surface->pitch);
-
- delete mhkSurface;
- _dirtyScreen = true;
-}
-
-void RivenGraphics::beginCredits() {
- // Clear the old cache
- clearCache();
-
- // Now cache all the credits images
- for (uint16 i = 302; i <= 320; i++) {
- MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, i));
- surface->convertToTrueColor();
- addImageToCache(i, surface);
- }
-
- // And clear our screen too
- clearMainScreen();
-}
-
-void RivenGraphics::updateCredits() {
- if ((_creditsImage == 303 || _creditsImage == 304) && _creditsPos == 0)
- fadeToBlack();
-
- if (_creditsImage < 304) {
- // For the first two credit images, they are faded from black to the image and then out again
- scheduleTransition(16);
-
- Graphics::Surface *frame = findImage(_creditsImage++)->getSurface();
-
- for (int y = 0; y < frame->h; y++)
- memcpy(_mainScreen->getBasePtr(124, y), frame->getBasePtr(0, y), frame->pitch);
-
- runScheduledTransition();
- } else {
- // Otheriwse, we're scrolling
- // Move the screen up one row
- memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1));
-
- // Only update as long as we're not before the last frame
- // Otherwise, we're just moving up a row (which we already did)
- if (_creditsImage <= 320) {
- // Copy the next row to the bottom of the screen
- Graphics::Surface *frame = findImage(_creditsImage)->getSurface();
- memcpy(_mainScreen->getBasePtr(124, _mainScreen->h - 1), frame->getBasePtr(0, _creditsPos), frame->pitch);
- _creditsPos++;
-
- if (_creditsPos == _mainScreen->h) {
- _creditsImage++;
- _creditsPos = 0;
- }
- }
-
- // Now flush the new screen
- _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h);
- _vm->_system->updateScreen();
- }
-}
-
-#endif // ENABLE_RIVEN
-
-LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height) : GraphicsManager(), _vm(vm) {
- _bmpDecoder = _vm->isPreMohawk() ? new LivingBooksBitmap_v1() : new MohawkBitmap();
-
- initGraphics(width, height, true);
-}
-
-LBGraphics::~LBGraphics() {
- delete _bmpDecoder;
-}
-
-MohawkSurface *LBGraphics::decodeImage(uint16 id) {
- if (_vm->isPreMohawk())
- return _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, id));
-
- return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id));
-}
-
-void LBGraphics::copyOffsetAnimImageToScreen(uint16 image, int left, int top) {
- MohawkSurface *mhkSurface = findImage(image);
-
- left -= mhkSurface->getOffsetX();
- top -= mhkSurface->getOffsetY();
-
- GraphicsManager::copyAnimImageToScreen(image, left, top);
-}
-
-bool LBGraphics::imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y) {
- MohawkSurface *mhkSurface = findImage(image);
-
- if (useOffsets) {
- x += mhkSurface->getOffsetX();
- y += mhkSurface->getOffsetY();
- }
-
- if (x < 0 || y < 0)
- return true;
-
- Graphics::Surface *surface = mhkSurface->getSurface();
- if (x >= surface->w || y >= surface->h)
- return true;
-
- return *(byte *)surface->getBasePtr(x, y) == 0;
-}
-
-void LBGraphics::setPalette(uint16 id) {
- // Old Living Books games use the old CTBL-style palette format while newer
- // games use the better tPAL format which can store partial palettes.
- if (_vm->isPreMohawk()) {
- Common::SeekableSubReadStreamEndian *ctblStream = _vm->wrapStreamEndian(ID_CTBL, id);
- uint16 colorCount = ctblStream->readUint16();
- byte *palette = new byte[colorCount * 3];
-
- for (uint16 i = 0; i < colorCount; i++) {
- palette[i * 3 + 0] = ctblStream->readByte();
- palette[i * 3 + 1] = ctblStream->readByte();
- palette[i * 3 + 2] = ctblStream->readByte();
- ctblStream->readByte();
- }
-
- delete ctblStream;
-
- _vm->_system->getPaletteManager()->setPalette(palette, 0, colorCount);
- delete[] palette;
- } else {
- GraphicsManager::setPalette(id);
- }
-}
-
-#ifdef ENABLE_CSTIME
-
-CSTimeGraphics::CSTimeGraphics(MohawkEngine_CSTime *vm) : GraphicsManager(), _vm(vm) {
- _bmpDecoder = new MohawkBitmap();
-
- initGraphics(640, 480, true);
-}
-
-CSTimeGraphics::~CSTimeGraphics() {
- delete _bmpDecoder;
-}
-
-void CSTimeGraphics::drawRect(Common::Rect rect, byte color) {
- rect.clip(Common::Rect(640, 480));
-
- // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active.
- if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0)
- return;
-
- Graphics::Surface *screen = _vm->_system->lockScreen();
-
- screen->frameRect(rect, color);
-
- _vm->_system->unlockScreen();
-}
-
-MohawkSurface *CSTimeGraphics::decodeImage(uint16 id) {
- return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id));
-}
-
-Common::Array<MohawkSurface *> CSTimeGraphics::decodeImages(uint16 id) {
- return _bmpDecoder->decodeImages(_vm->getResource(ID_TBMH, id));
-}
-
-#endif
-
} // End of namespace Mohawk
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index 8fa5d5f895..51d25db5d9 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -25,12 +25,11 @@
#include "mohawk/bitmap.h"
-#include "common/file.h"
#include "common/hashmap.h"
-#include "graphics/pict.h"
+#include "common/rect.h"
namespace Graphics {
-class JPEG;
+struct Surface;
}
namespace Mohawk {
@@ -103,196 +102,6 @@ private:
Common::HashMap<uint16, Common::Array<MohawkSurface *> > _subImageCache;
};
-#ifdef ENABLE_MYST
-
-class MystBitmap;
-class MohawkEngine_Myst;
-
-enum RectState {
- kRectEnabled,
- kRectDisabled,
- kRectUnreachable
-};
-
-class MystGraphics : public GraphicsManager {
-public:
- MystGraphics(MohawkEngine_Myst*);
- ~MystGraphics();
-
- void loadExternalPictureFile(uint16 stack);
- void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest);
- void copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest);
- void copyImageToScreen(uint16 image, Common::Rect dest);
- void copyImageToBackBuffer(uint16 image, Common::Rect dest);
- void copyBackBufferToScreen(Common::Rect r);
- void runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay);
- void drawRect(Common::Rect rect, RectState state);
- void drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color);
- void enableDrawingTimeSimulation(bool enable);
- void fadeToBlack();
- void fadeFromBlack();
-
-protected:
- MohawkSurface *decodeImage(uint16 id);
- MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
- void simulatePreviousDrawDelay(const Common::Rect &dest);
- void copyBackBufferToScreenWithSaturation(int16 saturation);
-
-private:
- MohawkEngine_Myst *_vm;
- MystBitmap *_bmpDecoder;
- Graphics::PictDecoder *_pictDecoder;
- Graphics::JPEG *_jpegDecoder;
-
- struct PictureFile {
- uint32 pictureCount;
- struct PictureEntry {
- uint32 offset;
- uint32 size;
- uint16 id;
- uint16 type;
- uint16 width;
- uint16 height;
- } *entries;
-
- Common::File picFile;
- } _pictureFile;
-
- Graphics::Surface *_backBuffer;
- Graphics::PixelFormat _pixelFormat;
- Common::Rect _viewport;
-
- int _enableDrawingTimeSimulation;
- uint32 _nextAllowedDrawTime;
- static const uint _constantDrawDelay = 10; // ms
- static const uint _proportionalDrawDelay = 500; // pixels per ms
-};
-
-#endif // ENABLE_MYST
-
-#ifdef ENABLE_RIVEN
-
-class MohawkEngine_Riven;
-
-class RivenGraphics : public GraphicsManager {
-public:
- RivenGraphics(MohawkEngine_Riven *vm);
- ~RivenGraphics();
-
- void copyImageToScreen(uint16, uint32, uint32, uint32, uint32);
- void updateScreen(Common::Rect updateRect = Common::Rect(0, 0, 608, 392));
- bool _updatesEnabled;
- Common::Array<uint16> _activatedPLSTs;
- void drawPLST(uint16 x);
- void drawRect(Common::Rect rect, bool active);
- void drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect);
- void drawExtrasImage(uint16 id, Common::Rect dstRect);
-
- // Water Effect
- void scheduleWaterEffect(uint16);
- void clearWaterEffects();
- bool runScheduledWaterEffects();
-
- // Transitions
- void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392));
- void runScheduledTransition();
- void fadeToBlack();
- void setTransitionSpeed(uint32 speed) { _transitionSpeed = speed; }
-
- // Inventory
- void showInventory();
- void hideInventory();
-
- // Credits
- void beginCredits();
- void updateCredits();
- uint getCurCreditsImage() { return _creditsImage; }
-
-protected:
- MohawkSurface *decodeImage(uint16 id);
- MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
-
-private:
- MohawkEngine_Riven *_vm;
- MohawkBitmap *_bitmapDecoder;
-
- // Water Effects
- struct SFXERecord {
- // Record values
- uint16 frameCount;
- Common::Rect rect;
- uint16 speed;
- Common::Array<Common::SeekableReadStream *> frameScripts;
-
- // Cur frame
- uint16 curFrame;
- uint32 lastFrameTime;
- };
- Common::Array<SFXERecord> _waterEffects;
-
- // Transitions
- int16 _scheduledTransition;
- Common::Rect _transitionRect;
- uint32 _transitionSpeed;
-
- // Inventory
- void clearInventoryArea();
- void drawInventoryImage(uint16 id, const Common::Rect *rect);
- bool _inventoryDrawn;
-
- // Screen Related
- Graphics::Surface *_mainScreen;
- bool _dirtyScreen;
- Graphics::PixelFormat _pixelFormat;
- void clearMainScreen();
-
- // Credits
- uint _creditsImage, _creditsPos;
-};
-
-#endif // ENABLE_RIVEN
-
-class LBGraphics : public GraphicsManager {
-public:
- LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height);
- ~LBGraphics();
-
- void setPalette(uint16 id);
- void copyOffsetAnimImageToScreen(uint16 image, int left = 0, int top = 0);
- bool imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y);
-
-protected:
- MohawkSurface *decodeImage(uint16 id);
- MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
-
-private:
- MohawkBitmap *_bmpDecoder;
- MohawkEngine_LivingBooks *_vm;
-};
-
-#ifdef ENABLE_CSTIME
-
-class MohawkEngine_CSTime;
-
-class CSTimeGraphics : public GraphicsManager {
-public:
- CSTimeGraphics(MohawkEngine_CSTime *vm);
- ~CSTimeGraphics();
-
- void drawRect(Common::Rect rect, byte color);
-
-protected:
- MohawkSurface *decodeImage(uint16 id);
- Common::Array<MohawkSurface *> decodeImages(uint16 id);
- MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
-
-private:
- MohawkBitmap *_bmpDecoder;
- MohawkEngine_CSTime *_vm;
-};
-
-#endif
-
} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index 23ab0acfb1..91d6a8cd30 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -25,7 +25,7 @@
#include "mohawk/mohawk.h"
#include "mohawk/console.h"
-#include "mohawk/graphics.h"
+#include "mohawk/livingbooks_graphics.h"
#include "mohawk/sound.h"
#include "common/config-file.h"
diff --git a/engines/mohawk/livingbooks_graphics.cpp b/engines/mohawk/livingbooks_graphics.cpp
new file mode 100644
index 0000000000..fb764fa15b
--- /dev/null
+++ b/engines/mohawk/livingbooks_graphics.cpp
@@ -0,0 +1,102 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mohawk/resource.h"
+#include "mohawk/livingbooks.h"
+#include "mohawk/livingbooks_graphics.h"
+
+#include "common/substream.h"
+#include "common/system.h"
+#include "engines/util.h"
+#include "graphics/palette.h"
+
+namespace Mohawk {
+
+LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height) : GraphicsManager(), _vm(vm) {
+ _bmpDecoder = _vm->isPreMohawk() ? new LivingBooksBitmap_v1() : new MohawkBitmap();
+
+ initGraphics(width, height, true);
+}
+
+LBGraphics::~LBGraphics() {
+ delete _bmpDecoder;
+}
+
+MohawkSurface *LBGraphics::decodeImage(uint16 id) {
+ if (_vm->isPreMohawk())
+ return _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, id));
+
+ return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id));
+}
+
+void LBGraphics::copyOffsetAnimImageToScreen(uint16 image, int left, int top) {
+ MohawkSurface *mhkSurface = findImage(image);
+
+ left -= mhkSurface->getOffsetX();
+ top -= mhkSurface->getOffsetY();
+
+ GraphicsManager::copyAnimImageToScreen(image, left, top);
+}
+
+bool LBGraphics::imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y) {
+ MohawkSurface *mhkSurface = findImage(image);
+
+ if (useOffsets) {
+ x += mhkSurface->getOffsetX();
+ y += mhkSurface->getOffsetY();
+ }
+
+ if (x < 0 || y < 0)
+ return true;
+
+ Graphics::Surface *surface = mhkSurface->getSurface();
+ if (x >= surface->w || y >= surface->h)
+ return true;
+
+ return *(byte *)surface->getBasePtr(x, y) == 0;
+}
+
+void LBGraphics::setPalette(uint16 id) {
+ // Old Living Books games use the old CTBL-style palette format while newer
+ // games use the better tPAL format which can store partial palettes.
+ if (_vm->isPreMohawk()) {
+ Common::SeekableSubReadStreamEndian *ctblStream = _vm->wrapStreamEndian(ID_CTBL, id);
+ uint16 colorCount = ctblStream->readUint16();
+ byte *palette = new byte[colorCount * 3];
+
+ for (uint16 i = 0; i < colorCount; i++) {
+ palette[i * 3 + 0] = ctblStream->readByte();
+ palette[i * 3 + 1] = ctblStream->readByte();
+ palette[i * 3 + 2] = ctblStream->readByte();
+ ctblStream->readByte();
+ }
+
+ delete ctblStream;
+
+ _vm->_system->getPaletteManager()->setPalette(palette, 0, colorCount);
+ delete[] palette;
+ } else {
+ GraphicsManager::setPalette(id);
+ }
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/livingbooks_graphics.h b/engines/mohawk/livingbooks_graphics.h
new file mode 100644
index 0000000000..3e2609750a
--- /dev/null
+++ b/engines/mohawk/livingbooks_graphics.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MOHAWK_LIVINGBOOKS_GRAPHICS_H
+#define MOHAWK_LIVINGBOOKS_GRAPHICS_H
+
+#include "mohawk/graphics.h"
+
+namespace Mohawk {
+
+class MohawkEngine_LivingBooks;
+
+class LBGraphics : public GraphicsManager {
+public:
+ LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height);
+ ~LBGraphics();
+
+ void setPalette(uint16 id);
+ void copyOffsetAnimImageToScreen(uint16 image, int left = 0, int top = 0);
+ bool imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y);
+
+protected:
+ MohawkSurface *decodeImage(uint16 id);
+ MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
+
+private:
+ MohawkBitmap *_bmpDecoder;
+ MohawkEngine_LivingBooks *_vm;
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk
index 882f3966b2..83e541e3e4 100644
--- a/engines/mohawk/module.mk
+++ b/engines/mohawk/module.mk
@@ -10,6 +10,7 @@ MODULE_OBJS = \
installer_archive.o \
livingbooks.o \
livingbooks_code.o \
+ livingbooks_graphics.o \
livingbooks_lbx.o \
mohawk.o \
resource.o \
@@ -22,6 +23,7 @@ MODULE_OBJS += \
cstime.o \
cstime_cases.o \
cstime_game.o \
+ cstime_graphics.o \
cstime_ui.o \
cstime_view.o
endif
@@ -30,6 +32,7 @@ ifdef ENABLE_MYST
MODULE_OBJS += \
myst.o \
myst_areas.o \
+ myst_graphics.o \
myst_scripts.o \
myst_state.o \
resource_cache.o \
@@ -51,6 +54,7 @@ ifdef ENABLE_RIVEN
MODULE_OBJS += \
riven.o \
riven_external.o \
+ riven_graphics.o \
riven_saveload.o \
riven_scripts.o \
riven_vars.o
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index eeb4594f3c..c22b30ad4d 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -27,9 +27,9 @@
#include "common/textconsole.h"
#include "mohawk/cursors.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_scripts.h"
#include "mohawk/myst_state.h"
#include "mohawk/dialogs.h"
diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp
index 294fcea2f1..fe33ceaa9b 100644
--- a/engines/mohawk/myst_areas.cpp
+++ b/engines/mohawk/myst_areas.cpp
@@ -20,8 +20,8 @@
*
*/
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_scripts.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h
index 297a7cc92b..62af5ec4cf 100644
--- a/engines/mohawk/myst_areas.h
+++ b/engines/mohawk/myst_areas.h
@@ -20,11 +20,13 @@
*
*/
+#ifndef MYST_AREAS_H
+#define MYST_AREAS_H
+
#include "mohawk/myst.h"
#include "mohawk/video.h"
-#ifndef MYST_AREAS_H
-#define MYST_AREAS_H
+#include "common/rect.h"
namespace Mohawk {
diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp
new file mode 100644
index 0000000000..151390580f
--- /dev/null
+++ b/engines/mohawk/myst_graphics.cpp
@@ -0,0 +1,493 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mohawk/myst.h"
+#include "mohawk/myst_graphics.h"
+#include "mohawk/resource.h"
+
+#include "common/substream.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "engines/util.h"
+#include "graphics/jpeg.h"
+#include "graphics/pict.h"
+
+namespace Mohawk {
+
+MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
+ _bmpDecoder = new MystBitmap();
+
+ _viewport = Common::Rect(544, 332);
+
+ // The original version of Myst could run in 8bpp color too.
+ // However, it dithered videos to 8bpp and they looked considerably
+ // worse (than they already did :P). So we're not even going to
+ // support 8bpp mode in Myst (Myst ME required >8bpp anyway).
+ initGraphics(_viewport.width(), _viewport.height(), true, NULL); // What an odd screen size!
+
+ _pixelFormat = _vm->_system->getScreenFormat();
+
+ if (_pixelFormat.bytesPerPixel == 1)
+ error("Myst requires greater than 256 colors to run");
+
+ if (_vm->getFeatures() & GF_ME) {
+ _jpegDecoder = new Graphics::JPEG();
+ _pictDecoder = new Graphics::PictDecoder(_pixelFormat);
+ } else {
+ _jpegDecoder = NULL;
+ _pictDecoder = NULL;
+ }
+
+ _pictureFile.entries = NULL;
+
+ // Initialize our buffer
+ _backBuffer = new Graphics::Surface();
+ _backBuffer->create(_vm->_system->getWidth(), _vm->_system->getHeight(), _pixelFormat);
+
+ _nextAllowedDrawTime = _vm->_system->getMillis();
+ _enableDrawingTimeSimulation = 0;
+}
+
+MystGraphics::~MystGraphics() {
+ delete _bmpDecoder;
+ delete _jpegDecoder;
+ delete _pictDecoder;
+ delete[] _pictureFile.entries;
+
+ _backBuffer->free();
+ delete _backBuffer;
+}
+
+static const char *s_picFileNames[] = {
+ "CHpics",
+ "",
+ "",
+ "DUpics",
+ "INpics",
+ "",
+ "MEpics",
+ "MYpics",
+ "SEpics",
+ "",
+ "",
+ "STpics"
+};
+
+void MystGraphics::loadExternalPictureFile(uint16 stack) {
+ if (_vm->getPlatform() != Common::kPlatformMacintosh)
+ return;
+
+ if (_pictureFile.picFile.isOpen())
+ _pictureFile.picFile.close();
+ delete[] _pictureFile.entries;
+
+ if (!scumm_stricmp(s_picFileNames[stack], ""))
+ return;
+
+ if (!_pictureFile.picFile.open(s_picFileNames[stack]))
+ error ("Could not open external picture file \'%s\'", s_picFileNames[stack]);
+
+ _pictureFile.pictureCount = _pictureFile.picFile.readUint32BE();
+ _pictureFile.entries = new PictureFile::PictureEntry[_pictureFile.pictureCount];
+
+ for (uint32 i = 0; i < _pictureFile.pictureCount; i++) {
+ _pictureFile.entries[i].offset = _pictureFile.picFile.readUint32BE();
+ _pictureFile.entries[i].size = _pictureFile.picFile.readUint32BE();
+ _pictureFile.entries[i].id = _pictureFile.picFile.readUint16BE();
+ _pictureFile.entries[i].type = _pictureFile.picFile.readUint16BE();
+ _pictureFile.entries[i].width = _pictureFile.picFile.readUint16BE();
+ _pictureFile.entries[i].height = _pictureFile.picFile.readUint16BE();
+ }
+}
+
+MohawkSurface *MystGraphics::decodeImage(uint16 id) {
+ MohawkSurface *mhkSurface = 0;
+
+ // Myst ME uses JPEG/PICT images instead of compressed Windows Bitmaps for room images,
+ // though there are a few weird ones that use that format. For further nonsense with images,
+ // the Macintosh version stores images in external "picture files." We check them before
+ // going to check for a PICT resource.
+ if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) {
+ for (uint32 i = 0; i < _pictureFile.pictureCount; i++)
+ if (_pictureFile.entries[i].id == id) {
+ if (_pictureFile.entries[i].type == 0) {
+ Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size);
+
+ if (!_jpegDecoder->read(stream))
+ error("Could not decode Myst ME Mac JPEG");
+
+ mhkSurface = new MohawkSurface(_jpegDecoder->getSurface(_pixelFormat));
+ delete stream;
+ } else if (_pictureFile.entries[i].type == 1) {
+ mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size)));
+ } else
+ error ("Unknown Picture File type %d", _pictureFile.entries[i].type);
+ break;
+ }
+ }
+
+ // We're not using the external Mac files, so it's time to delve into the main Mohawk
+ // archives. However, we still don't know if it's a PICT or WDIB resource. If it's Myst
+ // ME it's most likely a PICT, and if it's original it's definitely a WDIB. However,
+ // Myst ME throws us another curve ball in that PICT resources can contain WDIB's instead
+ // of PICT's.
+ if (!mhkSurface) {
+ bool isPict = false;
+ Common::SeekableReadStream *dataStream = NULL;
+
+ if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) {
+ // The PICT resource exists. However, it could still contain a MystBitmap
+ // instead of a PICT image...
+ dataStream = _vm->getResource(ID_PICT, id);
+ } else // No PICT, so the WDIB must exist. Let's go grab it.
+ dataStream = _vm->getResource(ID_WDIB, id);
+
+ if (_vm->getFeatures() & GF_ME) {
+ // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap
+ // would be compressed, there's no way to detect for the BM without a hack.
+ // So, we search for the PICT version opcode for detection.
+ dataStream->seek(512 + 10); // 512 byte pict header
+ isPict = (dataStream->readUint32BE() == 0x001102FF);
+ dataStream->seek(0);
+ }
+
+ if (isPict)
+ mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(dataStream));
+ else {
+ mhkSurface = _bmpDecoder->decodeImage(dataStream);
+ mhkSurface->convertToTrueColor();
+ }
+ }
+
+ assert(mhkSurface);
+ return mhkSurface;
+}
+
+void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest) {
+ Graphics::Surface *surface = findImage(image)->getSurface();
+
+ // Make sure the image is bottom aligned in the dest rect
+ dest.top = dest.bottom - MIN<int>(surface->h, dest.height());
+
+ // Convert from bitmap coordinates to surface coordinates
+ uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height()));
+
+ // Do not draw the top pixels if the image is too tall
+ if (dest.height() > _viewport.height())
+ top += dest.height() - _viewport.height();
+
+ // Clip the destination rect to the screen
+ if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight())
+ dest.debugPrint(4, "Clipping destination rect to the screen");
+ dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth());
+ dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight());
+
+ uint16 width = MIN<int>(surface->w, dest.width());
+ uint16 height = MIN<int>(surface->h, dest.height());
+
+ // Clamp Width and Height to within src surface dimensions
+ if (src.left + width > surface->w)
+ width = surface->w - src.left;
+ if (src.top + height > surface->h)
+ height = surface->h - src.top;
+
+ debug(3, "MystGraphics::copyImageSectionToScreen()");
+ debug(3, "\tImage: %d", image);
+ debug(3, "\tsrc.left: %d", src.left);
+ debug(3, "\tsrc.top: %d", src.top);
+ debug(3, "\tdest.left: %d", dest.left);
+ debug(3, "\tdest.top: %d", dest.top);
+ debug(3, "\twidth: %d", width);
+ debug(3, "\theight: %d", height);
+
+ simulatePreviousDrawDelay(dest);
+
+ _vm->_system->copyRectToScreen((byte *)surface->getBasePtr(src.left, top), surface->pitch, dest.left, dest.top, width, height);
+}
+
+void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest) {
+ Graphics::Surface *surface = findImage(image)->getSurface();
+
+ // Make sure the image is bottom aligned in the dest rect
+ dest.top = dest.bottom - MIN<int>(surface->h, dest.height());
+
+ // Convert from bitmap coordinates to surface coordinates
+ uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height()));
+
+ // Do not draw the top pixels if the image is too tall
+ if (dest.height() > _viewport.height()) {
+ top += dest.height() - _viewport.height();
+ }
+
+ // Clip the destination rect to the screen
+ if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight())
+ dest.debugPrint(4, "Clipping destination rect to the screen");
+ dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth());
+ dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight());
+
+ uint16 width = MIN<int>(surface->w, dest.width());
+ uint16 height = MIN<int>(surface->h, dest.height());
+
+ // Clamp Width and Height to within src surface dimensions
+ if (src.left + width > surface->w)
+ width = surface->w - src.left;
+ if (src.top + height > surface->h)
+ height = surface->h - src.top;
+
+ debug(3, "MystGraphics::copyImageSectionToBackBuffer()");
+ debug(3, "\tImage: %d", image);
+ debug(3, "\tsrc.left: %d", src.left);
+ debug(3, "\tsrc.top: %d", src.top);
+ debug(3, "\tdest.left: %d", dest.left);
+ debug(3, "\tdest.top: %d", dest.top);
+ debug(3, "\twidth: %d", width);
+ debug(3, "\theight: %d", height);
+
+ for (uint16 i = 0; i < height; i++)
+ memcpy(_backBuffer->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->format.bytesPerPixel);
+}
+
+void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) {
+ copyImageSectionToScreen(image, Common::Rect(544, 333), dest);
+}
+
+void MystGraphics::copyImageToBackBuffer(uint16 image, Common::Rect dest) {
+ copyImageSectionToBackBuffer(image, Common::Rect(544, 333), dest);
+}
+
+void MystGraphics::copyBackBufferToScreen(Common::Rect r) {
+ r.clip(_viewport);
+
+ simulatePreviousDrawDelay(r);
+
+ _vm->_system->copyRectToScreen((byte *)_backBuffer->getBasePtr(r.left, r.top), _backBuffer->pitch, r.left, r.top, r.width(), r.height());
+}
+
+void MystGraphics::runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay) {
+
+ // Do not artificially delay during transitions
+ int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation;
+ _enableDrawingTimeSimulation = 0;
+
+ switch (type) {
+ case 0: {
+ debugC(kDebugScript, "Left to Right");
+
+ uint16 step = (rect.right - rect.left) / steps;
+ Common::Rect area = rect;
+ for (uint i = 0; i < steps; i++) {
+ area.left = rect.left + step * i;
+ area.right = area.left + step;
+
+ _vm->_system->delayMillis(delay);
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ if (area.right < rect.right) {
+ area.left = area.right;
+ area.right = rect.right;
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ }
+ break;
+ case 1: {
+ debugC(kDebugScript, "Right to Left");
+
+ uint16 step = (rect.right - rect.left) / steps;
+ Common::Rect area = rect;
+ for (uint i = 0; i < steps; i++) {
+ area.right = rect.right - step * i;
+ area.left = area.right - step;
+
+ _vm->_system->delayMillis(delay);
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ if (area.left > rect.left) {
+ area.right = area.left;
+ area.left = rect.left;
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ }
+ break;
+ case 5: {
+ debugC(kDebugScript, "Top to Bottom");
+
+ uint16 step = (rect.bottom - rect.top) / steps;
+ Common::Rect area = rect;
+ for (uint i = 0; i < steps; i++) {
+ area.top = rect.top + step * i;
+ area.bottom = area.top + step;
+
+ _vm->_system->delayMillis(delay);
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ if (area.bottom < rect.bottom) {
+ area.top = area.bottom;
+ area.bottom = rect.bottom;
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ }
+ break;
+ case 6: {
+ debugC(kDebugScript, "Bottom to Top");
+
+ uint16 step = (rect.bottom - rect.top) / steps;
+ Common::Rect area = rect;
+ for (uint i = 0; i < steps; i++) {
+ area.bottom = rect.bottom - step * i;
+ area.top = area.bottom - step;
+
+ _vm->_system->delayMillis(delay);
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ if (area.top > rect.top) {
+ area.bottom = area.top;
+ area.top = rect.top;
+
+ copyBackBufferToScreen(area);
+ _vm->_system->updateScreen();
+ }
+ }
+ break;
+ default:
+ warning("Unknown Update Direction");
+
+ //TODO: Replace minimal implementation
+ copyBackBufferToScreen(rect);
+ _vm->_system->updateScreen();
+ break;
+ }
+
+ _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation;
+}
+
+void MystGraphics::drawRect(Common::Rect rect, RectState state) {
+ rect.clip(_viewport);
+
+ // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active.
+ if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0)
+ return;
+
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+
+ if (state == kRectEnabled)
+ screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0));
+ else if (state == kRectUnreachable)
+ screen->frameRect(rect, _pixelFormat.RGBToColor(0, 0, 255));
+ else
+ screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0));
+
+ _vm->_system->unlockScreen();
+}
+
+void MystGraphics::drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color) {
+ _backBuffer->drawLine(p1.x, p1.y, p2.x, p2.y, color);
+}
+
+void MystGraphics::enableDrawingTimeSimulation(bool enable) {
+ if (enable)
+ _enableDrawingTimeSimulation++;
+ else
+ _enableDrawingTimeSimulation--;
+
+ if (_enableDrawingTimeSimulation < 0)
+ _enableDrawingTimeSimulation = 0;
+}
+
+void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) {
+ uint32 time = 0;
+
+ if (_enableDrawingTimeSimulation) {
+ time = _vm->_system->getMillis();
+
+ // Do not draw anything new too quickly after the previous draw call
+ // so that images stay at least a little while on screen
+ // This is enabled only for scripted draw calls
+ if (time < _nextAllowedDrawTime)
+ _vm->_system->delayMillis(_nextAllowedDrawTime - time);
+ }
+
+ // Next draw call allowed at DELAY + AERA * COEFF milliseconds from now
+ time = _vm->_system->getMillis();
+ _nextAllowedDrawTime = time + _constantDrawDelay + dest.height() * dest.width() / _proportionalDrawDelay;
+}
+
+void MystGraphics::copyBackBufferToScreenWithSaturation(int16 saturation) {
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+
+ for (uint16 y = 0; y < _viewport.height(); y++)
+ for (uint16 x = 0; x < _viewport.width(); x++) {
+ uint32 color;
+ uint8 r, g, b;
+
+ if (_pixelFormat.bytesPerPixel == 2)
+ color = *(const uint16 *)_backBuffer->getBasePtr(x, y);
+ else
+ color = *(const uint32 *)_backBuffer->getBasePtr(x, y);
+
+ _pixelFormat.colorToRGB(color, r, g, b);
+
+ r = CLIP<int16>((int16)r - saturation, 0, 255);
+ g = CLIP<int16>((int16)g - saturation, 0, 255);
+ b = CLIP<int16>((int16)b - saturation, 0, 255);
+
+ color = _pixelFormat.RGBToColor(r, g, b);
+
+ if (_pixelFormat.bytesPerPixel == 2) {
+ uint16 *dst = (uint16 *)screen->getBasePtr(x, y);
+ *dst = color;
+ } else {
+ uint32 *dst = (uint32 *)screen->getBasePtr(x, y);
+ *dst = color;
+ }
+ }
+
+ _vm->_system->unlockScreen();
+ _vm->_system->updateScreen();
+}
+
+void MystGraphics::fadeToBlack() {
+ for (int16 i = 0; i < 256; i += 32) {
+ copyBackBufferToScreenWithSaturation(i);
+ }
+}
+
+void MystGraphics::fadeFromBlack() {
+ for (int16 i = 256; i >= 0; i -= 32) {
+ copyBackBufferToScreenWithSaturation(i);
+ }
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h
new file mode 100644
index 0000000000..e2b02db5fc
--- /dev/null
+++ b/engines/mohawk/myst_graphics.h
@@ -0,0 +1,102 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MOHAWK_MYST_GRAPHICS_H
+#define MOHAWK_MYST_GRAPHICS_H
+
+#include "mohawk/graphics.h"
+
+#include "common/file.h"
+
+namespace Graphics {
+class JPEG;
+class PictDecoder;
+}
+
+namespace Mohawk {
+
+class MystBitmap;
+class MohawkEngine_Myst;
+
+enum RectState {
+ kRectEnabled,
+ kRectDisabled,
+ kRectUnreachable
+};
+
+class MystGraphics : public GraphicsManager {
+public:
+ MystGraphics(MohawkEngine_Myst*);
+ ~MystGraphics();
+
+ void loadExternalPictureFile(uint16 stack);
+ void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest);
+ void copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest);
+ void copyImageToScreen(uint16 image, Common::Rect dest);
+ void copyImageToBackBuffer(uint16 image, Common::Rect dest);
+ void copyBackBufferToScreen(Common::Rect r);
+ void runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay);
+ void drawRect(Common::Rect rect, RectState state);
+ void drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color);
+ void enableDrawingTimeSimulation(bool enable);
+ void fadeToBlack();
+ void fadeFromBlack();
+
+protected:
+ MohawkSurface *decodeImage(uint16 id);
+ MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
+ void simulatePreviousDrawDelay(const Common::Rect &dest);
+ void copyBackBufferToScreenWithSaturation(int16 saturation);
+
+private:
+ MohawkEngine_Myst *_vm;
+ MystBitmap *_bmpDecoder;
+ Graphics::PictDecoder *_pictDecoder;
+ Graphics::JPEG *_jpegDecoder;
+
+ struct PictureFile {
+ uint32 pictureCount;
+ struct PictureEntry {
+ uint32 offset;
+ uint32 size;
+ uint16 id;
+ uint16 type;
+ uint16 width;
+ uint16 height;
+ } *entries;
+
+ Common::File picFile;
+ } _pictureFile;
+
+ Graphics::Surface *_backBuffer;
+ Graphics::PixelFormat _pixelFormat;
+ Common::Rect _viewport;
+
+ int _enableDrawingTimeSimulation;
+ uint32 _nextAllowedDrawTime;
+ static const uint _constantDrawDelay = 10; // ms
+ static const uint _proportionalDrawDelay = 500; // pixels per ms
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index ca8e985491..b9353312c7 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -22,8 +22,8 @@
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_scripts.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp
index 9ca47cc92a..069281f5dc 100644
--- a/engines/mohawk/myst_stacks/channelwood.cpp
+++ b/engines/mohawk/myst_stacks/channelwood.cpp
@@ -22,8 +22,8 @@
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp
index ad593e3542..192e55d5e3 100644
--- a/engines/mohawk/myst_stacks/credits.cpp
+++ b/engines/mohawk/myst_stacks/credits.cpp
@@ -21,8 +21,8 @@
*/
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/credits.h"
diff --git a/engines/mohawk/myst_stacks/demo.cpp b/engines/mohawk/myst_stacks/demo.cpp
index fbad7dc384..29a12571fd 100644
--- a/engines/mohawk/myst_stacks/demo.cpp
+++ b/engines/mohawk/myst_stacks/demo.cpp
@@ -21,8 +21,8 @@
*/
#include "mohawk/cursors.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_stacks/demo.h"
#include "common/system.h"
diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp
index 7d3179fa24..0af386f51f 100644
--- a/engines/mohawk/myst_stacks/intro.cpp
+++ b/engines/mohawk/myst_stacks/intro.cpp
@@ -21,8 +21,8 @@
*/
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index 12d9dc7e2f..79de03308c 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -22,8 +22,8 @@
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp
index b3222e0322..c1ddc74c82 100644
--- a/engines/mohawk/myst_stacks/myst.cpp
+++ b/engines/mohawk/myst_stacks/myst.cpp
@@ -22,8 +22,8 @@
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp
index 31e22bb8c5..0b8dcf897a 100644
--- a/engines/mohawk/myst_stacks/preview.cpp
+++ b/engines/mohawk/myst_stacks/preview.cpp
@@ -22,8 +22,8 @@
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/preview.h"
diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp
index 794793e49c..c0bb400db1 100644
--- a/engines/mohawk/myst_stacks/slides.cpp
+++ b/engines/mohawk/myst_stacks/slides.cpp
@@ -22,8 +22,8 @@
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/slides.h"
diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp
index 6d54d0c586..ef228e62f3 100644
--- a/engines/mohawk/myst_stacks/stoneship.cpp
+++ b/engines/mohawk/myst_stacks/stoneship.cpp
@@ -22,8 +22,8 @@
#include "mohawk/cursors.h"
#include "mohawk/myst.h"
-#include "mohawk/graphics.h"
#include "mohawk/myst_areas.h"
+#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 3e2fa4f979..38b38d2c56 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -27,11 +27,11 @@
#include "common/system.h"
#include "mohawk/cursors.h"
-#include "mohawk/graphics.h"
#include "mohawk/installer_archive.h"
#include "mohawk/resource.h"
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
+#include "mohawk/riven_graphics.h"
#include "mohawk/riven_saveload.h"
#include "mohawk/dialogs.h"
#include "mohawk/sound.h"
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 9e1365f8da..8dfc74ebf0 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -21,9 +21,9 @@
*/
#include "mohawk/cursors.h"
-#include "mohawk/graphics.h"
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
+#include "mohawk/riven_graphics.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp
new file mode 100644
index 0000000000..9415e51412
--- /dev/null
+++ b/engines/mohawk/riven_graphics.cpp
@@ -0,0 +1,445 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mohawk/resource.h"
+#include "mohawk/riven.h"
+#include "mohawk/riven_graphics.h"
+
+#include "common/system.h"
+#include "engines/util.h"
+
+namespace Mohawk {
+
+RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm) {
+ _bitmapDecoder = new MohawkBitmap();
+
+ // Give me the best you've got!
+ initGraphics(608, 436, true, NULL);
+ _pixelFormat = _vm->_system->getScreenFormat();
+
+ if (_pixelFormat.bytesPerPixel == 1)
+ error("Riven requires greater than 256 colors to run");
+
+ // The actual game graphics only take up the first 392 rows. The inventory
+ // occupies the rest of the screen and we don't use the buffer to hold that.
+ _mainScreen = new Graphics::Surface();
+ _mainScreen->create(608, 392, _pixelFormat);
+
+ _updatesEnabled = true;
+ _scheduledTransition = -1; // no transition
+ _dirtyScreen = false;
+ _inventoryDrawn = false;
+
+ _creditsImage = 302;
+ _creditsPos = 0;
+}
+
+RivenGraphics::~RivenGraphics() {
+ _mainScreen->free();
+ delete _mainScreen;
+ delete _bitmapDecoder;
+}
+
+MohawkSurface *RivenGraphics::decodeImage(uint16 id) {
+ MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getResource(ID_TBMP, id));
+ surface->convertToTrueColor();
+ return surface;
+}
+
+void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uint32 right, uint32 bottom) {
+ Graphics::Surface *surface = findImage(image)->getSurface();
+
+ // Clip the width to fit on the screen. Fixes some images.
+ if (left + surface->w > 608)
+ surface->w = 608 - left;
+
+ for (uint16 i = 0; i < surface->h; i++)
+ memcpy(_mainScreen->getBasePtr(left, i + top), surface->getBasePtr(0, i), surface->w * surface->format.bytesPerPixel);
+
+ _dirtyScreen = true;
+}
+
+void RivenGraphics::drawPLST(uint16 x) {
+ Common::SeekableReadStream* plst = _vm->getResource(ID_PLST, _vm->getCurCard());
+ uint16 recordCount = plst->readUint16BE();
+
+ for (uint16 i = 0; i < recordCount; i++) {
+ uint16 index = plst->readUint16BE();
+ uint16 id = plst->readUint16BE();
+ uint16 left = plst->readUint16BE();
+ uint16 top = plst->readUint16BE();
+ uint16 right = plst->readUint16BE();
+ uint16 bottom = plst->readUint16BE();
+
+ // We are also checking here to make sure we haven't drawn the image yet on screen.
+ // This fixes problems with drawing PLST 1 twice and some other images twice. PLST
+ // 1 is sometimes not called by the scripts, so some cards don't appear if we don't
+ // draw PLST 1 each time. This "hack" is here to catch any PLST attempting to draw
+ // twice. There should never be a problem with doing it this way.
+ if (index == x && !(Common::find(_activatedPLSTs.begin(), _activatedPLSTs.end(), x) != _activatedPLSTs.end())) {
+ debug(0, "Drawing image %d", id);
+ copyImageToScreen(id, left, top, right, bottom);
+ _activatedPLSTs.push_back(x);
+ break;
+ }
+ }
+
+ delete plst;
+}
+
+void RivenGraphics::updateScreen(Common::Rect updateRect) {
+ if (_updatesEnabled) {
+ _vm->runUpdateScreenScript();
+
+ if (_dirtyScreen) {
+ _activatedPLSTs.clear();
+
+ // Copy to screen if there's no transition. Otherwise transition. ;)
+ if (_scheduledTransition < 0)
+ _vm->_system->copyRectToScreen((byte *)_mainScreen->getBasePtr(updateRect.left, updateRect.top), _mainScreen->pitch, updateRect.left, updateRect.top, updateRect.width(), updateRect.height());
+ else
+ runScheduledTransition();
+
+ // Finally, update the screen.
+ _vm->_system->updateScreen();
+ _dirtyScreen = false;
+ }
+ }
+}
+
+void RivenGraphics::scheduleWaterEffect(uint16 sfxeID) {
+ Common::SeekableReadStream *sfxeStream = _vm->getResource(ID_SFXE, sfxeID);
+
+ if (sfxeStream->readUint16BE() != 'SL')
+ error ("Unknown sfxe tag");
+
+ // Read in header info
+ SFXERecord sfxeRecord;
+ sfxeRecord.frameCount = sfxeStream->readUint16BE();
+ uint32 offsetTablePosition = sfxeStream->readUint32BE();
+ sfxeRecord.rect.left = sfxeStream->readUint16BE();
+ sfxeRecord.rect.top = sfxeStream->readUint16BE();
+ sfxeRecord.rect.right = sfxeStream->readUint16BE();
+ sfxeRecord.rect.bottom = sfxeStream->readUint16BE();
+ sfxeRecord.speed = sfxeStream->readUint16BE();
+ // Skip the rest of the fields...
+
+ // Read in offsets
+ sfxeStream->seek(offsetTablePosition);
+ uint32 *frameOffsets = new uint32[sfxeRecord.frameCount];
+ for (uint16 i = 0; i < sfxeRecord.frameCount; i++)
+ frameOffsets[i] = sfxeStream->readUint32BE();
+ sfxeStream->seek(frameOffsets[0]);
+
+ // Read in the scripts
+ for (uint16 i = 0; i < sfxeRecord.frameCount; i++)
+ sfxeRecord.frameScripts.push_back(sfxeStream->readStream((i == sfxeRecord.frameCount - 1) ? sfxeStream->size() - frameOffsets[i] : frameOffsets[i + 1] - frameOffsets[i]));
+
+ // Set it to the first frame
+ sfxeRecord.curFrame = 0;
+ sfxeRecord.lastFrameTime = 0;
+
+ delete[] frameOffsets;
+ delete sfxeStream;
+ _waterEffects.push_back(sfxeRecord);
+}
+
+void RivenGraphics::clearWaterEffects() {
+ _waterEffects.clear();
+}
+
+bool RivenGraphics::runScheduledWaterEffects() {
+ // Don't run the effect if it's disabled
+ if (_vm->_vars["waterenabled"] == 0)
+ return false;
+
+ Graphics::Surface *screen = NULL;
+
+ for (uint16 i = 0; i < _waterEffects.size(); i++) {
+ if (_vm->_system->getMillis() > _waterEffects[i].lastFrameTime + 1000 / _waterEffects[i].speed) {
+ // Lock the screen!
+ if (!screen)
+ screen = _vm->_system->lockScreen();
+
+ // Make sure the script is at the starting point
+ Common::SeekableReadStream *script = _waterEffects[i].frameScripts[_waterEffects[i].curFrame];
+ if (script->pos() != 0)
+ script->seek(0);
+
+ // Run script
+ uint16 curRow = 0;
+ for (uint16 op = script->readUint16BE(); op != 4; op = script->readUint16BE()) {
+ if (op == 1) { // Increment Row
+ curRow++;
+ } else if (op == 3) { // Copy Pixels
+ uint16 dstLeft = script->readUint16BE();
+ uint16 srcLeft = script->readUint16BE();
+ uint16 srcTop = script->readUint16BE();
+ uint16 rowWidth = script->readUint16BE();
+ memcpy ((byte *)screen->getBasePtr(dstLeft, curRow + _waterEffects[i].rect.top), (byte *)_mainScreen->getBasePtr(srcLeft, srcTop), rowWidth * _pixelFormat.bytesPerPixel);
+ } else if (op != 4) { // End of Script
+ error ("Unknown SFXE opcode %d", op);
+ }
+ }
+
+ // Increment frame
+ _waterEffects[i].curFrame++;
+ if (_waterEffects[i].curFrame == _waterEffects[i].frameCount)
+ _waterEffects[i].curFrame = 0;
+
+ // Set the new time
+ _waterEffects[i].lastFrameTime = _vm->_system->getMillis();
+ }
+ }
+
+ // Unlock the screen if it has been locked and return true to update the screen
+ if (screen) {
+ _vm->_system->unlockScreen();
+ return true;
+ }
+
+ return false;
+}
+
+void RivenGraphics::scheduleTransition(uint16 id, Common::Rect rect) {
+ _scheduledTransition = id;
+ _transitionRect = rect;
+}
+
+void RivenGraphics::runScheduledTransition() {
+ if (_scheduledTransition < 0) // No transition is scheduled
+ return;
+
+ // TODO: There's a lot to be done here...
+
+ // Note: Transitions 0-11 are actual transitions, but none are used in-game.
+ // There's no point in implementing them if they're not used. These extra
+ // transitions were found by hacking scripts.
+
+ switch (_scheduledTransition) {
+ case 0: // Swipe Left
+ case 1: // Swipe Right
+ case 2: // Swipe Up
+ case 3: // Swipe Down
+ case 12: // Pan Left
+ case 13: // Pan Right
+ case 14: // Pan Up
+ case 15: // Pan Down
+ case 16: // Dissolve
+ case 17: // Dissolve (tspit CARD 155)
+ break;
+ default:
+ if (_scheduledTransition >= 4 && _scheduledTransition <= 11)
+ error("Found unused transition %d", _scheduledTransition);
+ else
+ error("Found unknown transition %d", _scheduledTransition);
+ }
+
+ // For now, just copy the image to screen without doing any transition.
+ _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h);
+ _vm->_system->updateScreen();
+
+ _scheduledTransition = -1; // Clear scheduled transition
+}
+
+void RivenGraphics::clearMainScreen() {
+ _mainScreen->fillRect(Common::Rect(0, 0, 608, 392), _pixelFormat.RGBToColor(0, 0, 0));
+}
+
+void RivenGraphics::fadeToBlack() {
+ // The transition speed is forced to best here
+ setTransitionSpeed(kRivenTransitionSpeedBest);
+ scheduleTransition(16);
+ clearMainScreen();
+ runScheduledTransition();
+}
+
+void RivenGraphics::showInventory() {
+ // Don't redraw the inventory
+ if (_inventoryDrawn)
+ return;
+
+ // Clear the inventory area
+ clearInventoryArea();
+
+ // Draw the demo's exit button
+ if (_vm->getFeatures() & GF_DEMO) {
+ // extras.mhk tBMP 101 contains "EXIT" instead of Atrus' journal in the demo!
+ // The demo's extras.mhk contains all the other inventory/marble/credits image
+ // but has hacked tBMP 101 with "EXIT". *sigh*
+ drawInventoryImage(101, g_demoExitRect);
+ } else {
+ // We don't want to show the inventory on setup screens or in other journals.
+ if (_vm->getCurStack() == aspit)
+ return;
+
+ // There are three books and three vars. We have three different
+ // combinations. At the start you have just Atrus' journal. Later,
+ // you get Catherine's journal and the trap book. Near the end,
+ // you lose the trap book and have just the two journals.
+
+ bool hasCathBook = _vm->_vars["acathbook"] != 0;
+ bool hasTrapBook = _vm->_vars["atrapbook"] != 0;
+
+ if (!hasCathBook) {
+ drawInventoryImage(101, g_atrusJournalRect1);
+ } else if (!hasTrapBook) {
+ drawInventoryImage(101, g_atrusJournalRect2);
+ drawInventoryImage(102, g_cathJournalRect2);
+ } else {
+ drawInventoryImage(101, g_atrusJournalRect3);
+ drawInventoryImage(102, g_cathJournalRect3);
+ drawInventoryImage(100, g_trapBookRect3);
+ }
+ }
+
+ _vm->_system->updateScreen();
+ _inventoryDrawn = true;
+}
+
+void RivenGraphics::hideInventory() {
+ // Don't hide the inventory twice
+ if (!_inventoryDrawn)
+ return;
+
+ // Clear the area
+ clearInventoryArea();
+
+ _inventoryDrawn = false;
+}
+
+void RivenGraphics::clearInventoryArea() {
+ // Clear the inventory area
+ static const Common::Rect inventoryRect = Common::Rect(0, 392, 608, 436);
+
+ // Lock the screen
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+
+ // Fill the inventory area with black
+ screen->fillRect(inventoryRect, _pixelFormat.RGBToColor(0, 0, 0));
+
+ _vm->_system->unlockScreen();
+}
+
+void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) {
+ MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id));
+ mhkSurface->convertToTrueColor();
+ Graphics::Surface *surface = mhkSurface->getSurface();
+
+ _vm->_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h);
+
+ delete mhkSurface;
+}
+
+void RivenGraphics::drawRect(Common::Rect rect, bool active) {
+ // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active.
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+
+ if (active)
+ screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0));
+ else
+ screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0));
+
+ _vm->_system->unlockScreen();
+}
+
+void RivenGraphics::drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect) {
+ // Draw tBMP id from srcRect to dstRect
+ Graphics::Surface *surface = findImage(id)->getSurface();
+
+ assert(srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height());
+
+ for (uint16 i = 0; i < srcRect.height(); i++)
+ memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(srcRect.left, i + srcRect.top), srcRect.width() * surface->format.bytesPerPixel);
+
+ _dirtyScreen = true;
+}
+
+void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) {
+ MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id));
+ mhkSurface->convertToTrueColor();
+ Graphics::Surface *surface = mhkSurface->getSurface();
+
+ assert(dstRect.width() == surface->w);
+
+ for (uint16 i = 0; i < surface->h; i++)
+ memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(0, i), surface->pitch);
+
+ delete mhkSurface;
+ _dirtyScreen = true;
+}
+
+void RivenGraphics::beginCredits() {
+ // Clear the old cache
+ clearCache();
+
+ // Now cache all the credits images
+ for (uint16 i = 302; i <= 320; i++) {
+ MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, i));
+ surface->convertToTrueColor();
+ addImageToCache(i, surface);
+ }
+
+ // And clear our screen too
+ clearMainScreen();
+}
+
+void RivenGraphics::updateCredits() {
+ if ((_creditsImage == 303 || _creditsImage == 304) && _creditsPos == 0)
+ fadeToBlack();
+
+ if (_creditsImage < 304) {
+ // For the first two credit images, they are faded from black to the image and then out again
+ scheduleTransition(16);
+
+ Graphics::Surface *frame = findImage(_creditsImage++)->getSurface();
+
+ for (int y = 0; y < frame->h; y++)
+ memcpy(_mainScreen->getBasePtr(124, y), frame->getBasePtr(0, y), frame->pitch);
+
+ runScheduledTransition();
+ } else {
+ // Otheriwse, we're scrolling
+ // Move the screen up one row
+ memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1));
+
+ // Only update as long as we're not before the last frame
+ // Otherwise, we're just moving up a row (which we already did)
+ if (_creditsImage <= 320) {
+ // Copy the next row to the bottom of the screen
+ Graphics::Surface *frame = findImage(_creditsImage)->getSurface();
+ memcpy(_mainScreen->getBasePtr(124, _mainScreen->h - 1), frame->getBasePtr(0, _creditsPos), frame->pitch);
+ _creditsPos++;
+
+ if (_creditsPos == _mainScreen->h) {
+ _creditsImage++;
+ _creditsPos = 0;
+ }
+ }
+
+ // Now flush the new screen
+ _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h);
+ _vm->_system->updateScreen();
+ }
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_graphics.h b/engines/mohawk/riven_graphics.h
new file mode 100644
index 0000000000..48dda28afd
--- /dev/null
+++ b/engines/mohawk/riven_graphics.h
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MOHAWK_RIVEN_GRAPHICS_H
+#define MOHAWK_RIVEN_GRAPHICS_H
+
+#include "mohawk/graphics.h"
+
+namespace Mohawk {
+
+class MohawkEngine_Riven;
+
+class RivenGraphics : public GraphicsManager {
+public:
+ RivenGraphics(MohawkEngine_Riven *vm);
+ ~RivenGraphics();
+
+ void copyImageToScreen(uint16, uint32, uint32, uint32, uint32);
+ void updateScreen(Common::Rect updateRect = Common::Rect(0, 0, 608, 392));
+ bool _updatesEnabled;
+ Common::Array<uint16> _activatedPLSTs;
+ void drawPLST(uint16 x);
+ void drawRect(Common::Rect rect, bool active);
+ void drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect);
+ void drawExtrasImage(uint16 id, Common::Rect dstRect);
+
+ // Water Effect
+ void scheduleWaterEffect(uint16);
+ void clearWaterEffects();
+ bool runScheduledWaterEffects();
+
+ // Transitions
+ void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392));
+ void runScheduledTransition();
+ void fadeToBlack();
+ void setTransitionSpeed(uint32 speed) { _transitionSpeed = speed; }
+
+ // Inventory
+ void showInventory();
+ void hideInventory();
+
+ // Credits
+ void beginCredits();
+ void updateCredits();
+ uint getCurCreditsImage() { return _creditsImage; }
+
+protected:
+ MohawkSurface *decodeImage(uint16 id);
+ MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
+
+private:
+ MohawkEngine_Riven *_vm;
+ MohawkBitmap *_bitmapDecoder;
+
+ // Water Effects
+ struct SFXERecord {
+ // Record values
+ uint16 frameCount;
+ Common::Rect rect;
+ uint16 speed;
+ Common::Array<Common::SeekableReadStream *> frameScripts;
+
+ // Cur frame
+ uint16 curFrame;
+ uint32 lastFrameTime;
+ };
+ Common::Array<SFXERecord> _waterEffects;
+
+ // Transitions
+ int16 _scheduledTransition;
+ Common::Rect _transitionRect;
+ uint32 _transitionSpeed;
+
+ // Inventory
+ void clearInventoryArea();
+ void drawInventoryImage(uint16 id, const Common::Rect *rect);
+ bool _inventoryDrawn;
+
+ // Screen Related
+ Graphics::Surface *_mainScreen;
+ bool _dirtyScreen;
+ Graphics::PixelFormat _pixelFormat;
+ void clearMainScreen();
+
+ // Credits
+ uint _creditsImage, _creditsPos;
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index 6e3e9a34dc..352a018990 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -21,9 +21,9 @@
*/
#include "mohawk/cursors.h"
-#include "mohawk/graphics.h"
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
+#include "mohawk/riven_graphics.h"
#include "mohawk/riven_scripts.h"
#include "mohawk/sound.h"
#include "mohawk/video.h"
diff --git a/engines/mohawk/riven_scripts.h b/engines/mohawk/riven_scripts.h
index a871f0afa0..6df4a2e523 100644
--- a/engines/mohawk/riven_scripts.h
+++ b/engines/mohawk/riven_scripts.h
@@ -27,8 +27,6 @@
#include "common/ptr.h"
#include "common/textconsole.h"
-class MohawkEngine_Riven;
-
#define DECLARE_OPCODE(x) void x(uint16 op, uint16 argc, uint16 *argv)
namespace Mohawk {
@@ -50,6 +48,7 @@ enum {
kStoredOpcodeScript // This is ScummVM-only to denote the script from a storeMovieOpcode() call
};
+class MohawkEngine_Riven;
class RivenScript;
class RivenScript {