sandbox
Loading...
Searching...
No Matches
engine.hpp
1#ifndef LIBSBX_CORE_ENGINE_HPP_
2#define LIBSBX_CORE_ENGINE_HPP_
3
4#include <map>
5#include <vector>
6#include <typeindex>
7#include <memory>
8#include <span>
9#include <string_view>
10#include <cmath>
11#include <chrono>
12#include <ranges>
13
14#include <libsbx/utility/concepts.hpp>
15#include <libsbx/utility/noncopyable.hpp>
16#include <libsbx/utility/assert.hpp>
17
18#include <libsbx/units/time.hpp>
19
20#include <libsbx/core/module.hpp>
21#include <libsbx/core/application.hpp>
23#include <libsbx/core/cli.hpp>
24
25namespace sbx::core {
26
28
29 using stage = module_manager::stage;
30 using module_base = module_manager::module_base;
31 using module_factory = module_manager::module_factory;
32
33public:
34
35 engine(std::span<std::string_view> args)
36 : _cli{args} {
37 utility::assert_that(_instance == nullptr, "Engine already exists.");
38
39 _instance = this;
40
41 for (const auto& [type, factory] : module_manager::_factories()) {
42 _create_module(type, factory);
43 }
44 }
45
46 ~engine() {
47 for (const auto& entry : _modules | std::views::reverse) {
48 _destroy_module(entry.first);
49 }
50
51 _instance = nullptr;
52 }
53
54 static auto delta_time() -> units::second {
55 return _instance->_delta_time;
56 }
57
58 static auto fixed_delta_time() -> units::second {
59 return units::second{1.0f / 60.0f};
60 }
61
62 static auto time() -> units::second {
63 return _instance->_time;
64 }
65
66 static auto quit() -> void {
67 _instance->_is_running = false;
68 }
69
70 static auto cli() noexcept -> core::cli& {
71 return _instance->_cli;
72 }
73
74 template<typename Module>
75 requires (std::is_base_of_v<module_base, Module>)
76 [[nodiscard]] static auto get_module() -> Module& {
77 const auto type = std::type_index{typeid(Module)};
78
79 if (auto entry = _instance->_modules.find(type); entry != _instance->_modules.end()) {
80 return *static_cast<Module*>(entry->second);
81 }
82
83 throw std::runtime_error{fmt::format("Failed to find module '{}'", typeid(Module).name())};
84 }
85
86 auto run(std::unique_ptr<application> application) -> void {
87 if (_is_running) {
88 return;
89 }
90
91 using clock_type = std::chrono::high_resolution_clock;
92
93 _is_running = true;
94
95 auto last = clock_type::now();
96
97 auto fixed_accumulator = units::second{};
98
99 while (_is_running) {
100 const auto now = clock_type::now();
101 const auto delta_time = std::chrono::duration_cast<std::chrono::duration<std::float_t>>(now - last).count();
102 last = now;
103
104
105 _instance->_delta_time = units::second{delta_time};
106 _instance->_time += _instance->_delta_time;
107
108 fixed_accumulator += _instance->_delta_time;
109
110 application->update();
111
112 _update_stage(stage::pre);
113 _update_stage(stage::normal);
114 _update_stage(stage::post);
115
116 while (fixed_accumulator >= fixed_delta_time()) {
117 application->fixed_update();
118 _update_stage(stage::fixed);
119 fixed_accumulator -= fixed_delta_time();
120 }
121
122 _update_stage(stage::rendering);
123 }
124 }
125
126private:
127
128 auto _create_module(const std::type_index& type, const module_factory& factory) -> void {
129 if (_modules.contains(type)) {
130 return;
131 }
132
133 for (const auto& dependency : factory.dependencies) {
134 _create_module(dependency, module_manager::_factories().at(dependency));
135 }
136
137 _modules.insert({type, std::invoke(factory.create)});
138 _module_by_stage[factory.stage].push_back(type);
139 }
140
141 auto _destroy_module(const std::type_index& type) -> void {
142 if (!_modules.at(type)) {
143 return;
144 }
145
146 auto& factory = module_manager::_factories().at(type);
147
148 for (const auto& dependency : factory.dependencies) {
149 _destroy_module(dependency);
150 }
151
152 auto* module_instance = _modules.at(type);
153 std::invoke(factory.destroy, module_instance);
154 _modules.at(type) = nullptr;
155 }
156
157 auto _update_stage(stage stage) -> void {
158 if (auto entry = _module_by_stage.find(stage); entry != _module_by_stage.end()) {
159 for (const auto& type : entry->second) {
160 _modules.at(type)->update();
161 }
162 }
163 }
164
165 static engine* _instance;
166
167 units::second _delta_time;
168 units::second _time;
169
170 bool _is_running{};
171 // std::vector<std::string_view> _args{};
172 core::cli _cli;
173
174 std::map<std::type_index, module_base*> _modules{};
175 std::map<stage, std::vector<std::type_index>> _module_by_stage{};
176
177}; // class engine
178
179} // namespace sbx::core
180
181#endif // LIBSBX_CORE_ENGINE_HPP_
Definition: application.hpp:6
Definition: cli.hpp:23
Definition: engine.hpp:27
Definition: quantity.hpp:65
Definition: noncopyable.hpp:6