diff options
Diffstat (limited to 'engines/mohawk/graphics.cpp')
-rw-r--r-- | engines/mohawk/graphics.cpp | 434 |
1 files changed, 182 insertions, 252 deletions
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index f472a9d721..65eebf7134 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -27,43 +27,94 @@ #include "mohawk/graphics.h" #include "mohawk/myst.h" #include "mohawk/riven.h" -#include "mohawk/riven_cursors.h" #include "engines/util.h" -#include "graphics/cursorman.h" #include "graphics/primitives.h" #include "gui/message.h" namespace Mohawk { -Graphics::Surface *ImageData::getSurface() { +MohawkSurface::MohawkSurface() : _surface(0), _palette(0) { + _offsetX = 0; + _offsetY = 0; +} + +MohawkSurface::MohawkSurface(Graphics::Surface *surface, byte *palette, int offsetX, int offsetY) : _palette(palette), _offsetX(offsetX), _offsetY(offsetY) { + assert(surface); + + _surface = surface; +} + +MohawkSurface::~MohawkSurface() { + free(_palette); + + if (_surface) { + _surface->free(); + delete _surface; + } +} + +void MohawkSurface::convertToTrueColor() { + assert(_surface); + + if (_surface->bytesPerPixel > 1) + return; + + assert(_palette); + Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); Graphics::Surface *surface = new Graphics::Surface(); surface->create(_surface->w, _surface->h, pixelFormat.bytesPerPixel); - if (_surface->bytesPerPixel == 1) { - assert(_palette); - - 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 * 4]; - byte g = _palette[palIndex * 4 + 1]; - byte b = _palette[palIndex * 4 + 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); - } + 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 * 4]; + byte g = _palette[palIndex * 4 + 1]; + byte b = _palette[palIndex * 4 + 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); } - } else - memcpy(surface->pixels, _surface->pixels, _surface->w * _surface->h * _surface->bytesPerPixel); + } - return surface; + // Free everything and set the new surface as the converted surface + _surface->free(); + delete _surface; + free(_palette); + _palette = 0; + _surface = surface; +} + +GraphicsManager::GraphicsManager() { +} + +GraphicsManager::~GraphicsManager() { + clearCache(); +} + +void GraphicsManager::clearCache() { + for (Common::HashMap<uint16, MohawkSurface*>::iterator it = _cache.begin(); it != _cache.end(); it++) + delete it->_value; + + _cache.clear(); } -MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : _vm(vm) { +MohawkSurface *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]; +} + +MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { _bmpDecoder = new MystBitmap(); // The original version of Myst could run in 8bpp color too. @@ -86,12 +137,21 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : _vm(vm) { } _pictureFile.entries = NULL; + + // Initialize our buffer + _mainScreen = new Graphics::Surface(); + _mainScreen->create(_vm->_system->getWidth(), _vm->_system->getHeight(), _pixelFormat.bytesPerPixel); + _dirtyScreen = false; } MystGraphics::~MystGraphics() { delete _bmpDecoder; delete _jpegDecoder; delete _pictDecoder; + delete[] _pictureFile.entries; + + _mainScreen->free(); + delete _mainScreen; } static const char* picFileNames[] = { @@ -133,16 +193,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; - +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, @@ -150,13 +202,14 @@ 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); - } else if (_pictureFile.entries[i].type == 1) - surface = _pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size)); - else + Graphics::Surface *surface = new Graphics::Surface(); + surface->copyFrom(*_jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size))); + mhkSurface = new MohawkSurface(surface); + } 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; } @@ -167,14 +220,14 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm // 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 (!surface) { + if (!mhkSurface) { 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->getResource(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. @@ -183,17 +236,30 @@ 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->getResource(ID_WDIB, id); if (isPict) - surface = _pictDecoder->decodeImage(dataStream); + mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(dataStream)); else { - ImageData *imageData = _bmpDecoder->decodeImage(dataStream); - surface = imageData->getSurface(); - delete imageData; + mhkSurface = _bmpDecoder->decodeImage(dataStream); + mhkSurface->convertToTrueColor(); } } + assert(mhkSurface); + return mhkSurface; +} + +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)->getSurface(); + debug(3, "Image Blit:"); debug(3, "src.x: %d", src.left); debug(3, "src.y: %d", src.top); @@ -202,48 +268,30 @@ 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()); - _vm->_system->copyRectToScreen((byte *)surface->getBasePtr(src.left, src.top), surface->pitch, dest.left, dest.top, width, height); - surface->free(); - delete surface; - } + uint16 width = MIN<int>(surface->w, dest.width()); + uint16 height = MIN<int>(surface->h, dest.height()); - // FIXME: Remove this and update only at certain points - _vm->_system->updateScreen(); -} + // Convert from bitmap coordinates to surface coordinates + uint16 top = surface->h - src.top - height; -void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) { - copyImageSectionToScreen(image, Common::Rect(0, 0, 544, 333), dest); -} + for (uint16 i = 0; i < height; i++) + memcpy(_mainScreen->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->bytesPerPixel); -void MystGraphics::showCursor(void) { - CursorMan.showMouse(true); - _vm->_needsUpdate = true; + // Mark the screen as dirty + _dirtyScreen = true; } -void MystGraphics::hideCursor(void) { - CursorMan.showMouse(false); - _vm->_needsUpdate = true; +void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) { + copyImageSectionToScreen(image, Common::Rect(0, 0, 544, 333), dest); } -void MystGraphics::changeCursor(uint16 cursor) { - // Both Myst and Myst ME use the "MystBitmap" format for cursor images. - ImageData *data = _bmpDecoder->decodeImage(_vm->getRawData(ID_WDIB, cursor)); - Common::SeekableReadStream *clrcStream = _vm->getRawData(ID_CLRC, cursor); - uint16 hotspotX = clrcStream->readUint16LE(); - uint16 hotspotY = clrcStream->readUint16LE(); - delete clrcStream; - - // Myst ME stores some cursors as 24bpp images instead of 8bpp - if (data->_surface->bytesPerPixel == 1) { - CursorMan.replaceCursor((byte *)data->_surface->pixels, data->_surface->w, data->_surface->h, hotspotX, hotspotY, 0); - CursorMan.replaceCursorPalette(data->_palette, 0, 256); - } else - CursorMan.replaceCursor((byte *)data->_surface->pixels, data->_surface->w, data->_surface->h, hotspotX, hotspotY, _pixelFormat.RGBToColor(255, 255, 255), 1, &_pixelFormat); - - _vm->_needsUpdate = true; +void MystGraphics::updateScreen() { + if (_dirtyScreen) { + // Only copy the buffer to the screen if it's dirty + _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->updateScreen(); + _dirtyScreen = false; + } } void MystGraphics::drawRect(Common::Rect rect, bool active) { @@ -261,7 +309,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! @@ -288,11 +336,14 @@ RivenGraphics::~RivenGraphics() { 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) { - // First, decode the image and get the high color surface - ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getRawData(ID_TBMP, image)); - Graphics::Surface *surface = imageData->getSurface(); - delete imageData; + Graphics::Surface *surface = findImage(image)->getSurface(); // Clip the width to fit on the screen. Fixes some images. if (left + surface->w > 608) @@ -301,14 +352,11 @@ 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; } void RivenGraphics::drawPLST(uint16 x) { - Common::SeekableReadStream* plst = _vm->getRawData(ID_PLST, _vm->getCurCard()); + Common::SeekableReadStream* plst = _vm->getResource(ID_PLST, _vm->getCurCard()); uint16 index, id, left, top, right, bottom; uint16 recordCount = plst->readUint16BE(); @@ -357,7 +405,7 @@ void RivenGraphics::updateScreen() { } void RivenGraphics::scheduleWaterEffect(uint16 sfxeID) { - Common::SeekableReadStream *sfxeStream = _vm->getRawData(ID_SFXE, sfxeID); + Common::SeekableReadStream *sfxeStream = _vm->getResource(ID_SFXE, sfxeID); if (sfxeStream->readUint16BE() != 'SL') error ("Unknown sfxe tag"); @@ -491,115 +539,6 @@ void RivenGraphics::runScheduledTransition() { _scheduledTransition = -1; // Clear scheduled transition } -void RivenGraphics::changeCursor(uint16 num) { - // All of Riven's cursors are hardcoded. See riven_cursors.h for these definitions. - - switch (num) { - case 1002: - // Zip Mode - CursorMan.replaceCursor(s_zipModeCursor, 16, 16, 8, 8, 0); - CursorMan.replaceCursorPalette(s_zipModeCursorPalette, 1, ARRAYSIZE(s_zipModeCursorPalette) / 4); - break; - case 2003: - // Hand Over Object - CursorMan.replaceCursor(s_objectHandCursor, 16, 16, 8, 8, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 2004: - // Grabbing/Using Object - CursorMan.replaceCursor(s_grabbingHandCursor, 13, 13, 6, 6, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3000: - // Standard Hand - CursorMan.replaceCursor(s_standardHandCursor, 15, 16, 6, 0, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3001: - // Pointing Left - CursorMan.replaceCursor(s_pointingLeftCursor, 15, 13, 0, 3, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3002: - // Pointing Right - CursorMan.replaceCursor(s_pointingRightCursor, 15, 13, 14, 3, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3003: - // Pointing Down (Palm Up) - CursorMan.replaceCursor(s_pointingDownCursorPalmUp, 13, 16, 3, 15, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3004: - // Pointing Up (Palm Up) - CursorMan.replaceCursor(s_pointingUpCursorPalmUp, 13, 16, 3, 0, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3005: - // Pointing Left (Curved) - CursorMan.replaceCursor(s_pointingLeftCursorBent, 15, 13, 0, 5, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3006: - // Pointing Right (Curved) - CursorMan.replaceCursor(s_pointingRightCursorBent, 15, 13, 14, 5, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 3007: - // Pointing Down (Palm Down) - CursorMan.replaceCursor(s_pointingDownCursorPalmDown, 15, 16, 7, 15, 0); - CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 4); - break; - case 4001: - // Red Marble - CursorMan.replaceCursor(s_redMarbleCursor, 12, 12, 5, 5, 0); - CursorMan.replaceCursorPalette(s_redMarbleCursorPalette, 1, ARRAYSIZE(s_redMarbleCursorPalette) / 4); - break; - case 4002: - // Orange Marble - CursorMan.replaceCursor(s_orangeMarbleCursor, 12, 12, 5, 5, 0); - CursorMan.replaceCursorPalette(s_orangeMarbleCursorPalette, 1, ARRAYSIZE(s_orangeMarbleCursorPalette) / 4); - break; - case 4003: - // Yellow Marble - CursorMan.replaceCursor(s_yellowMarbleCursor, 12, 12, 5, 5, 0); - CursorMan.replaceCursorPalette(s_yellowMarbleCursorPalette, 1, ARRAYSIZE(s_yellowMarbleCursorPalette) / 4); - break; - case 4004: - // Green Marble - CursorMan.replaceCursor(s_greenMarbleCursor, 12, 12, 5, 5, 0); - CursorMan.replaceCursorPalette(s_greenMarbleCursorPalette, 1, ARRAYSIZE(s_greenMarbleCursorPalette) / 4); - break; - case 4005: - // Blue Marble - CursorMan.replaceCursor(s_blueMarbleCursor, 12, 12, 5, 5, 0); - CursorMan.replaceCursorPalette(s_blueMarbleCursorPalette, 1, ARRAYSIZE(s_blueMarbleCursorPalette) / 4); - break; - case 4006: - // Violet Marble - CursorMan.replaceCursor(s_violetMarbleCursor, 12, 12, 5, 5, 0); - CursorMan.replaceCursorPalette(s_violetMarbleCursorPalette, 1, ARRAYSIZE(s_violetMarbleCursorPalette) / 4); - break; - case 5000: - // Pellet - CursorMan.replaceCursor(s_pelletCursor, 8, 8, 4, 4, 0); - CursorMan.replaceCursorPalette(s_pelletCursorPalette, 1, ARRAYSIZE(s_pelletCursorPalette) / 4); - break; - case 9000: - // Hide Cursor - CursorMan.showMouse(false); - break; - default: - error("Cursor %d does not exist!", num); - } - - if (num != 9000) // Show Cursor - CursorMan.showMouse(true); - - // Should help in cases where we need to hide the cursor immediately. - _vm->_system->updateScreen(); -} - void RivenGraphics::showInventory() { // Don't redraw the inventory if (_inventoryDrawn) @@ -668,14 +607,13 @@ void RivenGraphics::clearInventoryArea() { } void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) { - ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); - Graphics::Surface *surface = imageData->getSurface(); - delete imageData; + 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); - surface->free(); - delete surface; + delete mhkSurface; } void RivenGraphics::drawRect(Common::Rect rect, bool active) { @@ -692,100 +630,92 @@ 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)->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->bytesPerPixel); - surface->free(); - delete surface; - _dirtyScreen = true; } void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) { - ImageData *imageData = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); - Graphics::Surface *surface = imageData->getSurface(); - delete imageData; + 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); - surface->free(); - delete surface; - + delete mhkSurface; _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); } LBGraphics::~LBGraphics() { delete _bmpDecoder; - delete[] _palette; } -void LBGraphics::copyImageToScreen(uint16 image, uint16 left, uint16 right) { - if (_vm->getGameType() == GType_LIVINGBOOKSV1) { - // Drawing images in the old format isn't supported (yet) - ImageData *imageData = _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, image)); - delete imageData; - } else { - ImageData *imageData = _bmpDecoder->decodeImage(_vm->getRawData(ID_TBMP, image)); - imageData->_palette = _palette; - Graphics::Surface *surface = imageData->getSurface(); - imageData->_palette = NULL; // Unset the palette so it doesn't get deleted - delete imageData; - - uint16 width = MIN<int>(surface->w, 640); - uint16 height = MIN<int>(surface->h, 480); - _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 - _vm->_system->updateScreen(); - } +MohawkSurface *LBGraphics::decodeImage(uint16 id) { + if (_vm->getGameType() == GType_LIVINGBOOKSV1) + return _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, id)); + + return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); +} + +void LBGraphics::copyImageToScreen(uint16 image, uint16 left, uint16 top) { + Graphics::Surface *surface = findImage(image)->getSurface(); + + 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, top, width, height); + + // FIXME: Remove this and update only when necessary + _vm->_system->updateScreen(); } 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->getGameType() == GType_LIVINGBOOKSV1) { Common::SeekableSubReadStreamEndian *ctblStream = _vm->wrapStreamEndian(ID_CTBL, id); uint16 colorCount = ctblStream->readUint16(); + byte *palette = new byte[colorCount * 4]; for (uint16 i = 0; i < colorCount; i++) { - _palette[i * 4] = ctblStream->readByte(); - _palette[i * 4 + 1] = ctblStream->readByte(); - _palette[i * 4 + 2] = ctblStream->readByte(); - _palette[i * 4 + 3] = ctblStream->readByte(); + palette[i * 4] = ctblStream->readByte(); + palette[i * 4 + 1] = ctblStream->readByte(); + palette[i * 4 + 2] = ctblStream->readByte(); + palette[i * 4 + 3] = ctblStream->readByte(); } delete ctblStream; + + _vm->_system->setPalette(palette, 0, colorCount); + delete[] palette; } else { - Common::SeekableReadStream *tpalStream = _vm->getRawData(ID_TPAL, id); + Common::SeekableReadStream *tpalStream = _vm->getResource(ID_TPAL, id); uint16 colorStart = tpalStream->readUint16BE(); uint16 colorCount = tpalStream->readUint16BE(); + byte *palette = new byte[colorCount * 4]; - for (uint16 i = colorStart; i < colorStart + colorCount; i++) { - _palette[i * 4] = tpalStream->readByte(); - _palette[i * 4 + 1] = tpalStream->readByte(); - _palette[i * 4 + 2] = tpalStream->readByte(); - _palette[i * 4 + 3] = tpalStream->readByte(); + for (uint16 i = 0; i < colorCount; i++) { + palette[i * 4] = tpalStream->readByte(); + palette[i * 4 + 1] = tpalStream->readByte(); + palette[i * 4 + 2] = tpalStream->readByte(); + palette[i * 4 + 3] = tpalStream->readByte(); } delete tpalStream; + + _vm->_system->setPalette(palette, colorStart, colorCount); + delete[] palette; } } |