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>
27 #include <dali-toolkit/public-api/dali-toolkit-common.h>
29 namespace Dali::Toolkit::Physics
37 } // namespace Internal
40 * Adaptor to manage access to the physics world and pairing actors and physics
41 * bodies, plus some translation methods to/from the physics space and dali space.
43 * Also manages a debug renderer that may utilize the physics engine debug.
44 * It is up to the developer to retrieve the root actor and parent it into the scene.
46 class DALI_TOOLKIT_API PhysicsAdaptor : public BaseHandle
50 * @brief Enumeration to turn the integration step on or off.
52 enum class IntegrationState
59 * @brief Enumeration to turn the debug rendering on or off
68 * @brief Scoped accessor to the physics world.
71 * Automatically locks the physics world with a mutex to prevent the
72 * integration step from running whilst the developer is accessing
73 * the world, e.g. to add/remove bodies or constraints, or to
76 * When it goes out of scope, the mutex is unlocked, and the integration step
79 struct ScopedPhysicsAccessor
83 * @brief Get a pointer to the native world.
86 * This uses DALi::Any wrapper to ensure that the same interface can be used
87 * for both 2d and 3d physics. It can be cast to the right type using the
88 * following construct:
89 * auto accessor = PhysicsAdaptor.GetPhysicsAccessor();
90 * auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamiscWorld*>();
92 Dali::Any GetNative();
95 * @brief Hit test the physics world and return the nearest body.
98 * @param[in] rayFromWorld The origin in physics world space
99 * @param[in] rayToWorld A point along the direction on the far side of the physics world
100 * @param[out] localPivot The hit point local to the body
101 * @param[out] distanceFromCamera The distance of the pick point from the camera
102 * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body.
104 Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera);
107 ScopedPhysicsAccessor(ScopedPhysicsAccessor&) = delete;
108 const ScopedPhysicsAccessor& operator=(const ScopedPhysicsAccessor&) = delete;
113 * On leaving scope, the mutex is unlocked and the physics integration step
116 ~ScopedPhysicsAccessor();
120 * @brief Private constructor.
122 * It is created by the physics adaptor.
124 ScopedPhysicsAccessor(Internal::PhysicsWorld& world);
125 friend Internal::PhysicsAdaptor;
127 struct Impl; ///< Opaque implementation structure
132 * @brief Creates an uninitalized PhysicsAdaptor, this can be initialized with PhysicsAdaptor::New().
135 * Calling member functions with an uninitialized PhysicsAdaptor handle is not allowed.
142 * This is non-virtual since derived Handle types must not contain data or virtual methods.
148 * @brief Copy Constructor.
151 * @param[in] handle The handle to copy
152 * @note This creates a new handle, but does not create a new implementation object.
154 PhysicsAdaptor(const PhysicsAdaptor& handle);
157 * @brief Move Constructor.
160 * @param[in] handle A reference to the handle to move
162 PhysicsAdaptor(PhysicsAdaptor&& rhs) noexcept;
165 * @brief Assignment operator.
168 * @param[in] handle A reference to the handle to move
169 * @return a reference to this handle
171 PhysicsAdaptor& operator=(const PhysicsAdaptor& handle);
174 * @brief Move Assignment operator.
177 * @param[in] handle A reference to the handle to move
178 * @return a reference to this handle
180 PhysicsAdaptor& operator=(PhysicsAdaptor&& handle) noexcept;
183 * @brief Initialize the physics system.
186 * @param[in] transform The transform matrix for DALi to Physics world space
187 * @param[in] size The size of the layer the physics actors will be drawn in
189 static PhysicsAdaptor New(const Dali::Matrix& transform, Uint16Pair size);
192 * @brief Downcasts a handle to PhysicsAdaptor handle.
194 * If handle points to an PhysicsAdaptor object, the downcast produces valid handle.
195 * If not, the returned handle is left uninitialized.
198 * @param[in] handle to an object
199 * @return handle to a PhysicsAdaptor object or an uninitialized handle
201 static PhysicsAdaptor DownCast(BaseHandle handle);
204 * @brief Set how long the integration should take.
207 * @param[in] timestep The length of time that the physics integration should take.
209 void SetTimestep(float timestep);
212 * @brief Get the current physics integration timestep.
215 * @return the current physics integration timestep
217 float GetTimestep() const;
220 * @brief Type to represent a pointer to a scoped accessor.
224 using ScopedPhysicsAccessorPtr = std::unique_ptr<PhysicsAdaptor::ScopedPhysicsAccessor>;
227 * @brief Returns an accessor to the physics world.
230 * It automatically locks a mutex to prevent the integration step
231 * from running whilst the world is being modified.
233 * When the pointer goes out of scope, the mutex is unlocked and the physics world
235 * @return the scoped accessor
237 ScopedPhysicsAccessorPtr GetPhysicsAccessor();
240 * @brief Create a layer & debug renderer.
243 * The debug renderer may utilize the debug features of the native physics
246 * @param[in] window The window to draw in (requires camera)
247 * @return The debug layer
249 Dali::Layer CreateDebugLayer(Dali::Window window);
252 * @brief Converts a point in RootActor local coords (e.g. gesture)
253 * into physics space coords.
256 * @param vector The point to convert
257 * @return The converted point
259 Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector) const;
262 * @brief Convert a rotation in DALi coordinate system into physics space.
265 * @param[in] rotation The rotation to convert
266 * @return the converted rotation.
268 Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation) const;
271 * @brief Converts a point in physics space coords into RootActor local coords.
274 * @param vector The point to convert
275 * @return The converted point
277 Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector) const;
280 * @brief Convert a rotation in physics coordinate system into DALi space.
283 * @param[in] rotation The rotation to convert
284 * @return the converted rotation.
286 Dali::Quaternion TranslateFromPhysicsSpace(Dali::Quaternion rotation) const;
289 * @brief Converts a vector (not a point) in DALi space into physics space.
292 * @param vector The vector to convert
293 * @return The converted vector
295 Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const;
298 * @brief Converts a vector (not a point) in physics space to DALi space.
301 * @param vector The vector to convert
302 * @return The converted vector
304 Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const;
307 * @brief Set up the transform from world space to physics space.
310 * @param[in] transform The transform matrix for DALi to Physics world space
311 * @param[in] size The size of the layer the physics actors will be drawn in
313 void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size);
316 * @brief Set the integration state.
319 * If it's turned off, physics will be paused.
320 * @note This is ON by default
321 * @param[in] state the new integration state
323 void SetIntegrationState(IntegrationState state);
326 * @brief Get the integration state.
329 * @return the new integration state
331 IntegrationState GetIntegrationState() const;
334 * @brief Set the debug state.
337 * If debug is turned on, use the physics engine
338 * debug to show wireframes in a layer above the root actor.
339 * @note This is OFF by default
340 * @param[in] state the new debug state
342 void SetDebugState(DebugState state);
345 * @brief Get the debug state.
348 * @return the new debug state
350 DebugState GetDebugState() const;
353 * @brief Add an actor / body pair.
354 * @pre It's expected that the client has added the body to the physics world.
356 * The adaptor does not "take ownership" of the actor or the physics body.
358 * @param[in] actor The actor used for rendering the physics object
359 * @param[in] body The physics object
360 * @return a handle to the actor / body pair.
362 PhysicsActor AddActorBody(Dali::Actor actor, Dali::Any body);
365 * @brief Remove the actor / body.
367 * This will unparent the actor from the root actor and disassociate it from
370 * It is the responsibility of the client to remove the body from the physics world
371 * and destroy it at an appropriate time. Create a scoped accessor to ensure
372 * that the integration step isn't being run when doing so.
374 * If the root actor is holding the last reference to the actor, it will be
375 * destroyed automatically, otherwise it is the responsibility of the client to
376 * dereference the actor.
379 * @param[in] physicsActor The actor / body pair to remove.
381 void RemoveActorBody(PhysicsActor physicsActor);
384 * @brief Get the physics actor associated with the given body.
387 * @param[in] body The physics body
388 * @return the associated physics actor
390 PhysicsActor GetPhysicsActor(Dali::Any body) const;
393 * @brief Get the root actor (which holds all the actor/body pairs).
396 * @return the root actor.
398 Dali::Actor GetRootActor() const;
401 * @brief Convert DALi touch point into a picking ray in the physics world.
403 * These can then be used to hit test the PhysicsWorld
406 * @param[in] origin The origin in DALi world space
407 * @param[in] direction The direction of the picking ray
408 * @param[out] rayFromWorld The origin in physics world space
409 * @param[out] rayToWorld A point along the direction on the far side of the physics world
412 * OnTouched(Dali::Actor actor, Dali::TouchEvent& touch)
415 * Vector3 origin, direction;
416 * Dali::HitTestAlgorithm::BuildPickingRay(renderTask, touch.GetScreenPosition(0), origin, direction);
417 * btVector3 rayFromWorld, rayToWorld;
418 * physicsAdaptor.BuildPickingRay(origin, direction, rayFromWorld, rayToWorld);
419 * auto scopedAccessor = physicsAdaptor.GetPhysicsAccessor();
420 * body = scopedAccessor->Get().HitTest(rayFromWorld, rayToWorld, ..);
423 void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld);
426 * @brief Project a point from the origin (in DALi space) a distance along
427 * the direction vector (in DALi space), and return the projected
428 * point in Physics space.
431 * @param[in] origin Origin in DALi world space
432 * @param[in] direction Direction in DALi world space
433 * @param[in] distance Distance along the direction vector
434 * @return the projected point, converted to the Physics space.
436 Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance);
439 * @brief Queue a function to be executed before the physics integration in the update thread.
442 * Multiple functions can be queued up. They are executed in the update frame
443 * callback when the next sync point is seen, so CreateSyncPoint() should be called
444 * afterwards for this to be executed.
446 * @param[in] function to execute. This can be any method, and it can work fine with
447 * physics bodies etc, but it must not be used with DALI event side objects, as this
448 * will very likely cause the update thread to crash.
450 void Queue(std::function<void(void)> function);
453 * @brief Create a sync point for queued functions.
456 * Ensures that any previously queued functions are processed
457 * in the Update::FrameCallback during the same frame as other
458 * DALi properties set during this event handler invocation.
460 * boxActor = Actor::New();
461 * //... Create box actor renderer ...
462 * btRigidBodyConstructionInfo info;
463 * //... set construction properties
464 * boxBody = new btRigidBody(info);
465 * auto boxPhysicsActor = physicsAdaptor.AddActorBody(boxActor, boxBody);
466 * boxActor.SetProperty(Actor::Property::VISIBLE, true);
467 * boxActor.SetProperty(Actor::Property::OPACITY, 0.5f);
468 * physicsAdaptor.Queue([boxBody](){ boxBody->activate(true);});
469 * btVector3 impulse(4, 5, 6);
470 * btVector3 position();
471 * physicsAdaptor.Queue([boxBody](){ boxBody->applyImpulse(impulse, position);});
472 * physicsAdaptor.CreateSyncPoint();
474 * Ensures that the box has both render properties and physics properties applied
475 * during the same frame.
477 void CreateSyncPoint();
479 public: // Not intended for developer use
482 * @brief This constructor is used by PhysicsAdaptor::New() methods.
485 * @param[in] impl A pointer to a newly allocated Dali resource.
486 * @note Not intended for application developers
488 explicit DALI_INTERNAL PhysicsAdaptor(Internal::PhysicsAdaptor* impl);
492 } // namespace Dali::Toolkit::Physics
494 #endif //DALI_TOOLKIT_PHYSICS_ADAPTOR_H