1#ifndef LIBSBX_CORE_ENGINE_HPP_
2#define LIBSBX_CORE_ENGINE_HPP_
14#include <range/v3/all.hpp>
16#include <easy/profiler.h>
18#include <libsbx/utility/concepts.hpp>
19#include <libsbx/utility/noncopyable.hpp>
20#include <libsbx/utility/assert.hpp>
21#include <libsbx/utility/type_name.hpp>
22#include <libsbx/utility/timer.hpp>
24#include <libsbx/units/time.hpp>
26#include <libsbx/core/module.hpp>
27#include <libsbx/core/application.hpp>
28#include <libsbx/core/cli.hpp>
29#include <libsbx/core/profiler.hpp>
30#include <libsbx/core/settings.hpp>
36 using stage = module_manager::stage;
37 using module_base = module_manager::module_base;
38 using module_factory = module_manager::module_factory;
42 engine(std::span<std::string_view> args)
44 utility::assert_that(_instance ==
nullptr,
"Engine already exists.");
48 for (
auto&& [type, factory] : module_manager::_factories() | ranges::views::filter([](
const auto& entry) {
return entry.has_value(); }) | ranges::views::enumerate) {
49 _create_module(type, *factory);
54 for (
auto&& [type, entry] : _modules | ranges::views::enumerate | std::views::reverse) {
55 _destroy_module(type);
62 return _instance->_delta_time;
70 return _instance->_time;
73 static auto quit() ->
void {
74 _instance->_is_running =
false;
78 return _instance->_cli;
86 return _instance->_settings;
89 template<
typename Module>
90 requires (std::is_base_of_v<module_base, Module>)
91 [[nodiscard]]
static auto get_module() -> Module& {
94 auto& modules = _instance->_modules;
96 if (type >= modules.size() || !modules[type]) {
97 throw std::runtime_error{fmt::format(
"Failed to find module '{}'", utility::type_name<Module>())};
100 return *
static_cast<Module*
>(modules[type]);
103 auto run(std::unique_ptr<application>
application) ->
void {
108 using clock_type = std::chrono::high_resolution_clock;
112 auto last = clock_type::now();
116 while (_is_running) {
117 const auto now = clock_type::now();
118 const auto delta_time = std::chrono::duration_cast<std::chrono::duration<std::float_t>>(now - last).count();
123 _instance->_time += _instance->_delta_time;
125 fixed_accumulator += _instance->_delta_time;
127 EASY_BLOCK(
"stage pre");
128 _update_stage(stage::pre);
131 EASY_BLOCK(
"application update");
135 EASY_BLOCK(
"stage normal");
136 _update_stage(stage::normal);
139 EASY_BLOCK(
"stage post");
140 _update_stage(stage::post);
143 EASY_BLOCK(
"stage pre_fixed");
144 _update_stage(stage::pre_fixed);
147 while (fixed_accumulator >= fixed_delta_time()) {
148 EASY_BLOCK(
"stage fixed");
150 _update_stage(stage::fixed);
151 fixed_accumulator -= fixed_delta_time();
155 EASY_BLOCK(
"stage post_fixed");
156 _update_stage(stage::post_fixed);
159 EASY_BLOCK(
"stage rendering");
160 _update_stage(stage::rendering);
167 auto _create_module(
const std::uint32_t type,
const module_factory& factory) ->
void {
168 if (type < _modules.size() && _modules[type]) {
172 for (
const auto& dependency : factory.dependencies) {
173 _create_module(dependency, *module_manager::_factories().at(dependency));
176 if (type >= _modules.size()) {
177 _modules.resize(std::max(_modules.size(),
static_cast<std::size_t
>(type + 1u)));
180 _modules[type] = std::invoke(factory.create);
181 _module_by_stage[factory.stage].push_back(type);
184 auto _destroy_module(
const std::uint32_t type) ->
void {
185 if (type >= _modules.size() || !_modules.at(type)) {
189 auto& factory = module_manager::_factories().at(type);
191 for (
const auto& dependency : factory->dependencies) {
192 _destroy_module(dependency);
195 auto* module_instance = _modules.at(type);
196 std::invoke(factory->destroy, module_instance);
197 _modules.at(type) =
nullptr;
200 auto _update_stage(stage stage) ->
void {
201 if (
auto entry = _module_by_stage.find(stage); entry != _module_by_stage.end()) {
202 for (
const auto& type : entry->second) {
203 _modules.at(type)->update();
219 std::vector<module_base*> _modules{};
220 std::map<stage, std::vector<std::uint32_t>> _module_by_stage{};
Definition: application.hpp:6
Definition: engine.hpp:34
Definition: settings.hpp:17
Definition: quantity.hpp:65
Definition: noncopyable.hpp:6
static auto value() noexcept -> std::uint32_t
Generates a unique ID for the type.
Definition: type_id.hpp:40