diff options
-rw-r--r-- | engines/mohawk/graphics.cpp | 124 | ||||
-rw-r--r-- | engines/mohawk/graphics.h | 38 | ||||
-rw-r--r-- | engines/mohawk/myst.cpp | 4 | ||||
-rw-r--r-- | engines/mohawk/riven.cpp | 7 | ||||
-rw-r--r-- | engines/mohawk/riven_external.cpp | 2 |
5 files changed, 124 insertions, 51 deletions
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index c1c41e21e7..5215e2b78c 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -37,6 +37,34 @@ namespace Mohawk { +GraphicsManager::GraphicsManager() { +} + +GraphicsManager::~GraphicsManager() { + clearCache(); +} + +void GraphicsManager::clearCache() { + for (Common::HashMap<uint16, Graphics::Surface *>::iterator it = _cache.begin(); it != _cache.end(); it++) { + it->_value->free(); + delete it->_value; + } + + _cache.clear(); +} + +Graphics::Surface *GraphicsManager::findImage(uint16 id) { + if (!_cache.contains(id)) + _cache[id] = decodeImage(id); + + // TODO: Probably would be nice to limit the size of the cache + // Currently, this can't get large because it is freed on every + // card/stack change in Myst/Riven so I'm not worried about it. + // Doesn't mean this shouldn't be done in the future. + + return _cache[id]; +} + Graphics::Surface *ImageData::getSurface() { Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); Graphics::Surface *surface = new Graphics::Surface(); @@ -63,7 +91,7 @@ Graphics::Surface *ImageData::getSurface() { return surface; } -MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : _vm(vm) { +MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { _bmpDecoder = new MystBitmap(); // The original version of Myst could run in 8bpp color too. @@ -142,15 +170,8 @@ void MystGraphics::loadExternalPictureFile(uint16 stack) { } } -void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest) { - // 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()); - - Graphics::Surface *surface = NULL; +Graphics::Surface *MystGraphics::decodeImage(uint16 id) { + Graphics::Surface *surface = 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, @@ -158,7 +179,7 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm // 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 == image) { + if (_pictureFile.entries[i].id == id) { if (_pictureFile.entries[i].type == 0) { Graphics::Surface *jpegSurface = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size)); surface->copyFrom(*jpegSurface); @@ -179,10 +200,10 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm bool isPict = false; Common::SeekableReadStream *dataStream = NULL; - if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, image)) { + 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->getRawData(ID_PICT, image); + dataStream = _vm->getRawData(ID_PICT, id); // 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. @@ -191,7 +212,7 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm isPict = (dataStream->readUint32BE() == 0x001102FF); dataStream->seek(0); } else // No PICT, so the WDIB must exist. Let's go grab it. - dataStream = _vm->getRawData(ID_WDIB, image); + dataStream = _vm->getRawData(ID_WDIB, id); if (isPict) surface = _pictDecoder->decodeImage(dataStream); @@ -202,6 +223,20 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm } } + assert(surface); + return surface; +} + +void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest) { + // 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()); + + Graphics::Surface *surface = findImage(image); + debug(3, "Image Blit:"); debug(3, "src.x: %d", src.left); debug(3, "src.y: %d", src.top); @@ -210,22 +245,17 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm debug(3, "width: %d", src.width()); debug(3, "height: %d", src.height()); - if (surface) { - uint16 width = MIN<int>(surface->w, dest.width()); - uint16 height = MIN<int>(surface->h, dest.height()); - - // Convert from bitmap coordinates to surface coordinates - uint16 top = surface->h - src.top - height; + uint16 width = MIN<int>(surface->w, dest.width()); + uint16 height = MIN<int>(surface->h, dest.height()); - for (uint16 i = 0; i < height; i++) - memcpy(_mainScreen->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->bytesPerPixel); + // Convert from bitmap coordinates to surface coordinates + uint16 top = surface->h - src.top - height; - surface->free(); - delete surface; + for (uint16 i = 0; i < height; i++) + memcpy(_mainScreen->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->bytesPerPixel); - // Mark the screen as dirty - _dirtyScreen = true; - } + // Mark the screen as dirty + _dirtyScreen = true; } void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) { @@ -285,7 +315,7 @@ void MystGraphics::drawRect(Common::Rect rect, bool active) { _vm->_system->unlockScreen(); } -RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : _vm(vm) { +RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm) { _bitmapDecoder = new MohawkBitmap(); // Give me the best you've got! @@ -312,11 +342,15 @@ RivenGraphics::~RivenGraphics() { delete _bitmapDecoder; } -void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uint32 right, uint32 bottom) { - // First, decode the image and get the high color surface - ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getRawData(ID_TBMP, image)); +Graphics::Surface *RivenGraphics::decodeImage(uint16 id) { + ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getRawData(ID_TBMP, id)); Graphics::Surface *surface = imageData->getSurface(); delete imageData; + return surface; +} + +void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uint32 right, uint32 bottom) { + Graphics::Surface *surface = findImage(image); // Clip the width to fit on the screen. Fixes some images. if (left + surface->w > 608) @@ -325,9 +359,6 @@ void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uin for (uint16 i = 0; i < surface->h; i++) memcpy(_mainScreen->getBasePtr(left, i + top), surface->getBasePtr(0, i), surface->w * surface->bytesPerPixel); - surface->free(); - delete surface; - _dirtyScreen = true; } @@ -716,18 +747,13 @@ void RivenGraphics::drawRect(Common::Rect rect, bool active) { void RivenGraphics::drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect) { // Draw tBMP id from srcRect to dstRect - ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getRawData(ID_TBMP, id)); - Graphics::Surface *surface = imageData->getSurface(); - delete imageData; + Graphics::Surface *surface = findImage(id); 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->bytesPerPixel); - surface->free(); - delete surface; - _dirtyScreen = true; } @@ -747,7 +773,7 @@ void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) { _dirtyScreen = true; } -LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm) : _vm(vm) { +LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm) : GraphicsManager(), _vm(vm) { _bmpDecoder = (_vm->getGameType() == GType_LIVINGBOOKSV1) ? new OldMohawkBitmap() : new MohawkBitmap(); _palette = new byte[256 * 4]; memset(_palette, 0, 256 * 4); @@ -758,26 +784,30 @@ LBGraphics::~LBGraphics() { delete[] _palette; } -void LBGraphics::copyImageToScreen(uint16 image, uint16 left, uint16 right) { +Graphics::Surface *LBGraphics::decodeImage(uint16 id) { ImageData *imageData; if (_vm->getGameType() == GType_LIVINGBOOKSV1) - imageData = _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, image)); + imageData = _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, id)); else - imageData = _bmpDecoder->decodeImage(_vm->getRawData(ID_TBMP, image)); + imageData = _bmpDecoder->decodeImage(_vm->getRawData(ID_TBMP, id)); imageData->_palette = _palette; Graphics::Surface *surface = imageData->getSurface(); imageData->_palette = NULL; // Unset the palette so it doesn't get deleted delete imageData; + return surface; +} + +void LBGraphics::copyImageToScreen(uint16 image, uint16 left, uint16 right) { + Graphics::Surface *surface = findImage(image); + uint16 width = MIN<int>(surface->w, _vm->_system->getWidth()); uint16 height = MIN<int>(surface->h, _vm->_system->getHeight()); _vm->_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, left, right, width, height); - surface->free(); - delete surface; - // FIXME: Remove this and update only at certain points + // FIXME: Remove this and update only when necessary _vm->_system->updateScreen(); } diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index e44bba213b..31a31aa237 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -30,6 +30,7 @@ #include "mohawk/livingbooks.h" #include "common/file.h" +#include "common/hashmap.h" #include "graphics/pict.h" #include "graphics/video/codecs/mjpeg.h" @@ -90,7 +91,28 @@ public: byte *_palette; }; -class MystGraphics { +class GraphicsManager { +public: + GraphicsManager(); + virtual ~GraphicsManager(); + + // Free all surfaces in the cache + void clearCache(); + +protected: + // findImage will search the cache to find the image. + // If not found, it will call decodeImage to get a new one. + Graphics::Surface *findImage(uint16 id); + + // decodeImage will always return a new image. + virtual Graphics::Surface *decodeImage(uint16 id) = 0; + +private: + // An image cache that stores images until clearCache() is called + Common::HashMap<uint16, Graphics::Surface *> _cache; +}; + +class MystGraphics : public GraphicsManager { public: MystGraphics(MohawkEngine_Myst*); ~MystGraphics(); @@ -104,6 +126,10 @@ public: void updateScreen(); void drawRect(Common::Rect rect, bool active); + +protected: + Graphics::Surface *decodeImage(uint16 id); + private: MohawkEngine_Myst *_vm; MystBitmap *_bmpDecoder; @@ -141,7 +167,7 @@ struct SFXERecord { uint32 lastFrameTime; }; -class RivenGraphics { +class RivenGraphics : public GraphicsManager { public: RivenGraphics(MohawkEngine_Riven *vm); ~RivenGraphics(); @@ -169,6 +195,9 @@ public: void showInventory(); void hideInventory(); +protected: + Graphics::Surface *decodeImage(uint16 id); + private: MohawkEngine_Riven *_vm; MohawkBitmap *_bitmapDecoder; @@ -191,7 +220,7 @@ private: Graphics::PixelFormat _pixelFormat; }; -class LBGraphics { +class LBGraphics : public GraphicsManager { public: LBGraphics(MohawkEngine_LivingBooks *vm); ~LBGraphics(); @@ -199,6 +228,9 @@ public: void copyImageToScreen(uint16 image, uint16 left = 0, uint16 top = 0); void setPalette(uint16 id); +protected: + Graphics::Surface *decodeImage(uint16 id); + private: MohawkBitmap *_bmpDecoder; MohawkEngine_LivingBooks *_vm; diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index 9f822eb012..dd5d045fc6 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -367,7 +367,9 @@ void MohawkEngine_Myst::changeToStack(uint16 stack) { _runExitScript = false; + // Clear the resource cache and the image cache _cache.clear(); + _gfx->clearCache(); } void MohawkEngine_Myst::changeToCard(uint16 card) { @@ -385,7 +387,9 @@ void MohawkEngine_Myst::changeToCard(uint16 card) { unloadCard(); + // Clear the resource cache and image cache _cache.clear(); + _gfx->clearCache(); _curCard = card; diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index f2f4a42f0e..6e292a1a0e 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -264,6 +264,9 @@ void MohawkEngine_Riven::changeToStack(uint16 n) { _video->stopVideos(); _video->clearMLST(); + // Clear the graphics cache; images aren't used across stack boundaries + _gfx->clearCache(); + // Clear the old stack files out for (uint32 i = 0; i < _mhk.size(); i++) delete _mhk[i]; @@ -317,6 +320,10 @@ void MohawkEngine_Riven::changeToCard(uint16 dest) { _curCard = dest; debug (1, "Changing to card %d", _curCard); + // Clear the graphics cache (images typically aren't used + // on different cards). + _gfx->clearCache(); + if (!(getFeatures() & GF_DEMO)) { for (byte i = 0; i < 13; i++) if (_curStack == rivenSpecialChange[i].startStack && _curCard == matchRMAPToCard(rivenSpecialChange[i].startCardRMAP)) { diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index de18509daa..704301c454 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -281,7 +281,7 @@ void RivenExternal::resetDomeSliders(uint16 bitmapId, uint16 soundId, uint16 sta if (slidersFound) { _vm->_sound->playSound(soundId); drawDomeSliders(bitmapId, startHotspot); - _vm->_system->delayMillis(10); + _vm->_system->delayMillis(100); } } } |