[Scummvm-cvs-logs] scummvm master -> 5e52b0a5d46e4c5b230cba7464301484d27804f7

clone2727 clone2727 at gmail.com
Sat Mar 10 19:55:50 CET 2012


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
5e52b0a5d4 MOHAWK: Split the graphics classes into their own files


Commit: 5e52b0a5d46e4c5b230cba7464301484d27804f7
    https://github.com/scummvm/scummvm/commit/5e52b0a5d46e4c5b230cba7464301484d27804f7
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-03-10T10:55:08-08:00

Commit Message:
MOHAWK: Split the graphics classes into their own files

Changed paths:
  A engines/mohawk/cstime_graphics.cpp
  A engines/mohawk/cstime_graphics.h
  A engines/mohawk/livingbooks_graphics.cpp
  A engines/mohawk/livingbooks_graphics.h
  A engines/mohawk/myst_graphics.cpp
  A engines/mohawk/myst_graphics.h
  A engines/mohawk/riven_graphics.cpp
  A engines/mohawk/riven_graphics.h
    engines/mohawk/console.cpp
    engines/mohawk/cstime.h
    engines/mohawk/graphics.cpp
    engines/mohawk/graphics.h
    engines/mohawk/livingbooks.h
    engines/mohawk/module.mk
    engines/mohawk/myst.cpp
    engines/mohawk/myst_areas.cpp
    engines/mohawk/myst_areas.h
    engines/mohawk/myst_scripts.cpp
    engines/mohawk/myst_stacks/channelwood.cpp
    engines/mohawk/myst_stacks/credits.cpp
    engines/mohawk/myst_stacks/demo.cpp
    engines/mohawk/myst_stacks/intro.cpp
    engines/mohawk/myst_stacks/mechanical.cpp
    engines/mohawk/myst_stacks/myst.cpp
    engines/mohawk/myst_stacks/preview.cpp
    engines/mohawk/myst_stacks/slides.cpp
    engines/mohawk/myst_stacks/stoneship.cpp
    engines/mohawk/riven.cpp
    engines/mohawk/riven_external.cpp
    engines/mohawk/riven_scripts.cpp
    engines/mohawk/riven_scripts.h



diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index 0234c86..a7a650d 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 0bc236f..db06b97 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 0000000..3a1452e
--- /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 0000000..5f034f4
--- /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 2ffabf1..a08d034 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 8fa5d5f..51d25db 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 23ab0ac..91d6a8c 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 0000000..fb764fa
--- /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 0000000..3e26097
--- /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 882f396..83e541e 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 eeb4594..c22b30a 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 294fcea..fe33cea 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 297a7cc..62af5ec 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 0000000..1513905
--- /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 0000000..e2b02db
--- /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 ca8e985..b935331 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 9ca47cc..069281f 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 ad593e3..192e55d 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 fbad7dc..29a1257 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 7d3179f..0af386f 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 12d9dc7..79de033 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 b3222e0..c1ddc74 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 31e22bb..0b8dcf8 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 794793e..c0bb400 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 6d54d0c..ef228e6 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 3e2fa4f..38b38d2 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 9e1365f..8dfc74e 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 0000000..9415e51
--- /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 0000000..48dda28
--- /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 6e3e9a3..352a018 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 a871f0a..6df4a2e 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 {






More information about the Scummvm-git-logs mailing list