From d8f9be74ff63d2ab21f23e6c1520a7bdebdf1286 Mon Sep 17 00:00:00 2001 From: richiesams Date: Wed, 14 Aug 2013 10:41:20 -0500 Subject: ZVISION: Add panning support --- engines/zvision/events.cpp | 92 +++++++++++++++++++++++++++++++++++--- engines/zvision/render_manager.cpp | 62 +++++++++++++++++++++++++ engines/zvision/render_manager.h | 10 +++++ 3 files changed, 157 insertions(+), 7 deletions(-) diff --git a/engines/zvision/events.cpp b/engines/zvision/events.cpp index 79ef0bd6b0..68fa81ede3 100644 --- a/engines/zvision/events.cpp +++ b/engines/zvision/events.cpp @@ -26,6 +26,8 @@ #include "zvision/console.h" #include "common/events.h" #include "engines/util.h" +#include "common/system.h" +#include "common/rational.h" #include "zvision/cursor_manager.h" #include "zvision/render_manager.h" @@ -95,7 +97,7 @@ void ZVision::onMouseDown(const Common::Point &pos) { void ZVision::onMouseUp(const Common::Point &pos) { _cursorManager->cursorDown(false); - Common::Point imageCoord(_renderManager->convertToImageCoords(pos)); + Common::Point imageCoord(_renderManager->screenSpaceToImageSpace(pos)); for (Common::List::iterator iter = _mouseEvents.begin(); iter != _mouseEvents.end(); iter++) { if (iter->withinHotspot(imageCoord)) { @@ -105,17 +107,93 @@ void ZVision::onMouseUp(const Common::Point &pos) { } void ZVision::onMouseMove(const Common::Point &pos) { - Common::Point imageCoord(_renderManager->convertToImageCoords(pos)); + Common::Point imageCoord(_renderManager->screenSpaceToImageSpace(pos)); bool isWithinAHotspot = false; - for (Common::List::iterator iter = _mouseEvents.begin(); iter != _mouseEvents.end(); iter++) { - if (iter->withinHotspot(imageCoord)) { - _cursorManager->changeCursor(iter->getHoverCursor()); - isWithinAHotspot = true; + if (_workingWindow.contains(pos)) { + for (Common::List::iterator iter = _mouseEvents.begin(); iter != _mouseEvents.end(); iter++) { + if (iter->withinHotspot(imageCoord)) { + _cursorManager->changeCursor(iter->getHoverCursor()); + isWithinAHotspot = true; + } } } - + // Graph of the function governing rotation velocity: + // + // |--------------- working window -----------------| + // ^ |--------| + // | | + // +Max velocity | rotation screen edge offset _____________________ + // | / + // | / + // | / + // | / + // | / + // | / + // | / + // | / + // | / + // Zero velocity |______________________________ ______________________________/____________________________________> + // | Position -> / + // | / + // | / + // | / + // | / + // | / + // | / + // | / + // | / + // -Max velocity |_____________________/ + // | + // | + // ^ + + // NOTE: RenderManger uses the inverse of velocity (ms/pixel instead of pixels/ms) because it allows you to accumulate whole + // pixels 'steps' instead of rounding pixels every frame + + if (_workingWindow.contains(pos)) { + RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState(); + if (renderState == RenderTable::PANORAMA) { + if (pos.x >= _workingWindow.left && pos.x < _workingWindow.left + ROTATION_SCREEN_EDGE_OFFSET) { + // Linear function of distance to the left edge (y = -mx + b) + // We use fixed point math to get better accuracy + Common::Rational velocity = (Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.x - _workingWindow.left)) - MAX_ROTATION_SPEED; + _renderManager->setBackgroundVelocity(velocity.toInt()); + _cursorManager->setLeftCursor(); + isWithinAHotspot = true; + } else if (pos.x <= _workingWindow.right && pos.x > _workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET) { + // Linear function of distance to the right edge (y = mx) + // We use fixed point math to get better accuracy + Common::Rational velocity = Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.x - _workingWindow.right + ROTATION_SCREEN_EDGE_OFFSET); + _renderManager->setBackgroundVelocity(velocity.toInt()); + _cursorManager->setRightCursor(); + isWithinAHotspot = true; + } else { + _renderManager->setBackgroundVelocity(0); + } + } else if (renderState == RenderTable::TILT) { + if (pos.y >= _workingWindow.top && pos.y < _workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET) { + // Linear function of distance to top edge + // We use fixed point math to get better accuracy + Common::Rational velocity = (Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.top)) - MAX_ROTATION_SPEED; + _renderManager->setBackgroundVelocity(velocity.toInt()); + _cursorManager->setUpCursor(); + isWithinAHotspot = true; + } else if (pos.y <= _workingWindow.bottom && pos.y > _workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET) { + // Linear function of distance to the bottom edge (y = mx) + // We use fixed point math to get better accuracy + Common::Rational velocity = Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.bottom + ROTATION_SCREEN_EDGE_OFFSET); + _renderManager->setBackgroundVelocity(velocity.toInt()); + _cursorManager->setDownCursor(); + isWithinAHotspot = true; + } else { + _renderManager->setBackgroundVelocity(0); + } + } + } else { + _renderManager->setBackgroundVelocity(0); + } if (!isWithinAHotspot) { _cursorManager->revertToIdle(); diff --git a/engines/zvision/render_manager.cpp b/engines/zvision/render_manager.cpp index 7855dc3903..b8dcd0dd87 100644 --- a/engines/zvision/render_manager.cpp +++ b/engines/zvision/render_manager.cpp @@ -40,6 +40,10 @@ RenderManager::RenderManager(OSystem *system, const Common::Rect workingWindow) _workingHeight(workingWindow.height()), _workingWindow(workingWindow), _currentBackground(0), + _backgroundWidth(0), + _backgroundHeight(0), + _backgroundInverseVelocity(0), + _accumulatedVelocityMilliseconds(0), _renderTable(workingWindow.width(), workingWindow.height()) { } @@ -56,6 +60,24 @@ void RenderManager::renderSubRectToScreen(uint16 *buffer, uint32 imageWidth, uin uint32 temp = imageHeight; imageHeight = imageWidth; imageWidth = temp; +void RenderManager::update(uint deltaTimeInMillis) { + // An inverse velocity of 0 would be infinitely fast, so we'll let 0 mean no velocity. + if (_backgroundInverseVelocity == 0) + return; + + _accumulatedVelocityMilliseconds += deltaTimeInMillis; + + int absVelocity = abs(_backgroundInverseVelocity); + + uint numberOfSteps = 0; + while (_accumulatedVelocityMilliseconds >= absVelocity) { + _accumulatedVelocityMilliseconds -= absVelocity; + numberOfSteps++; + } + + // Choose the direction of movement using the sign of the velocity + moveBackground(_backgroundInverseVelocity < 0 ? -numberOfSteps : numberOfSteps); +} } // If subRect is empty, use the entire image @@ -178,6 +200,46 @@ void RenderManager::setBackgroundImage(const Common::String &fileName) { _currentBackground = file; renderImageToScreen(*_currentBackground, 0, 0, Common::Rect(), true); +void RenderManager::setBackgroundPosition(int offset) { + if (_renderTable.getRenderState() == RenderTable::TILT) { + _backgroundOffset = Common::Point(0, offset); + } else { + _backgroundOffset = Common::Point(offset, 0); + } +} + +void RenderManager::setBackgroundVelocity(int velocity) { + // setBackgroundVelocity(0) will be called quite often, so make sure + // _backgroundInverseVelocity isn't already 0 to prevent an extraneous assignment + if (velocity == 0) { + if (_backgroundInverseVelocity != 0) { + _backgroundInverseVelocity = 0; + } + } else { + _backgroundInverseVelocity = 1000 / velocity; + } +} + +void RenderManager::moveBackground(int offset) { + if (_renderTable.getRenderState() == RenderTable::TILT) { + _backgroundOffset += Common::Point(0, offset); + } else { + _backgroundOffset += Common::Point(offset, 0); + } + + // Make sure the offset is within image bounds + if (_backgroundOffset.x < 0) + _backgroundOffset.x += _backgroundWidth; + if (_backgroundOffset.x > _backgroundWidth) + _backgroundOffset.x -= _backgroundWidth; + if (_backgroundOffset.y < 0) + _backgroundOffset.y += _backgroundHeight; + if (_backgroundOffset.y > _backgroundHeight) + _backgroundOffset.y -= _backgroundHeight; + + _currentBackground->seek(0); + // Purposely make the subRectangle empty. renderImageToScreen will then set the width and height automatically. + renderImageToScreen(*_currentBackground, 0, 0, Common::Rect(_backgroundOffset.x, _backgroundOffset.y, _backgroundOffset.x, _backgroundOffset.y), true); } } // End of namespace ZVision diff --git a/engines/zvision/render_manager.h b/engines/zvision/render_manager.h index 8731675ef6..7d44a37726 100644 --- a/engines/zvision/render_manager.h +++ b/engines/zvision/render_manager.h @@ -55,12 +55,18 @@ private: Common::SeekableReadStream *_currentBackground; Common::Point _backgroundOffset; + uint16 _backgroundWidth; + uint16 _backgroundHeight; + + int _backgroundInverseVelocity; + uint _accumulatedVelocityMilliseconds; Video::VideoDecoder *_currentVideo; byte *_scaledVideoFrameBuffer; public: void initialize(); + void update(uint deltaTimeInMillis); /** * Blits the image or a portion of the image to the screen. Actual screen updates won't happen until the end of the frame. @@ -92,6 +98,10 @@ public: */ void setBackgroundImage(const Common::String &fileName); + void setBackgroundPosition(int offset); + + void setBackgroundVelocity(int velocity); + const Common::Point screenSpaceToImageSpace(const Common::Point &point); RenderTable *getRenderTable(); -- cgit v1.2.3