Kale
Loading...
Searching...
No Matches
Application.cpp
Go to the documentation of this file.
1/*
2 Copyright 2022 Rishi Challa
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#include "Application.hpp"
18
19#ifdef KALE_VULKAN
21#endif
22
23#ifdef KALE_OPENGL
25#endif
26
28
29#include <exception>
30#include <chrono>
31#include <string>
32
33using namespace Kale;
34
38std::vector<std::function<void()>> Application::nodeSetupFuncs = { PathNode::setup };
39
43std::vector<std::function<void()>> Application::nodeCleanupFuncs = { PathNode::cleanup };
44
49Application::Application(const char* applicationName) noexcept : applicationName(applicationName) {
50 try {
51 console.load(this->applicationName);
52 }
53 catch (const std::exception&) {
54 // We have no way of logging effectively, so we'll just have to exit
55 exit(-1);
56 }
57}
58
63 return window;
64}
65
70std::shared_ptr<Scene> Application::getPresentedScene() noexcept {
71 return presentedScene;
72}
73
77const Window& Application::getWindow() const noexcept {
78 return window;
79}
80
85std::shared_ptr<const Scene> Application::getPresentedScene() const noexcept {
86 return presentedScene;
87}
88
93size_t Application::getNumUpdateThreads() const noexcept {
94 return updateThreads.size();
95}
96
101void Application::presentScene(const std::shared_ptr<Scene>& scene) {
102 sceneToPresent = scene;
103}
104
110void Application::runTaskOnMainThread(std::function<void()> task) {
111 std::lock_guard lock(taskManagerMutex);
112 tasks.push(task);
113}
114
120 return "." + applicationName + "/assets/";
121}
122
127 std::unique_lock lock(threadSyncMutex);
129 renderingFinished = false;
130
131 if (numThreadsUpdated == 0) {
132 updatingFinished = true;
134 renderSyncCondVar.notify_one();
135 }
136
137 threadSyncCondVar.wait(lock, [&]() -> bool { return renderingFinished; });
138}
139
144void Application::update(size_t threadNum) noexcept {
145
146 // Update loop
147 while (window.isOpen()) {
148
149 // Wait until we should update
150 synchronizeUpdate();
151
152 // Perform updating
153 if (presentedScene != nullptr) try {
154 presentedScene->update(threadNum, deltaTime);
155 }
156 catch (const std::exception& e) {
157 console.error("Failed to update presented screen on update thread " + std::to_string(threadNum) + " - " + e.what());
158 }
159 }
160
161 // Avoid the main thread waiting for update threads which are already finished
162 synchronizeUpdate();
163}
164
168void Application::run() noexcept {
169
170 using namespace std::string_literals;
171 using namespace std::chrono_literals;
172
173 // Creates the window
175
176
177#ifdef KALE_VULKAN
178 // Setup Vulkan
180#endif
181
182#ifdef KALE_OPENGL
183 // Setup OpenGL
185#endif
186
187 try {
188 onBegin();
189 }
190 catch (const std::exception& e) {
191 console.error("Failed to call onBegin in application - "s + e.what());
192 }
193
194 // Setup nodes
195 try {
196 for (std::function<void()> setupFunc : nodeSetupFuncs) setupFunc();
197 }
198 catch (const std::exception& e) {
199 console.error("Terminating application due to failure to setup nodes - "s + e.what());
200 return;
201 }
202
203 // Create update threads
204 numThreadsUpdated = std::thread::hardware_concurrency();
205 for (size_t i = 0; i < std::thread::hardware_concurrency(); i++)
206 updateThreads.emplace_back(&Application::update, this, i);
207
208 // Render loop
209 auto previousTime = std::chrono::high_resolution_clock::now();
210 while (window.isOpen()) {
211
212 // Update the window for event polling, etc
213 window.update();
214
215 // Calculate FPS
216 auto currentTime = std::chrono::high_resolution_clock::now();
217 deltaTime = static_cast<float>(std::chrono::duration_cast<std::chrono::microseconds>(currentTime - previousTime).count());
218 previousTime = std::chrono::high_resolution_clock::now();
219
220 // Check if scene has changed prior to updating
221 if (sceneToPresent != nullptr) {
222 try {
223 sceneToPresent->onPresent();
224 if (presentedScene != nullptr) presentedScene->onSceneChange();
226 sceneToPresent = nullptr;
227 }
228 catch (const std::exception& e) {
229 console.error("Failed to present scene - "s + e.what());
230 }
231 }
232
233 // Synchronize with the update threads
234 {
235 std::unique_lock lock(threadSyncMutex);
236 updatingFinished = false;
237 renderingFinished = true;
238 threadSyncCondVar.notify_all();
239 renderSyncCondVar.wait(lock, [&]() -> bool { return updatingFinished; });
240 }
241
242 // Run all tasks required
243 while (!tasks.empty()) try {
244 tasks.front()();
245 tasks.pop();
246 }
247 catch (const std::exception& e) {
248 console.error("Failed to execute task on main thread - "s + e.what());
249 }
250
251 if (presentedScene != nullptr) try {
252 // Update node structures
253 presentedScene->updateNodeStructures();
254 // Render scene
255 presentedScene->render(deltaTime);
256 }
257 catch (const std::exception& e) {
258 console.error("Failed to render presented scene - "s + e.what());
259 }
260 }
261
262 // Wait for threads
263 renderingFinished = true;
264 threadSyncCondVar.notify_all();
265 for (std::thread& thread : updateThreads) thread.join();
266
267 onEnd();
268
269 // Cleanup nodes
270 try {
271 for (std::function<void()> cleanupFunc : nodeCleanupFuncs) cleanupFunc();
272 }
273 catch (const std::exception& e) {
274 console.error("Terminating application due to failure to cleanup nodes - "s + e.what());
275 return;
276 }
277
278#ifdef KALE_VULKAN
279 // Cleanup vulkan now that execution is done
281#endif
282
283#ifdef KALE_OPENGL
284 // Setup OpenGL
286#endif
287}
std::string getAssetFolderPath() const
std::condition_variable threadSyncCondVar
static std::vector< std::function< void()> > nodeCleanupFuncs
std::condition_variable renderSyncCondVar
void runTaskOnMainThread(std::function< void()> task)
std::shared_ptr< Scene > presentedScene
virtual void onBegin()
const std::string applicationName
std::shared_ptr< Scene > sceneToPresent
std::mutex taskManagerMutex
std::list< std::thread > updateThreads
virtual void onEnd()
std::mutex threadSyncMutex
static std::vector< std::function< void()> > nodeSetupFuncs
void presentScene(const std::shared_ptr< Scene > &scene)
size_t getNumUpdateThreads() const noexcept
Application(const char *applicationName) noexcept
void run() noexcept
std::queue< std::function< void()> > tasks
Window & getWindow() noexcept
std::shared_ptr< Scene > getPresentedScene() noexcept
void update(size_t threadNum) noexcept
void load(const std::string &applicationName)
Definition Logger.cpp:52
void error(T msg)
Definition Logger.hpp:198
static void setupCore() noexcept
Definition Core.cpp:42
static void cleanupCore() noexcept
Definition Core.cpp:126
static void setup()
static void cleanup()
static void cleanupCore()
Definition CoreSetup.cpp:68
static void setupCore(std::optional< uint32_t > gpuID=std::optional< uint32_t >())
Definition CoreSetup.cpp:37
bool isOpen() const
void create(const char *title)
Logger console
Definition Logger.hpp:317