From 7594507277ba7506b8c7142b8a1463a97036c14d Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 27 Jun 2015 19:23:42 -0400 Subject: SHERLOCK: RT: Properly implement StreamingImageFile class --- engines/sherlock/image_file.cpp | 95 +++++++++++++++++++---- engines/sherlock/image_file.h | 58 ++++++++++++-- engines/sherlock/objects.cpp | 36 --------- engines/sherlock/objects.h | 38 --------- engines/sherlock/scalpel/scalpel_scene.cpp | 2 +- engines/sherlock/scene.cpp | 34 ++++---- engines/sherlock/scene.h | 2 +- engines/sherlock/tattoo/tattoo_scene.cpp | 39 +++++----- engines/sherlock/tattoo/tattoo_scene.h | 2 +- engines/sherlock/tattoo/tattoo_user_interface.cpp | 2 +- 10 files changed, 174 insertions(+), 134 deletions(-) (limited to 'engines/sherlock') diff --git a/engines/sherlock/image_file.cpp b/engines/sherlock/image_file.cpp index 78284e416d..4d713b155a 100644 --- a/engines/sherlock/image_file.cpp +++ b/engines/sherlock/image_file.cpp @@ -93,9 +93,10 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool } // Load data for frame and decompress it - byte *data = new byte[frame._size]; + byte *data = new byte[frame._size + 4]; stream.read(data, frame._size); - decompressFrame(frame, data); + Common::fill(data + frame._size, data + frame._size + 4, 0); + frame.decompressFrame(data, _vm->getGameID() == GType_RoseTattoo); delete[] data; push_back(frame); @@ -134,21 +135,21 @@ void ImageFile::loadPalette(Common::SeekableReadStream &stream) { } } -void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) { - frame._frame.create(frame._width, frame._height, Graphics::PixelFormat::createFormatCLUT8()); - byte *dest = (byte *)frame._frame.getPixels(); - Common::fill(dest, dest + frame._width * frame._height, 0xff); +void ImageFrame::decompressFrame(const byte *src, bool isRoseTattoo) { + _frame.create(_width, _height, Graphics::PixelFormat::createFormatCLUT8()); + byte *dest = (byte *)_frame.getPixels(); + Common::fill(dest, dest + _width * _height, 0xff); - if (frame._paletteBase) { + if (_paletteBase) { // Nibble-packed - for (uint idx = 0; idx < frame._size; ++idx, ++src) { + for (uint idx = 0; idx < _size; ++idx, ++src) { *dest++ = *src & 0xF; *dest++ = (*src >> 4); } - } else if (frame._rleEncoded && _vm->getGameID() == GType_RoseTattoo) { + } else if (_rleEncoded && isRoseTattoo) { // Rose Tattoo run length encoding doesn't use the RLE marker byte - for (int yp = 0; yp < frame._height; ++yp) { - int xSize = frame._width; + for (int yp = 0; yp < _height; ++yp) { + int xSize = _width; while (xSize > 0) { // Skip a given number of pixels byte skip = *src++; @@ -165,11 +166,11 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) { } assert(xSize == 0); } - } else if (frame._rleEncoded) { + } else if (_rleEncoded) { // RLE encoded - int frameSize = frame._width * frame._height; + int frameSize = _width * _height; while (frameSize > 0) { - if (*src == frame._rleMarker) { + if (*src == _rleMarker) { byte rleColor = src[1]; byte rleCount = src[2]; src += 3; @@ -184,7 +185,7 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) { assert(frameSize == 0); } else { // Uncompressed frame - Common::copy(src, src + frame._width * frame._height, dest); + Common::copy(src, src + _width * _height, dest); } } @@ -1007,4 +1008,68 @@ void ImageFile3DO::loadFont(Common::SeekableReadStream &stream) { delete[] widthTablePtr; } +/*----------------------------------------------------------------*/ + +StreamingImageFile::StreamingImageFile() { + _frameNumber = 0; + _stream = nullptr; + _flags = 0; + _scaleVal = 0; + _zPlacement = 0; +} + +StreamingImageFile::~StreamingImageFile() { + close(); +} + +void StreamingImageFile::load(Common::SeekableReadStream *stream, bool compressed) { + _stream = stream; + _compressed = compressed; + _frameNumber = -1; +} + +void StreamingImageFile::close() { + delete _stream; + _stream = nullptr; + _frameNumber = -1; +} + +void StreamingImageFile::getNextFrame() { + // Don't proceed if we're already at the end of the stream + if (_stream->pos() >= _stream->size()) + return; + + // Increment frame number + ++_frameNumber; + + // If necessary, decompress the next frame + Common::SeekableReadStream *frameStream = _stream; + if (_compressed) { + uint32 inSize = _stream->readUint32LE(); + Resources::decompressLZ(*_stream, _buffer, STREAMING_BUFFER_SIZE, inSize); + frameStream = new Common::MemoryReadStream(_buffer, 11, DisposeAfterUse::NO); + } + + // Load the data for the frame + _imageFrame._width = frameStream->readUint16LE() + 1; + _imageFrame._height = frameStream->readUint16LE() + 1; + _imageFrame._paletteBase = frameStream->readByte(); + _imageFrame._rleEncoded = frameStream->readByte() == 1; + _imageFrame._offset.x = frameStream->readByte(); + _imageFrame._offset.y = frameStream->readByte(); + _imageFrame._size = frameStream->readUint16LE() - 11; + _imageFrame._rleMarker = frameStream->readByte(); + + // Decode the frame + if (_compressed) { + delete frameStream; + _imageFrame.decompressFrame(_buffer + 11, true); + } else { + byte *data = new byte[_imageFrame._size]; + _stream->read(data, _imageFrame._size); + _imageFrame.decompressFrame(_buffer + 11, true); + delete[] data; + } +} + } // End of namespace Sherlock diff --git a/engines/sherlock/image_file.h b/engines/sherlock/image_file.h index f24e831440..3ac0cf4b5f 100644 --- a/engines/sherlock/image_file.h +++ b/engines/sherlock/image_file.h @@ -45,6 +45,11 @@ struct ImageFrame { byte _rleMarker; Graphics::Surface _frame; + /** + * Decompress a single frame for the sprite + */ + void decompressFrame(const byte *src, bool isRoseTattoo); + /** * Return the frame width adjusted by a specified scale amount */ @@ -79,11 +84,6 @@ private: * Gets the palette at the start of the sprite file */ void loadPalette(Common::SeekableReadStream &stream); - - /** - * Decompress a single frame for the sprite - */ - void decompressFrame(ImageFrame &frame, const byte *src); public: byte _palette[256 * 3]; public: @@ -154,6 +154,54 @@ public: static void setVm(SherlockEngine *vm); }; +#define STREAMING_BUFFER_SIZE 65536 + +class StreamingImageFile { +private: + int _frameNumber; + Common::SeekableReadStream *_stream; + bool _compressed; + byte _buffer[STREAMING_BUFFER_SIZE]; +public: + ImageFrame _imageFrame; + + Common::Point _position; // Animation position + Common::Rect _oldBounds; // Bounds of previous frame + Common::Rect _removeBounds; // Remove area for just drawn frame + + int _flags; // Flags + int _scaleVal; // Specifies the scale amount + int _zPlacement; // Used by doBgAnim for determining Z order +public: + StreamingImageFile(); + ~StreamingImageFile(); + + /** + * Initialize reading of the specified stream + */ + void load(Common::SeekableReadStream *stream, bool compressed); + + /** + * Close the streamining image file + */ + void close(); + + /** + * Get the next frame of the file + */ + void getNextFrame(); + + /** + * Returns whether there are any remaining frames or not + */ + bool active() const { return _stream != nullptr && _stream->pos() < _stream->size(); } + + /** + * Return the current frame number + */ + int frameNumber() const { return _frameNumber; } +}; + } // End of namespace Sherlock #endif diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp index 79822623d2..97d63c5da6 100644 --- a/engines/sherlock/objects.cpp +++ b/engines/sherlock/objects.cpp @@ -1498,42 +1498,6 @@ void CAnim::load3DO(Common::SeekableReadStream &s, uint32 dataOffset) { /*----------------------------------------------------------------*/ -CAnimStream::CAnimStream() { - _images = nullptr; - _imageFrame = nullptr; - _frameNumber = 0; - _flags = 0; - _scaleVal = 0; - _zPlacement = 0; -} - -CAnimStream::~CAnimStream() { - delete _images; -} - -void CAnimStream::load(Common::SeekableReadStream *stream) { - delete _images; - _images = new ImageFile(*stream, false); - _imageFrame = &(*_images)[0]; - _frameNumber = 0; -} - -void CAnimStream::close() { - delete _images; - _images = nullptr; - _imageFrame = nullptr; - _frameNumber = 0; -} - -void CAnimStream::getNextFrame() { - if (++_frameNumber < (int)_images->size()) - _imageFrame = &(*_images)[_frameNumber]; - else - _imageFrame = nullptr; -} - -/*----------------------------------------------------------------*/ - SceneImage::SceneImage() { _images = nullptr; _maxFrames = 0; diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h index f29c7890ab..7e94dd2bdd 100644 --- a/engines/sherlock/objects.h +++ b/engines/sherlock/objects.h @@ -458,44 +458,6 @@ struct CAnim { void load3DO(Common::SeekableReadStream &s, uint32 dataOffset); }; -class CAnimStream { - ImageFile *_images; - int _frameNumber; -public: - ImageFrame *_imageFrame; - - Common::Point _position; // Animation position - Common::Rect _oldBounds; // Bounds of previous frame - Common::Rect _removeBounds; // Remove area for just drawn frame - - int _flags; // Flags - int _scaleVal; // Specifies the scale amount - int _zPlacement; // Used by doBgAnim for determining Z order -public: - CAnimStream(); - ~CAnimStream(); - - /** - * Load the animation's images - */ - void load(Common::SeekableReadStream *stream); - - /** - * Close any currently active animation - */ - void close(); - - /** - * Get the next frame of the animation - */ - void getNextFrame(); - - /** - * Returns whether the animation is active - */ - bool active() const { return _imageFrame != nullptr; } -}; - struct SceneImage { ImageFile *_images; // Object images int _maxFrames; // How many frames in object diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp index bbe6674837..fa820d95fd 100644 --- a/engines/sherlock/scalpel/scalpel_scene.cpp +++ b/engines/sherlock/scalpel/scalpel_scene.cpp @@ -574,7 +574,7 @@ int ScalpelScene::startCAnim(int cAnimNum, int playRate) { //rrmStream->seek(rrmStream->readUint32LE()); // Load the canimation into the cache - Common::SeekableReadStream *imgStream = !_lzwMode ? roomStream->readStream(cAnim._dataSize) : + Common::SeekableReadStream *imgStream = !_compressed ? roomStream->readStream(cAnim._dataSize) : Resources::decompressLZ(*roomStream, cAnim._dataSize); res.addToCache(fname, *imgStream); diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index e6a2762055..c3917fb003 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -224,7 +224,7 @@ Scene::Scene(SherlockEngine *vm): _vm(vm) { _loadingSavedGame = false; _walkedInScene = false; _version = 0; - _lzwMode = false; + _compressed = false; _invGraphicItems = 0; _cAnimFramePause = 0; _restoreFlag = false; @@ -350,9 +350,9 @@ bool Scene::loadScene(const Common::String &filename) { rrmStream->seek(39); if (IS_SERRATED_SCALPEL) { _version = rrmStream->readByte(); - _lzwMode = _version == 10; + _compressed = _version == 10; } else { - _lzwMode = rrmStream->readByte() > 0; + _compressed = rrmStream->readByte() > 0; } // Go to header and read it in @@ -370,7 +370,7 @@ bool Scene::loadScene(const Common::String &filename) { paletteLoaded(); // Read in background - if (_lzwMode) { + if (_compressed) { res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); } else { rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT); @@ -387,29 +387,29 @@ bool Scene::loadScene(const Common::String &filename) { // Read information if (IS_ROSE_TATTOO) { // Load shapes - Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625); + Common::SeekableReadStream *infoStream = !_compressed ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625); _bgShapes.resize(bgHeader._numStructs); for (int idx = 0; idx < bgHeader._numStructs; ++idx) _bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo); - if (_lzwMode) + if (_compressed) delete infoStream; // Load description text _descText.resize(bgHeader._descSize); - if (_lzwMode) + if (_compressed) res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize); else rrmStream->read(&_descText[0], bgHeader._descSize); // Load sequences _sequenceBuffer.resize(bgHeader._seqSize); - if (_lzwMode) + if (_compressed) res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize); else rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize); - } else if (!_lzwMode) { + } else if (!_compressed) { // Serrated Scalpel uncompressed info _bgShapes.resize(bgHeader._numStructs); for (int idx = 0; idx < bgHeader._numStructs; ++idx) @@ -465,7 +465,7 @@ bool Scene::loadScene(const Common::String &filename) { _images[idx + 1]._maxFrames = bgInfo[idx]._maxFrames; // Read in the image data - Common::SeekableReadStream *imageStream = _lzwMode ? + Common::SeekableReadStream *imageStream = _compressed ? res.decompress(*rrmStream, bgInfo[idx]._filesize) : rrmStream->readStream(bgInfo[idx]._filesize); @@ -495,7 +495,7 @@ bool Scene::loadScene(const Common::String &filename) { _cAnim.clear(); if (bgHeader._numcAnimations) { int animSize = IS_SERRATED_SCALPEL ? 65 : 47; - Common::SeekableReadStream *cAnimStream = _lzwMode ? + Common::SeekableReadStream *cAnimStream = _compressed ? res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) : rrmStream->readStream(animSize * bgHeader._numcAnimations); @@ -533,7 +533,7 @@ bool Scene::loadScene(const Common::String &filename) { // Read in the room bounding areas int size = rrmStream->readUint16LE(); - Common::SeekableReadStream *boundsStream = !_lzwMode ? rrmStream : + Common::SeekableReadStream *boundsStream = !_compressed ? rrmStream : res.decompress(*rrmStream, size); _zones.resize(size / 10); @@ -545,7 +545,7 @@ bool Scene::loadScene(const Common::String &filename) { boundsStream->skip(2); // Skip unused scene number field } - if (_lzwMode) + if (_compressed) delete boundsStream; // Ensure we've reached the path version byte @@ -564,7 +564,7 @@ bool Scene::loadScene(const Common::String &filename) { // Read in the walk data size = rrmStream->readUint16LE(); - Common::SeekableReadStream *walkStream = !_lzwMode ? rrmStream : + Common::SeekableReadStream *walkStream = !_compressed ? rrmStream : res.decompress(*rrmStream, size); int startPos = walkStream->pos(); @@ -574,7 +574,7 @@ bool Scene::loadScene(const Common::String &filename) { _walkPoints[_walkPoints.size() - 1].load(*walkStream, IS_ROSE_TATTOO); } - if (_lzwMode) + if (_compressed) delete walkStream; // Translate the file offsets of the walk directory to indexes in the loaded walk data @@ -639,12 +639,12 @@ bool Scene::loadScene(const Common::String &filename) { Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap); // Read in the background - Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream : + Common::SeekableReadStream *bgStream = !_compressed ? rrmStream : res.decompress(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT); - if (_lzwMode) + if (_compressed) delete bgStream; } diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h index d4c88350cc..5037b9d2cf 100644 --- a/engines/sherlock/scene.h +++ b/engines/sherlock/scene.h @@ -216,7 +216,7 @@ public: bool **_sceneStats; bool _walkedInScene; int _version; - bool _lzwMode; + bool _compressed; int _invGraphicItems; Common::String _comments; Common::Array _descText; diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp index 1c6f9263e9..3a0888ca57 100644 --- a/engines/sherlock/tattoo/tattoo_scene.cpp +++ b/engines/sherlock/tattoo/tattoo_scene.cpp @@ -130,8 +130,8 @@ void TattooScene::drawAllShapes() { } // Draw the animation if it is behind the person - if (_activeCAnim._imageFrame != nullptr && _activeCAnim._zPlacement == BEHIND) - screen._backBuffer1.transBlitFrom(*_activeCAnim._imageFrame, _activeCAnim._position, + if (_activeCAnim.active() && _activeCAnim._zPlacement == BEHIND) + screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); screen.resetDisplayBounds(); @@ -151,13 +151,13 @@ void TattooScene::drawAllShapes() { } // Queue drawing the animation if it is NORMAL and can fall in front of, or behind the people - if (_activeCAnim._imageFrame != nullptr && (_activeCAnim._zPlacement == NORMAL_BEHIND || _activeCAnim._zPlacement == NORMAL_FORWARD)) { + if (_activeCAnim.active() && (_activeCAnim._zPlacement == NORMAL_BEHIND || _activeCAnim._zPlacement == NORMAL_FORWARD)) { if (_activeCAnim._scaleVal == SCALE_THRESHOLD) - shapeList.push_back(ShapeEntry(_activeCAnim._position.y + _activeCAnim._imageFrame->_offset.y + - _activeCAnim._imageFrame->_height)); + shapeList.push_back(ShapeEntry(_activeCAnim._position.y + _activeCAnim._imageFrame._offset.y + + _activeCAnim._imageFrame._height)); else - shapeList.push_back(ShapeEntry(_activeCAnim._position.y + _activeCAnim._imageFrame->sDrawYOffset(_activeCAnim._scaleVal) + - _activeCAnim._imageFrame->sDrawYSize(_activeCAnim._scaleVal))); + shapeList.push_back(ShapeEntry(_activeCAnim._position.y + _activeCAnim._imageFrame.sDrawYOffset(_activeCAnim._scaleVal) + + _activeCAnim._imageFrame.sDrawYSize(_activeCAnim._scaleVal))); } // Queue all active characters for drawing @@ -182,7 +182,7 @@ void TattooScene::drawAllShapes() { se._shape->_flags & OBJ_FLIPPED, 0, se._shape->_scaleVal); } else if (se._isAnimation) { // It's an active animation - screen._backBuffer1.transBlitFrom(*_activeCAnim._imageFrame, _activeCAnim._position, + screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); } else { // Drawing person @@ -244,8 +244,8 @@ void TattooScene::drawAllShapes() { } // Draw the canimation if it is set as FORWARD - if (_activeCAnim._imageFrame != nullptr && _activeCAnim._zPlacement == FORWARD) - screen._backBuffer1.transBlitFrom(*_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); + if (_activeCAnim.active() && _activeCAnim._zPlacement == FORWARD) + screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal); // Draw all NO_SHAPE shapes which have their flag bits clear for (uint idx = 0; idx < _bgShapes.size(); ++idx) { @@ -268,13 +268,13 @@ void TattooScene::checkBgShapes() { Scene::checkBgShapes(); // Check for any active playing animation - if (_activeCAnim._imageFrame && _activeCAnim._zPlacement != REMOVE) { + if (_activeCAnim.active() && _activeCAnim._zPlacement != REMOVE) { switch (_activeCAnim._flags & 3) { case 0: _activeCAnim._zPlacement = BEHIND; break; case 1: - _activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame->_frame.h - 1)) ? + _activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame._frame.h - 1)) ? NORMAL_FORWARD : NORMAL_BEHIND; break; case 2: @@ -381,10 +381,6 @@ void TattooScene::doBgAnimUpdateBgObjectsAndAnim() { people[idx].adjustSprite(); } - if (_activeCAnim._imageFrame != nullptr && _activeCAnim._zPlacement != REMOVE) { - _activeCAnim.getNextFrame(); - } - // Flag the bg shapes which need to be redrawn checkBgShapes(); drawAllShapes(); @@ -531,9 +527,9 @@ void TattooScene::doBgAnimDrawSprites() { } } - if (_activeCAnim._imageFrame != nullptr || _activeCAnim._zPlacement == REMOVE) { + if (_activeCAnim.active() || _activeCAnim._zPlacement == REMOVE) { if (_activeCAnim._zPlacement != REMOVE) { - screen.flushImage(_activeCAnim._imageFrame, _activeCAnim._position, _activeCAnim._oldBounds, _activeCAnim._scaleVal); + screen.flushImage(&_activeCAnim._imageFrame, _activeCAnim._position, _activeCAnim._oldBounds, _activeCAnim._scaleVal); } else { screen.slamArea(_activeCAnim._removeBounds.left - ui._currentScroll.x, _activeCAnim._removeBounds.top, _activeCAnim._removeBounds.width(), _activeCAnim._removeBounds.height()); @@ -651,11 +647,16 @@ int TattooScene::startCAnim(int cAnimNum, int playRate) { _activeCAnim._scaleVal = cAnim._scaleVal; _activeCAnim._zPlacement = 0; - _activeCAnim.load(animStream); + _activeCAnim.load(animStream, _compressed); while (_activeCAnim.active() && !_vm->shouldQuit()) { + // Get the next frame + _activeCAnim.getNextFrame(); + + // Draw the frame doBgAnim(); + // Check for Escape key being pressed to abort animation events.pollEvents(); if (events.kbHit()) { Common::KeyState keyState = events.getKey(); diff --git a/engines/sherlock/tattoo/tattoo_scene.h b/engines/sherlock/tattoo/tattoo_scene.h index 106903f076..81d76374f3 100644 --- a/engines/sherlock/tattoo/tattoo_scene.h +++ b/engines/sherlock/tattoo/tattoo_scene.h @@ -97,7 +97,7 @@ protected: */ virtual void synchronize(Serializer &s); public: - CAnimStream _activeCAnim; + StreamingImageFile _activeCAnim; Common::Array _sceneTripCounters; bool _labTableScene; public: diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp index ff98706844..51dd4d1f7c 100644 --- a/engines/sherlock/tattoo/tattoo_user_interface.cpp +++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp @@ -323,7 +323,7 @@ void TattooUserInterface::doBgAnimRestoreUI() { _tooltipWidget.erase(); // If a canimation is active, restore the graphics underneath it - if (scene._activeCAnim._imageFrame != nullptr) + if (scene._activeCAnim.active()) screen.restoreBackground(scene._activeCAnim._oldBounds); // If a canimation just ended, remove it's graphics from the backbuffer -- cgit v1.2.3