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[in] nativeFilter a native body / shape filter
102 * @param[out] localPivot The hit point local to the body
103 * @param[out] distanceFromCamera The distance of the pick point from the camera
104 * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body.
106 Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera);
109 ScopedPhysicsAccessor(ScopedPhysicsAccessor&) = delete;
110 const ScopedPhysicsAccessor& operator=(const ScopedPhysicsAccessor&) = delete;
115 * On leaving scope, the mutex is unlocked and the physics integration step
118 ~ScopedPhysicsAccessor();
122 * @brief Private constructor.
124 * It is created by the physics adaptor.
126 ScopedPhysicsAccessor(Internal::PhysicsWorld& world);
127 friend Internal::PhysicsAdaptor;
129 struct Impl; ///< Opaque implementation structure
134 * @brief Creates an uninitalized PhysicsAdaptor, this can be initialized with PhysicsAdaptor::New().
137 * Calling member functions with an uninitialized PhysicsAdaptor handle is not allowed.
144 * This is non-virtual since derived Handle types must not contain data or virtual methods.
150 * @brief Copy Constructor.
153 * @param[in] handle The handle to copy
154 * @note This creates a new handle, but does not create a new implementation object.
156 PhysicsAdaptor(const PhysicsAdaptor& handle);
159 * @brief Move Constructor.
162 * @param[in] handle A reference to the handle to move
164 PhysicsAdaptor(PhysicsAdaptor&& rhs) noexcept;
167 * @brief Assignment operator.
170 * @param[in] handle A reference to the handle to move
171 * @return a reference to this handle
173 PhysicsAdaptor& operator=(const PhysicsAdaptor& handle);
176 * @brief Move Assignment operator.
179 * @param[in] handle A reference to the handle to move
180 * @return a reference to this handle
182 PhysicsAdaptor& operator=(PhysicsAdaptor&& handle) noexcept;
185 * @brief Initialize the physics system.
188 * @param[in] transform The transform matrix for DALi to Physics world space
189 * @param[in] size The size of the layer the physics actors will be drawn in
191 static PhysicsAdaptor New(const Dali::Matrix& transform, Uint16Pair size);
194 * @brief Downcasts a handle to PhysicsAdaptor handle.
196 * If handle points to an PhysicsAdaptor object, the downcast produces valid handle.
197 * If not, the returned handle is left uninitialized.
200 * @param[in] handle to an object
201 * @return handle to a PhysicsAdaptor object or an uninitialized handle
203 static PhysicsAdaptor DownCast(BaseHandle handle);
206 * @brief Set how long the integration should take.
209 * @param[in] timestep The length of time that the physics integration should take.
211 void SetTimestep(float timestep);
214 * @brief Get the current physics integration timestep.
217 * @return the current physics integration timestep
219 float GetTimestep() const;
222 * @brief Type to represent a pointer to a scoped accessor.
226 using ScopedPhysicsAccessorPtr = std::unique_ptr<PhysicsAdaptor::ScopedPhysicsAccessor>;
229 * @brief Returns an accessor to the physics world.
232 * It automatically locks a mutex to prevent the integration step
233 * from running whilst the world is being modified.
235 * When the pointer goes out of scope, the mutex is unlocked and the physics world
237 * @return the scoped accessor
239 ScopedPhysicsAccessorPtr GetPhysicsAccessor();
242 * @brief Create a layer & debug renderer.
245 * The debug renderer may utilize the debug features of the native physics
248 * @param[in] window The window to draw in (requires camera)
249 * @return The debug layer
251 Dali::Layer CreateDebugLayer(Dali::Window window);
254 * @brief Converts a point in RootActor local coords (e.g. gesture)
255 * into physics space coords.
258 * @param vector The point to convert
259 * @return The converted point
261 Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector) const;
264 * @brief Convert a rotation in DALi coordinate system into physics space.
267 * @param[in] rotation The rotation to convert
268 * @return the converted rotation.
270 Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation) const;
273 * @brief Converts a point in physics space coords into RootActor local coords.
276 * @param vector The point to convert
277 * @return The converted point
279 Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector) const;
282 * @brief Convert a rotation in physics coordinate system into DALi space.
285 * @param[in] rotation The rotation to convert
286 * @return the converted rotation.
288 Dali::Quaternion TranslateFromPhysicsSpace(Dali::Quaternion rotation) const;
291 * @brief Converts a vector (not a point) in DALi space into physics space.
294 * @param vector The vector to convert
295 * @return The converted vector
297 Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const;
300 * @brief Converts a vector (not a point) in physics space to DALi space.
303 * @param vector The vector to convert
304 * @return The converted vector
306 Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const;
309 * @brief Set up the transform from world space to physics space.
312 * @param[in] transform The transform matrix for DALi to Physics world space
313 * @param[in] size The size of the layer the physics actors will be drawn in
315 void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size);
318 * @brief Set the integration state.
321 * If it's turned off, physics will be paused.
322 * @note This is ON by default
323 * @param[in] state the new integration state
325 void SetIntegrationState(IntegrationState state);
328 * @brief Get the integration state.
331 * @return the new integration state
333 IntegrationState GetIntegrationState() const;
336 * @brief Set the debug state.
339 * If debug is turned on, use the physics engine
340 * debug to show wireframes in a layer above the root actor.
341 * @note This is OFF by default
342 * @param[in] state the new debug state
344 void SetDebugState(DebugState state);
347 * @brief Get the debug state.
350 * @return the new debug state
352 DebugState GetDebugState() const;
355 * @brief Add an actor / body pair.
356 * @pre It's expected that the client has added the body to the physics world.
358 * The adaptor does not "take ownership" of the actor or the physics body.
360 * @param[in] actor The actor used for rendering the physics object
361 * @param[in] body The physics object
362 * @return a handle to the actor / body pair.
364 PhysicsActor AddActorBody(Dali::Actor actor, Dali::Any body);
367 * @brief Remove the actor / body.
369 * This will unparent the actor from the root actor and disassociate it from
372 * It is the responsibility of the client to remove the body from the physics world
373 * and destroy it at an appropriate time. Create a scoped accessor to ensure
374 * that the integration step isn't being run when doing so.
376 * If the root actor is holding the last reference to the actor, it will be
377 * destroyed automatically, otherwise it is the responsibility of the client to
378 * dereference the actor.
381 * @param[in] physicsActor The actor / body pair to remove.
383 void RemoveActorBody(PhysicsActor physicsActor);
386 * @brief Get the physics actor associated with the given body.
389 * @param[in] body The physics body
390 * @return the associated physics actor
392 PhysicsActor GetPhysicsActor(Dali::Any body) const;
395 * @brief Get the root actor (which holds all the actor/body pairs).
398 * @return the root actor.
400 Dali::Actor GetRootActor() const;
403 * @brief Convert DALi touch point into a picking ray in the physics world.
405 * These can then be used to hit test the PhysicsWorld
408 * @param[in] origin The origin in DALi world space
409 * @param[in] direction The direction of the picking ray
410 * @param[out] rayFromWorld The origin in physics world space
411 * @param[out] rayToWorld A point along the direction on the far side of the physics world
414 * OnTouched(Dali::Actor actor, Dali::TouchEvent& touch)
417 * Vector3 origin, direction;
418 * Dali::HitTestAlgorithm::BuildPickingRay(renderTask, touch.GetScreenPosition(0), origin, direction);
419 * btVector3 rayFromWorld, rayToWorld;
420 * physicsAdaptor.BuildPickingRay(origin, direction, rayFromWorld, rayToWorld);
421 * auto scopedAccessor = physicsAdaptor.GetPhysicsAccessor();
422 * Dali::Any nativeFilter;
423 * body = scopedAccessor->Get().HitTest(rayFromWorld, rayToWorld, nativeFilter, ..);
426 void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld);
429 * @brief Project a point from the origin (in DALi space) a distance along
430 * the direction vector (in DALi space), and return the projected
431 * point in Physics space.
434 * @param[in] origin Origin in DALi world space
435 * @param[in] direction Direction in DALi world space
436 * @param[in] distance Distance along the direction vector
437 * @return the projected point, converted to the Physics space.
439 Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance);
442 * @brief Queue a function to be executed before the physics integration in the update thread.
445 * Multiple functions can be queued up. They are executed in the update frame
446 * callback when the next sync point is seen, so CreateSyncPoint() should be called
447 * afterwards for this to be executed.
449 * @param[in] function to execute. This can be any method, and it can work fine with
450 * physics bodies etc, but it must not be used with DALI event side objects, as this
451 * will very likely cause the update thread to crash.
453 void Queue(std::function<void(void)> function);
456 * @brief Create a sync point for queued functions.
459 * Ensures that any previously queued functions are processed
460 * in the Update::FrameCallback during the same frame as other
461 * DALi properties set during this event handler invocation.
463 * boxActor = Actor::New();
464 * //... Create box actor renderer ...
465 * btRigidBodyConstructionInfo info;
466 * //... set construction properties
467 * boxBody = new btRigidBody(info);
468 * auto boxPhysicsActor = physicsAdaptor.AddActorBody(boxActor, boxBody);
469 * boxActor.SetProperty(Actor::Property::VISIBLE, true);
470 * boxActor.SetProperty(Actor::Property::OPACITY, 0.5f);
471 * physicsAdaptor.Queue([boxBody](){ boxBody->activate(true);});
472 * btVector3 impulse(4, 5, 6);
473 * btVector3 position();
474 * physicsAdaptor.Queue([boxBody](){ boxBody->applyImpulse(impulse, position);});
475 * physicsAdaptor.CreateSyncPoint();
477 * Ensures that the box has both render properties and physics properties applied
478 * during the same frame.
480 void CreateSyncPoint();
482 public: // Not intended for developer use
485 * @brief This constructor is used by PhysicsAdaptor::New() methods.
488 * @param[in] impl A pointer to a newly allocated Dali resource.
489 * @note Not intended for application developers
491 explicit DALI_INTERNAL PhysicsAdaptor(Internal::PhysicsAdaptor* impl);
495 } // namespace Dali::Toolkit::Physics
497 #endif //DALI_TOOLKIT_PHYSICS_ADAPTOR_H