1 #ifndef DALI_TOOLKIT_PHYSICS_ADAPTOR_H
2 #define DALI_TOOLKIT_PHYSICS_ADAPTOR_H
5 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or adaptoried.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 #include <dali/public-api/actors/actor.h>
22 #include <dali/public-api/adaptor-framework/window.h>
23 #include <dali/public-api/object/any.h>
24 #include <dali/public-api/object/base-handle.h>
25 #include <functional> ///< for std::function
28 #include <dali-toolkit/public-api/dali-toolkit-common.h>
30 namespace Dali::Toolkit::Physics
38 } // namespace Internal
41 * Adaptor to manage access to the physics world and pairing actors and physics
42 * bodies, plus some translation methods to/from the physics space and dali space.
44 * Also manages a debug renderer that may utilize the physics engine debug.
45 * It is up to the developer to retrieve the root actor and parent it into the scene.
47 class DALI_TOOLKIT_API PhysicsAdaptor : public BaseHandle
51 * @brief Enumeration to turn the integration step on or off.
53 enum class IntegrationState
60 * @brief Enumeration to turn the debug rendering on or off
69 * @brief Scoped accessor to the physics world.
72 * Automatically locks the physics world with a mutex to prevent the
73 * integration step from running whilst the developer is accessing
74 * the world, e.g. to add/remove bodies or constraints, or to
77 * When it goes out of scope, the mutex is unlocked, and the integration step
80 struct ScopedPhysicsAccessor
84 * @brief Get a pointer to the native world.
87 * This uses DALi::Any wrapper to ensure that the same interface can be used
88 * for both 2d and 3d physics. It can be cast to the right type using the
89 * following construct:
90 * auto accessor = PhysicsAdaptor.GetPhysicsAccessor();
91 * auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamiscWorld*>();
93 Dali::Any GetNative();
96 * @brief Hit test the physics world and return the nearest body.
99 * @param[in] rayFromWorld The origin in physics world space
100 * @param[in] rayToWorld A point along the direction on the far side of the physics world
101 * @param[out] localPivot The hit point local to the body
102 * @param[out] distanceFromCamera The distance of the pick point from the camera
103 * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body.
105 Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera);
108 ScopedPhysicsAccessor(ScopedPhysicsAccessor&) = delete;
109 const ScopedPhysicsAccessor& operator=(const ScopedPhysicsAccessor&) = delete;
114 * On leaving scope, the mutex is unlocked and the physics integration step
117 ~ScopedPhysicsAccessor();
121 * @brief Private constructor.
123 * It is created by the physics adaptor.
125 ScopedPhysicsAccessor(Internal::PhysicsWorld& world);
126 friend Internal::PhysicsAdaptor;
128 struct Impl; ///< Opaque implementation structure
133 * @brief Creates an uninitalized PhysicsAdaptor, this can be initialized with PhysicsAdaptor::New().
136 * Calling member functions with an uninitialized PhysicsAdaptor handle is not allowed.
143 * This is non-virtual since derived Handle types must not contain data or virtual methods.
149 * @brief Copy Constructor.
152 * @param[in] handle The handle to copy
153 * @note This creates a new handle, but does not create a new implementation object.
155 PhysicsAdaptor(const PhysicsAdaptor& handle);
158 * @brief Move Constructor.
161 * @param[in] handle A reference to the handle to move
163 PhysicsAdaptor(PhysicsAdaptor&& rhs) noexcept;
166 * @brief Assignment operator.
169 * @param[in] handle A reference to the handle to move
170 * @return a reference to this handle
172 PhysicsAdaptor& operator=(const PhysicsAdaptor& handle);
175 * @brief Move Assignment operator.
178 * @param[in] handle A reference to the handle to move
179 * @return a reference to this handle
181 PhysicsAdaptor& operator=(PhysicsAdaptor&& handle) noexcept;
184 * @brief Initialize the physics system.
187 * @param[in] transform The transform matrix for DALi to Physics world space
188 * @param[in] size The size of the layer the physics actors will be drawn in
190 static PhysicsAdaptor New(const Dali::Matrix& transform, Uint16Pair size);
193 * @brief Downcasts a handle to PhysicsAdaptor handle.
195 * If handle points to an PhysicsAdaptor object, the downcast produces valid handle.
196 * If not, the returned handle is left uninitialized.
199 * @param[in] handle to an object
200 * @return handle to a PhysicsAdaptor object or an uninitialized handle
202 static PhysicsAdaptor DownCast(BaseHandle handle);
205 * @brief Set how long the integration should take.
208 * @param[in] timestep The length of time that the physics integration should take.
210 void SetTimestep(float timestep);
213 * @brief Get the current physics integration timestep.
216 * @return the current physics integration timestep
218 float GetTimestep() const;
221 * @brief Type to represent a pointer to a scoped accessor.
225 using ScopedPhysicsAccessorPtr = std::unique_ptr<PhysicsAdaptor::ScopedPhysicsAccessor>;
228 * @brief Returns an accessor to the physics world.
231 * It automatically locks a mutex to prevent the integration step
232 * from running whilst the world is being modified.
234 * When the pointer goes out of scope, the mutex is unlocked and the physics world
236 * @return the scoped accessor
238 ScopedPhysicsAccessorPtr GetPhysicsAccessor();
241 * @brief Create a layer & debug renderer.
244 * The debug renderer may utilize the debug features of the native physics
247 * @param[in] window The window to draw in (requires camera)
248 * @return The debug layer
250 Dali::Layer CreateDebugLayer(Dali::Window window);
253 * @brief Converts a point in RootActor local coords (e.g. gesture)
254 * into physics space coords.
257 * @param vector The point to convert
258 * @return The converted point
260 Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector) const;
263 * @brief Convert a rotation in DALi coordinate system into physics space.
266 * @param[in] rotation The rotation to convert
267 * @return the converted rotation.
269 Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation) const;
272 * @brief Converts a point in physics space coords into RootActor local coords.
275 * @param vector The point to convert
276 * @return The converted point
278 Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector) const;
281 * @brief Convert a rotation in physics coordinate system into DALi space.
284 * @param[in] rotation The rotation to convert
285 * @return the converted rotation.
287 Dali::Quaternion TranslateFromPhysicsSpace(Dali::Quaternion rotation) const;
290 * @brief Converts a vector (not a point) in DALi space into physics space.
293 * @param vector The vector to convert
294 * @return The converted vector
296 Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const;
299 * @brief Converts a vector (not a point) in physics space to DALi space.
302 * @param vector The vector to convert
303 * @return The converted vector
305 Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const;
308 * @brief Set up the transform from world space to physics space.
311 * @param[in] transform The transform matrix for DALi to Physics world space
312 * @param[in] size The size of the layer the physics actors will be drawn in
314 void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size);
317 * @brief Set the integration state.
320 * If it's turned off, physics will be paused.
321 * @note This is ON by default
322 * @param[in] state the new integration state
324 void SetIntegrationState(IntegrationState state);
327 * @brief Get the integration state.
330 * @return the new integration state
332 IntegrationState GetIntegrationState() const;
335 * @brief Set the debug state.
338 * If debug is turned on, use the physics engine
339 * debug to show wireframes in a layer above the root actor.
340 * @note This is OFF by default
341 * @param[in] state the new debug state
343 void SetDebugState(DebugState state);
346 * @brief Get the debug state.
349 * @return the new debug state
351 DebugState GetDebugState() const;
354 * @brief Add an actor / body pair.
355 * @pre It's expected that the client has added the body to the physics world.
357 * The adaptor does not "take ownership" of the actor or the physics body.
359 * @param[in] actor The actor used for rendering the physics object
360 * @param[in] body The physics object
361 * @return a handle to the actor / body pair.
363 PhysicsActor AddActorBody(Dali::Actor actor, Dali::Any body);
366 * @brief Remove the actor / body.
368 * This will unparent the actor from the root actor and disassociate it from
371 * It is the responsibility of the client to remove the body from the physics world
372 * and destroy it at an appropriate time. Create a scoped accessor to ensure
373 * that the integration step isn't being run when doing so.
375 * If the root actor is holding the last reference to the actor, it will be
376 * destroyed automatically, otherwise it is the responsibility of the client to
377 * dereference the actor.
380 * @param[in] physicsActor The actor / body pair to remove.
382 void RemoveActorBody(PhysicsActor physicsActor);
385 * @brief Get the physics actor associated with the given body.
388 * @param[in] body The physics body
389 * @return the associated physics actor
391 PhysicsActor GetPhysicsActor(Dali::Any body) const;
394 * @brief Get the root actor (which holds all the actor/body pairs).
397 * @return the root actor.
399 Dali::Actor GetRootActor() const;
402 * @brief Convert DALi touch point into a picking ray in the physics world.
404 * These can then be used to hit test the PhysicsWorld
407 * @param[in] origin The origin in DALi world space
408 * @param[in] direction The direction of the picking ray
409 * @param[out] rayFromWorld The origin in physics world space
410 * @param[out] rayToWorld A point along the direction on the far side of the physics world
413 * OnTouched(Dali::Actor actor, Dali::TouchEvent& touch)
416 * Vector3 origin, direction;
417 * Dali::HitTestAlgorithm::BuildPickingRay(renderTask, touch.GetScreenPosition(0), origin, direction);
418 * btVector3 rayFromWorld, rayToWorld;
419 * physicsAdaptor.BuildPickingRay(origin, direction, rayFromWorld, rayToWorld);
420 * auto scopedAccessor = physicsAdaptor.GetPhysicsAccessor();
421 * body = scopedAccessor->Get().HitTest(rayFromWorld, rayToWorld, ..);
424 void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld);
427 * @brief Project a point from the origin (in DALi space) a distance along
428 * the direction vector (in DALi space), and return the projected
429 * point in Physics space.
432 * @param[in] origin Origin in DALi world space
433 * @param[in] direction Direction in DALi world space
434 * @param[in] distance Distance along the direction vector
435 * @return the projected point, converted to the Physics space.
437 Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance);
440 * @brief Queue a function to be executed before the physics integration in the update thread.
443 * Multiple functions can be queued up. They are executed in the update frame
444 * callback when the next sync point is seen, so CreateSyncPoint() should be called
445 * afterwards for this to be executed.
447 * @param[in] function to execute. This can be any method, and it can work fine with
448 * physics bodies etc, but it must not be used with DALI event side objects, as this
449 * will very likely cause the update thread to crash.
451 void Queue(std::function<void(void)> function);
454 * @brief Create a sync point for queued functions.
457 * Ensures that any previously queued functions are processed
458 * in the Update::FrameCallback during the same frame as other
459 * DALi properties set during this event handler invocation.
461 * boxActor = Actor::New();
462 * //... Create box actor renderer ...
463 * btRigidBodyConstructionInfo info;
464 * //... set construction properties
465 * boxBody = new btRigidBody(info);
466 * auto boxPhysicsActor = physicsAdaptor.AddActorBody(boxActor, boxBody);
467 * boxActor.SetProperty(Actor::Property::VISIBLE, true);
468 * boxActor.SetProperty(Actor::Property::OPACITY, 0.5f);
469 * physicsAdaptor.Queue([boxBody](){ boxBody->activate(true);});
470 * btVector3 impulse(4, 5, 6);
471 * btVector3 position();
472 * physicsAdaptor.Queue([boxBody](){ boxBody->applyImpulse(impulse, position);});
473 * physicsAdaptor.CreateSyncPoint();
475 * Ensures that the box has both render properties and physics properties applied
476 * during the same frame.
478 void CreateSyncPoint();
480 public: // Not intended for developer use
483 * @brief This constructor is used by PhysicsAdaptor::New() methods.
486 * @param[in] impl A pointer to a newly allocated Dali resource.
487 * @note Not intended for application developers
489 explicit DALI_INTERNAL PhysicsAdaptor(Internal::PhysicsAdaptor* impl);
493 } // namespace Dali::Toolkit::Physics
495 #endif //DALI_TOOLKIT_PHYSICS_ADAPTOR_H