slideshow/source/engine/animationfactory.cxx | 4 slideshow/source/engine/box2dtools.cxx | 189 ++++++++++++++++++--------- slideshow/source/inc/box2dtools.hxx | 44 +++++- 3 files changed, 168 insertions(+), 69 deletions(-)
New commits: commit 1fb53ef7b889b8cc3e6941c64df7c129575c1c5c Author: Sarper Akdemir <q.sarperakde...@gmail.com> AuthorDate: Thu Aug 13 03:40:25 2020 +0300 Commit: Sarper Akdemir <q.sarperakde...@gmail.com> CommitDate: Thu Aug 13 03:40:25 2020 +0300 make physics animations handle sequential animations correctly Change-Id: Ie8bb8b32588f4c7bf16317b5229adc5b0334d192 diff --git a/slideshow/source/engine/animationfactory.cxx b/slideshow/source/engine/animationfactory.cxx index bc1848f68435..d6198439b327 100644 --- a/slideshow/source/engine/animationfactory.cxx +++ b/slideshow/source/engine/animationfactory.cxx @@ -323,7 +323,9 @@ namespace slideshow::internal { mpShapeManager->notifyShapeUpdate( mpShape ); if ( mpBox2DWorld->isInitialized() ) - mpBox2DWorld->queuePositionUpdate( mpShape->getXShape(), rOutPos ); + { + mpBox2DWorld->queueShapePathAnimationUpdate( mpShape->getXShape(), mpAttrLayer ); + } } return true; diff --git a/slideshow/source/engine/box2dtools.cxx b/slideshow/source/engine/box2dtools.cxx index 68ab37fb6868..383836b7dca2 100644 --- a/slideshow/source/engine/box2dtools.cxx +++ b/slideshow/source/engine/box2dtools.cxx @@ -203,7 +203,7 @@ box2DWorld::box2DWorld(const ::basegfx::B2DVector& rSlideSize) , mbShapesInitialized(false) , mbHasWorldStepper(false) , mpXShapeToBodyMap() - , maShapeUpdateQueue() + , maShapeParallelUpdateQueue() { } @@ -253,6 +253,13 @@ void box2DWorld::createStaticFrameAroundSlide(const ::basegfx::B2DVector& rSlide pStaticBody->CreateFixture(&aFixtureDef); } +void box2DWorld::setShapePosition(const css::uno::Reference<com::sun::star::drawing::XShape> xShape, + const basegfx::B2DPoint& rOutPos) +{ + Box2DBodySharedPtr pBox2DBody = mpXShapeToBodyMap.find(xShape)->second; + pBox2DBody->setPosition(rOutPos); +} + void box2DWorld::setShapePositionByLinearVelocity( const css::uno::Reference<com::sun::star::drawing::XShape> xShape, const basegfx::B2DPoint& rOutPos, const double fPassedTime) @@ -274,6 +281,13 @@ void box2DWorld::setShapeLinearVelocity( pBox2DBody->setLinearVelocity(rVelocity); } +void box2DWorld::setShapeAngle(const css::uno::Reference<com::sun::star::drawing::XShape> xShape, + const double fAngle) +{ + Box2DBodySharedPtr pBox2DBody = mpXShapeToBodyMap.find(xShape)->second; + pBox2DBody->setAngle(fAngle); +} + void box2DWorld::setShapeAngleByAngularVelocity( const css::uno::Reference<com::sun::star::drawing::XShape> xShape, const double fAngle, const double fPassedTime) @@ -305,42 +319,65 @@ void box2DWorld::setShapeCollision( void box2DWorld::processUpdateQueue(const double fPassedTime) { - while (!maShapeUpdateQueue.empty()) + if (maShapeSequentialUpdate.empty()) { - Box2DShapeUpdateInformation& aQueueElement = maShapeUpdateQueue.front(); - - if (aQueueElement.mnDelayForSteps > 0) - { - // it was queued as a delayed action, skip it, don't pop - aQueueElement.mnDelayForSteps--; - } - else + while (!maShapeParallelUpdateQueue.empty()) { - switch (aQueueElement.meUpdateType) + Box2DDynamicUpdateInformation& aQueueElement = maShapeParallelUpdateQueue.front(); + + if (aQueueElement.mnDelayForSteps > 0) + { + // it was queued as a delayed action, skip it, don't pop + aQueueElement.mnDelayForSteps--; + } + else { - default: - case BOX2D_UPDATE_POSITION: - setShapePositionByLinearVelocity(aQueueElement.mxShape, - aQueueElement.maPosition, fPassedTime); - break; - case BOX2D_UPDATE_ANGLE: - setShapeAngleByAngularVelocity(aQueueElement.mxShape, aQueueElement.mfAngle, - fPassedTime); - break; - case BOX2D_UPDATE_SIZE: - break; - case BOX2D_UPDATE_VISIBILITY: - setShapeCollision(aQueueElement.mxShape, aQueueElement.mbVisibility); - break; - case BOX2D_UPDATE_LINEAR_VELOCITY: - setShapeLinearVelocity(aQueueElement.mxShape, aQueueElement.maVelocity); - break; - case BOX2D_UPDATE_ANGULAR_VELOCITY: - setShapeAngularVelocity(aQueueElement.mxShape, aQueueElement.mfAngularVelocity); + switch (aQueueElement.meUpdateType) + { + default: + case BOX2D_UPDATE_POSITION: + setShapePositionByLinearVelocity(aQueueElement.mxShape, + aQueueElement.maPosition, fPassedTime); + break; + case BOX2D_UPDATE_ANGLE: + setShapeAngleByAngularVelocity(aQueueElement.mxShape, aQueueElement.mfAngle, + fPassedTime); + break; + case BOX2D_UPDATE_SIZE: + break; + case BOX2D_UPDATE_VISIBILITY: + setShapeCollision(aQueueElement.mxShape, aQueueElement.mbVisibility); + break; + case BOX2D_UPDATE_LINEAR_VELOCITY: + setShapeLinearVelocity(aQueueElement.mxShape, aQueueElement.maVelocity); + break; + case BOX2D_UPDATE_ANGULAR_VELOCITY: + setShapeAngularVelocity(aQueueElement.mxShape, + aQueueElement.mfAngularVelocity); + } + maShapeParallelUpdateQueue.pop(); } - maShapeUpdateQueue.pop(); } } + else + { + // clear the Parallel Update Queue since the updates in it + // are not relevant now - if there's any + maShapeParallelUpdateQueue = {}; + + for (auto aIt : maShapeSequentialUpdate) + { + css::uno::Reference<css::drawing::XShape> xShape = aIt.first; + Box2DStaticUpdateInformation& aUpdateInformation = aIt.second; + + setShapePosition(xShape, aUpdateInformation.maPosition); + setShapeAngle(xShape, aUpdateInformation.mfAngle); + setShapeCollision(xShape, aUpdateInformation.mbVisibility); + } + + // After applying all required updates empty map + maShapeSequentialUpdate.clear(); + } } void box2DWorld::initateAllShapesAsStaticBodies( @@ -376,47 +413,58 @@ void box2DWorld::setHasWorldStepper(const bool bHasWorldStepper) mbHasWorldStepper = bHasWorldStepper; } -void box2DWorld::queuePositionUpdate( +void box2DWorld::queueDynamicPositionUpdate( const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, const basegfx::B2DPoint& rOutPos) { - Box2DShapeUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_POSITION }; + Box2DDynamicUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_POSITION }; aQueueElement.maPosition = rOutPos; - maShapeUpdateQueue.push(aQueueElement); + maShapeParallelUpdateQueue.push(aQueueElement); } void box2DWorld::queueLinearVelocityUpdate( const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, - const basegfx::B2DVector& rVelocity) + const basegfx::B2DVector& rVelocity, const int nDelayForSteps) { - Box2DShapeUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_LINEAR_VELOCITY, 1 }; + Box2DDynamicUpdateInformation aQueueElement + = { xShape, {}, BOX2D_UPDATE_LINEAR_VELOCITY, nDelayForSteps }; aQueueElement.maVelocity = rVelocity; - maShapeUpdateQueue.push(aQueueElement); + maShapeParallelUpdateQueue.push(aQueueElement); } -void box2DWorld::queueRotationUpdate( +void box2DWorld::queueDynamicRotationUpdate( const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, const double fAngle) { - Box2DShapeUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_ANGLE }; + Box2DDynamicUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_ANGLE }; aQueueElement.mfAngle = fAngle; - maShapeUpdateQueue.push(aQueueElement); + maShapeParallelUpdateQueue.push(aQueueElement); } void box2DWorld::queueAngularVelocityUpdate( const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, - const double fAngularVelocity) + const double fAngularVelocity, const int nDelayForSteps) { - Box2DShapeUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_ANGULAR_VELOCITY, 1 }; + Box2DDynamicUpdateInformation aQueueElement + = { xShape, {}, BOX2D_UPDATE_ANGULAR_VELOCITY, nDelayForSteps }; aQueueElement.mfAngularVelocity = fAngularVelocity; - maShapeUpdateQueue.push(aQueueElement); + maShapeParallelUpdateQueue.push(aQueueElement); } void box2DWorld::queueShapeVisibilityUpdate( const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, const bool bVisibility) { - Box2DShapeUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_VISIBILITY }; + Box2DDynamicUpdateInformation aQueueElement = { xShape, {}, BOX2D_UPDATE_VISIBILITY }; aQueueElement.mbVisibility = bVisibility; - maShapeUpdateQueue.push(aQueueElement); + maShapeParallelUpdateQueue.push(aQueueElement); +} + +void box2DWorld::queueShapePathAnimationUpdate( + const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, + const slideshow::internal::ShapeAttributeLayerSharedPtr& pAttrLayer) +{ + // Workaround for PathAnimations since they do not have their own AttributeType + // - using PosX makes it register a DynamicPositionUpdate - + queueShapeAnimationUpdate(xShape, pAttrLayer, slideshow::internal::AttributeType::PosX); } void box2DWorld::queueShapeAnimationUpdate( @@ -424,20 +472,30 @@ void box2DWorld::queueShapeAnimationUpdate( const slideshow::internal::ShapeAttributeLayerSharedPtr& pAttrLayer, const slideshow::internal::AttributeType eAttrType) { - switch (eAttrType) + if (mbHasWorldStepper) // if there's a physics animation going on { - case slideshow::internal::AttributeType::Visibility: - queueShapeVisibilityUpdate(xShape, pAttrLayer->getVisibility()); - return; - case slideshow::internal::AttributeType::Rotate: - queueRotationUpdate(xShape, pAttrLayer->getRotationAngle()); - return; - case slideshow::internal::AttributeType::PosX: - case slideshow::internal::AttributeType::PosY: - queuePositionUpdate(xShape, { pAttrLayer->getPosX(), pAttrLayer->getPosY() }); - return; - default: - return; + switch (eAttrType) + { + case slideshow::internal::AttributeType::Visibility: + queueShapeVisibilityUpdate(xShape, pAttrLayer->getVisibility()); + return; + case slideshow::internal::AttributeType::Rotate: + queueDynamicRotationUpdate(xShape, pAttrLayer->getRotationAngle()); + return; + case slideshow::internal::AttributeType::PosX: + case slideshow::internal::AttributeType::PosY: + queueDynamicPositionUpdate(xShape, + { pAttrLayer->getPosX(), pAttrLayer->getPosY() }); + return; + default: + return; + } + } + else + { + maShapeSequentialUpdate[xShape] = { { pAttrLayer->getPosX(), pAttrLayer->getPosY() }, + pAttrLayer->getRotationAngle(), + pAttrLayer->getVisibility() }; } } @@ -448,11 +506,11 @@ void box2DWorld::queueShapeAnimationEndUpdate( switch (eAttrType) { case slideshow::internal::AttributeType::Rotate: - queueAngularVelocityUpdate(xShape, 0.0f); + queueAngularVelocityUpdate(xShape, 0.0, 1); return; case slideshow::internal::AttributeType::PosX: case slideshow::internal::AttributeType::PosY: - queueLinearVelocityUpdate(xShape, { 0, 0 }); + queueLinearVelocityUpdate(xShape, { 0, 0 }, 1); return; default: return; @@ -617,6 +675,12 @@ box2DBody::box2DBody(std::shared_ptr<b2Body> pBox2DBody, double fScaleFactor) return ::basegfx::B2DPoint(fX, fY); } +void box2DBody::setPosition(const basegfx::B2DPoint& rPos) +{ + mpBox2DBody->SetTransform(convertB2DPointToBox2DVec2(rPos, mfScaleFactor), + mpBox2DBody->GetAngle()); +} + void box2DBody::setPositionByLinearVelocity(const basegfx::B2DPoint& rDesiredPos, const double fPassedTime) { @@ -675,6 +739,11 @@ double box2DBody::getAngle() return ::basegfx::rad2deg(-fAngle); } +void box2DBody::setAngle(double fAngle) +{ + mpBox2DBody->SetTransform(mpBox2DBody->GetPosition(), ::basegfx::deg2rad(-fAngle)); +} + void box2DBody::setType(box2DBodyType eType) { mpBox2DBody->SetType(getBox2DInternalBodyType(eType)); diff --git a/slideshow/source/inc/box2dtools.hxx b/slideshow/source/inc/box2dtools.hxx index 7f01f09eb607..41dd721de597 100644 --- a/slideshow/source/inc/box2dtools.hxx +++ b/slideshow/source/inc/box2dtools.hxx @@ -50,7 +50,7 @@ enum box2DNonsimulatedShapeUpdateType /// Holds required information to perform an update to box2d /// body of a shape that was altered by an animation effect -struct Box2DShapeUpdateInformation +struct Box2DDynamicUpdateInformation { css::uno::Reference<css::drawing::XShape> mxShape; union { @@ -64,6 +64,13 @@ struct Box2DShapeUpdateInformation int mnDelayForSteps = 0; }; +struct Box2DStaticUpdateInformation +{ + ::basegfx::B2DPoint maPosition; + double mfAngle; + bool mbVisibility; +}; + /** Class that manages the Box2D World This class is used when there's a simulated animation going on, @@ -78,15 +85,24 @@ private: /// Scale factor for conversions between LO user space coordinates to Box2D World coordinates double mfScaleFactor; bool mbShapesInitialized; + /// Holds whether or not there is a Physics Animation node that + /// is stepping the Box2D World bool mbHasWorldStepper; std::unordered_map<css::uno::Reference<css::drawing::XShape>, Box2DBodySharedPtr> mpXShapeToBodyMap; /// Holds any information needed to keep LO animations and Box2D world in sync - std::queue<Box2DShapeUpdateInformation> maShapeUpdateQueue; + /// if they are ongoing on parallel + std::queue<Box2DDynamicUpdateInformation> maShapeParallelUpdateQueue; + /// Holds necessary information if a shape was altered by an animation update + /// while there was no Physics animation going on in parallel + std::unordered_map<css::uno::Reference<css::drawing::XShape>, Box2DStaticUpdateInformation> + maShapeSequentialUpdate; /// Creates a static frame in Box2D world that corresponds to the slide borders void createStaticFrameAroundSlide(const ::basegfx::B2DVector& rSlideSize); + void setShapePosition(const css::uno::Reference<css::drawing::XShape> xShape, + const ::basegfx::B2DPoint& rOutPos); /** Sets shape's corresponding Box2D body to specified position Sets shape's corresponding Box2D body to specified position as if @@ -108,6 +124,8 @@ private: void setShapeLinearVelocity(const css::uno::Reference<com::sun::star::drawing::XShape> xShape, const basegfx::B2DVector& rVelocity); + void setShapeAngle(const css::uno::Reference<com::sun::star::drawing::XShape> xShape, + const double fAngle); /** Sets shape's corresponding Box2D body to specified angle Sets shape's corresponding Box2D body to specified angle as if @@ -157,14 +175,15 @@ private: const int nPositionIterations = 2); /// Queue a rotation update on the next step of the box2DWorld for the corresponding body - void queueRotationUpdate(const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, - const double fAngle); + void + queueDynamicRotationUpdate(const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, + const double fAngle); /// Queue an angular velocity update for the corresponding body /// to take place after the next step of the box2DWorld void queueAngularVelocityUpdate(const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, - const double fAngularVelocity); + const double fAngularVelocity, const int nDelayForSteps = 0); /// Queue an update that changes collision of the corresponding body /// on the next step of the box2DWorld, used for animations that change visibility @@ -244,19 +263,24 @@ public: void setHasWorldStepper(const bool bHasWorldStepper); /// Queue a position update the next step of the box2DWorld for the corresponding body - void queuePositionUpdate(const css::uno::Reference<css::drawing::XShape>& xShape, - const ::basegfx::B2DPoint& rOutPos); + void queueDynamicPositionUpdate(const css::uno::Reference<css::drawing::XShape>& xShape, + const ::basegfx::B2DPoint& rOutPos); /// Queue a linear velocity update for the corresponding body /// to take place after the next step of the box2DWorld void queueLinearVelocityUpdate(const css::uno::Reference<css::drawing::XShape>& xShape, - const ::basegfx::B2DVector& rVelocity); + const ::basegfx::B2DVector& rVelocity, + const int nDelayForSteps = 0); void queueShapeAnimationUpdate(const css::uno::Reference<css::drawing::XShape>& xShape, const slideshow::internal::ShapeAttributeLayerSharedPtr& pAttrLayer, const slideshow::internal::AttributeType eAttrType); + void queueShapePathAnimationUpdate( + const css::uno::Reference<com::sun::star::drawing::XShape>& xShape, + const slideshow::internal::ShapeAttributeLayerSharedPtr& pAttrLayer); + void queueShapeAnimationEndUpdate(const css::uno::Reference<css::drawing::XShape>& xShape, const slideshow::internal::AttributeType eAttrType); }; @@ -276,6 +300,8 @@ public: /// @return current position in LO user space coordinates ::basegfx::B2DPoint getPosition(); + void setPosition(const ::basegfx::B2DPoint& rPos); + /** Sets body to specified position Sets body to specified position as if the body had @@ -315,6 +341,8 @@ public: /// @return current angle of rotation of the body double getAngle(); + void setAngle(double fAngle); + /// Set type of the body void setType(box2DBodyType eType); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits