galaxy 1.0.0
Real-Time C++23 Game Programming Framework. Built on data-driven design principles and agile software engineering.
Loading...
Searching...
No Matches
Application.cpp
Go to the documentation of this file.
1
7
8#define BS_THREAD_POOL_NATIVE_EXTENSIONS
9
10#include <format>
11#include <filesystem>
12
13#include <BS_thread_pool.hpp>
14#include <entt/locator/locator.hpp>
15#include <entt/signal/dispatcher.hpp>
16#include <mimalloc.h>
17#include <Raylib.hpp>
18#include <sol/sol.hpp>
19
26#include "galaxy/lua/Lua.hpp"
28#include "galaxy/time/Time.hpp"
29
30#include "Application.hpp"
31
32using namespace std::chrono_literals;
33
34namespace galaxy
35{
36 App::App(const std::string& config_file)
37 {
40 setup_config(config_file);
42 setup_fs();
44 // setup_input();
45 // setup_nuklear();
46 // setup_loader();
47 // setup_meta();
48 // setup_services();
50
51 // Load game assets.
52 // core::entt::locator<core::Loader>::ref().load_all();
53 }
54
56 {
57 // entt::locator<VirtualFileSystem>::reset();
58 // entt::locator<Config>::reset();
59
60 // GALAXY_LOG(GALAXY_INFO, "Application closed.");
61 // entt::locator<BS::priority_thread_pool>::value().wait();
62
63 // entt::locator<Log>::reset();
64 // entt::locator<BS::priority_thread_pool>::reset();
65
66 ray::CloseWindow();
67 }
68
69 void App::load()
70 {
71 // const auto path = Settings::root_dir() / Settings::asset_pack();
72
73 // auto& sm = entt::locator<scene::SceneManager>::value();
74 // sm.load_app(path.string());
75 }
76
77 void App::run()
78 {
79 // https://stackoverflow.com/a/59446610
80 // We dont need 't' or 'alpha/render' sections.
81
82 // auto& window = entt::locator<Window>::value();
83 // auto& scenes = entt::locator<SceneManager>::value();
84
85 // The expression dt/1s simply converts the double-based chrono seconds
86 // into a double so it can participate in the physics computation.
87 constexpr const auto dt = std::chrono::duration<long long, std::ratio<1, 60>> {1};
88 time::dt(dt / 1.0s);
89
90 using clock = std::chrono::steady_clock;
91 using duration = decltype(clock::duration {} + dt);
92 using time_point = std::chrono::time_point<clock, duration>;
93
94 duration accum = 0s;
95 time_point prev = clock::now();
96 time_point now = clock::now();
97
98 auto updates = 0u;
99 auto frames = 0u;
100 duration perf = 0s;
101
102 if (!m_update)
103 {
104 m_update = [&](App* app) {
105 ray::PollInputEvents();
106 // scenes.update();
107 };
108 }
109
110 if (!m_render)
111 {
112 m_render = [&](App* app) {
113 ray::BeginDrawing();
114 ray::ClearBackground(RAY_WHITE);
115
116 // scenes.render();
117 // window.swap();
118 ray::EndDrawing();
119 ray::SwapScreenBuffer();
120 };
121 }
122
123 while (!ray::WindowShouldClose())
124 {
125 now = clock::now();
126 auto elapsed = now - prev;
127
128 // 250ms is the limit put in place on the frame time to cope with the spiral of death.
129 // It doesn't have to be 250ms exactly but it should be sufficiently high enough to deal with spikes in load.
130 if (elapsed > 250ms)
131 {
132 elapsed = 250ms;
133 }
134
135 prev = now;
136 accum += elapsed;
137
138 while (accum >= dt)
139 {
140 perf += dt;
141 accum -= dt;
142
143 m_update(this);
144
145 updates++;
146 }
147
148 m_render(this);
149
150 frames++;
151
152 if (perf >= 1s)
153 {
154 ray::SetWindowTitle(std::format(" | UPS: {0}, FPS: {1}", updates, frames).c_str());
155
156 frames = 0;
157 updates = 0;
158 perf = 0s;
159 }
160 }
161 }
162
164 {
165 m_update = std::move(update);
166 }
167
169 {
170 m_render = std::move(render);
171 }
172
174 {
175 // Configure threadpool.
176
177 // Calc threads.
178 // We optimize for 6: 1 for audio, 1 for main, 4 for tasks.
179 auto system_cores = std::thread::hardware_concurrency();
180 if (system_cores < 6)
181 {
182 system_cores = std::thread::hardware_concurrency();
183 }
184
185 // Check for highest available priority.
186 BS::set_os_process_priority(BS::os_process_priority::high);
187 entt::locator<BS::priority_thread_pool>::emplace(system_cores, [](const std::size_t idx) {
188 BS::this_thread::set_os_thread_priority(BS::os_thread_priority::highest);
189 });
190 }
191
193 {
194 platform::configure_terminal();
195 if (!std::filesystem::exists(Settings::log_dir()))
196 {
197 std::filesystem::create_directory(Settings::log_dir());
198 }
199 entt::locator<Log>::emplace();
200
201 const auto path = std::format("{0}{1}{2}", Settings::log_dir(), std::format("{0:%d-%m-%Y-[%H-%M]}", time::now()), ".log");
203
205 GALAXY_LOG(GALAXY_INFO, "App started.");
206 }
207
208 void App::setup_config(std::string_view config_file)
209 {
210 auto& config = entt::locator<Config>::emplace(config_file);
213 }
214
219
221 {
222 entt::locator<VirtualFileSystem>::emplace();
223 }
224
226 {
227 if (Settings::vsync())
228 {
229 ray::SetConfigFlags(ray::FLAG_VSYNC_HINT);
230 }
231
233 {
234 ray::SetConfigFlags(ray::FLAG_WINDOW_RESIZABLE);
235 }
236
238 {
239 ray::SetConfigFlags(ray::FLAG_FULLSCREEN_MODE);
240 }
241
243 {
244 ray::SetConfigFlags(ray::FLAG_BORDERLESS_WINDOWED_MODE);
245 }
246
248 {
249 ray::SetConfigFlags(ray::FLAG_WINDOW_UNDECORATED);
250 }
251
252 if (Settings::ontop())
253 {
254 ray::SetConfigFlags(ray::FLAG_WINDOW_TOPMOST);
255 }
256
257 ray::SetConfigFlags(ray::FLAG_WINDOW_HIGHDPI);
258 ray::SetConfigFlags(ray::FLAG_WINDOW_HIDDEN);
259 ray::SetConfigFlags(ray::FLAG_WINDOW_TRANSPARENT);
260 ray::InitWindow(Settings::window_width(), Settings::window_height(), Settings::title().c_str());
261 ray::SetExitKey(ray::KEY_NULL);
262
264 {
265 ray::SetWindowState(ray::FLAG_WINDOW_MAXIMIZED);
266 }
267
269 {
270 ray::SetWindowState(ray::FLAG_WINDOW_MINIMIZED);
271 }
272
273 if (!Settings::window_icon().empty())
274 {
275 auto& fs = entt::locator<VirtualFileSystem>::value();
276
277 const auto image = fs.load_ray_image(Settings::window_icon());
278 if (image.has_value())
279 {
280 ray::SetWindowIcon(image.value());
281 ray::UnloadImage(image.value());
282 }
283 }
284
285 ray::ClearWindowState(ray::FLAG_WINDOW_HIDDEN);
286 ray::SetWindowFocused();
287
288 // FLAG_WINDOW_UNFOCUSED = 0x00000800, // Set to window non focused
289 // FLAG_WINDOW_ALWAYS_RUN = 0x00000100, // Set to allow windows running while minimized
290 // FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED
291 // FLAG_MSAA_4X_HINT = 0x00000020, // Set to try enabling MSAA 4X
292 // FLAG_INTERLACED_HINT = 0x00010000 // Set to try enabling interlaced video format (for V3D)
293 }
294
296 {
298 {
299 ray::DisableCursor();
300 }
301 else
302 {
303 ray::EnableCursor();
304 }
305
307 {
308 ray::ShowCursor();
309 }
310 else
311 {
312 ray::HideCursor();
313 }
314 }
315
317 {
318 // auto& nui = ServiceLocator<ui::NuklearUI>::make();
319 }
320
322 {
323 // entt::locator<Loader>::make();
324 }
325
327 {
328 // auto& sf = entt::locator<SystemFactory>::emplace();
329 // auto& ef = entt::locator<meta::EntityFactory>::emplace();
330
331 /*ef.register_component<components::Tag>("Tag");
332
333 em.register_component<components::Animated>("Animated");
334 em.register_component<components::Circle>("Circle");
335 em.register_component<components::Ellipse>("Ellipse");
336 em.register_component<components::Point>("Point");
337 em.register_component<components::Polygon>("Polygon");
338 em.register_component<components::Polyline>("Polyline");
339 em.register_component<components::RigidBody>("RigidBody");
340 em.register_component<components::Script>("Script");
341 em.register_component<components::Sprite>("Sprite");
342 em.register_component<components::Text>("Text");
343 em.register_component<components::TileMap>("TileMap");
344 em.register_component<components::Transform>("Transform");
345 em.register_component<flags::DenySerialization>("DenySerialization");
346 em.register_component<flags::Disabled>("Disabled");
347
348 em.register_dependencies<components::Animated, components::Sprite>();
349 em.register_dependencies<components::Circle, components::Transform>();
350 em.register_dependencies<components::Ellipse, components::Transform>();
351 em.register_dependencies<components::Point, components::Transform>();
352 em.register_dependencies<components::Polygon, components::Transform>();
353 em.register_dependencies<components::Polyline, components::Transform>();
354 em.register_dependencies<components::RigidBody, components::Transform>();
355 em.register_dependencies<components::Sprite, components::Transform>();
356 em.register_dependencies<components::Text, components::Transform>();
357 */
358 }
359
361 {
362 // entt::locator<media::SoundEngine>::make(listener_count);
363 // entt::locator<media::MusicEngine>::make(listener_count);
364 // entt::locator<media::VoiceEngine>::make(listener_count);
365 // entt::locator<resource::SoundCache>::make();
366 // entt::locator<resource::MusicCache>::make();
367 // entt::locator<resource::VoiceCache>::make();
368 // entt::locator<resource::VideoCache>::make();
369 // entt::locator<resource::Animations>::make();
370 // entt::locator<resource::Shaders>::make();
371 // entt::locator<resource::Fonts>::make();
372 // entt::locator<resource::Textures>::make();
373 // entt::locator<resource::Prefabs>::make();
374 // entt::locator<resource::Scripts>::make();
375 // entt::locator<SceneManager>::emplace();
376 }
377
379 {
380 auto& lua = entt::locator<sol::state>::emplace();
381 lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::coroutine, sol::lib::string, sol::lib::os, sol::lib::math, sol::lib::table, sol::lib::io, sol::lib::utf8);
382
383 //
384 // Add external libraries to Lua.
385 // Inject all configured galaxy into Lua.
386 // Add engine services to lua.
387 //
388 Lua::inject();
389 }
390} // namespace galaxy
#define GALAXY_ADD_SINK(sink,...)
Definition Log.hpp:28
#define GALAXY_INFO
Log.hpp galaxy.
Definition Log.hpp:23
#define GALAXY_LOG(level, msg,...)
Definition Log.hpp:29
void setup_config(std::string_view config_file)
void run()
Main game loop.
App(const std::string &config_file="config.json")
Default constructor.
void load()
Loads the default appdata file.
void setup_logging()
void set_render_func(LoopFunc &&render)
Use a custom rendering step in game loop.
void setup_async()
void setup_input()
void setup_rendering()
void setup_meta()
std::move_only_function< void(App *app)> LoopFunc
Defines a callback for update() or render() loops in app.run().
void set_update_func(LoopFunc &&update)
Use a custom update step in game loop.
void setup_services()
void setup_nuklear()
void setup_scripting()
void setup_platform()
LoopFunc m_render
Render step in gameloop.
void setup_loader()
~App()
Destructor.
LoopFunc m_update
Update step in gameloop.
Logs a message to the console.
static void inject() noexcept
Inject everything into Lua.
Definition Lua.cpp:12
void seed_random() noexcept
Seed the cstdlib rng algos.
Definition Platform.cpp:19
double dt() noexcept
Get galaxy delta time.
Definition Time.cpp:32
auto now() noexcept -> std::chrono::local_time< std::chrono::system_clock::duration >
Current local time.
Definition Time.cpp:16
Application.hpp galaxy.
static auto window_icon() noexcept -> const std::string &
Window icon file in vfs.
Definition Settings.cpp:193
static auto window_height() noexcept -> int
Window creation height.
Definition Settings.cpp:148
static auto log_dir() noexcept -> const std::string &
Current root directory of application, unless it has been changed.
Definition Settings.cpp:137
static auto fullscreen() noexcept -> bool
Is window started fullscreen.
Definition Settings.cpp:173
static auto vsync() noexcept -> bool
Vsync control.
Definition Settings.cpp:158
static auto minimized() noexcept -> bool
Is window started minimized?
Definition Settings.cpp:183
static auto cursor_locked() noexcept -> bool
Is the cursor grabbed.
Definition Settings.cpp:283
static auto window_width() noexcept -> int
Window creation width.
Definition Settings.cpp:143
static auto set_settings_from_config() -> void
Set all our settings using the provided config file.
Definition Settings.cpp:80
static auto window_resizable() noexcept -> bool
Is the window resizable.
Definition Settings.cpp:163
static auto maximized() noexcept -> bool
Is window started maximized?
Definition Settings.cpp:178
static auto title() noexcept -> const std::string &
Game title.
Definition Settings.cpp:153
static auto cursor_show() noexcept -> bool
Is the mouse cursor visible or not.
Definition Settings.cpp:288
static auto ontop() noexcept -> bool
Should the window always be on top.
Definition Settings.cpp:198
static auto borderless_fullscreen() noexcept -> bool
Is window in borderless fullscreen?
Definition Settings.cpp:188
static auto set_config_to_default() -> void
Restore all config settings to default.
Definition Settings.cpp:23
static auto decoration() noexcept -> bool
Controls if a window has a border around it (including titlebar).
Definition Settings.cpp:168