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/chipmunk-impl/chipmunk-physics-adaptor-impl.h>
24 #include <dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h>
25 #include <dali/dali.h>
26 #include <dali/integration-api/debug.h>
30 #if defined(DEBUG_ENABLED)
31 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_PHYSICS");
34 inline cpVect ConvertVector(Dali::Vector3 vector)
36 return cpv(vector.x, vector.y);
41 namespace Dali::Toolkit::Physics::Internal
43 PhysicsAdaptorPtr CreateNewPhysicsAdaptor(const Dali::Matrix& transform, Uint16Pair worldSize)
45 PhysicsAdaptorPtr adaptor(new ChipmunkPhysicsAdaptor());
46 adaptor->Initialize(transform, worldSize);
50 ChipmunkPhysicsAdaptor::ChipmunkPhysicsAdaptor()
55 ChipmunkPhysicsAdaptor::~ChipmunkPhysicsAdaptor()
57 // @todo Ensure physics bodies don't leak
60 void ChipmunkPhysicsAdaptor::OnInitialize(const Dali::Matrix& transform, Uint16Pair worldSize)
62 mTransform = transform;
63 mInverseTransform = transform;
64 mInverseTransform.Invert();
67 mPhysicsWorld = ChipmunkPhysicsWorld::New(mRootActor,
68 Dali::MakeCallback(mSlotDelegate.GetSlot(),
69 &PhysicsAdaptor::OnUpdateActors));
72 Layer ChipmunkPhysicsAdaptor::CreateDebugLayer(Dali::Window window)
76 auto renderTaskList = window.GetRenderTaskList();
77 auto renderTask = renderTaskList.GetTask(0);
78 auto windowSize = window.GetSize();
80 debugLayer = Layer::New();
81 debugLayer[Actor::Property::NAME] = "PhysicsDebugLayer";
82 debugLayer[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER;
83 debugLayer[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
85 Constraint positionConstraint = Constraint::New<Vector3>(debugLayer, Actor::Property::POSITION, EqualToConstraint());
86 positionConstraint.AddSource(Source(mRootActor, Actor::Property::POSITION));
87 positionConstraint.Apply();
88 Constraint sizeConstraint = Constraint::New<Vector2>(debugLayer, Actor::Property::SIZE, EqualToConstraint());
89 sizeConstraint.AddSource(Source(mRootActor, Actor::Property::SIZE));
90 sizeConstraint.Apply();
92 auto world = static_cast<ChipmunkPhysicsWorld*>(mPhysicsWorld.get());
94 std::unique_ptr<PhysicsDebugRenderer> debugRenderer = PhysicsDebugRenderer::New(windowSize.GetWidth(), windowSize.GetHeight(), renderTask.GetCameraActor(), this);
96 mDebugActor = DrawableActor::New(*(debugRenderer->GetCallback().get()));
97 world->SetDebugRenderer(debugRenderer.release());
99 mDebugActor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER;
100 mDebugActor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
102 Constraint sizeConstraint2 = Constraint::New<Vector2>(mDebugActor, Actor::Property::SIZE, EqualToConstraint());
103 sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE));
104 sizeConstraint2.Apply();
106 debugLayer.Add(mDebugActor);
108 window.Add(debugLayer);
112 void ChipmunkPhysicsAdaptor::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);
121 auto world = static_cast<ChipmunkPhysicsWorld*>(mPhysicsWorld.get());
122 if(world->HasDebugRenderer())
124 Actor layer = mDebugActor.GetParent();
125 layer[Actor::Property::SIZE] = Vector3(worldSize);
126 world->GetDebugRenderer().UpdateWindowSize(worldSize);
130 PhysicsActorPtr ChipmunkPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body)
132 uint32_t id = static_cast<uint32_t>(actor.GetProperty<int>(Actor::Property::ID));
133 cpBody* cBody = body.Get<cpBody*>();
134 cpBodySetUserData(cBody, this);
136 mPhysicsActors.insert(std::make_pair(id, PhysicsActor::New(actor, body, *this)));
137 actor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
138 actor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER;
139 mRootActor.Add(actor);
140 return mPhysicsActors.at(id);
143 void ChipmunkPhysicsAdaptor::RemoveActorBody(PhysicsActor& physicsActor)
145 auto iter = mPhysicsActors.find(physicsActor.GetId());
146 if(iter != mPhysicsActors.end())
148 mPhysicsActors.erase(iter);
150 Dali::Actor actor = mRootActor.FindChildById(physicsActor.GetId());
155 auto body = physicsActor.GetBody();
156 cpBody* cBody = body.Get<cpBody*>();
159 cpBodySetUserData(cBody, nullptr);
163 PhysicsActorPtr ChipmunkPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const
165 cpBody* cBody = body.Get<cpBody*>();
168 return reinterpret_cast<PhysicsActor*>(cpBodyGetUserData(cBody));
170 DALI_LOG_ERROR("Body not found in physics actors");
174 // Convert a position from root actor local space to physics space
175 Vector3 ChipmunkPhysicsAdaptor::TranslateToPhysicsSpace(Vector3 vector) const
177 Vector4 position = mTransform * Vector4(vector.x, vector.y, vector.z, 1.0f);
178 return Vector3(position);
181 // Convert a position from physics space to root actor local space
182 Vector3 ChipmunkPhysicsAdaptor::TranslateFromPhysicsSpace(Vector3 vector) const
184 Vector4 position = mInverseTransform * Vector4(vector.x, vector.y, vector.z, 1.0f);
185 return Vector3(position);
188 Quaternion ChipmunkPhysicsAdaptor::TranslateToPhysicsSpace(Quaternion orientation) const
190 // Actors face outwards (+ve Z)
191 // In DALi world, +ve angle about +ve Z is clockwise.
192 // But, if physics is mirrored in Y axis, so +ve angle is anti-clockwise.
194 // Compute angle about Z axis
197 orientation.ToAxisAngle(axis, angle);
199 // Check if Transform matrix is mirrored in X xor Y
200 if(std::signbit(mTransform.AsFloat()[0]) ^ std::signbit(mTransform.AsFloat()[5]))
202 return Quaternion(-angle, axis);
205 return Quaternion(angle, axis);
208 Quaternion ChipmunkPhysicsAdaptor::TranslateFromPhysicsSpace(Quaternion orientation) const
210 // Mirroring conversion is identical in both transforms
211 return TranslateToPhysicsSpace(orientation);
214 // Convert a vector from dali space to physics space
215 Vector3 ChipmunkPhysicsAdaptor::ConvertVectorToPhysicsSpace(Vector3 vector) const
217 Vector4 otherVector(mTransform * Vector4(vector.x, vector.y, vector.z, 0.0f));
218 return Vector3(otherVector);
221 // Convert a vector from physics space to root actor local space
222 Vector3 ChipmunkPhysicsAdaptor::ConvertVectorFromPhysicsSpace(Vector3 vector) const
224 Vector4 otherVector(mInverseTransform * Vector4(vector.x, vector.y, vector.z, 0.0f));
225 return Vector3(otherVector);
228 void ChipmunkPhysicsAdaptor::BuildPickingRay(Vector3 origin, Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld)
230 rayFromWorld = TranslateToPhysicsSpace(origin);
231 rayToWorld = TranslateToPhysicsSpace(origin); // rayToWorld is identical - there's no depth
234 Vector3 ChipmunkPhysicsAdaptor::ProjectPoint(Vector3 origin, Vector3 direction, float distance)
236 // Ignore direction & distance.
237 return TranslateToPhysicsSpace(origin);
240 } // namespace Dali::Toolkit::Physics::Internal