diff options
Diffstat (limited to 'engines/mohawk')
46 files changed, 1599 insertions, 1395 deletions
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp index 4edde31236..952b6daec2 100644 --- a/engines/mohawk/bitmap.cpp +++ b/engines/mohawk/bitmap.cpp @@ -29,6 +29,7 @@ #include "common/substream.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/decoders/bmp.h" namespace Mohawk { @@ -631,97 +632,37 @@ void MohawkBitmap::drawRLE8(Graphics::Surface *surface, bool isLE) { MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream* stream) { uint32 uncompressedSize = stream->readUint32LE(); - Common::SeekableReadStream* bmpStream = decompressLZ(stream, uncompressedSize); + Common::SeekableReadStream *bmpStream = decompressLZ(stream, uncompressedSize); delete stream; - _header.type = bmpStream->readUint16BE(); + Graphics::BitmapDecoder bitmapDecoder; + if (!bitmapDecoder.loadStream(*bmpStream)) + error("Could not decode Myst bitmap"); - if (_header.type != 'BM') - error("BMP header not detected"); + const Graphics::Surface *bmpSurface = bitmapDecoder.getSurface(); + Graphics::Surface *newSurface = 0; - _header.size = bmpStream->readUint32LE(); - assert (_header.size > 0); - _header.res1 = bmpStream->readUint16LE(); - _header.res2 = bmpStream->readUint16LE(); - _header.imageOffset = bmpStream->readUint32LE(); - - _info.size = bmpStream->readUint32LE(); - - if (_info.size != 40) - error("Only Windows v3 BMP's are supported"); - - _info.width = bmpStream->readUint32LE(); - _info.height = bmpStream->readUint32LE(); - _info.planes = bmpStream->readUint16LE(); - _info.bitsPerPixel = bmpStream->readUint16LE(); - _info.compression = bmpStream->readUint32LE(); - _info.imageSize = bmpStream->readUint32LE(); - _info.pixelsPerMeterX = bmpStream->readUint32LE(); - _info.pixelsPerMeterY = bmpStream->readUint32LE(); - _info.colorsUsed = bmpStream->readUint32LE(); - _info.colorsImportant = bmpStream->readUint32LE(); - - if (_info.compression != 0) - error("Unhandled BMP compression %d", _info.compression); - - if (_info.colorsUsed == 0) - _info.colorsUsed = 256; - - if (_info.bitsPerPixel != 8 && _info.bitsPerPixel != 24) - error("%dbpp Bitmaps not supported", _info.bitsPerPixel); - - byte *palData = NULL; - - if (_info.bitsPerPixel == 8) { - palData = (byte *)malloc(256 * 3); - for (uint16 i = 0; i < _info.colorsUsed; i++) { - palData[i * 3 + 2] = bmpStream->readByte(); - palData[i * 3 + 1] = bmpStream->readByte(); - palData[i * 3 + 0] = bmpStream->readByte(); - bmpStream->readByte(); - } - } - - bmpStream->seek(_header.imageOffset); - - Graphics::Surface *surface = createSurface(_info.width, _info.height); - int srcPitch = _info.width * (_info.bitsPerPixel >> 3); - const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0; - - if (_info.bitsPerPixel == 8) { - byte *dst = (byte *)surface->pixels; - - for (uint32 i = 0; i < _info.height; i++) { - bmpStream->read(dst + (_info.height - i - 1) * _info.width, _info.width); - bmpStream->skip(extraDataLength); - } + if (bmpSurface->format.bytesPerPixel == 1) { + _bitsPerPixel = 8; + newSurface = new Graphics::Surface(); + newSurface->copyFrom(*bmpSurface); } else { - Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); - - byte *dst = (byte *)surface->pixels + (surface->h - 1) * surface->pitch; - - for (uint32 i = 0; i < _info.height; i++) { - for (uint32 j = 0; j < _info.width; j++) { - byte b = bmpStream->readByte(); - byte g = bmpStream->readByte(); - byte r = bmpStream->readByte(); + _bitsPerPixel = 24; + newSurface = bmpSurface->convertTo(g_system->getScreenFormat()); + } - if (pixelFormat.bytesPerPixel == 2) - *((uint16 *)dst) = pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)dst) = pixelFormat.RGBToColor(r, g, b); + // Copy the palette to one of our own + const byte *palette = bitmapDecoder.getPalette(); + byte *newPal = 0; - dst += pixelFormat.bytesPerPixel; - } - - bmpStream->skip(extraDataLength); - dst -= surface->pitch * 2; - } + if (palette) { + newPal = (byte *)malloc(256 * 3); + memcpy(newPal, palette, 256 * 3); } delete bmpStream; - return new MohawkSurface(surface, palData); + return new MohawkSurface(newSurface, newPal); } #endif diff --git a/engines/mohawk/bitmap.h b/engines/mohawk/bitmap.h index 74218882e8..73c117b5c7 100644 --- a/engines/mohawk/bitmap.h +++ b/engines/mohawk/bitmap.h @@ -154,30 +154,10 @@ public: MohawkSurface *decodeImage(Common::SeekableReadStream *stream); protected: - byte getBitsPerPixel() { return _info.bitsPerPixel; } + byte getBitsPerPixel() { return _bitsPerPixel; } private: - struct BitmapHeader { - uint16 type; - uint32 size; - uint16 res1; - uint16 res2; - uint32 imageOffset; - } _header; - - struct InfoHeader { - uint32 size; - uint32 width; - uint32 height; - uint16 planes; - uint16 bitsPerPixel; - uint32 compression; - uint32 imageSize; - uint32 pixelsPerMeterX; - uint32 pixelsPerMeterY; - uint32 colorsUsed; - uint32 colorsImportant; - } _info; + uint16 _bitsPerPixel; }; #endif diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 0234c86c7e..a7a650d8ed 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -21,7 +21,6 @@ */ #include "mohawk/console.h" -#include "mohawk/graphics.h" #include "mohawk/livingbooks.h" #include "mohawk/sound.h" #include "mohawk/video.h" @@ -36,6 +35,7 @@ #ifdef ENABLE_MYST #include "mohawk/myst.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_scripts.h" #endif diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h index 0bc236f930..db06b9791e 100644 --- a/engines/mohawk/cstime.h +++ b/engines/mohawk/cstime.h @@ -25,7 +25,7 @@ #include "mohawk/mohawk.h" #include "mohawk/console.h" -#include "mohawk/graphics.h" +#include "mohawk/cstime_graphics.h" #include "common/random.h" #include "common/list.h" diff --git a/engines/mohawk/cstime_graphics.cpp b/engines/mohawk/cstime_graphics.cpp new file mode 100644 index 0000000000..3a1452e67c --- /dev/null +++ b/engines/mohawk/cstime_graphics.cpp @@ -0,0 +1,64 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "mohawk/cstime.h" +#include "mohawk/cstime_graphics.h" +#include "mohawk/resource.h" + +#include "common/system.h" +#include "engines/util.h" + +namespace Mohawk { + +CSTimeGraphics::CSTimeGraphics(MohawkEngine_CSTime *vm) : GraphicsManager(), _vm(vm) { + _bmpDecoder = new MohawkBitmap(); + + initGraphics(640, 480, true); +} + +CSTimeGraphics::~CSTimeGraphics() { + delete _bmpDecoder; +} + +void CSTimeGraphics::drawRect(Common::Rect rect, byte color) { + rect.clip(Common::Rect(640, 480)); + + // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. + if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0) + return; + + Graphics::Surface *screen = _vm->_system->lockScreen(); + + screen->frameRect(rect, color); + + _vm->_system->unlockScreen(); +} + +MohawkSurface *CSTimeGraphics::decodeImage(uint16 id) { + return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); +} + +Common::Array<MohawkSurface *> CSTimeGraphics::decodeImages(uint16 id) { + return _bmpDecoder->decodeImages(_vm->getResource(ID_TBMH, id)); +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/cstime_graphics.h b/engines/mohawk/cstime_graphics.h new file mode 100644 index 0000000000..5f034f47f4 --- /dev/null +++ b/engines/mohawk/cstime_graphics.h @@ -0,0 +1,51 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MOHAWK_CSTIME_GRAPHICS_H +#define MOHAWK_CSTIME_GRAPHICS_H + +#include "mohawk/graphics.h" + +namespace Mohawk { + +class MohawkEngine_CSTime; + +class CSTimeGraphics : public GraphicsManager { +public: + CSTimeGraphics(MohawkEngine_CSTime *vm); + ~CSTimeGraphics(); + + void drawRect(Common::Rect rect, byte color); + +protected: + MohawkSurface *decodeImage(uint16 id); + Common::Array<MohawkSurface *> decodeImages(uint16 id); + MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + +private: + MohawkBitmap *_bmpDecoder; + MohawkEngine_CSTime *_vm; +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 998c2ef56d..5acc1bb179 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -376,7 +376,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUIO2(GUIO_NOASPECT, GUIO_NOLAUNCHLOAD) }, GType_RIVEN, GF_DEMO, @@ -1011,6 +1011,22 @@ static const MohawkGameDescription gameDescriptions[] = { 0, }, + // Tortoise and the Hare Hebrew variant - From georgeqgreg on bug #3441928 + { + { + "tortoise", + "", + AD_ENTRY1("TORTB.LB", "23135777370cf1ff00aa7247e93642d3"), + Common::HE_ISR, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV2, + 0, + 0, + }, + // From afholman in bug#3309308 { { @@ -1293,6 +1309,23 @@ static const MohawkGameDescription gameDescriptions[] = { 0 }, + // Just Grandma and Me 2.0 Macintosh + // From aluff in bug #3461368 + { + { + "grandma", + "v2.0", + AD_ENTRY1("BookOutline", "99fe5c8ace79f0542e6390bc3b58f25a"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + // Just Grandma and Me 1.0 // From scoriae { @@ -1782,6 +1815,23 @@ static const MohawkGameDescription gameDescriptions[] = { 0 }, + // Arthur Birthday (English) Version 2.0 Macintosh + // From aluff in bug #3461368 + { + { + "arthurbday", + "", + AD_ENTRY1("BookOutline", "8e4fddb5b761c8cf2a3b448dd38422be"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + { { "arthurbday", @@ -1970,6 +2020,22 @@ static const MohawkGameDescription gameDescriptions[] = { "MONSTER.EXE" }, + // From GeorgeQGreg + { + { + "lilmonster", + "Demo", + AD_ENTRY1("MONSTER.512", "f603f04c1824d1034ec0366416a059c9"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + "MONSTER.EXE" + }, + { { "catinthehat", @@ -2235,6 +2301,22 @@ static const MohawkGameDescription gameDescriptions[] = { 0 }, + // From aluff in bug #3461368 + { + { + "beardark", + "", + AD_ENTRY1("BookOutline", "b56746b3b2c062c8588bfb6b28e137c1"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + { { "arthurcomp", diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index dcb0c7940d..0f9a62c891 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 { @@ -75,22 +58,7 @@ void MohawkSurface::convertToTrueColor() { assert(_palette); - Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); - Graphics::Surface *surface = new Graphics::Surface(); - surface->create(_surface->w, _surface->h, pixelFormat); - - for (uint16 i = 0; i < _surface->h; i++) { - for (uint16 j = 0; j < _surface->w; j++) { - byte palIndex = *((byte *)_surface->pixels + i * _surface->pitch + j); - byte r = _palette[palIndex * 3 + 0]; - byte g = _palette[palIndex * 3 + 1]; - byte b = _palette[palIndex * 3 + 2]; - if (pixelFormat.bytesPerPixel == 2) - *((uint16 *)surface->getBasePtr(j, i)) = pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)surface->getBasePtr(j, i)) = pixelFormat.RGBToColor(r, g, b); - } - } + Graphics::Surface *surface = _surface->convertTo(g_system->getScreenFormat(), _palette); // Free everything and set the new surface as the converted surface _surface->free(); @@ -108,9 +76,9 @@ GraphicsManager::~GraphicsManager() { } void GraphicsManager::clearCache() { - for (Common::HashMap<uint16, MohawkSurface*>::iterator it = _cache.begin(); it != _cache.end(); it++) + for (Common::HashMap<uint16, MohawkSurface *>::iterator it = _cache.begin(); it != _cache.end(); it++) delete it->_value; - for (Common::HashMap<uint16, Common::Array<MohawkSurface*> >::iterator it = _subImageCache.begin(); it != _subImageCache.end(); it++) { + for (Common::HashMap<uint16, Common::Array<MohawkSurface *> >::iterator it = _subImageCache.begin(); it != _subImageCache.end(); it++) { Common::Array<MohawkSurface *> &array = it->_value; for (uint i = 0; i < array.size(); i++) delete array[i]; @@ -262,986 +230,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 463608a2aa..51d25db5d9 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -25,12 +25,11 @@ #include "mohawk/bitmap.h" -#include "common/file.h" #include "common/hashmap.h" -#include "graphics/pict.h" +#include "common/rect.h" namespace Graphics { -class JPEG; +struct Surface; } namespace Mohawk { @@ -99,200 +98,10 @@ protected: private: // An image cache that stores images until clearCache() is called - Common::HashMap<uint16, MohawkSurface*> _cache; - Common::HashMap<uint16, Common::Array<MohawkSurface*> > _subImageCache; + Common::HashMap<uint16, MohawkSurface *> _cache; + 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/installer_archive.cpp b/engines/mohawk/installer_archive.cpp index 83796158a6..636b7ae476 100644 --- a/engines/mohawk/installer_archive.cpp +++ b/engines/mohawk/installer_archive.cpp @@ -107,18 +107,18 @@ void InstallerArchive::close() { _map.clear(); } -bool InstallerArchive::hasFile(const Common::String &name) { +bool InstallerArchive::hasFile(const Common::String &name) const { return _map.contains(name); } -int InstallerArchive::listMembers(Common::ArchiveMemberList &list) { +int InstallerArchive::listMembers(Common::ArchiveMemberList &list) const { for (FileMap::const_iterator it = _map.begin(); it != _map.end(); it++) list.push_back(getMember(it->_key)); return _map.size(); } -Common::ArchiveMemberPtr InstallerArchive::getMember(const Common::String &name) { +const Common::ArchiveMemberPtr InstallerArchive::getMember(const Common::String &name) const { return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); } diff --git a/engines/mohawk/installer_archive.h b/engines/mohawk/installer_archive.h index 27877d69f9..89d2d85f8d 100644 --- a/engines/mohawk/installer_archive.h +++ b/engines/mohawk/installer_archive.h @@ -43,9 +43,9 @@ public: bool isOpen() const { return _stream != 0; } // Common::Archive API implementation - bool hasFile(const Common::String &name); - int listMembers(Common::ArchiveMemberList &list); - Common::ArchiveMemberPtr getMember(const Common::String &name); + bool hasFile(const Common::String &name) const; + int listMembers(Common::ArchiveMemberList &list) const; + const Common::ArchiveMemberPtr getMember(const Common::String &name) const; Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; private: diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp index 08f3b86c7c..708478a6d8 100644 --- a/engines/mohawk/livingbooks.cpp +++ b/engines/mohawk/livingbooks.cpp @@ -388,10 +388,13 @@ bool MohawkEngine_LivingBooks::loadPage(LBMode mode, uint page, uint subpage) { } // TODO: fading between pages +#if 0 bool fade = false; if (leftover.contains("fade")) { fade = true; } +#endif + if (leftover.contains("read")) { _readOnly = true; } diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h index 23ab0acfb1..91d6a8cd30 100644 --- a/engines/mohawk/livingbooks.h +++ b/engines/mohawk/livingbooks.h @@ -25,7 +25,7 @@ #include "mohawk/mohawk.h" #include "mohawk/console.h" -#include "mohawk/graphics.h" +#include "mohawk/livingbooks_graphics.h" #include "mohawk/sound.h" #include "common/config-file.h" diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp index 41acea19c4..bb8f7a0d05 100644 --- a/engines/mohawk/livingbooks_code.cpp +++ b/engines/mohawk/livingbooks_code.cpp @@ -1766,7 +1766,7 @@ uint LBCode::parseCode(const Common::String &source) { { Common::String tempString; while (pos < source.size()) { - if (!isalpha(source[pos]) && !isdigit(source[pos])) + if (!Common::isAlpha(source[pos]) && !Common::isDigit(source[pos])) break; tempString += source[pos++]; } @@ -1777,7 +1777,7 @@ uint LBCode::parseCode(const Common::String &source) { } break; default: - if (isdigit(token)) { + if (Common::isDigit(token)) { const char *in = source.c_str() + pos - 1; // FIXME: handle floats? char *endptr; @@ -1792,11 +1792,11 @@ uint LBCode::parseCode(const Common::String &source) { WRITE_BE_UINT16(tmp, (int16)intValue); code.push_back(tmp[0]); code.push_back(tmp[1]); - } else if (isalpha(token)) { + } else if (Common::isAlpha(token)) { Common::String tempString; tempString += token; while (pos < source.size()) { - if (!isalpha(source[pos]) && !isdigit(source[pos])) + if (!Common::isAlpha(source[pos]) && !Common::isDigit(source[pos])) break; tempString += source[pos++]; } diff --git a/engines/mohawk/livingbooks_graphics.cpp b/engines/mohawk/livingbooks_graphics.cpp new file mode 100644 index 0000000000..fb764fa15b --- /dev/null +++ b/engines/mohawk/livingbooks_graphics.cpp @@ -0,0 +1,102 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "mohawk/resource.h" +#include "mohawk/livingbooks.h" +#include "mohawk/livingbooks_graphics.h" + +#include "common/substream.h" +#include "common/system.h" +#include "engines/util.h" +#include "graphics/palette.h" + +namespace Mohawk { + +LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height) : GraphicsManager(), _vm(vm) { + _bmpDecoder = _vm->isPreMohawk() ? new LivingBooksBitmap_v1() : new MohawkBitmap(); + + initGraphics(width, height, true); +} + +LBGraphics::~LBGraphics() { + delete _bmpDecoder; +} + +MohawkSurface *LBGraphics::decodeImage(uint16 id) { + if (_vm->isPreMohawk()) + return _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, id)); + + return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); +} + +void LBGraphics::copyOffsetAnimImageToScreen(uint16 image, int left, int top) { + MohawkSurface *mhkSurface = findImage(image); + + left -= mhkSurface->getOffsetX(); + top -= mhkSurface->getOffsetY(); + + GraphicsManager::copyAnimImageToScreen(image, left, top); +} + +bool LBGraphics::imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y) { + MohawkSurface *mhkSurface = findImage(image); + + if (useOffsets) { + x += mhkSurface->getOffsetX(); + y += mhkSurface->getOffsetY(); + } + + if (x < 0 || y < 0) + return true; + + Graphics::Surface *surface = mhkSurface->getSurface(); + if (x >= surface->w || y >= surface->h) + return true; + + return *(byte *)surface->getBasePtr(x, y) == 0; +} + +void LBGraphics::setPalette(uint16 id) { + // Old Living Books games use the old CTBL-style palette format while newer + // games use the better tPAL format which can store partial palettes. + if (_vm->isPreMohawk()) { + Common::SeekableSubReadStreamEndian *ctblStream = _vm->wrapStreamEndian(ID_CTBL, id); + uint16 colorCount = ctblStream->readUint16(); + byte *palette = new byte[colorCount * 3]; + + for (uint16 i = 0; i < colorCount; i++) { + palette[i * 3 + 0] = ctblStream->readByte(); + palette[i * 3 + 1] = ctblStream->readByte(); + palette[i * 3 + 2] = ctblStream->readByte(); + ctblStream->readByte(); + } + + delete ctblStream; + + _vm->_system->getPaletteManager()->setPalette(palette, 0, colorCount); + delete[] palette; + } else { + GraphicsManager::setPalette(id); + } +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/livingbooks_graphics.h b/engines/mohawk/livingbooks_graphics.h new file mode 100644 index 0000000000..3e2609750a --- /dev/null +++ b/engines/mohawk/livingbooks_graphics.h @@ -0,0 +1,52 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MOHAWK_LIVINGBOOKS_GRAPHICS_H +#define MOHAWK_LIVINGBOOKS_GRAPHICS_H + +#include "mohawk/graphics.h" + +namespace Mohawk { + +class MohawkEngine_LivingBooks; + +class LBGraphics : public GraphicsManager { +public: + LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height); + ~LBGraphics(); + + void setPalette(uint16 id); + void copyOffsetAnimImageToScreen(uint16 image, int left = 0, int top = 0); + bool imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y); + +protected: + MohawkSurface *decodeImage(uint16 id); + MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + +private: + MohawkBitmap *_bmpDecoder; + MohawkEngine_LivingBooks *_vm; +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk index 882f3966b2..83e541e3e4 100644 --- a/engines/mohawk/module.mk +++ b/engines/mohawk/module.mk @@ -10,6 +10,7 @@ MODULE_OBJS = \ installer_archive.o \ livingbooks.o \ livingbooks_code.o \ + livingbooks_graphics.o \ livingbooks_lbx.o \ mohawk.o \ resource.o \ @@ -22,6 +23,7 @@ MODULE_OBJS += \ cstime.o \ cstime_cases.o \ cstime_game.o \ + cstime_graphics.o \ cstime_ui.o \ cstime_view.o endif @@ -30,6 +32,7 @@ ifdef ENABLE_MYST MODULE_OBJS += \ myst.o \ myst_areas.o \ + myst_graphics.o \ myst_scripts.o \ myst_state.o \ resource_cache.o \ @@ -51,6 +54,7 @@ ifdef ENABLE_RIVEN MODULE_OBJS += \ riven.o \ riven_external.o \ + riven_graphics.o \ riven_saveload.o \ riven_scripts.o \ riven_vars.o diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index eeb4594f3c..c22b30ad4d 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -27,9 +27,9 @@ #include "common/textconsole.h" #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/myst.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_scripts.h" #include "mohawk/myst_state.h" #include "mohawk/dialogs.h" diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h index 02f0a46e3f..30770f7ec9 100644 --- a/engines/mohawk/myst.h +++ b/engines/mohawk/myst.h @@ -173,7 +173,7 @@ public: MystGraphics *_gfx; MystGameState *_gameState; MystScriptParser *_scriptParser; - Common::Array<MystResource*> _resources; + Common::Array<MystResource *> _resources; MystResource *_dragResource; Common::RandomSource *_rnd; diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp index 294fcea2f1..a54b67bef4 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" @@ -134,7 +134,7 @@ const Common::String MystResourceType5::describe() { desc += " ops:"; for (uint i = 0; i < _script->size(); i++) - desc += " " + _vm->_scriptParser->getOpcodeDesc(_script->operator[](i).opcode); + desc += " " + _vm->_scriptParser->getOpcodeDesc((*_script)[i].opcode); } return desc; diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h index 136356ea4f..62af5ec4cf 100644 --- a/engines/mohawk/myst_areas.h +++ b/engines/mohawk/myst_areas.h @@ -20,11 +20,13 @@ * */ +#ifndef MYST_AREAS_H +#define MYST_AREAS_H + #include "mohawk/myst.h" #include "mohawk/video.h" -#ifndef MYST_AREAS_H -#define MYST_AREAS_H +#include "common/rect.h" namespace Mohawk { @@ -137,7 +139,7 @@ public: protected: uint16 _var7; uint16 _numSubResources; - Common::Array<MystResource*> _subResources; + Common::Array<MystResource *> _subResources; }; class MystResourceType8 : public MystResourceType7 { diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp new file mode 100644 index 0000000000..484e49d529 --- /dev/null +++ b/engines/mohawk/myst_graphics.cpp @@ -0,0 +1,494 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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/decoders/jpeg.h" +#include "graphics/decoders/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"); + + _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[] _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) { + Graphics::JPEGDecoder jpeg; + Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); + + if (!jpeg.loadStream(subStream)) + error("Could not decode Myst ME Mac JPEG"); + + mhkSurface = new MohawkSurface(jpeg.getSurface()->convertTo(_pixelFormat)); + } else if (_pictureFile.entries[i].type == 1) { + Graphics::PICTDecoder pict; + Common::SeekableSubReadStream subStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); + + if (!pict.loadStream(subStream)) + error("Could not decode Myst ME Mac PICT"); + + mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); + } 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) { + Graphics::PICTDecoder pict; + + if (!pict.loadStream(*dataStream)) + error("Could not decode Myst ME PICT"); + + mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); + } else { + mhkSurface = _bmpDecoder->decodeImage(dataStream); + mhkSurface->convertToTrueColor(); + } + } + + assert(mhkSurface); + return mhkSurface; +} + +void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest) { + Graphics::Surface *surface = findImage(image)->getSurface(); + + // Make sure the image is bottom aligned in the dest rect + dest.top = dest.bottom - MIN<int>(surface->h, dest.height()); + + // Convert from bitmap coordinates to surface coordinates + uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height())); + + // Do not draw the top pixels if the image is too tall + if (dest.height() > _viewport.height()) + top += dest.height() - _viewport.height(); + + // Clip the destination rect to the screen + if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight()) + dest.debugPrint(4, "Clipping destination rect to the screen"); + dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth()); + dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight()); + + uint16 width = MIN<int>(surface->w, dest.width()); + uint16 height = MIN<int>(surface->h, dest.height()); + + // Clamp Width and Height to within src surface dimensions + if (src.left + width > surface->w) + width = surface->w - src.left; + if (src.top + height > surface->h) + height = surface->h - src.top; + + debug(3, "MystGraphics::copyImageSectionToScreen()"); + debug(3, "\tImage: %d", image); + debug(3, "\tsrc.left: %d", src.left); + debug(3, "\tsrc.top: %d", src.top); + debug(3, "\tdest.left: %d", dest.left); + debug(3, "\tdest.top: %d", dest.top); + debug(3, "\twidth: %d", width); + debug(3, "\theight: %d", height); + + simulatePreviousDrawDelay(dest); + + _vm->_system->copyRectToScreen((byte *)surface->getBasePtr(src.left, top), surface->pitch, dest.left, dest.top, width, height); +} + +void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest) { + Graphics::Surface *surface = findImage(image)->getSurface(); + + // Make sure the image is bottom aligned in the dest rect + dest.top = dest.bottom - MIN<int>(surface->h, dest.height()); + + // Convert from bitmap coordinates to surface coordinates + uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height())); + + // Do not draw the top pixels if the image is too tall + if (dest.height() > _viewport.height()) { + top += dest.height() - _viewport.height(); + } + + // Clip the destination rect to the screen + if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight()) + dest.debugPrint(4, "Clipping destination rect to the screen"); + dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth()); + dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight()); + + uint16 width = MIN<int>(surface->w, dest.width()); + uint16 height = MIN<int>(surface->h, dest.height()); + + // Clamp Width and Height to within src surface dimensions + if (src.left + width > surface->w) + width = surface->w - src.left; + if (src.top + height > surface->h) + height = surface->h - src.top; + + debug(3, "MystGraphics::copyImageSectionToBackBuffer()"); + debug(3, "\tImage: %d", image); + debug(3, "\tsrc.left: %d", src.left); + debug(3, "\tsrc.top: %d", src.top); + debug(3, "\tdest.left: %d", dest.left); + debug(3, "\tdest.top: %d", dest.top); + debug(3, "\twidth: %d", width); + debug(3, "\theight: %d", height); + + for (uint16 i = 0; i < height; i++) + memcpy(_backBuffer->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->format.bytesPerPixel); +} + +void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) { + copyImageSectionToScreen(image, Common::Rect(544, 333), dest); +} + +void MystGraphics::copyImageToBackBuffer(uint16 image, Common::Rect dest) { + copyImageSectionToBackBuffer(image, Common::Rect(544, 333), dest); +} + +void MystGraphics::copyBackBufferToScreen(Common::Rect r) { + r.clip(_viewport); + + simulatePreviousDrawDelay(r); + + _vm->_system->copyRectToScreen((byte *)_backBuffer->getBasePtr(r.left, r.top), _backBuffer->pitch, r.left, r.top, r.width(), r.height()); +} + +void MystGraphics::runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay) { + + // Do not artificially delay during transitions + int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation; + _enableDrawingTimeSimulation = 0; + + switch (type) { + case 0: { + debugC(kDebugScript, "Left to Right"); + + uint16 step = (rect.right - rect.left) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.left = rect.left + step * i; + area.right = area.left + step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.right < rect.right) { + area.left = area.right; + area.right = rect.right; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + case 1: { + debugC(kDebugScript, "Right to Left"); + + uint16 step = (rect.right - rect.left) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.right = rect.right - step * i; + area.left = area.right - step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.left > rect.left) { + area.right = area.left; + area.left = rect.left; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + case 5: { + debugC(kDebugScript, "Top to Bottom"); + + uint16 step = (rect.bottom - rect.top) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.top = rect.top + step * i; + area.bottom = area.top + step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.bottom < rect.bottom) { + area.top = area.bottom; + area.bottom = rect.bottom; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + case 6: { + debugC(kDebugScript, "Bottom to Top"); + + uint16 step = (rect.bottom - rect.top) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.bottom = rect.bottom - step * i; + area.top = area.bottom - step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.top > rect.top) { + area.bottom = area.top; + area.top = rect.top; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + default: + warning("Unknown Update Direction"); + + //TODO: Replace minimal implementation + copyBackBufferToScreen(rect); + _vm->_system->updateScreen(); + break; + } + + _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation; +} + +void MystGraphics::drawRect(Common::Rect rect, RectState state) { + rect.clip(_viewport); + + // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. + if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0) + return; + + Graphics::Surface *screen = _vm->_system->lockScreen(); + + if (state == kRectEnabled) + screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0)); + else if (state == kRectUnreachable) + screen->frameRect(rect, _pixelFormat.RGBToColor(0, 0, 255)); + else + screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0)); + + _vm->_system->unlockScreen(); +} + +void MystGraphics::drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color) { + _backBuffer->drawLine(p1.x, p1.y, p2.x, p2.y, color); +} + +void MystGraphics::enableDrawingTimeSimulation(bool enable) { + if (enable) + _enableDrawingTimeSimulation++; + else + _enableDrawingTimeSimulation--; + + if (_enableDrawingTimeSimulation < 0) + _enableDrawingTimeSimulation = 0; +} + +void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) { + uint32 time = 0; + + if (_enableDrawingTimeSimulation) { + time = _vm->_system->getMillis(); + + // Do not draw anything new too quickly after the previous draw call + // so that images stay at least a little while on screen + // This is enabled only for scripted draw calls + if (time < _nextAllowedDrawTime) + _vm->_system->delayMillis(_nextAllowedDrawTime - time); + } + + // Next draw call allowed at DELAY + AERA * COEFF milliseconds from now + time = _vm->_system->getMillis(); + _nextAllowedDrawTime = time + _constantDrawDelay + dest.height() * dest.width() / _proportionalDrawDelay; +} + +void MystGraphics::copyBackBufferToScreenWithSaturation(int16 saturation) { + Graphics::Surface *screen = _vm->_system->lockScreen(); + + for (uint16 y = 0; y < _viewport.height(); y++) + for (uint16 x = 0; x < _viewport.width(); x++) { + uint32 color; + uint8 r, g, b; + + if (_pixelFormat.bytesPerPixel == 2) + color = *(const uint16 *)_backBuffer->getBasePtr(x, y); + else + color = *(const uint32 *)_backBuffer->getBasePtr(x, y); + + _pixelFormat.colorToRGB(color, r, g, b); + + r = CLIP<int16>((int16)r - saturation, 0, 255); + g = CLIP<int16>((int16)g - saturation, 0, 255); + b = CLIP<int16>((int16)b - saturation, 0, 255); + + color = _pixelFormat.RGBToColor(r, g, b); + + if (_pixelFormat.bytesPerPixel == 2) { + uint16 *dst = (uint16 *)screen->getBasePtr(x, y); + *dst = color; + } else { + uint32 *dst = (uint32 *)screen->getBasePtr(x, y); + *dst = color; + } + } + + _vm->_system->unlockScreen(); + _vm->_system->updateScreen(); +} + +void MystGraphics::fadeToBlack() { + for (int16 i = 0; i < 256; i += 32) { + copyBackBufferToScreenWithSaturation(i); + } +} + +void MystGraphics::fadeFromBlack() { + for (int16 i = 256; i >= 0; i -= 32) { + copyBackBufferToScreenWithSaturation(i); + } +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h new file mode 100644 index 0000000000..20fd46c5b9 --- /dev/null +++ b/engines/mohawk/myst_graphics.h @@ -0,0 +1,95 @@ +/* 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 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; + + struct PictureFile { + uint32 pictureCount; + struct PictureEntry { + uint32 offset; + uint32 size; + uint16 id; + uint16 type; + uint16 width; + uint16 height; + } *entries; + + Common::File picFile; + } _pictureFile; + + Graphics::Surface *_backBuffer; + Graphics::PixelFormat _pixelFormat; + Common::Rect _viewport; + + int _enableDrawingTimeSimulation; + uint32 _nextAllowedDrawTime; + static const uint _constantDrawDelay = 10; // ms + static const uint _proportionalDrawDelay = 500; // pixels per ms +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index ca8e985491..107a8b03e9 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" @@ -161,7 +161,7 @@ void MystScriptParser::runScript(MystScript script, MystResource *invokingResour _vm->_gfx->enableDrawingTimeSimulation(true); for (uint16 i = 0; i < script->size(); i++) { - MystScriptEntry &entry = script->operator[](i); + MystScriptEntry &entry = (*script)[i]; debugC(kDebugScript, "\tOpcode %d: %d", i, entry.opcode); if (entry.type == kMystScriptNormal) @@ -207,7 +207,7 @@ MystScript MystScriptParser::readScript(Common::SeekableReadStream *stream, Myst script->resize(opcodeCount); for (uint16 i = 0; i < opcodeCount; i++) { - MystScriptEntry &entry = script->operator[](i); + MystScriptEntry &entry = (*script)[i]; entry.type = type; // Resource ID only exists in INIT and EXIT scripts diff --git a/engines/mohawk/myst_scripts.h b/engines/mohawk/myst_scripts.h index 18f5b27a6d..ccb76e0dc8 100644 --- a/engines/mohawk/myst_scripts.h +++ b/engines/mohawk/myst_scripts.h @@ -143,7 +143,7 @@ protected: const char *desc; }; - Common::Array<MystOpcode*> _opcodes; + Common::Array<MystOpcode *> _opcodes; MystResource *_invokingResource; diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp index 9ca47cc92a..069281f5dc 100644 --- a/engines/mohawk/myst_stacks/channelwood.cpp +++ b/engines/mohawk/myst_stacks/channelwood.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp index ad593e3542..192e55d5e3 100644 --- a/engines/mohawk/myst_stacks/credits.cpp +++ b/engines/mohawk/myst_stacks/credits.cpp @@ -21,8 +21,8 @@ */ #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" #include "mohawk/myst_stacks/credits.h" diff --git a/engines/mohawk/myst_stacks/demo.cpp b/engines/mohawk/myst_stacks/demo.cpp index fbad7dc384..29a12571fd 100644 --- a/engines/mohawk/myst_stacks/demo.cpp +++ b/engines/mohawk/myst_stacks/demo.cpp @@ -21,8 +21,8 @@ */ #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/myst.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_stacks/demo.h" #include "common/system.h" diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp index 7d3179fa24..0af386f51f 100644 --- a/engines/mohawk/myst_stacks/intro.cpp +++ b/engines/mohawk/myst_stacks/intro.cpp @@ -21,8 +21,8 @@ */ #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp index 12d9dc7e2f..79de03308c 100644 --- a/engines/mohawk/myst_stacks/mechanical.cpp +++ b/engines/mohawk/myst_stacks/mechanical.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp index b6c0a3212f..c1ddc74c82 100644 --- a/engines/mohawk/myst_stacks/myst.cpp +++ b/engines/mohawk/myst_stacks/myst.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" @@ -2978,15 +2978,17 @@ void Myst::clockReset() { } void Myst::clockResetWeight() { - // Set video bounds, weight going up + _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0); + if (!(_vm->getFeatures() & GF_ME)) { - _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0); + // Set video bounds, weight going up _vm->_video->setVideoBounds(_clockWeightVideo, Audio::Timestamp(0, 2214 * 2 - _clockWeightPosition, 600), Audio::Timestamp(0, 2214 * 2, 600)); } else { - //FIXME: Needs QT backwards playing + //FIXME: Needs QT backwards playing, for now just display the weight up warning("Weight going back up not implemented"); + _vm->_video->drawVideoFrame(_clockWeightVideo, Audio::Timestamp(0, 0, 600)); } // Reset position diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp index 31e22bb8c5..0b8dcf897a 100644 --- a/engines/mohawk/myst_stacks/preview.cpp +++ b/engines/mohawk/myst_stacks/preview.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" #include "mohawk/myst_stacks/preview.h" diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp index 794793e49c..c0bb400db1 100644 --- a/engines/mohawk/myst_stacks/slides.cpp +++ b/engines/mohawk/myst_stacks/slides.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" #include "mohawk/myst_stacks/slides.h" diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp index 6d54d0c586..ef228e62f3 100644 --- a/engines/mohawk/myst_stacks/stoneship.cpp +++ b/engines/mohawk/myst_stacks/stoneship.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 3e2fa4f979..95a8313536 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" @@ -171,7 +171,7 @@ Common::Error MohawkEngine_Riven::run() { error ("Could not find saved game"); // Attempt to load the game. On failure, just send us to the main menu. - if (!_saveLoad->loadGame(savedGamesList[gameToLoad])) { + if (_saveLoad->loadGame(savedGamesList[gameToLoad]).getCode() != Common::kNoError) { changeToStack(aspit); changeToCard(1); } @@ -729,7 +729,7 @@ void MohawkEngine_Riven::runLoadDialog() { } Common::Error MohawkEngine_Riven::loadGameState(int slot) { - return _saveLoad->loadGame(_saveLoad->generateSaveGameList()[slot]) ? Common::kNoError : Common::kUnknownError; + return _saveLoad->loadGame(_saveLoad->generateSaveGameList()[slot]); } Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String &desc) { @@ -738,7 +738,7 @@ Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String & if ((uint)slot < saveList.size()) _saveLoad->deleteSave(saveList[slot]); - return _saveLoad->saveGame(Common::String(desc)) ? Common::kNoError : Common::kUnknownError; + return _saveLoad->saveGame(desc); } Common::String MohawkEngine_Riven::getStackName(uint16 stack) const { diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index e99a9f78fc..961d85d61a 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -130,8 +130,8 @@ public: GUI::Debugger *getDebugger(); - bool canLoadGameStateCurrently() { return true; } - bool canSaveGameStateCurrently() { return true; } + bool canLoadGameStateCurrently() { return !(getFeatures() & GF_DEMO); } + bool canSaveGameStateCurrently() { return !(getFeatures() & GF_DEMO); } Common::Error loadGameState(int slot); Common::Error saveGameState(int slot, const Common::String &desc); bool hasFeature(EngineFeature f) const; diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 9e1365f8da..8dfc74ebf0 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -21,9 +21,9 @@ */ #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/riven.h" #include "mohawk/riven_external.h" +#include "mohawk/riven_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h index 5f5d0cb0b2..9f076325a2 100644 --- a/engines/mohawk/riven_external.h +++ b/engines/mohawk/riven_external.h @@ -53,7 +53,7 @@ private: ExternalCmd proc; }; - Common::Array<RivenExternalCmd*> _externalCommands; + Common::Array<RivenExternalCmd *> _externalCommands; void setupCommands(); // Supplementary Functions diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp new file mode 100644 index 0000000000..9415e51412 --- /dev/null +++ b/engines/mohawk/riven_graphics.cpp @@ -0,0 +1,445 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "mohawk/resource.h" +#include "mohawk/riven.h" +#include "mohawk/riven_graphics.h" + +#include "common/system.h" +#include "engines/util.h" + +namespace Mohawk { + +RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm) { + _bitmapDecoder = new MohawkBitmap(); + + // Give me the best you've got! + initGraphics(608, 436, true, NULL); + _pixelFormat = _vm->_system->getScreenFormat(); + + if (_pixelFormat.bytesPerPixel == 1) + error("Riven requires greater than 256 colors to run"); + + // The actual game graphics only take up the first 392 rows. The inventory + // occupies the rest of the screen and we don't use the buffer to hold that. + _mainScreen = new Graphics::Surface(); + _mainScreen->create(608, 392, _pixelFormat); + + _updatesEnabled = true; + _scheduledTransition = -1; // no transition + _dirtyScreen = false; + _inventoryDrawn = false; + + _creditsImage = 302; + _creditsPos = 0; +} + +RivenGraphics::~RivenGraphics() { + _mainScreen->free(); + delete _mainScreen; + delete _bitmapDecoder; +} + +MohawkSurface *RivenGraphics::decodeImage(uint16 id) { + MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); + surface->convertToTrueColor(); + return surface; +} + +void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uint32 right, uint32 bottom) { + Graphics::Surface *surface = findImage(image)->getSurface(); + + // Clip the width to fit on the screen. Fixes some images. + if (left + surface->w > 608) + surface->w = 608 - left; + + for (uint16 i = 0; i < surface->h; i++) + memcpy(_mainScreen->getBasePtr(left, i + top), surface->getBasePtr(0, i), surface->w * surface->format.bytesPerPixel); + + _dirtyScreen = true; +} + +void RivenGraphics::drawPLST(uint16 x) { + Common::SeekableReadStream* plst = _vm->getResource(ID_PLST, _vm->getCurCard()); + uint16 recordCount = plst->readUint16BE(); + + for (uint16 i = 0; i < recordCount; i++) { + uint16 index = plst->readUint16BE(); + uint16 id = plst->readUint16BE(); + uint16 left = plst->readUint16BE(); + uint16 top = plst->readUint16BE(); + uint16 right = plst->readUint16BE(); + uint16 bottom = plst->readUint16BE(); + + // We are also checking here to make sure we haven't drawn the image yet on screen. + // This fixes problems with drawing PLST 1 twice and some other images twice. PLST + // 1 is sometimes not called by the scripts, so some cards don't appear if we don't + // draw PLST 1 each time. This "hack" is here to catch any PLST attempting to draw + // twice. There should never be a problem with doing it this way. + if (index == x && !(Common::find(_activatedPLSTs.begin(), _activatedPLSTs.end(), x) != _activatedPLSTs.end())) { + debug(0, "Drawing image %d", id); + copyImageToScreen(id, left, top, right, bottom); + _activatedPLSTs.push_back(x); + break; + } + } + + delete plst; +} + +void RivenGraphics::updateScreen(Common::Rect updateRect) { + if (_updatesEnabled) { + _vm->runUpdateScreenScript(); + + if (_dirtyScreen) { + _activatedPLSTs.clear(); + + // Copy to screen if there's no transition. Otherwise transition. ;) + if (_scheduledTransition < 0) + _vm->_system->copyRectToScreen((byte *)_mainScreen->getBasePtr(updateRect.left, updateRect.top), _mainScreen->pitch, updateRect.left, updateRect.top, updateRect.width(), updateRect.height()); + else + runScheduledTransition(); + + // Finally, update the screen. + _vm->_system->updateScreen(); + _dirtyScreen = false; + } + } +} + +void RivenGraphics::scheduleWaterEffect(uint16 sfxeID) { + Common::SeekableReadStream *sfxeStream = _vm->getResource(ID_SFXE, sfxeID); + + if (sfxeStream->readUint16BE() != 'SL') + error ("Unknown sfxe tag"); + + // Read in header info + SFXERecord sfxeRecord; + sfxeRecord.frameCount = sfxeStream->readUint16BE(); + uint32 offsetTablePosition = sfxeStream->readUint32BE(); + sfxeRecord.rect.left = sfxeStream->readUint16BE(); + sfxeRecord.rect.top = sfxeStream->readUint16BE(); + sfxeRecord.rect.right = sfxeStream->readUint16BE(); + sfxeRecord.rect.bottom = sfxeStream->readUint16BE(); + sfxeRecord.speed = sfxeStream->readUint16BE(); + // Skip the rest of the fields... + + // Read in offsets + sfxeStream->seek(offsetTablePosition); + uint32 *frameOffsets = new uint32[sfxeRecord.frameCount]; + for (uint16 i = 0; i < sfxeRecord.frameCount; i++) + frameOffsets[i] = sfxeStream->readUint32BE(); + sfxeStream->seek(frameOffsets[0]); + + // Read in the scripts + for (uint16 i = 0; i < sfxeRecord.frameCount; i++) + sfxeRecord.frameScripts.push_back(sfxeStream->readStream((i == sfxeRecord.frameCount - 1) ? sfxeStream->size() - frameOffsets[i] : frameOffsets[i + 1] - frameOffsets[i])); + + // Set it to the first frame + sfxeRecord.curFrame = 0; + sfxeRecord.lastFrameTime = 0; + + delete[] frameOffsets; + delete sfxeStream; + _waterEffects.push_back(sfxeRecord); +} + +void RivenGraphics::clearWaterEffects() { + _waterEffects.clear(); +} + +bool RivenGraphics::runScheduledWaterEffects() { + // Don't run the effect if it's disabled + if (_vm->_vars["waterenabled"] == 0) + return false; + + Graphics::Surface *screen = NULL; + + for (uint16 i = 0; i < _waterEffects.size(); i++) { + if (_vm->_system->getMillis() > _waterEffects[i].lastFrameTime + 1000 / _waterEffects[i].speed) { + // Lock the screen! + if (!screen) + screen = _vm->_system->lockScreen(); + + // Make sure the script is at the starting point + Common::SeekableReadStream *script = _waterEffects[i].frameScripts[_waterEffects[i].curFrame]; + if (script->pos() != 0) + script->seek(0); + + // Run script + uint16 curRow = 0; + for (uint16 op = script->readUint16BE(); op != 4; op = script->readUint16BE()) { + if (op == 1) { // Increment Row + curRow++; + } else if (op == 3) { // Copy Pixels + uint16 dstLeft = script->readUint16BE(); + uint16 srcLeft = script->readUint16BE(); + uint16 srcTop = script->readUint16BE(); + uint16 rowWidth = script->readUint16BE(); + memcpy ((byte *)screen->getBasePtr(dstLeft, curRow + _waterEffects[i].rect.top), (byte *)_mainScreen->getBasePtr(srcLeft, srcTop), rowWidth * _pixelFormat.bytesPerPixel); + } else if (op != 4) { // End of Script + error ("Unknown SFXE opcode %d", op); + } + } + + // Increment frame + _waterEffects[i].curFrame++; + if (_waterEffects[i].curFrame == _waterEffects[i].frameCount) + _waterEffects[i].curFrame = 0; + + // Set the new time + _waterEffects[i].lastFrameTime = _vm->_system->getMillis(); + } + } + + // Unlock the screen if it has been locked and return true to update the screen + if (screen) { + _vm->_system->unlockScreen(); + return true; + } + + return false; +} + +void RivenGraphics::scheduleTransition(uint16 id, Common::Rect rect) { + _scheduledTransition = id; + _transitionRect = rect; +} + +void RivenGraphics::runScheduledTransition() { + if (_scheduledTransition < 0) // No transition is scheduled + return; + + // TODO: There's a lot to be done here... + + // Note: Transitions 0-11 are actual transitions, but none are used in-game. + // There's no point in implementing them if they're not used. These extra + // transitions were found by hacking scripts. + + switch (_scheduledTransition) { + case 0: // Swipe Left + case 1: // Swipe Right + case 2: // Swipe Up + case 3: // Swipe Down + case 12: // Pan Left + case 13: // Pan Right + case 14: // Pan Up + case 15: // Pan Down + case 16: // Dissolve + case 17: // Dissolve (tspit CARD 155) + break; + default: + if (_scheduledTransition >= 4 && _scheduledTransition <= 11) + error("Found unused transition %d", _scheduledTransition); + else + error("Found unknown transition %d", _scheduledTransition); + } + + // For now, just copy the image to screen without doing any transition. + _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->updateScreen(); + + _scheduledTransition = -1; // Clear scheduled transition +} + +void RivenGraphics::clearMainScreen() { + _mainScreen->fillRect(Common::Rect(0, 0, 608, 392), _pixelFormat.RGBToColor(0, 0, 0)); +} + +void RivenGraphics::fadeToBlack() { + // The transition speed is forced to best here + setTransitionSpeed(kRivenTransitionSpeedBest); + scheduleTransition(16); + clearMainScreen(); + runScheduledTransition(); +} + +void RivenGraphics::showInventory() { + // Don't redraw the inventory + if (_inventoryDrawn) + return; + + // Clear the inventory area + clearInventoryArea(); + + // Draw the demo's exit button + if (_vm->getFeatures() & GF_DEMO) { + // extras.mhk tBMP 101 contains "EXIT" instead of Atrus' journal in the demo! + // The demo's extras.mhk contains all the other inventory/marble/credits image + // but has hacked tBMP 101 with "EXIT". *sigh* + drawInventoryImage(101, g_demoExitRect); + } else { + // We don't want to show the inventory on setup screens or in other journals. + if (_vm->getCurStack() == aspit) + return; + + // There are three books and three vars. We have three different + // combinations. At the start you have just Atrus' journal. Later, + // you get Catherine's journal and the trap book. Near the end, + // you lose the trap book and have just the two journals. + + bool hasCathBook = _vm->_vars["acathbook"] != 0; + bool hasTrapBook = _vm->_vars["atrapbook"] != 0; + + if (!hasCathBook) { + drawInventoryImage(101, g_atrusJournalRect1); + } else if (!hasTrapBook) { + drawInventoryImage(101, g_atrusJournalRect2); + drawInventoryImage(102, g_cathJournalRect2); + } else { + drawInventoryImage(101, g_atrusJournalRect3); + drawInventoryImage(102, g_cathJournalRect3); + drawInventoryImage(100, g_trapBookRect3); + } + } + + _vm->_system->updateScreen(); + _inventoryDrawn = true; +} + +void RivenGraphics::hideInventory() { + // Don't hide the inventory twice + if (!_inventoryDrawn) + return; + + // Clear the area + clearInventoryArea(); + + _inventoryDrawn = false; +} + +void RivenGraphics::clearInventoryArea() { + // Clear the inventory area + static const Common::Rect inventoryRect = Common::Rect(0, 392, 608, 436); + + // Lock the screen + Graphics::Surface *screen = _vm->_system->lockScreen(); + + // Fill the inventory area with black + screen->fillRect(inventoryRect, _pixelFormat.RGBToColor(0, 0, 0)); + + _vm->_system->unlockScreen(); +} + +void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) { + MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); + mhkSurface->convertToTrueColor(); + Graphics::Surface *surface = mhkSurface->getSurface(); + + _vm->_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h); + + delete mhkSurface; +} + +void RivenGraphics::drawRect(Common::Rect rect, bool active) { + // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. + Graphics::Surface *screen = _vm->_system->lockScreen(); + + if (active) + screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0)); + else + screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0)); + + _vm->_system->unlockScreen(); +} + +void RivenGraphics::drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect) { + // Draw tBMP id from srcRect to dstRect + Graphics::Surface *surface = findImage(id)->getSurface(); + + assert(srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()); + + for (uint16 i = 0; i < srcRect.height(); i++) + memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(srcRect.left, i + srcRect.top), srcRect.width() * surface->format.bytesPerPixel); + + _dirtyScreen = true; +} + +void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) { + MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); + mhkSurface->convertToTrueColor(); + Graphics::Surface *surface = mhkSurface->getSurface(); + + assert(dstRect.width() == surface->w); + + for (uint16 i = 0; i < surface->h; i++) + memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(0, i), surface->pitch); + + delete mhkSurface; + _dirtyScreen = true; +} + +void RivenGraphics::beginCredits() { + // Clear the old cache + clearCache(); + + // Now cache all the credits images + for (uint16 i = 302; i <= 320; i++) { + MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, i)); + surface->convertToTrueColor(); + addImageToCache(i, surface); + } + + // And clear our screen too + clearMainScreen(); +} + +void RivenGraphics::updateCredits() { + if ((_creditsImage == 303 || _creditsImage == 304) && _creditsPos == 0) + fadeToBlack(); + + if (_creditsImage < 304) { + // For the first two credit images, they are faded from black to the image and then out again + scheduleTransition(16); + + Graphics::Surface *frame = findImage(_creditsImage++)->getSurface(); + + for (int y = 0; y < frame->h; y++) + memcpy(_mainScreen->getBasePtr(124, y), frame->getBasePtr(0, y), frame->pitch); + + runScheduledTransition(); + } else { + // Otheriwse, we're scrolling + // Move the screen up one row + memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1)); + + // Only update as long as we're not before the last frame + // Otherwise, we're just moving up a row (which we already did) + if (_creditsImage <= 320) { + // Copy the next row to the bottom of the screen + Graphics::Surface *frame = findImage(_creditsImage)->getSurface(); + memcpy(_mainScreen->getBasePtr(124, _mainScreen->h - 1), frame->getBasePtr(0, _creditsPos), frame->pitch); + _creditsPos++; + + if (_creditsPos == _mainScreen->h) { + _creditsImage++; + _creditsPos = 0; + } + } + + // Now flush the new screen + _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->updateScreen(); + } +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/riven_graphics.h b/engines/mohawk/riven_graphics.h new file mode 100644 index 0000000000..48dda28afd --- /dev/null +++ b/engines/mohawk/riven_graphics.h @@ -0,0 +1,110 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MOHAWK_RIVEN_GRAPHICS_H +#define MOHAWK_RIVEN_GRAPHICS_H + +#include "mohawk/graphics.h" + +namespace Mohawk { + +class MohawkEngine_Riven; + +class RivenGraphics : public GraphicsManager { +public: + RivenGraphics(MohawkEngine_Riven *vm); + ~RivenGraphics(); + + void copyImageToScreen(uint16, uint32, uint32, uint32, uint32); + void updateScreen(Common::Rect updateRect = Common::Rect(0, 0, 608, 392)); + bool _updatesEnabled; + Common::Array<uint16> _activatedPLSTs; + void drawPLST(uint16 x); + void drawRect(Common::Rect rect, bool active); + void drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect); + void drawExtrasImage(uint16 id, Common::Rect dstRect); + + // Water Effect + void scheduleWaterEffect(uint16); + void clearWaterEffects(); + bool runScheduledWaterEffects(); + + // Transitions + void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392)); + void runScheduledTransition(); + void fadeToBlack(); + void setTransitionSpeed(uint32 speed) { _transitionSpeed = speed; } + + // Inventory + void showInventory(); + void hideInventory(); + + // Credits + void beginCredits(); + void updateCredits(); + uint getCurCreditsImage() { return _creditsImage; } + +protected: + MohawkSurface *decodeImage(uint16 id); + MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + +private: + MohawkEngine_Riven *_vm; + MohawkBitmap *_bitmapDecoder; + + // Water Effects + struct SFXERecord { + // Record values + uint16 frameCount; + Common::Rect rect; + uint16 speed; + Common::Array<Common::SeekableReadStream *> frameScripts; + + // Cur frame + uint16 curFrame; + uint32 lastFrameTime; + }; + Common::Array<SFXERecord> _waterEffects; + + // Transitions + int16 _scheduledTransition; + Common::Rect _transitionRect; + uint32 _transitionSpeed; + + // Inventory + void clearInventoryArea(); + void drawInventoryImage(uint16 id, const Common::Rect *rect); + bool _inventoryDrawn; + + // Screen Related + Graphics::Surface *_mainScreen; + bool _dirtyScreen; + Graphics::PixelFormat _pixelFormat; + void clearMainScreen(); + + // Credits + uint _creditsImage, _creditsPos; +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp index 18c13ec12b..f5bf7782d4 100644 --- a/engines/mohawk/riven_saveload.cpp +++ b/engines/mohawk/riven_saveload.cpp @@ -88,13 +88,13 @@ static uint16 mapNewStackIDToOld(uint16 newID) { return 0; } -bool RivenSaveLoad::loadGame(Common::String filename) { +Common::Error RivenSaveLoad::loadGame(Common::String filename) { if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo - return false; + return Common::kNoError; Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); if (!loadFile) - return false; + return Common::kReadingFailed; debug(0, "Loading game from \'%s\'", filename.c_str()); @@ -103,7 +103,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) { if (!mhk->openStream(loadFile)) { warning("Save file is not a Mohawk archive"); delete mhk; - return false; + return Common::Error(Common::kUnknownError, "Invalid save file"); } // First, let's make sure we're using a saved game file from this version of Riven by checking the VERS resource @@ -114,7 +114,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) { || (saveGameVersion == kDVDSaveGameVersion && !(_vm->getFeatures() & GF_DVD))) { warning("Incompatible saved game versions. No support for this yet"); delete mhk; - return false; + return Common::Error(Common::kUnknownError, "Incompatible save version"); } // Now, we'll read in the variable values. @@ -206,7 +206,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) { delete zips; delete mhk; - return true; + return Common::kNoError; } Common::MemoryWriteStreamDynamic *RivenSaveLoad::genVERSSection() { @@ -273,7 +273,7 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genZIPSSection() { return stream; } -bool RivenSaveLoad::saveGame(Common::String filename) { +Common::Error RivenSaveLoad::saveGame(Common::String filename) { // NOTE: This code is designed to only output a Mohawk archive // for a Riven saved game. It's hardcoded to do this because // (as of right now) this is the only place in the engine @@ -295,7 +295,7 @@ bool RivenSaveLoad::saveGame(Common::String filename) { Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename); if (!saveFile) - return false; + return Common::kWritingFailed; debug (0, "Saving game to \'%s\'", filename.c_str()); @@ -418,7 +418,7 @@ bool RivenSaveLoad::saveGame(Common::String filename) { delete varsSection; delete zipsSection; - return true; + return Common::kNoError; } void RivenSaveLoad::deleteSave(Common::String saveName) { diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h index c1b3fc639e..37b73c26c6 100644 --- a/engines/mohawk/riven_saveload.h +++ b/engines/mohawk/riven_saveload.h @@ -42,8 +42,8 @@ public: ~RivenSaveLoad(); Common::StringArray generateSaveGameList(); - bool loadGame(Common::String); - bool saveGame(Common::String); + Common::Error loadGame(Common::String); + Common::Error saveGame(Common::String); void deleteSave(Common::String); private: diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index 6e3e9a34dc..352a018990 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -21,9 +21,9 @@ */ #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/riven.h" #include "mohawk/riven_external.h" +#include "mohawk/riven_graphics.h" #include "mohawk/riven_scripts.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/riven_scripts.h b/engines/mohawk/riven_scripts.h index 2932ba5939..6df4a2e523 100644 --- a/engines/mohawk/riven_scripts.h +++ b/engines/mohawk/riven_scripts.h @@ -27,8 +27,6 @@ #include "common/ptr.h" #include "common/textconsole.h" -class MohawkEngine_Riven; - #define DECLARE_OPCODE(x) void x(uint16 op, uint16 argc, uint16 *argv) namespace Mohawk { @@ -50,6 +48,7 @@ enum { kStoredOpcodeScript // This is ScummVM-only to denote the script from a storeMovieOpcode() call }; +class MohawkEngine_Riven; class RivenScript; class RivenScript { @@ -125,7 +124,7 @@ private: DECLARE_OPCODE(activateMLST); }; -typedef Common::Array<RivenScript*> RivenScriptList; +typedef Common::Array<RivenScript *> RivenScriptList; class RivenScriptManager { public: diff --git a/engines/mohawk/riven_vars.cpp b/engines/mohawk/riven_vars.cpp index ba5c343e07..8ddb76eec9 100644 --- a/engines/mohawk/riven_vars.cpp +++ b/engines/mohawk/riven_vars.cpp @@ -305,6 +305,7 @@ void MohawkEngine_Riven::initVars() { _vars["gnmagcar"] = 1; _vars["omusicplayer"] = 1; _vars["transitionmode"] = kRivenTransitionSpeedFastest; + _vars["tdomeelev"] = 1; // Randomize the telescope combination uint32 &teleCombo = _vars["tcorrectorder"]; diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 7958906897..80fa4bf9a0 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -235,25 +235,7 @@ bool VideoManager::updateMovies() { if (_videoStreams[i]->hasDirtyPalette()) _videoStreams[i]->setSystemPalette(); } else { - convertedFrame = new Graphics::Surface(); - const byte *palette = _videoStreams[i]->getPalette(); - assert(palette); - - convertedFrame->create(frame->w, frame->h, pixelFormat); - - for (uint16 j = 0; j < frame->h; j++) { - for (uint16 k = 0; k < frame->w; k++) { - byte palIndex = *((const byte *)frame->getBasePtr(k, j)); - byte r = palette[palIndex * 3]; - byte g = palette[palIndex * 3 + 1]; - byte b = palette[palIndex * 3 + 2]; - if (pixelFormat.bytesPerPixel == 2) - *((uint16 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)convertedFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); - } - } - + convertedFrame = frame->convertTo(pixelFormat, _videoStreams[i]->getPalette()); frame = convertedFrame; } } @@ -261,7 +243,7 @@ bool VideoManager::updateMovies() { // Clip the width/height to make sure we stay on the screen (Myst does this a few times) uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); - _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); + _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); // We've drawn something to the screen, make sure we update it updateScreen = true; |