2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.h>
21 #include <btBulletDynamicsCommon.h>
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>
33 #if defined(DEBUG_ENABLED)
34 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_PHYSICS");
39 namespace Dali::Toolkit::Physics::Internal
41 PhysicsAdaptorPtr CreateNewPhysicsAdaptor(const Dali::Matrix& transform, Uint16Pair worldSize)
43 PhysicsAdaptorPtr adaptor(new BulletPhysicsAdaptor());
44 adaptor->Initialize(transform, worldSize);
48 BulletPhysicsAdaptor::BulletPhysicsAdaptor()
53 BulletPhysicsAdaptor::~BulletPhysicsAdaptor()
55 // @todo Ensure physics bodies don't leak
58 void BulletPhysicsAdaptor::OnInitialize(const Dali::Matrix& transform, Uint16Pair worldSize)
60 mTransform = transform;
61 mInverseTransform = transform;
62 mInverseTransform.Invert();
65 mPhysicsWorld = BulletPhysicsWorld::New(mRootActor,
66 Dali::MakeCallback(mSlotDelegate.GetSlot(),
67 &PhysicsAdaptor::OnUpdateActors));
70 Layer BulletPhysicsAdaptor::CreateDebugLayer(Dali::Window window)
74 auto renderTaskList = window.GetRenderTaskList();
75 auto renderTask = renderTaskList.GetTask(0);
76 auto windowSize = window.GetSize();
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;
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();
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;
95 Constraint sizeConstraint2 = Constraint::New<Vector2>(mDebugActor, Actor::Property::SIZE, EqualToConstraint());
96 sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE));
97 sizeConstraint2.Apply();
99 debugLayer.Add(mDebugActor);
101 auto bulletWorld = mPhysicsWorld->GetNative().Get<btDiscreteDynamicsWorld*>();
103 bulletWorld->setDebugDrawer(mDebugRenderer.get());
104 mDebugRenderer->setDebugMode(btIDebugDraw::DBG_DrawWireframe |
105 btIDebugDraw::DBG_DrawContactPoints |
106 btIDebugDraw::DBG_DrawNormals);
108 window.Add(debugLayer);
112 void BulletPhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair worldSize)
114 mTransform = transform;
115 mInverseTransform = transform;
116 mInverseTransform.Invert();
119 GetRootActor()[Actor::Property::SIZE] = Vector3(worldSize.GetWidth(), worldSize.GetHeight(), 0);
123 Actor layer = mDebugActor.GetParent();
124 layer[Actor::Property::SIZE] = Vector3(worldSize);
125 mDebugRenderer->UpdateWindowSize(worldSize);
129 PhysicsActorPtr BulletPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body)
131 uint32_t id = static_cast<uint32_t>(actor.GetProperty<int>(Actor::Property::ID));
132 btRigidBody* btBody = body.Get<btRigidBody*>();
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);
142 void BulletPhysicsAdaptor::RemoveActorBody(PhysicsActor& physicsActor)
144 auto iter = mPhysicsActors.find(physicsActor.GetId());
145 if(iter != mPhysicsActors.end())
147 mPhysicsActors.erase(iter);
149 Dali::Actor actor = mRootActor.FindChildById(physicsActor.GetId());
155 auto body = physicsActor.GetBody();
156 btRigidBody* btBody = body.Get<btRigidBody*>();
159 btBody->setUserIndex(-1);
163 PhysicsActorPtr BulletPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const
165 btRigidBody* btBody = body.Get<btRigidBody*>();
168 int id = btBody->getUserIndex();
169 auto iter = mPhysicsActors.find(id);
170 if(iter != mPhysicsActors.end())
175 DALI_LOG_ERROR("Body not found in physics actors");
179 // Convert a position from root actor local space to physics space
180 Vector3 BulletPhysicsAdaptor::TranslateToPhysicsSpace(Vector3 vector) const
182 Vector4 position = mTransform * Vector4(vector.x, vector.y, vector.z, 1.0f);
183 return Vector3(position);
186 // Convert a position from physics space to root actor local space
187 Vector3 BulletPhysicsAdaptor::TranslateFromPhysicsSpace(Vector3 vector) const
189 Vector4 position = mInverseTransform * Vector4(vector.x, vector.y, vector.z, 1.0f);
190 return Vector3(position);
193 Quaternion BulletPhysicsAdaptor::TranslateToPhysicsSpace(Quaternion orientation) const
195 // Naive check for speed. Should pass scale in constructor/transform setter
197 if(std::signbit(mTransform.AsFloat()[0])) // mirrored in x
199 return Quaternion(orientation.mVector.w, orientation.mVector.x, -orientation.mVector.y, -orientation.mVector.z);
201 else if(std::signbit(mTransform.AsFloat()[5])) // mirrored in y
203 return Quaternion(orientation.mVector.w, -orientation.mVector.x, orientation.mVector.y, -orientation.mVector.z);
205 else if(std::signbit(mTransform.AsFloat()[10])) // mirrored in z
207 return Quaternion(orientation.mVector.w, -orientation.mVector.x, -orientation.mVector.y, orientation.mVector.z);
210 // No mirror, so rotation is invariant.
214 Quaternion BulletPhysicsAdaptor::TranslateFromPhysicsSpace(Quaternion orientation) const
216 // Mirroring conversion is identical in both transforms
217 return TranslateToPhysicsSpace(orientation);
220 // Convert a vector from dali space to physics space
221 Vector3 BulletPhysicsAdaptor::ConvertVectorToPhysicsSpace(Vector3 vector) const
223 Vector4 otherVector(mTransform * Vector4(vector.x, vector.y, vector.z, 0.0f));
224 return Vector3(otherVector);
227 // Convert a vector from physics space to root actor local space
228 Vector3 BulletPhysicsAdaptor::ConvertVectorFromPhysicsSpace(Vector3 vector) const
230 Vector4 otherVector(mInverseTransform * Vector4(vector.x, vector.y, vector.z, 0.0f));
231 return Vector3(otherVector);
234 void BulletPhysicsAdaptor::BuildPickingRay(Vector3 origin, Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld)
236 rayFromWorld = TranslateToPhysicsSpace(origin);
237 rayToWorld = TranslateToPhysicsSpace(origin + direction * 10000.0f);
240 Vector3 BulletPhysicsAdaptor::ProjectPoint(Vector3 origin, Vector3 direction, float distance)
242 Vector3 rayFromWorld = TranslateToPhysicsSpace(origin);
243 Vector3 rayToWorld = TranslateToPhysicsSpace(origin + direction * 10000.0f);
245 Vector3 dir = rayToWorld - rayFromWorld;
248 return (rayFromWorld + dir);
251 } // namespace Dali::Toolkit::Physics::Internal