7423edd971c482161982e7910fcee6299dbe1bf2
[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   Dali::Mutex::ScopedLock lock(mMutex);
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 }
103
104 Dali::Any ChipmunkPhysicsWorld::GetNative()
105 {
106   return mSpace;
107 }
108
109 void ChipmunkPhysicsWorld::Integrate(float timestep)
110 {
111   if(mPhysicsIntegrateState == Physics::PhysicsAdaptor::IntegrationState::ON)
112   {
113     cpSpaceStep(mSpace, timestep);
114   }
115
116   if(mPhysicsDebugState == Physics::PhysicsAdaptor::DebugState::ON)
117   {
118     if(mDebugRenderer)
119     {
120       cpSpaceDebugDraw(mSpace, const_cast<cpSpaceDebugDrawOptions*>(&mDebugRenderer->GetDebugDrawOptions()));
121     }
122   }
123 }
124
125 Dali::Any ChipmunkPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera)
126 {
127   cpVect           spacePosition = cpv(rayFromWorld.x, rayFromWorld.y);
128   cpFloat          radius        = 5.0f;
129   cpPointQueryInfo info          = {0};
130   cpShapeFilter    filter        = nativeFilter.Get<cpShapeFilter>();
131   cpShape*         shape         = cpSpacePointQueryNearest(mSpace, spacePosition, radius, filter, &info);
132   cpBody*          hitBody{nullptr};
133
134   if(shape && cpBodyGetMass(cpShapeGetBody(shape)) < INFINITY)
135   {
136     // Use the closest point on the surface if the click is outside the shape.
137     cpVect nearest = (info.distance > 0.0f ? info.point : spacePosition);
138     hitBody        = cpShapeGetBody(shape);
139     cpVect local   = cpBodyWorldToLocal(hitBody, nearest);
140     localPivot.x   = local.x;
141     localPivot.y   = local.y;
142     localPivot.z   = 0.0;
143   }
144
145   Dali::Any bodyPtr;
146   // Only set non-null ptr into bodyPtr, leave empty if null.
147   if(hitBody)
148   {
149     bodyPtr = hitBody;
150   }
151   return bodyPtr;
152 }
153
154 } // namespace Dali::Toolkit::Physics::Internal