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#include <format>
9
10#include <BS_thread_pool.hpp>
11#include <entt/signal/dispatcher.hpp>
12#include <mimalloc.h>
13#include <SDL3/SDL.h>
14#include <sol/sol.hpp>
15
23#include "galaxy/lua/Lua.hpp"
25#include "galaxy/time/Time.hpp"
26
27#include "Application.hpp"
28
29using namespace std::chrono_literals;
30
31namespace galaxy
32{
33 App::App(const std::string& config_file)
34 {
35 SDL_SetMemoryFunctions(&mi_malloc, &mi_calloc, &mi_realloc, &mi_free);
36
39 setup_config(config_file);
41 setup_fs();
44 // setup_nuklear();
45 // setup_loader();
46 // setup_meta();
47 // setup_services();
49
50 // Load game assets.
51 // core::entt::locator<core::Loader>::ref().load_all();
52 }
53
55 {
56 entt::locator<VirtualFileSystem>::reset();
57 entt::locator<Config>::reset();
58 entt::locator<BS::light_thread_pool>::reset();
59
60 GALAXY_LOG(GALAXY_INFO, "Application closed.");
61 entt::locator<Log>::reset();
62
63 SDL_Quit();
64 }
65
66 /*void App::load()
67 {
68 const auto path = Settings::root_dir() / Settings::asset_pack();
69
70 auto& sm = entt::locator<scene::SceneManager>::value();
71 sm.load_app(path.string());
72 }*/
73
74 void App::run()
75 {
76 // https://stackoverflow.com/a/59446610
77 // We dont need 't' or 'alpha/render' sections.
78
79 auto& window = entt::locator<Window>::value();
80 auto& dispatcher = entt::locator<entt::dispatcher>::value();
81 // auto& manager = entt::locator<scene::SceneManager>::value();
82
83 // The expression dt/1s simply converts the double-based chrono seconds
84 // into a double so it can participate in the physics computation.
85 constexpr const auto dt = std::chrono::duration<long long, std::ratio<1, 60>> {1};
86 time::dt(dt / 1.0s);
87
88 using clock = std::chrono::steady_clock;
89 using duration = decltype(clock::duration {} + dt);
90 using time_point = std::chrono::time_point<clock, duration>;
91
92 duration accum = 0s;
93 time_point prev = clock::now();
94 time_point now = clock::now();
95
96 auto updates = 0u;
97 auto frames = 0u;
98 duration perf = 0s;
99
100 while (window.is_open())
101 {
102 now = clock::now();
103 auto elapsed = now - prev;
104
105 // 250ms is the limit put in place on the frame time to cope with the spiral of death.
106 // It doesn't have to be 250ms exactly but it should be sufficiently high enough to deal with spikes in load.
107 if (elapsed > 250ms)
108 {
109 elapsed = 250ms;
110 }
111
112 prev = now;
113 accum += elapsed;
114
115 while (accum >= dt)
116 {
117 perf += dt;
118 accum -= dt;
119
120 // nui.begin_input();
121 window.process_events(dispatcher);
122 // nui.end_input();
123 // manager.update();
124
125 updates++;
126 }
127
128 // graphics::renderer::begin();
129 // manager.render();
130 // graphics::renderer::end();
131
132 frames++;
133
134 if (perf >= 1s)
135 {
136 window.append_title(std::format("{0} | UPS: {1}, FPS: {2}", Settings::title(), updates, frames));
137
138 frames = 0;
139 updates = 0;
140 perf = 0s;
141 }
142 }
143 }
144
146 {
147 platform::configure_terminal();
148 if (!std::filesystem::exists(Settings::log_dir()))
149 {
150 std::filesystem::create_directory(Settings::log_dir());
151 }
152 entt::locator<Log>::emplace();
153
154 const auto path = std::format("{0}{1}{2}", Settings::log_dir(), std::format("{0:%d-%m-%Y-[%H-%M]}", time::now()), ".log");
156
158 GALAXY_LOG(GALAXY_INFO, "App started.");
159 }
160
162 {
163 // Configure threadpool.
164 // Use half of available cores minus 2 for audio and main thread.
165 const auto system_cores = std::thread::hardware_concurrency();
166 if (system_cores < 4)
167 {
168 GALAXY_LOG(GALAXY_WARN, "Total cores are less than 4, this is not optimal.");
169 }
170
171 const auto cores = static_cast<int>(std::floor(system_cores / 2.0) - 2);
172 entt::locator<BS::light_thread_pool>::emplace(cores);
173 }
174
175 void App::setup_config(std::string_view config_file)
176 {
177 auto& config = entt::locator<Config>::emplace(config_file);
180 }
181
183 {
185
186 platform::set_metadata(SDL_PROP_APP_METADATA_NAME_STRING, Settings::title().c_str());
187 platform::set_metadata(SDL_PROP_APP_METADATA_VERSION_STRING, Settings::version().c_str());
188 platform::set_metadata(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, Settings::identifier().c_str());
189 platform::set_metadata(SDL_PROP_APP_METADATA_CREATOR_STRING, Settings::creator().c_str());
190 platform::set_metadata(SDL_PROP_APP_METADATA_COPYRIGHT_STRING, Settings::copyright().c_str());
191 platform::set_metadata(SDL_PROP_APP_METADATA_URL_STRING, Settings::website().c_str());
192 platform::set_metadata(SDL_PROP_APP_METADATA_TYPE_STRING, "game");
193
194 platform::set_hint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, "1");
195 platform::set_hint(SDL_HINT_ASSERT, "break");
196 platform::set_hint(SDL_HINT_AUDIO_CATEGORY, "playback");
197 platform::set_hint(SDL_HINT_AUDIO_CHANNELS, "2");
198 platform::set_hint(SDL_HINT_AUDIO_INCLUDE_MONITORS, "0");
199 platform::set_hint(SDL_HINT_AUTO_UPDATE_JOYSTICKS, "1");
200 platform::set_hint(SDL_HINT_AUTO_UPDATE_SENSORS, "1");
201 platform::set_hint(SDL_HINT_DEBUG_LOGGING, "1");
202 platform::set_hint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, "0");
203 platform::set_hint(SDL_HINT_EVENT_LOGGING, "0");
204 platform::set_hint(SDL_HINT_FRAMEBUFFER_ACCELERATION, "opengl");
205 platform::set_hint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION, "1");
206 platform::set_hint(SDL_HINT_GPU_DRIVER, "vulkan");
207 platform::set_hint(SDL_HINT_HIDAPI_ENUMERATE_ONLY_CONTROLLERS, "1");
208 platform::set_hint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "0");
209 platform::set_hint(SDL_HINT_JOYSTICK_DIRECTINPUT, "1");
210 platform::set_hint(SDL_HINT_TV_REMOTE_AS_JOYSTICK, "1");
211 // platform::set_hint(SDL_HINT_LOG_BACKENDS, "1");
212 platform::set_hint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
213 platform::set_hint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
214 platform::set_hint(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0");
215 platform::set_hint(SDL_HINT_MOUSE_TOUCH_EVENTS, "1");
216 platform::set_hint(SDL_HINT_PEN_MOUSE_EVENTS, "1");
217 platform::set_hint(SDL_HINT_PEN_TOUCH_EVENTS, "1");
218 platform::set_hint(SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE, "1");
219 platform::set_hint(SDL_HINT_RENDER_DRIVER, "opengl");
220 platform::set_hint(SDL_HINT_RENDER_GPU_DEBUG, "0");
221 platform::set_hint(SDL_HINT_RENDER_GPU_LOW_POWER, "0");
222 platform::set_hint(SDL_HINT_TOUCH_MOUSE_EVENTS, "1");
223 platform::set_hint(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, "0");
224 platform::set_hint(SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL, "0");
225 platform::set_hint(SDL_HINT_XINPUT_ENABLED, "1");
226 platform::set_hint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "0");
227 platform::set_hint(SDL_HINT_VIDEO_DUMMY_SAVE_FRAMES, "0");
228 platform::set_hint(SDL_HINT_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE, "1");
229 platform::set_hint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
230 platform::set_hint(SDL_HINT_VIDEO_OFFSCREEN_SAVE_FRAMES, "0");
231 platform::set_hint(SDL_HINT_VIDEO_SYNC_WINDOW_OPERATIONS, "0");
232 platform::set_hint(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, "1");
233 platform::set_hint(SDL_HINT_WINDOWS_CLOSE_ON_ALT_F4, "1");
234 platform::set_hint(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, "0");
235 platform::set_hint(SDL_HINT_WINDOWS_GAMEINPUT, "1");
236 platform::set_hint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "0");
237 // platform::set_hint(SDL_HINT_IME_IMPLEMENTED_UI, "0");
238
239 const auto vsync = Settings::vsync() ? "1" : "0";
240 platform::set_hint(SDL_HINT_RENDER_VSYNC, vsync);
241
242 const auto audio_freq = std::to_string(Settings::audio_freq());
243 platform::set_hint(SDL_HINT_AUDIO_FREQUENCY, audio_freq.c_str());
244
245 if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_HAPTIC | SDL_INIT_SENSOR))
246 {
247 GALAXY_LOG(GALAXY_FATAL, SDL_GetError());
248 }
249 }
250
252 {
253 entt::locator<VirtualFileSystem>::emplace();
254 }
255
257 {
258 auto& window = entt::locator<Window>::emplace();
259
260 window.set_icon(Settings::window_icon());
261 window.show();
262 }
263
265 {
266 entt::locator<entt::dispatcher>::emplace();
267 }
268
269 // void App::setup_nuklear()
270 //{
271 // }
272
273 // void App::setup_loader()
274 //{
275 // // entt::locator<Loader>::make();
276 // }
277
278 // void App::setup_meta()
279 //{
280 // auto& sf = entt::locator<meta::SystemFactory>::emplace();
281 // auto& ef = entt::locator<meta::EntityFactory>::emplace();
282
283 // ef.register_component<components::Tag>("Tag");
284 // /*
285 // em.register_component<components::Animated>("Animated");
286 // em.register_component<components::Circle>("Circle");
287 // em.register_component<components::Ellipse>("Ellipse");
288 // em.register_component<components::Point>("Point");
289 // em.register_component<components::Polygon>("Polygon");
290 // em.register_component<components::Polyline>("Polyline");
291 // em.register_component<components::RigidBody>("RigidBody");
292 // em.register_component<components::Script>("Script");
293 // em.register_component<components::Sprite>("Sprite");
294 // em.register_component<components::Text>("Text");
295 // em.register_component<components::TileMap>("TileMap");
296 // em.register_component<components::Transform>("Transform");
297 // em.register_component<flags::DenySerialization>("DenySerialization");
298 // em.register_component<flags::Disabled>("Disabled");
299
300 // em.register_dependencies<components::Animated, components::Sprite>();
301 // em.register_dependencies<components::Circle, components::Transform>();
302 // em.register_dependencies<components::Ellipse, components::Transform>();
303 // em.register_dependencies<components::Point, components::Transform>();
304 // em.register_dependencies<components::Polygon, components::Transform>();
305 // em.register_dependencies<components::Polyline, components::Transform>();
306 // em.register_dependencies<components::RigidBody, components::Transform>();
307 // em.register_dependencies<components::Sprite, components::Transform>();
308 // em.register_dependencies<components::Text, components::Transform>();
309 // */
310 //}
311
312 // void App::setup_services()
313 //{
314 // // entt::locator<media::SoundEngine>::make(listener_count);
315 // // entt::locator<media::MusicEngine>::make(listener_count);
316 // // entt::locator<media::VoiceEngine>::make(listener_count);
317 // // entt::locator<resource::SoundCache>::make();
318 // // entt::locator<resource::MusicCache>::make();
319 // // entt::locator<resource::VoiceCache>::make();
320 // // entt::locator<resource::VideoCache>::make();
321 // // entt::locator<resource::Animations>::make();
322 // // entt::locator<resource::Shaders>::make();
323 // // entt::locator<resource::Fonts>::make();
324 // // entt::locator<resource::Textures>::make();
325 // // entt::locator<resource::Prefabs>::make();
326 // // entt::locator<resource::Scripts>::make();
327 // entt::locator<scene::SceneManager>::emplace();
328 // }
329
331 {
332 auto& lua = entt::locator<sol::state>::emplace();
333 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);
334
335 //
336 // Add external libraries to Lua.
337 // Inject all configured galaxy into Lua.
338 // Add engine services to lua.
339 //
340 Lua::inject();
341 }
342} // namespace galaxy
#define GALAXY_ADD_SINK(sink,...)
Definition Log.hpp:27
#define GALAXY_INFO
Log.hpp galaxy.
Definition Log.hpp:22
#define GALAXY_LOG(level, msg,...)
Definition Log.hpp:28
#define GALAXY_WARN
Definition Log.hpp:23
#define GALAXY_FATAL
Definition Log.hpp:25
void setup_config(std::string_view config_file)
void run()
Loads the default appdata file.
App(const std::string &config_file="config.json")
Default constructor.
void setup_logging()
void setup_async()
void setup_events()
void setup_scripting()
void setup_platform()
void setup_window()
~App()
Destructor.
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:20
void set_metadata(const char *type, const char *value) noexcept
Sets metadata.
Definition Platform.cpp:25
void set_hint(const char *hint, const char *value) noexcept
Sets SDL hints.
Definition Platform.cpp:30
double dt() noexcept
Get galaxy delta time.
Definition Time.cpp:26
auto now() noexcept -> std::chrono::local_time< std::chrono::system_clock::duration >
Current local time.
Definition Time.cpp:16
Animated.cpp galaxy.
Definition Animated.cpp:16
static auto window_icon() noexcept -> const std::string &
Window icon file in vfs.
Definition Settings.cpp:126
static auto log_dir() noexcept -> const std::string &
Current root directory of application, unless it has been changed.
Definition Settings.cpp:211
static auto copyright() noexcept -> const std::string &
Copyright message.
Definition Settings.cpp:201
static auto vsync() noexcept -> bool
Vsync control.
Definition Settings.cpp:141
static auto set_settings_from_config() -> void
Set all our settings using the provided config file.
Definition Settings.cpp:70
static auto identifier() noexcept -> const std::string &
Game identifier i.e. com.galaxy.app.
Definition Settings.cpp:191
static auto title() noexcept -> const std::string &
Game title.
Definition Settings.cpp:181
static auto version() noexcept -> const std::string &
Game semver.
Definition Settings.cpp:186
static auto audio_freq() noexcept -> int
Set audio frequency to use with SDL.
Definition Settings.cpp:176
static auto website() noexcept -> const std::string &
Website URL.
Definition Settings.cpp:206
static auto set_config_to_default() -> void
Restore all config settings to default.
Definition Settings.cpp:22
static auto creator() noexcept -> const std::string &
Owner.
Definition Settings.cpp:196