Adding chipmunk implementation for physics adaptor
[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 #define GRABBABLE_MASK_BIT (1u << 31)
30 cpShapeFilter GRAB_FILTER = {CP_NO_GROUP, GRABBABLE_MASK_BIT, GRABBABLE_MASK_BIT};
31
32 inline cpVect ConvertVector(Dali::Vector3 vector)
33 {
34   return cpv(vector.x, vector.y);
35 }
36
37 static void ShapeFreeWrap(cpSpace* space, cpShape* shape, void* unused)
38 {
39   cpSpaceRemoveShape(space, shape);
40   cpShapeFree(shape);
41 }
42
43 static void PostShapeFree(cpShape* shape, cpSpace* space)
44 {
45   cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ShapeFreeWrap, shape, NULL);
46 }
47
48 static void ConstraintFreeWrap(cpSpace* space, cpConstraint* constraint, void* unused)
49 {
50   cpSpaceRemoveConstraint(space, constraint);
51   cpConstraintFree(constraint);
52 }
53
54 static void PostConstraintFree(cpConstraint* constraint, cpSpace* space)
55 {
56   cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ConstraintFreeWrap, constraint, NULL);
57 }
58
59 static void BodyFreeWrap(cpSpace* space, cpBody* body, void* unused)
60 {
61   cpSpaceRemoveBody(space, body);
62   cpBodyFree(body);
63 }
64
65 static void PostBodyFree(cpBody* body, cpSpace* space)
66 {
67   cpSpaceAddPostStepCallback(space, (cpPostStepFunc)BodyFreeWrap, body, NULL);
68 }
69 } // namespace
70
71 namespace Dali::Toolkit::Physics::Internal
72 {
73 std::unique_ptr<PhysicsWorld> ChipmunkPhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
74 {
75   std::unique_ptr<ChipmunkPhysicsWorld> world = std::make_unique<ChipmunkPhysicsWorld>(rootActor, updateCallback);
76   world->Initialize();
77   return world;
78 }
79
80 ChipmunkPhysicsWorld::ChipmunkPhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
81 : PhysicsWorld(rootActor, updateCallback)
82 {
83 }
84
85 void ChipmunkPhysicsWorld::OnInitialize(/*void* dynamicsWorld*/)
86 {
87   // @todo Should enable developer to optionally supply their own created cpSpace.
88   mSpace = cpSpaceNew();
89   cpSpaceSetIterations(mSpace, 30);
90   cpSpaceSetSleepTimeThreshold(mSpace, 0.5f);
91   cpSpaceSetGravity(mSpace, cpv(0, -200));
92 }
93
94 ChipmunkPhysicsWorld::~ChipmunkPhysicsWorld()
95 {
96   Dali::Mutex::ScopedLock lock(mMutex);
97   if(mSpace)
98   {
99     cpSpaceEachShape(mSpace, (cpSpaceShapeIteratorFunc)PostShapeFree, mSpace);
100     cpSpaceEachConstraint(mSpace, (cpSpaceConstraintIteratorFunc)PostConstraintFree, mSpace);
101     cpSpaceEachBody(mSpace, (cpSpaceBodyIteratorFunc)PostBodyFree, mSpace);
102     cpSpaceFree(mSpace);
103     mSpace = nullptr;
104   }
105 }
106
107 Dali::Any ChipmunkPhysicsWorld::GetNative()
108 {
109   return mSpace;
110 }
111
112 void ChipmunkPhysicsWorld::Integrate(float timestep)
113 {
114   if(mPhysicsIntegrateState == Physics::PhysicsAdaptor::IntegrationState::ON)
115   {
116     cpSpaceStep(mSpace, timestep);
117   }
118 }
119
120 Dali::Any ChipmunkPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera)
121 {
122   cpVect           spacePosition = cpv(rayFromWorld.x, rayFromWorld.y);
123   cpFloat          radius        = 5.0f;
124   cpPointQueryInfo info          = {0};
125   cpShape*         shape         = cpSpacePointQueryNearest(mSpace, spacePosition, radius, GRAB_FILTER, &info);
126   cpBody*          hitBody{nullptr};
127
128   if(shape && cpBodyGetMass(cpShapeGetBody(shape)) < INFINITY)
129   {
130     // Use the closest point on the surface if the click is outside the shape.
131     cpVect nearest = (info.distance > 0.0f ? info.point : spacePosition);
132     hitBody        = cpShapeGetBody(shape);
133     cpVect local   = cpBodyWorldToLocal(hitBody, nearest);
134     localPivot.x   = local.x;
135     localPivot.y   = local.y;
136     localPivot.z   = 0.0;
137   }
138
139   Dali::Any bodyPtr;
140   // Only set non-null ptr into bodyPtr, leave empty if null.
141   if(hitBody)
142   {
143     bodyPtr = hitBody;
144   }
145   return bodyPtr;
146 }
147
148 } // namespace Dali::Toolkit::Physics::Internal