diff options
Diffstat (limited to 'slideshow/source')
-rw-r--r-- | slideshow/source/engine/animationfactory.cxx | 24 | ||||
-rw-r--r-- | slideshow/source/engine/box2dtools.cxx | 164 | ||||
-rw-r--r-- | slideshow/source/inc/box2dtools.hxx | 19 |
3 files changed, 83 insertions, 124 deletions
diff --git a/slideshow/source/engine/animationfactory.cxx b/slideshow/source/engine/animationfactory.cxx index 327a048afeb1..8068bbfac83e 100644 --- a/slideshow/source/engine/animationfactory.cxx +++ b/slideshow/source/engine/animationfactory.cxx @@ -406,23 +406,18 @@ namespace slideshow::internal mpShape = rShape; mpAttrLayer = rAttrLayer; - if( !(mpBox2DWorld->isInitialized()) ) - mpBox2DWorld->initiateWorld(maPageSize); - - if( !(mpBox2DWorld->shapesInitialized()) ) - mpBox2DWorld->initateAllShapesAsStaticBodies( mpShapeManager ); - ENSURE_OR_THROW( rShape, "PhysicsAnimation::start(): Invalid shape" ); ENSURE_OR_THROW( rAttrLayer, "PhysicsAnimation::start(): Invalid attribute layer" ); - mpBox2DBody = mpBox2DWorld->makeShapeDynamic( rShape->getXShape(), maStartVelocity, mfDensity, mfBounciness ); - if( !mbAnimationStarted ) { mbAnimationStarted = true; + mpBox2DWorld->alertPhysicsAnimationStart(maPageSize, mpShapeManager); + mpBox2DBody = mpBox2DWorld->makeShapeDynamic( mpShape->getXShape(), maStartVelocity, mfDensity, mfBounciness ); + if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) mpShapeManager->enterAnimationMode( mpShape ); } @@ -441,15 +436,22 @@ namespace slideshow::internal { mbAnimationStarted = false; - // Animation have ended for this body, make it static - box2d::utils::makeBodyStatic( mpBox2DBody ); - if( !(mnFlags & AnimationFactory::FLAG_NO_SPRITE) ) mpShapeManager->leaveAnimationMode( mpShape ); if( mpShape->isContentChanged() ) mpShapeManager->notifyShapeUpdate( mpShape ); + + mpBox2DWorld->alertPhysicsAnimationEnd(mpShape); + // if this was the only physics animation effect going on + // all box2d bodies were destroyed on alertPhysicsAnimationEnd + // except the one owned by the animation. + // Try to destroy the remaining body - if it is unique + // (it being unique means all physics animation effects have ended + // since otherwise mpBox2DWorld would own a copy of the shared_ptr ) + mpBox2DBody.reset(); } + } // NumberAnimation interface diff --git a/slideshow/source/engine/box2dtools.cxx b/slideshow/source/engine/box2dtools.cxx index 402a71542dd3..565467fdb347 100644 --- a/slideshow/source/engine/box2dtools.cxx +++ b/slideshow/source/engine/box2dtools.cxx @@ -11,6 +11,7 @@ #include <Box2D/Box2D.h> #include <shapemanager.hxx> +#include <attributableshape.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolygontriangulator.hxx> @@ -208,9 +209,9 @@ box2DWorld::box2DWorld(const ::basegfx::B2DVector& rSlideSize) , mfScaleFactor(calculateScaleFactor(rSlideSize)) , mbShapesInitialized(false) , mbHasWorldStepper(false) + , mnPhysicsAnimationCounter(0) , mpXShapeToBodyMap() , maShapeParallelUpdateQueue() - , maShapeSequentialUpdate() { } @@ -326,75 +327,41 @@ void box2DWorld::setShapeCollision( void box2DWorld::processUpdateQueue(const double fPassedTime) { - if (maShapeSequentialUpdate.empty()) + while (!maShapeParallelUpdateQueue.empty()) { - while (!maShapeParallelUpdateQueue.empty()) - { - Box2DDynamicUpdateInformation& aQueueElement = maShapeParallelUpdateQueue.front(); + Box2DDynamicUpdateInformation& aQueueElement = maShapeParallelUpdateQueue.front(); - if (aQueueElement.mnDelayForSteps > 0) - { - // it was queued as a delayed action, skip it, don't pop - aQueueElement.mnDelayForSteps--; - } - else - { - 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(); - } + if (aQueueElement.mnDelayForSteps > 0) + { + // it was queued as a delayed action, skip it, don't pop + aQueueElement.mnDelayForSteps--; } - } - else - { - // clear the Parallel Update Queue since the updates in it - // are not relevant now - if there's any - maShapeParallelUpdateQueue = {}; - - for (auto& aIt : maShapeSequentialUpdate) + else { - const css::uno::Reference<css::drawing::XShape>& xShape = aIt.first.first; - const box2DNonsimulatedShapeUpdateType eUpdateType = aIt.first.second; - const Box2DStaticUpdateInformation& rUpdateInformation = aIt.second; - - switch (eUpdateType) + switch (aQueueElement.meUpdateType) { default: case BOX2D_UPDATE_POSITION: - setShapePosition(xShape, rUpdateInformation.maPosition); + setShapePositionByLinearVelocity(aQueueElement.mxShape, + aQueueElement.maPosition, fPassedTime); break; case BOX2D_UPDATE_ANGLE: - setShapeAngle(xShape, rUpdateInformation.mfAngle); + setShapeAngleByAngularVelocity(aQueueElement.mxShape, aQueueElement.mfAngle, + fPassedTime); + break; + case BOX2D_UPDATE_SIZE: break; case BOX2D_UPDATE_VISIBILITY: - setShapeCollision(xShape, rUpdateInformation.mbVisibility); + 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(); } - - // After applying all required updates empty map - maShapeSequentialUpdate.clear(); } } @@ -514,50 +481,20 @@ void box2DWorld::queueShapeAnimationUpdate( const slideshow::internal::ShapeAttributeLayerSharedPtr& pAttrLayer, const slideshow::internal::AttributeType eAttrType) { - if (mbHasWorldStepper) // if there's a physics animation going on - { - 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 + switch (eAttrType) { - Box2DStaticUpdateInformation aStaticUpdateInformation; - switch (eAttrType) - { - case slideshow::internal::AttributeType::Visibility: - aStaticUpdateInformation.mbVisibility = pAttrLayer->getVisibility(); - maShapeSequentialUpdate[std::make_pair(xShape, BOX2D_UPDATE_VISIBILITY)] - = aStaticUpdateInformation; - return; - case slideshow::internal::AttributeType::Rotate: - aStaticUpdateInformation.mfAngle = pAttrLayer->getRotationAngle(); - maShapeSequentialUpdate[std::make_pair(xShape, BOX2D_UPDATE_ANGLE)] - = aStaticUpdateInformation; - return; - case slideshow::internal::AttributeType::PosX: - case slideshow::internal::AttributeType::PosY: - aStaticUpdateInformation.maPosition - = basegfx::B2DPoint(pAttrLayer->getPosX(), pAttrLayer->getPosY()); - maShapeSequentialUpdate[std::make_pair(xShape, BOX2D_UPDATE_POSITION)] - = aStaticUpdateInformation; - return; - default: - return; - } + 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; } } @@ -579,11 +516,30 @@ void box2DWorld::queueShapeAnimationEndUpdate( } } -void box2DWorld::alertAnimationEndForShape(const slideshow::internal::ShapeSharedPtr& pShape) +void box2DWorld::alertPhysicsAnimationEnd(const slideshow::internal::ShapeSharedPtr& pShape) { Box2DBodySharedPtr pBox2DBody = mpXShapeToBodyMap.find(pShape->getXShape())->second; makeBodyStatic(pBox2DBody); pBox2DBody->setRestitution(fDefaultStaticBodyBounciness); + if (--mnPhysicsAnimationCounter == 0) + { + maShapeParallelUpdateQueue = {}; + mbShapesInitialized = false; + mpXShapeToBodyMap.clear(); + } +} + +void box2DWorld::alertPhysicsAnimationStart( + const ::basegfx::B2DVector& rSlideSize, + const slideshow::internal::ShapeManagerSharedPtr& pShapeManager) +{ + if (!mpBox2DWorld) + initiateWorld(rSlideSize); + + if (!mbShapesInitialized) + initateAllShapesAsStaticBodies(pShapeManager); + + mnPhysicsAnimationCounter++; } void box2DWorld::step(const float fTimeStep, const int nVelocityIterations, @@ -669,6 +625,14 @@ Box2DBodySharedPtr box2DWorld::createStaticBody(const slideshow::internal::Shape aBodyDef.type = b2_staticBody; aBodyDef.position = convertB2DPointToBox2DVec2(aShapeBounds.getCenter(), mfScaleFactor); + slideshow::internal::ShapeAttributeLayerSharedPtr pShapeAttributeLayer + = static_cast<slideshow::internal::AttributableShape*>(rShape.get()) + ->getTopmostAttributeLayer(); + if (pShapeAttributeLayer && pShapeAttributeLayer->isRotationAngleValid()) + { + aBodyDef.angle = ::basegfx::deg2rad(-pShapeAttributeLayer->getRotationAngle()); + } + std::shared_ptr<b2Body> pBody(mpBox2DWorld->CreateBody(&aBodyDef), [](b2Body* pB2Body) { pB2Body->GetWorld()->DestroyBody(pB2Body); }); diff --git a/slideshow/source/inc/box2dtools.hxx b/slideshow/source/inc/box2dtools.hxx index 0debf1da4ef0..6bfc9dfd1b7c 100644 --- a/slideshow/source/inc/box2dtools.hxx +++ b/slideshow/source/inc/box2dtools.hxx @@ -65,13 +65,6 @@ struct Box2DDynamicUpdateInformation int mnDelayForSteps = 0; }; -union Box2DStaticUpdateInformation { - ::basegfx::B2DPoint maPosition; - bool mbVisibility; - double mfAngle; - Box2DStaticUpdateInformation() {} -}; - /** Class that manages the Box2D World This class is used when there's a simulated animation going on, @@ -89,16 +82,12 @@ private: /// Holds whether or not there is a Physics Animation node that /// is stepping the Box2D World bool mbHasWorldStepper; + int mnPhysicsAnimationCounter; std::unordered_map<css::uno::Reference<css::drawing::XShape>, Box2DBodySharedPtr> mpXShapeToBodyMap; /// Holds any information needed to keep LO animations and Box2D world in sync /// if they are going in parallel std::queue<Box2DDynamicUpdateInformation> maShapeParallelUpdateQueue; - /// Holds necessary information to update a shape's body that was altered by an - /// animation effect while there was no Physics Animation going in parallel - std::map<std::pair<css::uno::Reference<css::drawing::XShape>, box2DNonsimulatedShapeUpdateType>, - Box2DStaticUpdateInformation> - maShapeSequentialUpdate; /// Creates a static frame in Box2D world that corresponds to the slide borders void createStaticFrameAroundSlide(const ::basegfx::B2DVector& rSlideSize); @@ -270,7 +259,11 @@ public: void queueShapeAnimationEndUpdate(const css::uno::Reference<css::drawing::XShape>& xShape, const slideshow::internal::AttributeType eAttrType); - void alertAnimationEndForShape(const slideshow::internal::ShapeSharedPtr& pShape); + void alertPhysicsAnimationEnd(const slideshow::internal::ShapeSharedPtr& pShape); + + void + alertPhysicsAnimationStart(const ::basegfx::B2DVector& rSlideSize, + const slideshow::internal::ShapeManagerSharedPtr& pShapeManager); }; /// Class that manages a single box2D Body |