From 30ee8ed0fd1e983f5472bd5f382c39ba7e400cb2 Mon Sep 17 00:00:00 2001 From: Marisa-Chan Date: Fri, 15 Nov 2013 18:34:11 +0000 Subject: ZVISION: Refactore AnimationControl to AnimationNode + changes for correct use it from actions. --- engines/zvision/actions.cpp | 58 ++++++-- engines/zvision/actions.h | 12 +- engines/zvision/animation_control.cpp | 268 ++++++++++++---------------------- engines/zvision/animation_control.h | 51 ++++--- 4 files changed, 168 insertions(+), 221 deletions(-) (limited to 'engines/zvision') diff --git a/engines/zvision/actions.cpp b/engines/zvision/actions.cpp index ea33736b5d..f83d295dde 100644 --- a/engines/zvision/actions.cpp +++ b/engines/zvision/actions.cpp @@ -274,17 +274,29 @@ ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, const Common::St char fileName[25]; // The two %*u are always 0 and dont seem to have a use - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%25s %*u %*u %u %u)", &_key, fileName, &_mask, &_framerate); + sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%25s %*u %*u %d %d)", &_key, fileName, &_mask, &_framerate); + + if (_mask > 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b); + _mask = _engine->_pixelFormat.RGBToColor(r, g, b); + } _fileName = Common::String(fileName); } -bool ActionPreloadAnimation::execute() { - // TODO: We ignore the mask and framerate atm. Mask refers to a key color used for binary alpha. We assume the framerate is the default framerate embedded in the videos +ActionPreloadAnimation::~ActionPreloadAnimation() { + _engine->getScriptManager()->deleteSideFx(_key); +} - // TODO: Check if the Control already exists +bool ActionPreloadAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_key); - // Create the control, but disable it until PlayPreload is called + if (!nod) { + nod = new AnimationNode(_engine, _key, _fileName, _mask, _framerate, false); + _engine->getScriptManager()->addSideFX(nod); + } else + nod->stop(); return true; } @@ -299,14 +311,34 @@ ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, const Common::String & // The two %*u are always 0 and dont seem to have a use sscanf(line.c_str(), - "%*[^:]:%*[^:]:%u(%25s %u %u %u %u %u %u %u %*u %*u %u %u)", + "%*[^:]:%*[^:]:%u(%25s %u %u %u %u %u %u %d %*u %*u %d %d)", &_key, fileName, &_x, &_y, &_width, &_height, &_start, &_end, &_loopCount, &_mask, &_framerate); + if (_mask > 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b); + _mask = _engine->_pixelFormat.RGBToColor(r, g, b); + } + _fileName = Common::String(fileName); } +ActionPlayAnimation::~ActionPlayAnimation() { + _engine->getScriptManager()->deleteSideFx(_key); +} + bool ActionPlayAnimation::execute() { - // TODO: Implement + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_key); + + if (!nod) { + nod = new AnimationNode(_engine, _key, _fileName, _mask, _framerate); + _engine->getScriptManager()->addSideFX(nod); + } else + nod->stop(); + + if (nod) + nod->addPlayNode(_key, _x, _y, _width, _height, _start, _end, _loopCount); + return true; } @@ -323,14 +355,10 @@ ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, const Co } bool ActionPlayPreloadAnimation::execute() { - // Find the control - AnimationControl *control = (AnimationControl *)_engine->getScriptManager()->getControl(_controlKey); - - // Set the needed values within the control - control->setAnimationKey(_animationKey); - control->setLoopCount(_loopCount); - control->setXPos(_x1); - control->setYPost(_y1); + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_animationKey); + + if (nod) + nod->addPlayNode(_controlKey, _x1, _y1, _x2, _y2, _startFrame, _endFrame, _loopCount); return true; } diff --git a/engines/zvision/actions.h b/engines/zvision/actions.h index 1d7a815819..b75c201d99 100644 --- a/engines/zvision/actions.h +++ b/engines/zvision/actions.h @@ -240,6 +240,7 @@ private: class ActionPlayAnimation : public ResultAction { public: ActionPlayAnimation(ZVision *engine, const Common::String &line); + ~ActionPlayAnimation(); bool execute(); private: @@ -251,9 +252,9 @@ private: uint32 _height; uint32 _start; uint32 _end; - uint _mask; - uint _framerate; - uint _loopCount; + int32 _mask; + int32 _framerate; + int32 _loopCount; }; class ActionPlayPreloadAnimation : public ResultAction { @@ -276,13 +277,14 @@ private: class ActionPreloadAnimation : public ResultAction { public: ActionPreloadAnimation(ZVision *engine, const Common::String &line); + ~ActionPreloadAnimation(); bool execute(); private: uint32 _key; Common::String _fileName; - uint _mask; - uint _framerate; + int32 _mask; + int32 _framerate; }; class ActionQuit : public ResultAction { diff --git a/engines/zvision/animation_control.cpp b/engines/zvision/animation_control.cpp index 5b35a4a468..f825bbedfc 100644 --- a/engines/zvision/animation_control.cpp +++ b/engines/zvision/animation_control.cpp @@ -37,222 +37,140 @@ namespace ZVision { -AnimationControl::AnimationControl(ZVision *engine, uint32 controlKey, const Common::String &fileName) - : Control(engine, controlKey), +AnimationNode::AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse) + : SideFX(engine, controlKey, SIDEFX_ANIM), _fileType(RLF), - _loopCount(1), - _currentLoop(0), - _accumulatedTime(0), - _cachedFrame(0), - _cachedFrameNeedsDeletion(false) { + _DisposeAfterUse(DisposeAfterUse), + _mask(mask) { if (fileName.hasSuffix(".rlf")) { _fileType = RLF; _animation.rlf = new RlfAnimation(fileName, false); + _frmDelay = _animation.rlf->frameTime(); } else if (fileName.hasSuffix(".avi")) { _fileType = AVI; _animation.avi = new ZorkAVIDecoder(); _animation.avi->loadFile(fileName); + _frmDelay = 1000.0 / _animation.avi->getDuration().framerate(); } else { warning("Unrecognized animation file type: %s", fileName.c_str()); } - _cachedFrame = new Graphics::Surface(); + if (frate > 0) + _frmDelay = 1000.0 / frate; } -AnimationControl::~AnimationControl() { +AnimationNode::~AnimationNode() { if (_fileType == RLF) { delete _animation.rlf; } else if (_fileType == AVI) { delete _animation.avi; } - _cachedFrame->free(); - delete _cachedFrame; -} - -bool AnimationControl::process(uint32 deltaTimeInMillis) { - - bool finished = false; + _engine->getScriptManager()->setStateValue(_key, 2); - if (_fileType == RLF) { - _accumulatedTime += deltaTimeInMillis; + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) + _engine->getScriptManager()->setStateValue((*it).slot, 2); - uint32 frameTime = _animation.rlf->frameTime(); - if (_accumulatedTime >= frameTime) { - while (_accumulatedTime >= frameTime) { - _accumulatedTime -= frameTime; + _playList.clear(); +} - // Make sure the frame is inside the working window - // If it's not, then just return +bool AnimationNode::process(uint32 deltaTimeInMillis) { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + playnode *nod = &(*it); + + nod->_delay -= deltaTimeInMillis; + if (nod->_delay <= 0) { + nod->_delay += _frmDelay; + + const Graphics::Surface *frame = NULL; + + if (nod->_cur_frm == -1) { // Start of new playlist node + nod->_cur_frm = nod->start; + if (_fileType == RLF) { + _animation.rlf->seekToFrame(nod->_cur_frm); + frame = _animation.rlf->decodeNextFrame(); + } else if (_fileType == AVI) { + _animation.avi->seekToFrame(nod->_cur_frm); + frame = _animation.avi->decodeNextFrame(); + } - RenderManager *renderManager = _engine->getRenderManager(); - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _animation.rlf->width(), workingWindowPoint.y + _animation.rlf->height()); + nod->_delay = _frmDelay; + if (nod->slot) + _engine->getScriptManager()->setStateValue(nod->slot, 1); + } else { + nod->_cur_frm++; - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } + if (nod->_cur_frm > nod->stop) { + nod->loop--; - const Graphics::Surface *frame = _animation.rlf->decodeNextFrame(); - - // Animation frames for PANORAMAs are transposed, so un-transpose them - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - if (state == RenderTable::PANORAMA) { - Graphics::Surface *tranposedFrame = RenderManager::tranposeSurface(frame); - - renderManager->copyRectToWorkingWindow((uint16 *)tranposedFrame->getBasePtr(tranposedFrame->w - subRect.width(), tranposedFrame->h - subRect.height()), subRect.left, subRect.top, _animation.rlf->width(), subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame = tranposedFrame; - _cachedFrameNeedsDeletion = true; - } else { - // Cleanup - tranposedFrame->free(); - delete tranposedFrame; + if (nod->loop == 0) { + if (nod->slot >= 0) + _engine->getScriptManager()->setStateValue(nod->slot, 2); + _playList.erase(it); + return _DisposeAfterUse; } - } else { - renderManager->copyRectToWorkingWindow((const uint16 *)frame->getBasePtr(frame->w - subRect.width(), frame->h - subRect.height()), subRect.left, subRect.top, _animation.rlf->width(), subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame->copyFrom(*frame); - } - } - // Check if we should continue looping - if (_animation.rlf->endOfAnimation()) { - _animation.rlf->seekToFrame(-1); - if (_loopCount > 0) { - _currentLoop++; - if (_currentLoop >= _loopCount) { - finished = true; - } + nod->_cur_frm = nod->start; + if (_fileType == RLF) { + _animation.rlf->seekToFrame(nod->_cur_frm); + frame = _animation.rlf->decodeNextFrame(); + } else if (_fileType == AVI) { + _animation.avi->seekToFrame(nod->_cur_frm); + frame = _animation.avi->decodeNextFrame(); } + } else { + if (_fileType == RLF) + frame = _animation.rlf->decodeNextFrame(); + else if (_fileType == AVI) + frame = _animation.avi->decodeNextFrame(); } } - } else { - // If the background can move, we have to keep rendering animation frames, otherwise the animation flickers during background movement - RenderManager *renderManager = _engine->getRenderManager(); - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _cachedFrame->w, workingWindowPoint.y + _cachedFrame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - renderManager->copyRectToWorkingWindow((uint16 *)_cachedFrame->getBasePtr(_cachedFrame->w - subRect.width(), _cachedFrame->h - subRect.height()), subRect.left, subRect.top, _cachedFrame->w, subRect.width(), subRect.height()); - } - } - } else if (_fileType == AVI) { - if (!_animation.avi->isPlaying()) { - _animation.avi->start(); - } - - if (_animation.avi->needsUpdate()) { - const Graphics::Surface *frame = _animation.avi->decodeNextFrame(); if (frame) { - // Make sure the frame is inside the working window - // If it's not, then just return - - RenderManager *renderManager = _engine->getRenderManager(); - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + frame->w, workingWindowPoint.y + frame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - // Animation frames for PANORAMAs are transposed, so un-transpose them - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - if (state == RenderTable::PANORAMA) { - Graphics::Surface *tranposedFrame = RenderManager::tranposeSurface(frame); - - renderManager->copyRectToWorkingWindow((uint16 *)tranposedFrame->getBasePtr(tranposedFrame->w - subRect.width(), tranposedFrame->h - subRect.height()), subRect.left, subRect.top, frame->w, subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame = tranposedFrame; - _cachedFrameNeedsDeletion = true; - } else { - // Cleanup - tranposedFrame->free(); - delete tranposedFrame; - } + if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) { + Graphics::Surface *transposed = RenderManager::tranposeSurface(frame); + if (_mask > 0) + _engine->getRenderManager()->renderImageToBackground(*transposed, nod->pos.left, nod->pos.top, _mask); + else + _engine->getRenderManager()->renderImageToBackground(*transposed, nod->pos.left, nod->pos.top); + delete transposed; } else { - renderManager->copyRectToWorkingWindow((const uint16 *)frame->getBasePtr(frame->w - subRect.width(), frame->h - subRect.height()), subRect.left, subRect.top, frame->w, subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame->copyFrom(*frame); - } + if (_mask > 0) + _engine->getRenderManager()->renderImageToBackground(*frame, nod->pos.left, nod->pos.top, _mask); + else + _engine->getRenderManager()->renderImageToBackground(*frame, nod->pos.left, nod->pos.top); } - } else { - // If the background can move, we have to keep rendering animation frames, otherwise the animation flickers during background movement - RenderManager *renderManager = _engine->getRenderManager(); - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); + } + } + } - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _cachedFrame->w, workingWindowPoint.y + _cachedFrame->h); + return false; +} - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - renderManager->copyRectToWorkingWindow((uint16 *)_cachedFrame->getBasePtr(_cachedFrame->w - subRect.width(), _cachedFrame->h - subRect.height()), subRect.left, subRect.top, _cachedFrame->w, subRect.width(), subRect.height()); - } - } - } - // Check if we should continue looping - if (_animation.avi->endOfVideo()) { - _animation.avi->rewind(); - if (_loopCount > 0) { - _currentLoop++; - if (_currentLoop >= _loopCount) { - _animation.avi->stop(); - finished = true; - } - } - } - } +void AnimationNode::addPlayNode(int32 slot, int x, int y, int w, int h, int start_frame, int end_frame, int loops) { + playnode nod; + nod.loop = loops; + nod.pos = Common::Rect(x, y, x + w - 1, y + h - 1); + nod.start = start_frame; + nod.stop = end_frame; + nod.slot = slot; + nod._cur_frm = -1; + nod._delay = 0; + _playList.push_back(nod); +} - // If we're done, set _animation key = 2 (Why 2? I don't know. It's just the value that they used) - // Then disable the control. DON'T delete it. It can be re-used - if (finished) { - _engine->getScriptManager()->setStateValue(_animationKey, 2); - _currentLoop = 0; - } +bool AnimationNode::stop() { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) + _engine->getScriptManager()->setStateValue((*it).slot, 2); + + _playList.clear(); + // We don't need to delete, it's may be reused return false; } diff --git a/engines/zvision/animation_control.h b/engines/zvision/animation_control.h index 247fbf765d..e63824f34b 100644 --- a/engines/zvision/animation_control.h +++ b/engines/zvision/animation_control.h @@ -23,7 +23,9 @@ #ifndef ZVISION_ANIMATION_CONTROL_H #define ZVISION_ANIMATION_CONTROL_H -#include "zvision/control.h" +#include "zvision/sidefx.h" +#include "common/rect.h" +#include "common/list.h" namespace Common { @@ -43,10 +45,20 @@ namespace ZVision { class ZVision; class RlfAnimation; -class AnimationControl : public Control { +class AnimationNode : public SideFX { public: - AnimationControl(ZVision *engine, uint32 controlKey, const Common::String &fileName); - ~AnimationControl(); + AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse = true); + ~AnimationNode(); + + struct playnode { + Common::Rect pos; + int32 slot; + int32 start; + int32 stop; + int32 loop; + int32 _cur_frm; + int32 _delay; + }; private: enum FileType { @@ -55,7 +67,9 @@ private: }; private: - uint32 _animationKey; + typedef Common::List PlayNodes; + + PlayNodes _playList; union { RlfAnimation *rlf; @@ -63,31 +77,16 @@ private: } _animation; FileType _fileType; - uint _loopCount; - int32 _x; - int32 _y; - - uint _accumulatedTime; - uint _currentLoop; - - Graphics::Surface *_cachedFrame; - bool _cachedFrameNeedsDeletion; + int32 _frmDelay; + int32 _mask; + bool _DisposeAfterUse; public: bool process(uint32 deltaTimeInMillis); - void setAnimationKey(uint32 animationKey) { - _animationKey = animationKey; - } - void setLoopCount(uint loopCount) { - _loopCount = loopCount; - } - void setXPos(int32 x) { - _x = x; - } - void setYPost(int32 y) { - _y = y; - } + void addPlayNode(int32 slot, int x, int y, int w, int h, int start_frame, int end_frame, int loops = 1); + + bool stop(); }; } // End of namespace ZVision -- cgit v1.2.3