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/physics-world-impl.h>
23 #include <dali/dali.h>
24 #include <dali/devel-api/common/stage-devel.h>
25 #include <dali/devel-api/update/frame-callback-interface.h>
27 thread_local int gLocked{0};
29 namespace Dali::Toolkit::Physics::Internal
32 * FrameCallback implementation. Will run the OnUpdate method.
34 class FrameCallback : public Dali::FrameCallbackInterface
40 explicit FrameCallback(PhysicsWorld& physicsWorld)
41 : mPhysicsWorld(physicsWorld)
48 * @param[in] updateProxy Used to set world matrix and size
49 * @param[in] elapsedSeconds Time since last frame
50 * @return Whether we should keep rendering.
52 bool Update(Dali::UpdateProxy& updateProxy, float elapsedSeconds) override
54 return mPhysicsWorld.OnUpdate(updateProxy, elapsedSeconds);
57 private: // Member variables
58 PhysicsWorld& mPhysicsWorld;
61 PhysicsWorld::PhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
62 : mUpdateCallback(updateCallback),
67 void PhysicsWorld::Initialize()
69 // Call derived class's initializer
72 // Automatically start the frame callback. This means everything should
73 // be accessed with a mutex lock, which is automatically locked when
74 // ScopedAccessor is used.
75 mFrameCallback = std::make_unique<FrameCallback>(*this);
76 Dali::DevelStage::AddFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback, mRootActor);
77 Dali::Stage::GetCurrent().KeepRendering(30); // @todo Remove!
80 PhysicsWorld::~PhysicsWorld()
82 // Derived class's destructor should clean down physics objects under mutex lock
83 // On completion, can remove the callback.
85 Dali::DevelStage::RemoveFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback);
88 bool PhysicsWorld::OnUpdate(Dali::UpdateProxy& updateProxy, float elapsedSeconds)
90 ScopedLock lock(*this);
92 // Process command queue
93 if(mNotifySyncPoint != Dali::UpdateProxy::INVALID_SYNC &&
94 mNotifySyncPoint == updateProxy.PopSyncPoint())
96 while(!commandQueue.empty())
98 commandQueue.front()(); // Execute the queued methods
102 mNotifySyncPoint = Dali::UpdateProxy::INVALID_SYNC;
105 // Perform as many integration steps as needed to handle elapsed time
106 static float frameTime = 0;
107 frameTime += elapsedSeconds;
110 Integrate(mPhysicsTimeStep);
111 frameTime -= mPhysicsTimeStep;
112 } while(frameTime > 0);
114 // Update the corresponding actors to their physics spaces
117 Dali::CallbackBase::Execute(*mUpdateCallback, &updateProxy); // Don't care about actor update return
120 // @todo Check physics world to see if everything is at rest
124 void PhysicsWorld::SetTimestep(float timeStep)
126 mPhysicsTimeStep = timeStep;
129 float PhysicsWorld::GetTimestep()
131 return mPhysicsTimeStep;
137 void PhysicsWorld::Lock()
139 //@todo Could replace the mutex with an atomic flag, if it's not set,
140 // the queue and integration step could be skipped
151 void PhysicsWorld::Unlock()
157 void PhysicsWorld::Queue(std::function<void(void)> function)
159 ScopedLock lock(*this);
160 commandQueue.push(function);
163 void PhysicsWorld::CreateSyncPoint()
165 mNotifySyncPoint = Dali::DevelStage::NotifyFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback);
168 void PhysicsWorld::SetIntegrationState(Physics::PhysicsAdaptor::IntegrationState state)
170 mPhysicsIntegrateState = state;
173 Physics::PhysicsAdaptor::IntegrationState PhysicsWorld::GetIntegrationState()
175 return mPhysicsIntegrateState;
178 void PhysicsWorld::SetDebugState(Physics::PhysicsAdaptor::DebugState state)
180 mPhysicsDebugState = state;
183 Physics::PhysicsAdaptor::DebugState PhysicsWorld::GetDebugState()
185 return mPhysicsDebugState;
188 } // namespace Dali::Toolkit::Physics::Internal