Rebased ref, commits from common ancestor: commit a6ec5da356aed1c3c53af4bd6fb50b58a42ada9d Author: Sarper Akdemir <q.sarperakde...@gmail.com> AuthorDate: Fri Aug 14 01:18:14 2020 +0300 Commit: Sarper Akdemir <q.sarperakde...@gmail.com> CommitDate: Fri Aug 14 10:31:12 2020 +0300
wip add bounciness velocity and density options to physics animations Change-Id: Ifaba785e82c8ee17be00711a3e7a75257e7704ae diff --git a/animations/source/animcore/animcore.cxx b/animations/source/animcore/animcore.cxx index 88e42772936a..107353cf327a 100644 --- a/animations/source/animcore/animcore.cxx +++ b/animations/source/animcore/animcore.cxx @@ -24,6 +24,7 @@ #include <com/sun/star/animations/XAnimateColor.hpp> #include <com/sun/star/animations/XAnimateSet.hpp> #include <com/sun/star/animations/XAnimateMotion.hpp> +#include <com/sun/star/animations/XAnimatePhysics.hpp> #include <com/sun/star/animations/XAnimateTransform.hpp> #include <com/sun/star/animations/XParallelTimeContainer.hpp> #include <com/sun/star/animations/XTransitionFilter.hpp> @@ -104,6 +105,7 @@ namespace animcore namespace { class AnimationNodeBase : public XAnimateMotion, + public XAnimatePhysics, public XAnimateColor, public XTransitionFilter, public XAnimateSet, @@ -224,6 +226,16 @@ public: virtual Any SAL_CALL getOrigin() override; virtual void SAL_CALL setOrigin( const Any& _origin ) override; + // XAnimatePhysics + virtual Any SAL_CALL getStartVelocityX() override; + virtual void SAL_CALL setStartVelocityX( const Any& _startvelocityx ) override; + virtual Any SAL_CALL getStartVelocityY() override; + virtual void SAL_CALL setStartVelocityY( const Any& _startvelocityy ) override; + virtual Any SAL_CALL getDensity() override; + virtual void SAL_CALL setDensity( const Any& _density ) override; + virtual Any SAL_CALL getBounciness() override; + virtual void SAL_CALL setBounciness( const Any& _bounciness ) override; + // XAnimateTransform virtual sal_Int16 SAL_CALL getTransformType() override; virtual void SAL_CALL setTransformType( sal_Int16 _transformtype ) override; @@ -322,6 +334,9 @@ private: // attributes for XAnimateMotion Any maPath, maOrigin; + // attributes for XAnimatePhysics + Any maStartVelocityX, maStartVelocityY, maDensity, maBounciness; + // attributes for XAnimateTransform sal_Int16 mnTransformType; @@ -671,8 +686,8 @@ Any SAL_CALL AnimationNode::queryInterface( const Type& aType ) case AnimationNodeType::ANIMATEPHYSICS: aRet = ::cppu::queryInterface( aType, - static_cast< XAnimate * >( static_cast< XAnimateMotion * >(this) ), - static_cast< XAnimateMotion * >( this ) ); + static_cast< XAnimate * >( static_cast< XAnimatePhysics * >(this) ), + static_cast< XAnimatePhysics * >( this ) ); break; case AnimationNodeType::ANIMATECOLOR: aRet = ::cppu::queryInterface( @@ -767,7 +782,7 @@ void AnimationNode::initTypeProvider( sal_Int16 nNodeType ) throw() pTypeAr[nPos++] = cppu::UnoType<XAnimateMotion>::get(); break; case AnimationNodeType::ANIMATEPHYSICS: - pTypeAr[nPos++] = cppu::UnoType<XAnimateMotion>::get(); + pTypeAr[nPos++] = cppu::UnoType<XAnimatePhysics>::get(); break; case AnimationNodeType::ANIMATECOLOR: pTypeAr[nPos++] = cppu::UnoType<XAnimateColor>::get(); @@ -1584,6 +1599,72 @@ void SAL_CALL AnimationNode::setOrigin( const Any& _origin ) fireChangeListener(); } +// XAnimatePhysics +Any SAL_CALL AnimationNode::getStartVelocityX() +{ + Guard< Mutex > aGuard( maMutex ); + return maStartVelocityX; +} + + +// XAnimatePhysics +void SAL_CALL AnimationNode::setStartVelocityX( const Any& _startvelocityx ) +{ + Guard< Mutex > aGuard( maMutex ); + maStartVelocityX = _startvelocityx; + fireChangeListener(); +} + +// XAnimatePhysics +Any SAL_CALL AnimationNode::getStartVelocityY() +{ + Guard< Mutex > aGuard( maMutex ); + return maStartVelocityY; +} + + +// XAnimatePhysics +void SAL_CALL AnimationNode::setStartVelocityY( const Any& _startvelocityy ) +{ + Guard< Mutex > aGuard( maMutex ); + maStartVelocityY = _startvelocityy; + fireChangeListener(); +} + + +// XAnimatePhysics +Any SAL_CALL AnimationNode::getDensity() +{ + Guard< Mutex > aGuard( maMutex ); + return maDensity; +} + + +// XAnimatePhysics +void SAL_CALL AnimationNode::setDensity( const Any& _density ) +{ + Guard< Mutex > aGuard( maMutex ); + maDensity = _density; + fireChangeListener(); +} + + +// XAnimatePhysics +Any SAL_CALL AnimationNode::getBounciness() +{ + Guard< Mutex > aGuard( maMutex ); + return maBounciness; +} + + +// XAnimatePhysics +void SAL_CALL AnimationNode::setBounciness( const Any& _bounciness ) +{ + Guard< Mutex > aGuard( maMutex ); + maBounciness = _bounciness; + fireChangeListener(); +} + // XAnimateTransform sal_Int16 SAL_CALL AnimationNode::getTransformType() diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index ffa9206d4f44..13fd270d5fb9 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -1445,6 +1445,10 @@ namespace xmloff::token { XML_PERSPECTIVE, XML_PHDTHESIS, XML_PHONG, + XML_PHYSICS_ANIMATION_START_VELOCITY_X, + XML_PHYSICS_ANIMATION_START_VELOCITY_Y, + XML_PHYSICS_ANIMATION_DENSITY, + XML_PHYSICS_ANIMATION_BOUNCINESS, XML_PIE_OFFSET, XML_PLACEHOLDER, XML_PLACEHOLDER_TYPE, diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk index 8d78a3c2f696..50f9e87c9dc2 100644 --- a/offapi/UnoApi_offapi.mk +++ b/offapi/UnoApi_offapi.mk @@ -1680,6 +1680,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/animations,\ XAnimate \ XAnimateColor \ XAnimateMotion \ + XAnimatePhysics \ XAnimateSet \ XAnimateTransform \ XAnimationListener \ diff --git a/offapi/com/sun/star/animations/XAnimatePhysics.idl b/offapi/com/sun/star/animations/XAnimatePhysics.idl new file mode 100644 index 000000000000..0b644bcd6528 --- /dev/null +++ b/offapi/com/sun/star/animations/XAnimatePhysics.idl @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef __com_sun_star_animations_XAnimatePhysics_idl__ +#define __com_sun_star_animations_XAnimatePhysics_idl__ + +#include <com/sun/star/animations/XAnimate.idl> + + + module com { module sun { module star { module animations { + + +/** Interface for physics animation. +*/ +interface XAnimatePhysics : XAnimate +{ + /** Specifies an optional starting velocity + */ + [attribute] any StartVelocityX; + + /** Specifies an optional starting velocity + */ + [attribute] any StartVelocityY; + + /** Specifies an optional density value + */ + [attribute] any Density; + + /** Specifies an optional bounciness value + + Takes a value between (0,1], 1 being no energy loss on collisions + Has a default value of 0.1 + */ + [attribute] any Bounciness; +}; + + +}; }; }; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/slideshow/source/engine/animationfactory.cxx b/slideshow/source/engine/animationfactory.cxx index d6198439b327..920dee35f0eb 100644 --- a/slideshow/source/engine/animationfactory.cxx +++ b/slideshow/source/engine/animationfactory.cxx @@ -362,6 +362,9 @@ namespace slideshow::internal const double fDuration, const ShapeManagerSharedPtr& rShapeManager, const ::basegfx::B2DVector& rSlideSize, + const ::basegfx::B2DVector& rStartVelocity, + const double fDensity, + const double fBounciness, int nFlags ) : mpShape(), mpAttrLayer(), @@ -372,6 +375,9 @@ namespace slideshow::internal mpBox2DBody(), mpBox2DWorld( pBox2DWorld ), mfDuration(fDuration), + maStartVelocity(rStartVelocity), + mfDensity(fDensity), + mfBounciness(fBounciness), mfPreviousElapsedTime(0.00f), mbIsBox2dWorldStepper(false) { @@ -411,7 +417,7 @@ namespace slideshow::internal ENSURE_OR_THROW( rAttrLayer, "PhysicsAnimation::start(): Invalid attribute layer" ); - mpBox2DBody = mpBox2DWorld->makeShapeDynamic( rShape ); + mpBox2DBody = mpBox2DWorld->makeShapeDynamic( rShape->getXShape(), maStartVelocity, mfDensity, mfBounciness ); if( !mbAnimationStarted ) { @@ -495,6 +501,9 @@ namespace slideshow::internal box2d::utils::Box2DBodySharedPtr mpBox2DBody; box2d::utils::Box2DWorldSharedPtr mpBox2DWorld; double mfDuration; + const ::basegfx::B2DVector maStartVelocity; + const double mfDensity; + const double mfBounciness; double mfPreviousElapsedTime; bool mbIsBox2dWorldStepper; }; @@ -1468,11 +1477,17 @@ namespace slideshow::internal const double fDuration, const ShapeManagerSharedPtr& rShapeManager, const ::basegfx::B2DVector& rSlideSize, + const ::basegfx::B2DVector& rStartVelocity, + const double fDensity, + const double fBounciness, int nFlags ) { return std::make_shared<PhysicsAnimation>( pBox2DWorld, fDuration, rShapeManager, rSlideSize, + rStartVelocity, + fDensity, + fBounciness, nFlags ); } diff --git a/slideshow/source/engine/animationnodes/animationphysicsnode.cxx b/slideshow/source/engine/animationnodes/animationphysicsnode.cxx index 28e247c30d6c..c056d999f850 100644 --- a/slideshow/source/engine/animationnodes/animationphysicsnode.cxx +++ b/slideshow/source/engine/animationnodes/animationphysicsnode.cxx @@ -19,6 +19,12 @@ #include "animationphysicsnode.hxx" #include <animationfactory.hxx> +#include <o3tl/any.hxx> + +#define DEFAULT_START_VELOCITY_X 0.0 +#define DEFAULT_START_VELOCITY_Y 0.0 +#define DEFAULT_DENSITY 1 +#define DEFAULT_BOUNCINESS 0.1 namespace slideshow::internal { @@ -34,12 +40,41 @@ AnimationActivitySharedPtr AnimationPhysicsNode::createActivity() const ENSURE_OR_THROW((mxPhysicsMotionNode->getDuration() >>= fDuration), "Couldn't get the animation duration."); + ::css::uno::Any aTemp; + double fStartVelocityX; + aTemp = mxPhysicsMotionNode->getStartVelocityX(); + if (aTemp.hasValue()) + aTemp >>= fStartVelocityX; + else + fStartVelocityX = DEFAULT_START_VELOCITY_X; + + double fStartVelocityY; + aTemp = mxPhysicsMotionNode->getStartVelocityY(); + if (aTemp.hasValue()) + aTemp >>= fStartVelocityY; + else + fStartVelocityY = DEFAULT_START_VELOCITY_Y; + + double fDensity; + aTemp = mxPhysicsMotionNode->getDensity(); + if (aTemp.hasValue()) + aTemp >>= fDensity; + else + fDensity = DEFAULT_DENSITY; + + double fBounciness; + aTemp = mxPhysicsMotionNode->getBounciness(); + if (aTemp.hasValue()) + aTemp >>= fBounciness; + else + fBounciness = DEFAULT_BOUNCINESS; + ActivitiesFactory::CommonParameters const aParms(fillCommonParameters()); return ActivitiesFactory::createSimpleActivity( aParms, - AnimationFactory::createPhysicsAnimation(getContext().mpBox2DWorld, fDuration, - getContext().mpSubsettableShapeManager, - getSlideSize(), 0), + AnimationFactory::createPhysicsAnimation( + getContext().mpBox2DWorld, fDuration, getContext().mpSubsettableShapeManager, + getSlideSize(), { fStartVelocityX, fStartVelocityY }, fDensity, fBounciness, 0), true); } diff --git a/slideshow/source/engine/animationnodes/animationphysicsnode.hxx b/slideshow/source/engine/animationnodes/animationphysicsnode.hxx index 15ac8911e916..5c82a7c5b164 100644 --- a/slideshow/source/engine/animationnodes/animationphysicsnode.hxx +++ b/slideshow/source/engine/animationnodes/animationphysicsnode.hxx @@ -20,6 +20,7 @@ #include "animationbasenode.hxx" #include <com/sun/star/animations/XAnimateMotion.hpp> +#include <com/sun/star/animations/XAnimatePhysics.hpp> namespace slideshow { @@ -45,7 +46,7 @@ protected: private: virtual AnimationActivitySharedPtr createActivity() const override; - css::uno::Reference<css::animations::XAnimateMotion> mxPhysicsMotionNode; + css::uno::Reference<css::animations::XAnimatePhysics> mxPhysicsMotionNode; }; } // namespace internal diff --git a/slideshow/source/engine/box2dtools.cxx b/slideshow/source/engine/box2dtools.cxx index e6ba7f385228..d1ef96f154ca 100644 --- a/slideshow/source/engine/box2dtools.cxx +++ b/slideshow/source/engine/box2dtools.cxx @@ -20,6 +20,7 @@ #include <svx/svdoashp.hxx> #define BOX2D_SLIDE_SIZE_IN_METERS 100.00f +#define DEFAULT_BOUNCINESS 0.1 namespace box2d::utils { @@ -549,6 +550,13 @@ void box2DWorld::queueShapeAnimationEndUpdate( } } +void box2DWorld::alertAnimationEndForShape(const slideshow::internal::ShapeSharedPtr& pShape) +{ + Box2DBodySharedPtr pBox2DBody = mpXShapeToBodyMap.find(pShape->getXShape())->second; + makeBodyStatic(pBox2DBody); + pBox2DBody->setRestitution(DEFAULT_BOUNCINESS); +} + void box2DWorld::step(const float fTimeStep, const int nVelocityIterations, const int nPositionIterations) { @@ -584,10 +592,15 @@ bool box2DWorld::isInitialized() return false; } -Box2DBodySharedPtr box2DWorld::makeShapeDynamic(const slideshow::internal::ShapeSharedPtr& pShape) +Box2DBodySharedPtr +box2DWorld::makeShapeDynamic(const css::uno::Reference<css::drawing::XShape>& xShape, + const basegfx::B2DVector& rStartVelocity, const double fDensity, + const double fBounciness) { assert(mpBox2DWorld); - Box2DBodySharedPtr pBox2DBody = mpXShapeToBodyMap.find(pShape->getXShape())->second; + Box2DBodySharedPtr pBox2DBody = mpXShapeToBodyMap.find(xShape)->second; + pBox2DBody->setDensityAndRestitution(fDensity, fBounciness); + queueLinearVelocityUpdate(xShape, rStartVelocity); return makeBodyDynamic(pBox2DBody); } @@ -776,6 +789,25 @@ void box2DBody::setAngle(const double fAngle) mpBox2DBody->SetTransform(mpBox2DBody->GetPosition(), ::basegfx::deg2rad(-fAngle)); } +void box2DBody::setDensityAndRestitution(const double fDensity, const double fRestitution) +{ + for (b2Fixture* pFixture = mpBox2DBody->GetFixtureList(); pFixture; + pFixture = pFixture->GetNext()) + { + pFixture->SetDensity(static_cast<float>(fDensity)); + pFixture->SetRestitution(static_cast<float>(fRestitution)); + } +} + +void box2DBody::setRestitution(const double fRestitution) +{ + for (b2Fixture* pFixture = mpBox2DBody->GetFixtureList(); pFixture; + pFixture = pFixture->GetNext()) + { + pFixture->SetRestitution(static_cast<float>(fRestitution)); + } +} + void box2DBody::setType(box2DBodyType eType) { mpBox2DBody->SetType(getBox2DInternalBodyType(eType)); diff --git a/slideshow/source/inc/animationfactory.hxx b/slideshow/source/inc/animationfactory.hxx index 0517a7a79ee4..853546705cc7 100644 --- a/slideshow/source/inc/animationfactory.hxx +++ b/slideshow/source/inc/animationfactory.hxx @@ -139,6 +139,9 @@ namespace slideshow const double fDuration, const ShapeManagerSharedPtr& rShapeManager, const ::basegfx::B2DVector& rSlideSize, + const ::basegfx::B2DVector& rStartVelocity, + const double fDensity, + const double fBounciness, int nFlags ); } } diff --git a/slideshow/source/inc/box2dtools.hxx b/slideshow/source/inc/box2dtools.hxx index f22cc999e8fe..37ce739a2009 100644 --- a/slideshow/source/inc/box2dtools.hxx +++ b/slideshow/source/inc/box2dtools.hxx @@ -221,7 +221,9 @@ public: @param pShape Pointer to the shape to alter the corresponding Box2D body of */ - Box2DBodySharedPtr makeShapeDynamic(const slideshow::internal::ShapeSharedPtr& pShape); + Box2DBodySharedPtr makeShapeDynamic(const css::uno::Reference<css::drawing::XShape>& xShape, + const basegfx::B2DVector& rStartVelocity, + const double fDensity, const double fBounciness); /** Make the Box2D body a dynamic one @@ -285,6 +287,8 @@ public: void queueShapeAnimationEndUpdate(const css::uno::Reference<css::drawing::XShape>& xShape, const slideshow::internal::AttributeType eAttrType); + + void alertAnimationEndForShape(const slideshow::internal::ShapeSharedPtr& pShape); }; /// Class that manages a single box2D Body @@ -345,6 +349,10 @@ public: void setAngle(const double fAngle); + void setDensityAndRestitution(const double fDensity, const double fRestitution); + + void setRestitution(const double fRestitution); + /// Set type of the body void setType(box2DBodyType eType); diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 03e777185d0e..c9045ca3036f 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -1451,6 +1451,10 @@ namespace xmloff::token { TOKEN( "perspective", XML_PERSPECTIVE ), TOKEN( "phdthesis", XML_PHDTHESIS ), TOKEN( "phong", XML_PHONG ), + TOKEN( "velocity-x", XML_PHYSICS_ANIMATION_START_VELOCITY_X ), + TOKEN( "velocity-y", XML_PHYSICS_ANIMATION_START_VELOCITY_Y ), + TOKEN( "density", XML_PHYSICS_ANIMATION_DENSITY ), + TOKEN( "bounciness", XML_PHYSICS_ANIMATION_BOUNCINESS ), TOKEN( "pie-offset", XML_PIE_OFFSET ), TOKEN( "placeholder", XML_PLACEHOLDER ), TOKEN( "placeholder-type", XML_PLACEHOLDER_TYPE ), diff --git a/xmloff/source/draw/animationexport.cxx b/xmloff/source/draw/animationexport.cxx index f217e46a709d..13f296e57500 100644 --- a/xmloff/source/draw/animationexport.cxx +++ b/xmloff/source/draw/animationexport.cxx @@ -23,6 +23,7 @@ #include <com/sun/star/animations/Timing.hpp> #include <com/sun/star/animations/Event.hpp> #include <com/sun/star/animations/XAnimateMotion.hpp> +#include <com/sun/star/animations/XAnimatePhysics.hpp> #include <com/sun/star/animations/XAnimateTransform.hpp> #include <com/sun/star/animations/XTransitionFilter.hpp> #include <com/sun/star/animations/XIterateContainer.hpp> @@ -1243,9 +1244,40 @@ void AnimationsExporterImpl::exportAnimate( const Reference< XAnimate >& xAnimat case AnimationNodeType::ANIMATEPHYSICS: { eElementToken = XML_ANIMATEPHYSICS; + double fTemp; - Reference< XAnimateMotion > xAnimateMotion( xAnimate, UNO_QUERY_THROW ); - aTemp = xAnimateMotion->getOrigin(); + Reference< XAnimatePhysics > xAnimatePhysics( xAnimate, UNO_QUERY_THROW ); + aTemp = xAnimatePhysics->getStartVelocityX(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_X, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getStartVelocityY(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_Y, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getDensity(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_DENSITY, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getBounciness(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_BOUNCINESS, sTmp.makeStringAndClear() ); + } } break; diff --git a/xmloff/source/draw/animationimport.cxx b/xmloff/source/draw/animationimport.cxx index 52e020e8f939..ad34a6ad22ee 100644 --- a/xmloff/source/draw/animationimport.cxx +++ b/xmloff/source/draw/animationimport.cxx @@ -27,6 +27,7 @@ #include <com/sun/star/animations/SequenceTimeContainer.hpp> #include <com/sun/star/animations/XIterateContainer.hpp> #include <com/sun/star/animations/XAnimateMotion.hpp> +#include <com/sun/star/animations/XAnimatePhysics.hpp> #include <com/sun/star/animations/XAnimateColor.hpp> #include <com/sun/star/animations/XAnimateTransform.hpp> #include <com/sun/star/animations/XTransitionFilter.hpp> @@ -923,6 +924,38 @@ void AnimationNodeContext::init_node( const css::uno::Reference< css::xml::sax: } break; + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_X): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setStartVelocityX( makeAny(rValue.toDouble()) ); + } + break; + + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_Y): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setStartVelocityY( makeAny(rValue.toDouble()) ); + } + break; + + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_DENSITY): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setDensity( makeAny(rValue.toDouble()) ); + } + break; + + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_BOUNCINESS): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setBounciness( makeAny(rValue.toDouble()) ); + } + break; + case XML_ELEMENT(ANIMATION, XML_COLOR_INTERPOLATION): case XML_ELEMENT(ANIMATION_OOO, XML_COLOR_INTERPOLATION): { diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index 368cf7d67014..2a55186fdb3e 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -1361,6 +1361,10 @@ percentage-style perspective phdthesis phong +velocity-x +velocity-y +density +bounciness pie-offset placeholder placeholder-type commit 2bc46ffa1d21a74dc13c5a4e122420007960f3c8 Author: Sarper Akdemir <q.sarperakde...@gmail.com> AuthorDate: Thu Aug 13 03:40:25 2020 +0300 Commit: Sarper Akdemir <q.sarperakde...@gmail.com> CommitDate: Fri Aug 14 10:31:12 2020 +0300 make physics animations handle sequential animations correctly fixes a bug where if there is a sequence of animations between two physics animations that change the position, rotation or visibility of a shape - changes are not picked up by the latter physics animation. also renames some functions to better illustrate what are they doing. 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..e6ba7f385228 100644 --- a/slideshow/source/engine/box2dtools.cxx +++ b/slideshow/source/engine/box2dtools.cxx @@ -203,7 +203,8 @@ box2DWorld::box2DWorld(const ::basegfx::B2DVector& rSlideSize) , mbShapesInitialized(false) , mbHasWorldStepper(false) , mpXShapeToBodyMap() - , maShapeUpdateQueue() + , maShapeParallelUpdateQueue() + , maShapeSequentialUpdate() { } @@ -253,6 +254,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 +282,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,41 +320,75 @@ void box2DWorld::setShapeCollision( void box2DWorld::processUpdateQueue(const double fPassedTime) { - while (!maShapeUpdateQueue.empty()) + if (maShapeSequentialUpdate.empty()) { - Box2DShapeUpdateInformation& aQueueElement = maShapeUpdateQueue.front(); - - if (aQueueElement.mnDelayForSteps > 0) + while (!maShapeParallelUpdateQueue.empty()) { - // it was queued as a delayed action, skip it, don't pop - aQueueElement.mnDelayForSteps--; + 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(); + } } - else + } + else + { + // clear the Parallel Update Queue since the updates in it + // are not relevant now - if there's any + maShapeParallelUpdateQueue = {}; + + for (auto& aIt : maShapeSequentialUpdate) { - switch (aQueueElement.meUpdateType) + const css::uno::Reference<css::drawing::XShape>& xShape = aIt.first.first; + const box2DNonsimulatedShapeUpdateType eUpdateType = aIt.first.second; + const Box2DStaticUpdateInformation& rUpdateInformation = aIt.second; + + switch (eUpdateType) { default: case BOX2D_UPDATE_POSITION: - setShapePositionByLinearVelocity(aQueueElement.mxShape, - aQueueElement.maPosition, fPassedTime); + setShapePosition(xShape, rUpdateInformation.maPosition); break; case BOX2D_UPDATE_ANGLE: - setShapeAngleByAngularVelocity(aQueueElement.mxShape, aQueueElement.mfAngle, - fPassedTime); - break; - case BOX2D_UPDATE_SIZE: + setShapeAngle(xShape, rUpdateInformation.mfAngle); break; case BOX2D_UPDATE_VISIBILITY: - setShapeCollision(aQueueElement.mxShape, aQueueElement.mbVisibility); - break; - case BOX2D_UPDATE_LINEAR_VELOCITY: - setShapeLinearVelocity(aQueueElement.mxShape, aQueueElement.maVelocity); + setShapeCollision(xShape, rUpdateInformation.mbVisibility); break; - case BOX2D_UPDATE_ANGULAR_VELOCITY: - setShapeAngularVelocity(aQueueElement.mxShape, aQueueElement.mfAngularVelocity); } - maShapeUpdateQueue.pop(); } + + // After applying all required updates empty map + maShapeSequentialUpdate.clear(); } } @@ -376,47 +425,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 +484,50 @@ 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 + { + 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; + } } } @@ -448,11 +538,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 +707,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 +771,11 @@ double box2DBody::getAngle() return ::basegfx::rad2deg(-fAngle); } +void box2DBody::setAngle(const 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..f22cc999e8fe 100644 --- a/slideshow/source/inc/box2dtools.hxx +++ b/slideshow/source/inc/box2dtools.hxx @@ -12,6 +12,7 @@ #include "shape.hxx" #include "shapeattributelayer.hxx" #include "attributemap.hxx" +#include <map> #include <unordered_map> #include <queue> @@ -50,7 +51,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 +65,13 @@ struct Box2DShapeUpdateInformation 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, @@ -78,15 +86,25 @@ 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 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); + 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 +126,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 +177,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 +265,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 +302,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 +343,8 @@ public: /// @return current angle of rotation of the body double getAngle(); + void setAngle(const 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