summaryrefslogtreecommitdiff
path: root/slideshow/source
diff options
context:
space:
mode:
Diffstat (limited to 'slideshow/source')
-rw-r--r--slideshow/source/engine/animationfactory.cxx24
-rw-r--r--slideshow/source/engine/box2dtools.cxx164
-rw-r--r--slideshow/source/inc/box2dtools.hxx19
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