summaryrefslogtreecommitdiff
path: root/slideshow
diff options
context:
space:
mode:
authorSarper Akdemir <q.sarperakdemir@gmail.com>2020-08-25 11:24:22 +0300
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2020-08-26 14:47:52 +0200
commitd29c27af4aff3f5268bd4a07647fd7435603ba11 (patch)
tree9c3ca6917490e3e5b4146beeb6d9fe1d8030e761 /slideshow
parentf070bea92f2d494fc3da6fb2fab7b9c283955f5d (diff)
tdf#136097: make physics animation effects handle skips and rewinds
Making box2d world only stay populated when there's an animation effect going on. This makes it possible to get rid of big chunk of sequential update implementation. Change-Id: Iaf50d4871b2355035495618354f0ae09abe94164 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101304 Tested-by: Jenkins Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'slideshow')
-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