mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
MOHAWK: Implement an image cache system
This should greatly improve the performance in Myst (especially Myst ME, which uses the slow JPEG decoder). This should also slightly improve the Riven performance; the sliders now work a bit better. svn-id: r54388
This commit is contained in:
parent
199a1c7619
commit
7fb352e38a
@ -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());
|
||||
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;
|
||||
// Convert from bitmap coordinates to surface coordinates
|
||||
uint16 top = surface->h - src.top - 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);
|
||||
for (uint16 i = 0; i < height; i++)
|
||||
memcpy(_mainScreen->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->bytesPerPixel);
|
||||
|
||||
surface->free();
|
||||
delete surface;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user