[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-physics / internal / bullet-impl / bullet-physics-world-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-world-impl.h>
19
20 // External Headers
21 #include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h>
22 #include <btBulletCollisionCommon.h>
23 #include <memory>
24
25 // Internal Headers
26 #include <dali/dali.h>
27 #include <dali/devel-api/common/stage-devel.h>
28 #include <dali/devel-api/update/frame-callback-interface.h>
29
30 namespace Dali::Toolkit::Physics::Internal
31 {
32 std::unique_ptr<PhysicsWorld> BulletPhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
33 {
34   std::unique_ptr<BulletPhysicsWorld> world = std::make_unique<BulletPhysicsWorld>(rootActor, updateCallback);
35   world->Initialize();
36   return world;
37 }
38
39 BulletPhysicsWorld::BulletPhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
40 : PhysicsWorld(rootActor, updateCallback)
41 {
42 }
43
44 void BulletPhysicsWorld::OnInitialize(/*void* dynamicsWorld*/)
45 {
46   // @todo Should enable developer to supply their own created DynamicsWorld.
47
48   mCollisionConfiguration = new btDefaultCollisionConfiguration();
49   mDispatcher             = new btCollisionDispatcher(mCollisionConfiguration);
50   mBroadphase             = new btDbvtBroadphase();
51   mSolver                 = new btSequentialImpulseConstraintSolver;
52   mDynamicsWorld          = new btDiscreteDynamicsWorld(mDispatcher, mBroadphase, mSolver, mCollisionConfiguration);
53 }
54
55 BulletPhysicsWorld::~BulletPhysicsWorld()
56 {
57   Lock();
58
59   if(mDynamicsWorld)
60   {
61     int i;
62     for(i = mDynamicsWorld->getNumConstraints() - 1; i >= 0; i--)
63     {
64       mDynamicsWorld->removeConstraint(mDynamicsWorld->getConstraint(i));
65     }
66     for(i = mDynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
67     {
68       btCollisionObject* obj  = mDynamicsWorld->getCollisionObjectArray()[i];
69       btRigidBody*       body = btRigidBody::upcast(obj);
70       if(body && body->getMotionState())
71       {
72         delete body->getMotionState();
73       }
74       mDynamicsWorld->removeCollisionObject(obj);
75       delete obj;
76     }
77   }
78
79   // @todo Should clear down known collision shapes
80
81   delete mDynamicsWorld;
82   delete mSolver;
83   delete mBroadphase;
84   delete mDispatcher;
85   delete mCollisionConfiguration;
86
87   Unlock();
88 }
89
90 Dali::Any BulletPhysicsWorld::GetNative()
91 {
92   return mDynamicsWorld;
93 }
94
95 void BulletPhysicsWorld::Integrate(float timestep)
96 {
97   if(mPhysicsIntegrateState == Physics::PhysicsAdaptor::IntegrationState::ON)
98   {
99     mDynamicsWorld->stepSimulation(timestep);
100   }
101   if(mDynamicsWorld->getDebugDrawer() && mPhysicsDebugState == Physics::PhysicsAdaptor::DebugState::ON)
102   {
103     mDynamicsWorld->debugDrawWorld();
104   }
105 }
106
107 inline btVector3 ConvertVector(Dali::Vector3 vector)
108 {
109   return btVector3(vector.x, vector.y, vector.z);
110 }
111
112 Dali::Any BulletPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera)
113 {
114   btRigidBody* hitBody{nullptr};
115
116   btVector3                                  origin = ConvertVector(rayFromWorld);
117   btVector3                                  end    = ConvertVector(rayToWorld);
118   btCollisionWorld::ClosestRayResultCallback rayResultCallback(origin, end);
119   rayResultCallback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest;
120
121   mDynamicsWorld->rayTest(origin, end, rayResultCallback);
122   if(rayResultCallback.hasHit())
123   {
124     auto         pickPos = rayResultCallback.m_hitPointWorld;
125     btRigidBody* body    = (btRigidBody*)btRigidBody::upcast(rayResultCallback.m_collisionObject);
126     if(body)
127     {
128       if(!(body->isStaticObject() || body->isKinematicObject()))
129       {
130         hitBody            = body; // Found a dynamic body.
131         distanceFromCamera = (pickPos - origin).length();
132
133         btVector3 pivot = body->getCenterOfMassTransform().inverse() * pickPos;
134         localPivot.x    = pivot.x();
135         localPivot.y    = pivot.y();
136         localPivot.z    = pivot.z();
137       }
138     }
139   }
140   Dali::Any bodyPtr;
141   if(hitBody)
142   {
143     bodyPtr = hitBody;
144   }
145
146   return bodyPtr;
147 }
148
149 } // namespace Dali::Toolkit::Physics::Internal