1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 #include "shapeattributelayer.hxx"
14 #include "attributemap.hxx"
15 #include <unordered_map>
21 namespace slideshow::internal
24 typedef std::shared_ptr
<ShapeManager
> ShapeManagerSharedPtr
;
27 namespace box2d::utils
31 typedef std::shared_ptr
<box2DWorld
> Box2DWorldSharedPtr
;
32 typedef std::shared_ptr
<box2DBody
> Box2DBodySharedPtr
;
36 BOX2D_STATIC_BODY
= 0,
41 enum box2DNonsimulatedShapeUpdateType
43 BOX2D_UPDATE_POSITION_CHANGE
,
44 BOX2D_UPDATE_POSITION
,
47 BOX2D_UPDATE_VISIBILITY
,
48 BOX2D_UPDATE_LINEAR_VELOCITY
,
49 BOX2D_UPDATE_ANGULAR_VELOCITY
52 /// Holds required information to perform an update to box2d
53 /// body of a shape that was altered by an animation effect
54 struct Box2DDynamicUpdateInformation
56 /// reference to the shape that the update belongs to
57 css::uno::Reference
<css::drawing::XShape
> mxShape
;
59 ::basegfx::B2DPoint maPosition
;
60 ::basegfx::B2DVector maVelocity
;
62 double mfAngularVelocity
;
65 box2DNonsimulatedShapeUpdateType meUpdateType
;
66 /// amount of steps to delay the update for
67 int mnDelayForSteps
= 0;
70 /** Class that manages the Box2D World
72 This class is used when there's a physics animation going on,
73 it handles the stepping through the box2d world, updating the
74 shapes in the box2d world if they were changed by ongoing animations.
79 /// Pointer to the real Box2D World that this class manages
80 std::unique_ptr
<b2World
> mpBox2DWorld
;
81 /// Scale factor for conversions between LO user space coordinates to Box2D World coordinates
83 bool mbShapesInitialized
;
84 /// Holds whether or not there is a PhysicsAnimation that
85 /// is stepping the Box2D World. Used to create a lock mechanism
86 bool mbHasWorldStepper
;
87 /// Flag used to stop overstepping that occurs when a physics
88 /// animation effect transfers step-lock to another one.
89 bool mbAlreadyStepped
;
90 /// Number of Physics Animations going on
91 int mnPhysicsAnimationCounter
;
92 std::unordered_map
<css::uno::Reference
<css::drawing::XShape
>, Box2DBodySharedPtr
>
95 /** Queue that holds any required information to keep LO animation effects
96 and Box2DWorld in sync
98 Is processed before every step of the box2d world by processUpdateQueue.
99 Holds position, rotation, visibility etc. changes and associated values.
101 std::queue
<Box2DDynamicUpdateInformation
> maShapeParallelUpdateQueue
;
103 /// Creates a static frame in Box2D world that corresponds to the slide borders
104 void createStaticFrameAroundSlide(const ::basegfx::B2DVector
& rSlideSize
);
106 /** Sets shape's corresponding Box2D body to the specified position
108 Body is teleported to the specified position, not moved
114 Position in LO user space coordinates
116 void setShapePosition(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
117 const ::basegfx::B2DPoint
& rOutPos
);
119 /** Moves shape's corresponding Box2D body to specified position
121 Moves shape's corresponding Box2D body to specified position as if
122 the body had velocity to reach that point in given time frame.
128 Position in LO user space coordinates
131 Time frame which the Box2D body should move to the specified position.
133 void setShapePositionByLinearVelocity(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
134 const ::basegfx::B2DPoint
& rOutPos
,
135 const double fPassedTime
);
137 /** Sets linear velocity of the shape's corresponding Box2D body
139 Moves shape's corresponding Box2D body to specified position as if
140 the body had velocity to reach that point in given time frame.
146 Velocity vector in LO user space coordinates.
148 void setShapeLinearVelocity(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
149 const basegfx::B2DVector
& rVelocity
);
151 /** Sets rotation angle of the shape's corresponding Box2D body
157 Angle of rotation in degrees.
159 void setShapeAngle(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
160 const double fAngle
);
162 /** Rotates shape's corresponding Box2D body to specified angle
164 Rotates the Box2D body to specified angle as if the body
165 had exact angular velocity to reach that point in given
172 Angle of rotation in degrees.
175 Time frame which the Box2D body should rotate to the specified angle.
177 void setShapeAngleByAngularVelocity(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
178 const double fAngle
, const double fPassedTime
);
180 /** Sets angular velocity of the shape's corresponding Box2D body.
185 @param fAngularVelocity
186 Angular velocity in degrees per second.
188 void setShapeAngularVelocity(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
189 const double fAngularVelocity
);
191 /** Sets whether a shape's corresponding Box2D body has collision in the Box2D World or not
193 Used for animations that change the visibility of the shape.
199 true if collisions should be enabled for the corresponding Box2D body of this shape
200 and false if it should be disabled.
202 void setShapeCollision(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
203 const bool bCanCollide
);
205 /** Process the updates queued in the maShapeParallelUpdateQueue
207 Called on each step of the box2DWorld.
210 Time frame to process the updates accordingly (needed for proper simulations)
212 void processUpdateQueue(const double fPassedTime
);
214 /** Simulate and step through time in the Box2D World
218 @attention fTimeStep should not vary.
220 void step(const float fTimeStep
= 1.0f
/ 100.0f
, const int nVelocityIterations
= 6,
221 const int nPositionIterations
= 2);
223 /// Queue a rotation update that is simulated as if shape's corresponding box2D body rotated to given angle when processed
224 void queueDynamicRotationUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
225 const double fAngle
);
227 /// Queue an angular velocity update that sets the shape's corresponding box2D body angular velocity to the given value when processed
228 void queueAngularVelocityUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
229 const double fAngularVelocity
, const int nDelayForSteps
= 0);
231 /// Queue an collision update that sets the collision of shape's corresponding box2D body when processed
232 void queueShapeVisibilityUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
233 const bool bVisibility
);
235 void queueShapePositionUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
236 const ::basegfx::B2DPoint
& rOutPos
);
239 box2DWorld(const ::basegfx::B2DVector
& rSlideSize
);
242 bool initiateWorld(const ::basegfx::B2DVector
& rSlideSize
);
244 /** Simulate and step through a given amount of time in the Box2D World
247 Amount of time to step through
249 @return Amount of time actually stepped through, since it is possible
250 to only step through a multiple of fTimeStep
252 @attention fTimeStep should not vary.
254 double stepAmount(const double fPassedTime
, const float fTimeStep
= 1.0f
/ 100.0f
,
255 const int nVelocityIterations
= 6, const int nPositionIterations
= 2);
257 /// @return whether shapes in the slide are initialized as Box2D bodies or not
258 bool shapesInitialized();
259 /// @return whether the Box2D World is initialized or not
260 bool isInitialized() const;
262 /** Make the shape's corresponding box2D body a dynamic one.
264 A dynamic body will be affected by other bodies and the gravity.
269 @param rStartVelocity
270 Velocity of the shape after making it dynamic
273 Density of the body that is in kg/m^2
276 Bounciness of the body that is usually in between [0,1].
277 Even though it could take values that are >1, it is way too chaotic.
279 @return box2d body pointer
281 Box2DBodySharedPtr
makeShapeDynamic(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
282 const basegfx::B2DVector
& rStartVelocity
,
283 const double fDensity
, const double fBounciness
);
285 /** Make the Box2D body corresponding to the given shape a static one
287 A static body will not be affected by other bodies and the gravity. But will
288 affect other bodies that are dynamic (will still collide with them but won't
292 Pointer to the shape to alter the corresponding Box2D body of
294 @return box2d body pointer
296 Box2DBodySharedPtr
makeShapeStatic(const slideshow::internal::ShapeSharedPtr
& pShape
);
298 /** Create a static body that is represented by the shape's geometry
300 @return pointer to the box2d body
302 Box2DBodySharedPtr
createStaticBody(const slideshow::internal::ShapeSharedPtr
& rShape
,
303 const float fDensity
= 1.0f
, const float fFriction
= 0.3f
);
305 /// Initiate all the shapes in the current slide in the box2DWorld as static ones
306 void initiateAllShapesAsStaticBodies(
307 const slideshow::internal::ShapeManagerSharedPtr
& pShapeManager
);
309 /// @return whether the box2DWorld has a stepper or not
310 bool hasWorldStepper() const;
312 /// Set the flag for whether the box2DWorld has a stepper or not
313 void setHasWorldStepper(const bool bHasWorldStepper
);
315 /// Queue a position update that is simulated as if shape's corresponding box2D body moved to given position when processed
316 void queueDynamicPositionUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
317 const ::basegfx::B2DPoint
& rOutPos
);
319 /// Queue a update that sets the corresponding box2D body's linear velocity to the given value when processed
320 void queueLinearVelocityUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
321 const ::basegfx::B2DVector
& rVelocity
,
322 const int nDelayForSteps
= 0);
324 /// Queue an appropriate update for the animation effect that is in parallel with a physics animation
326 queueShapeAnimationUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
327 const slideshow::internal::ShapeAttributeLayerSharedPtr
& pAttrLayer
,
328 const slideshow::internal::AttributeType eAttrType
,
329 const bool bIsFirstUpdate
);
331 /// Queue an appropriate update for a path animation that is in parallel with a physics animation
332 void queueShapePathAnimationUpdate(
333 const css::uno::Reference
<css::drawing::XShape
>& xShape
,
334 const slideshow::internal::ShapeAttributeLayerSharedPtr
& pAttrLayer
,
335 const bool bIsFirstUpdate
);
337 /// Queue an appropriate update for the animation effect that just ended
338 void queueShapeAnimationEndUpdate(const css::uno::Reference
<css::drawing::XShape
>& xShape
,
339 const slideshow::internal::AttributeType eAttrType
);
341 /** Alert that a physics animation effect has ended
343 Makes the given shape static, if this was the last physics animation effect
344 that was in parallel, box2d bodies that are owned by the mpXShapeToBodyMap
345 are dumped and potentially destroyed.
347 @attention the box2d body owned by the PhysicsAnimation won't be destroyed.
349 void alertPhysicsAnimationEnd(const slideshow::internal::ShapeSharedPtr
& pShape
);
351 /** Alert that a physics animation effect has started
353 Initiates the box2D world if it is not initiated yet, and likewise constructs
354 box2d bodies for the shapes in the current slide if they are not constructed.
357 alertPhysicsAnimationStart(const ::basegfx::B2DVector
& rSlideSize
,
358 const slideshow::internal::ShapeManagerSharedPtr
& pShapeManager
);
361 /// Class that manages a single box2D Body
365 /// Pointer to the body that this class manages
366 std::shared_ptr
<b2Body
> mpBox2DBody
;
367 /// Scale factor for conversions between LO user space coordinates to Box2D World coordinates
368 double mfScaleFactor
;
371 box2DBody(std::shared_ptr
<b2Body
> pBox2DBody
, double fScaleFactor
);
373 /// @return current position in LO user space coordinates
374 ::basegfx::B2DPoint
getPosition() const;
376 /** Set the position of box2d body
379 Position in LO user space coordinates
381 void setPosition(const ::basegfx::B2DPoint
& rPos
);
383 /** Moves body to the specified position
385 Moves body to the specified position by setting velocity of
386 the body so that it reaches to rDesiredPos in given time fram
389 Position to arrive in the time frame
392 Amount of time for the movement to take place
394 void setPositionByLinearVelocity(const ::basegfx::B2DPoint
& rDesiredPos
,
395 const double fPassedTime
);
397 /** Sets linear velocity of the body
400 Velocity vector in LO user space coordinates
402 void setLinearVelocity(const ::basegfx::B2DVector
& rVelocity
);
404 /** Rotate body to specified angle of rotation
406 Rotates body to specified rotation as if the body had
407 angular velocity to reach that state in given time frame
410 Rotation angle in degrees to arrive in the time frame
413 Amount of time for the movement to take place
415 void setAngleByAngularVelocity(const double fDesiredAngle
, const double fPassedTime
);
417 /** Sets angular velocity of the body
419 @param fAngularVelocity
420 Angular velocity in degrees per second
422 void setAngularVelocity(const double fAngularVelocity
);
424 /// Sets whether the body have collisions or not
425 void setCollision(const bool bCanCollide
);
427 /// @return current angle of rotation of the body
428 double getAngle() const;
430 /** Set angle of the box2d body
435 void setAngle(const double fAngle
);
437 /** Set density and restitution of the box2d body
443 Restitution (elasticity) coefficient, usually in the range [0,1]
445 void setDensityAndRestitution(const double fDensity
, const double fRestitution
);
447 /** Set restitution of the box2d body
450 Restitution (elasticity) coefficient, usually in the range [0,1]
452 void setRestitution(const double fRestitution
);
454 /// Set type of the body
455 void setType(box2DBodyType eType
);
457 /// @return type of the body
458 box2DBodyType
getType() const;
461 /** Make the Box2D body a dynamic one
463 A dynamic body will be affected by other bodies and the gravity.
466 Pointer to the Box2D body
468 Box2DBodySharedPtr
makeBodyDynamic(const Box2DBodySharedPtr
& pBox2DBody
);
470 /** Make the Box2D body a static one
472 A static body will not be affected by other bodies and the gravity.
475 Pointer to the Box2D body
477 Box2DBodySharedPtr
makeBodyStatic(const Box2DBodySharedPtr
& pBox2DBody
);
480 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */