[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-physics / internal / chipmunk-impl / chipmunk-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/chipmunk-impl/chipmunk-physics-world-impl.h>
19
20 // External Headers
21
22 // Internal Headers
23 #include <dali/dali.h>
24 #include <dali/devel-api/common/stage-devel.h>
25 #include <dali/devel-api/update/frame-callback-interface.h>
26
27 namespace
28 {
29 inline cpVect ConvertVector(Dali::Vector3 vector)
30 {
31   return cpv(vector.x, vector.y);
32 }
33
34 static void ShapeFreeWrap(cpSpace* space, cpShape* shape, void* unused)
35 {
36   cpSpaceRemoveShape(space, shape);
37   cpShapeFree(shape);
38 }
39
40 static void PostShapeFree(cpShape* shape, cpSpace* space)
41 {
42   cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ShapeFreeWrap, shape, NULL);
43 }
44
45 static void ConstraintFreeWrap(cpSpace* space, cpConstraint* constraint, void* unused)
46 {
47   cpSpaceRemoveConstraint(space, constraint);
48   cpConstraintFree(constraint);
49 }
50
51 static void PostConstraintFree(cpConstraint* constraint, cpSpace* space)
52 {
53   cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ConstraintFreeWrap, constraint, NULL);
54 }
55
56 static void BodyFreeWrap(cpSpace* space, cpBody* body, void* unused)
57 {
58   cpSpaceRemoveBody(space, body);
59   cpBodyFree(body);
60 }
61
62 static void PostBodyFree(cpBody* body, cpSpace* space)
63 {
64   cpSpaceAddPostStepCallback(space, (cpPostStepFunc)BodyFreeWrap, body, NULL);
65 }
66 } // namespace
67
68 namespace Dali::Toolkit::Physics::Internal
69 {
70 std::unique_ptr<PhysicsWorld> ChipmunkPhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
71 {
72   std::unique_ptr<ChipmunkPhysicsWorld> world = std::make_unique<ChipmunkPhysicsWorld>(rootActor, updateCallback);
73   world->Initialize();
74   return world;
75 }
76
77 ChipmunkPhysicsWorld::ChipmunkPhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
78 : PhysicsWorld(rootActor, updateCallback)
79 {
80 }
81
82 void ChipmunkPhysicsWorld::OnInitialize(/*void* dynamicsWorld*/)
83 {
84   // @todo Should enable developer to optionally supply their own created cpSpace.
85   mSpace = cpSpaceNew();
86   cpSpaceSetIterations(mSpace, 30);
87   cpSpaceSetSleepTimeThreshold(mSpace, 0.5f);
88   cpSpaceSetGravity(mSpace, cpv(0, -200));
89 }
90
91 ChipmunkPhysicsWorld::~ChipmunkPhysicsWorld()
92 {
93   Lock();
94   if(mSpace)
95   {
96     cpSpaceEachShape(mSpace, (cpSpaceShapeIteratorFunc)PostShapeFree, mSpace);
97     cpSpaceEachConstraint(mSpace, (cpSpaceConstraintIteratorFunc)PostConstraintFree, mSpace);
98     cpSpaceEachBody(mSpace, (cpSpaceBodyIteratorFunc)PostBodyFree, mSpace);
99     cpSpaceFree(mSpace);
100     mSpace = nullptr;
101   }
102   Unlock();
103 }
104
105 Dali::Any ChipmunkPhysicsWorld::GetNative()
106 {
107   return mSpace;
108 }
109
110 void ChipmunkPhysicsWorld::Integrate(float timestep)
111 {
112   if(mPhysicsIntegrateState == Physics::PhysicsAdaptor::IntegrationState::ON)
113   {
114     cpSpaceStep(mSpace, timestep);
115   }
116
117   if(mPhysicsDebugState == Physics::PhysicsAdaptor::DebugState::ON)
118   {
119     if(mDebugRenderer)
120     {
121       cpSpaceDebugDraw(mSpace, const_cast<cpSpaceDebugDrawOptions*>(&mDebugRenderer->GetDebugDrawOptions()));
122     }
123   }
124 }
125
126 Dali::Any ChipmunkPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera)
127 {
128   cpVect           spacePosition = cpv(rayFromWorld.x, rayFromWorld.y);
129   cpFloat          radius        = 5.0f;
130   cpPointQueryInfo info          = {0};
131   cpShapeFilter    filter        = nativeFilter.Get<cpShapeFilter>();
132   cpShape*         shape         = cpSpacePointQueryNearest(mSpace, spacePosition, radius, filter, &info);
133   cpBody*          hitBody{nullptr};
134
135   if(shape && cpBodyGetMass(cpShapeGetBody(shape)) < INFINITY)
136   {
137     // Use the closest point on the surface if the click is outside the shape.
138     cpVect nearest = (info.distance > 0.0f ? info.point : spacePosition);
139     hitBody        = cpShapeGetBody(shape);
140     cpVect local   = cpBodyWorldToLocal(hitBody, nearest);
141     localPivot.x   = local.x;
142     localPivot.y   = local.y;
143     localPivot.z   = 0.0;
144   }
145
146   Dali::Any bodyPtr;
147   // Only set non-null ptr into bodyPtr, leave empty if null.
148   if(hitBody)
149   {
150     bodyPtr = hitBody;
151   }
152   return bodyPtr;
153 }
154
155 } // namespace Dali::Toolkit::Physics::Internal