[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-physics / internal / bullet-impl / bullet-physics-adaptor-impl.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // Class Header
18 #include <dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.h>
19
20 // External Headers
21 #include <btBulletDynamicsCommon.h>
22 #include <utility>
23
24 // Internal Headers
25 #include <dali-physics/internal/bullet-impl/bullet-physics-world-impl.h>
26 #include <dali/dali.h>
27 #include <dali/devel-api/threading/mutex.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/public-api/actors/drawable-actor.h>
30
31 namespace
32 {
33 #if defined(DEBUG_ENABLED)
34 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_PHYSICS");
35 #endif
36
37 } // namespace
38
39 namespace Dali::Toolkit::Physics::Internal
40 {
41 PhysicsAdaptorPtr CreateNewPhysicsAdaptor(const Dali::Matrix& transform, Uint16Pair worldSize)
42 {
43   PhysicsAdaptorPtr adaptor(new BulletPhysicsAdaptor());
44   adaptor->Initialize(transform, worldSize);
45   return adaptor;
46 }
47
48 BulletPhysicsAdaptor::BulletPhysicsAdaptor()
49 : PhysicsAdaptor()
50 {
51 }
52
53 BulletPhysicsAdaptor::~BulletPhysicsAdaptor()
54 {
55   // @todo Ensure physics bodies don't leak
56 }
57
58 void BulletPhysicsAdaptor::OnInitialize(const Dali::Matrix& transform, Uint16Pair worldSize)
59 {
60   mTransform        = transform;
61   mInverseTransform = transform;
62   mInverseTransform.Invert();
63   mSize = worldSize;
64
65   mPhysicsWorld = BulletPhysicsWorld::New(mRootActor,
66                                           Dali::MakeCallback(mSlotDelegate.GetSlot(),
67                                                              &PhysicsAdaptor::OnUpdateActors));
68 }
69
70 Layer BulletPhysicsAdaptor::CreateDebugLayer(Dali::Window window)
71 {
72   Layer debugLayer;
73
74   auto renderTaskList = window.GetRenderTaskList();
75   auto renderTask     = renderTaskList.GetTask(0);
76   auto windowSize     = window.GetSize();
77
78   debugLayer                                 = Layer::New();
79   debugLayer[Actor::Property::NAME]          = "PhysicsDebugLayer";
80   debugLayer[Actor::Property::ANCHOR_POINT]  = Dali::AnchorPoint::CENTER;
81   debugLayer[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
82
83   Constraint positionConstraint = Constraint::New<Vector3>(debugLayer, Actor::Property::POSITION, EqualToConstraint());
84   positionConstraint.AddSource(Source(mRootActor, Actor::Property::POSITION));
85   positionConstraint.Apply();
86   Constraint sizeConstraint = Constraint::New<Vector2>(debugLayer, Actor::Property::SIZE, EqualToConstraint());
87   sizeConstraint.AddSource(Source(mRootActor, Actor::Property::SIZE));
88   sizeConstraint.Apply();
89
90   mDebugRenderer                              = PhysicsDebugRenderer::New(windowSize.GetWidth(), windowSize.GetHeight(), renderTask.GetCameraActor(), this);
91   mDebugActor                                 = DrawableActor::New(*(mDebugRenderer->GetCallback().get()));
92   mDebugActor[Actor::Property::ANCHOR_POINT]  = Dali::AnchorPoint::CENTER;
93   mDebugActor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
94
95   Constraint sizeConstraint2 = Constraint::New<Vector2>(mDebugActor, Actor::Property::SIZE, EqualToConstraint());
96   sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE));
97   sizeConstraint2.Apply();
98
99   debugLayer.Add(mDebugActor);
100
101   auto bulletWorld = mPhysicsWorld->GetNative().Get<btDiscreteDynamicsWorld*>();
102
103   bulletWorld->setDebugDrawer(mDebugRenderer.get());
104   mDebugRenderer->setDebugMode(btIDebugDraw::DBG_DrawWireframe |
105                                btIDebugDraw::DBG_DrawContactPoints |
106                                btIDebugDraw::DBG_DrawNormals);
107
108   window.Add(debugLayer);
109   return debugLayer;
110 }
111
112 void BulletPhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair worldSize)
113 {
114   mTransform        = transform;
115   mInverseTransform = transform;
116   mInverseTransform.Invert();
117   mSize = worldSize;
118
119   GetRootActor()[Actor::Property::SIZE] = Vector3(worldSize.GetWidth(), worldSize.GetHeight(), 0);
120
121   if(mDebugRenderer)
122   {
123     Actor layer                  = mDebugActor.GetParent();
124     layer[Actor::Property::SIZE] = Vector3(worldSize);
125     mDebugRenderer->UpdateWindowSize(worldSize);
126   }
127 }
128
129 PhysicsActorPtr BulletPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body)
130 {
131   uint32_t     id     = static_cast<uint32_t>(actor.GetProperty<int>(Actor::Property::ID));
132   btRigidBody* btBody = body.Get<btRigidBody*>();
133
134   btBody->setUserIndex(id);
135   mPhysicsActors.insert(std::make_pair(id, PhysicsActor::New(actor, body, *this)));
136   actor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
137   actor[Actor::Property::ANCHOR_POINT]  = Dali::AnchorPoint::CENTER;
138   mRootActor.Add(actor);
139   return mPhysicsActors.at(id);
140 }
141
142 void BulletPhysicsAdaptor::RemoveActorBody(PhysicsActor& physicsActor)
143 {
144   auto iter = mPhysicsActors.find(physicsActor.GetId());
145   if(iter != mPhysicsActors.end())
146   {
147     mPhysicsActors.erase(iter);
148   }
149   Dali::Actor actor = mRootActor.FindChildById(physicsActor.GetId());
150   if(actor)
151   {
152     actor.Unparent();
153   }
154
155   auto         body   = physicsActor.GetBody();
156   btRigidBody* btBody = body.Get<btRigidBody*>();
157   if(btBody)
158   {
159     btBody->setUserIndex(-1);
160   }
161 }
162
163 PhysicsActorPtr BulletPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const
164 {
165   btRigidBody* btBody = body.Get<btRigidBody*>();
166   if(btBody)
167   {
168     int  id   = btBody->getUserIndex();
169     auto iter = mPhysicsActors.find(id);
170     if(iter != mPhysicsActors.end())
171     {
172       return iter->second;
173     }
174   }
175   DALI_LOG_ERROR("Body not found in physics actors");
176   return nullptr;
177 }
178
179 // Convert a position from root actor local space to physics space
180 Vector3 BulletPhysicsAdaptor::TranslateToPhysicsSpace(Vector3 vector) const
181 {
182   Vector4 position = mTransform * Vector4(vector.x, vector.y, vector.z, 1.0f);
183   return Vector3(position);
184 }
185
186 // Convert a position from physics space to root actor local space
187 Vector3 BulletPhysicsAdaptor::TranslateFromPhysicsSpace(Vector3 vector) const
188 {
189   Vector4 position = mInverseTransform * Vector4(vector.x, vector.y, vector.z, 1.0f);
190   return Vector3(position);
191 }
192
193 Quaternion BulletPhysicsAdaptor::TranslateToPhysicsSpace(Quaternion orientation) const
194 {
195   // Naive check for speed. Should pass scale in constructor/transform setter
196
197   if(std::signbit(mTransform.AsFloat()[0])) // mirrored in x
198   {
199     return Quaternion(orientation.mVector.w, orientation.mVector.x, -orientation.mVector.y, -orientation.mVector.z);
200   }
201   else if(std::signbit(mTransform.AsFloat()[5])) // mirrored in y
202   {
203     return Quaternion(orientation.mVector.w, -orientation.mVector.x, orientation.mVector.y, -orientation.mVector.z);
204   }
205   else if(std::signbit(mTransform.AsFloat()[10])) // mirrored in z
206   {
207     return Quaternion(orientation.mVector.w, -orientation.mVector.x, -orientation.mVector.y, orientation.mVector.z);
208   }
209
210   // No mirror, so rotation is invariant.
211   return orientation;
212 }
213
214 Quaternion BulletPhysicsAdaptor::TranslateFromPhysicsSpace(Quaternion orientation) const
215 {
216   // Mirroring conversion is identical in both transforms
217   return TranslateToPhysicsSpace(orientation);
218 }
219
220 // Convert a vector from dali space to physics space
221 Vector3 BulletPhysicsAdaptor::ConvertVectorToPhysicsSpace(Vector3 vector) const
222 {
223   Vector4 otherVector(mTransform * Vector4(vector.x, vector.y, vector.z, 0.0f));
224   return Vector3(otherVector);
225 }
226
227 // Convert a vector from physics space to root actor local space
228 Vector3 BulletPhysicsAdaptor::ConvertVectorFromPhysicsSpace(Vector3 vector) const
229 {
230   Vector4 otherVector(mInverseTransform * Vector4(vector.x, vector.y, vector.z, 0.0f));
231   return Vector3(otherVector);
232 }
233
234 void BulletPhysicsAdaptor::BuildPickingRay(Vector3 origin, Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld)
235 {
236   rayFromWorld = TranslateToPhysicsSpace(origin);
237   rayToWorld   = TranslateToPhysicsSpace(origin + direction * 10000.0f);
238 }
239
240 Vector3 BulletPhysicsAdaptor::ProjectPoint(Vector3 origin, Vector3 direction, float distance)
241 {
242   Vector3 rayFromWorld = TranslateToPhysicsSpace(origin);
243   Vector3 rayToWorld   = TranslateToPhysicsSpace(origin + direction * 10000.0f);
244
245   Vector3 dir = rayToWorld - rayFromWorld;
246   dir.Normalize();
247   dir *= distance;
248   return (rayFromWorld + dir);
249 }
250
251 } // namespace Dali::Toolkit::Physics::Internal