Unravel Engine C++ Reference
Loading...
Searching...
No Matches
engine.cpp
Go to the documentation of this file.
1#include "engine.h"
5#include <engine/play_mode.h>
11
12#include <engine/ecs/ecs.h>
13
14#include "events.h"
18#include <engine/input/input.h>
26#include <ospp/event.h>
27
28#include <crash/crash.hpp>
29#include <cstdlib>
30#include <exception>
31#include <logging/logging.h>
32
33
34#include <seq/seq.h>
36
38namespace unravel
39{
40namespace
41{
42
43auto context_ptr() -> rtti::context*&
44{
45 static rtti::context* ctx{};
46 return ctx;
47}
48std::atomic<bool> is_shutting_down{false};
49
50void update_input_zone(const renderer& rend, input_system& input)
51{
52 const auto& window = rend.get_main_window();
53 if(window)
54 {
55 auto main_pos = window->get_window().get_position();
56 auto main_size = window->get_window().get_size();
57
58 input::zone window_zone{};
59 window_zone.x = main_pos.x;
60 window_zone.y = main_pos.y;
61 window_zone.w = int(main_size.w);
62 window_zone.h = int(main_size.h);
63
64 input.manager.set_window_zone(window_zone);
65 }
66}
67
68// Engine crash handlers
69void engine_interrupt_handler(const crash::signal_info& info)
70{
71 APPLOG_INFO("User interrupt ({}) -> {}", info.signal_number, info.signal_name);
72
74
76}
77
78void engine_termination_handler(const crash::signal_info& info)
79{
80 APPLOG_INFO("Termination signal ({}) -> {}", info.signal_number, info.signal_name);
81
82 // Try to gracefully shutdown the engine
84
86}
87
88void engine_crash_handler(const crash::signal_info& info, const crash::trace_info& trace)
89{
90 // Log the crash with full details
91 APPLOG_CRITICAL("Crash signal ({}) -> {}\n{}", info.signal_number, info.signal_name, trace.formatted_trace);
92
93 // Try emergency cleanup
95
97}
98
99void engine_exception_handler(const crash::exception_info& info, const crash::trace_info& trace)
100{
101 APPLOG_CRITICAL("{}\n{}", info.exception_message, trace.formatted_trace);
102
103 // Same emergency cleanup as crash handler
105
106 APPLOG_FLUSH();
107}
108
109} // namespace
110
112{
113 return *context_ptr();
114}
115
117{
118
119 context_ptr() = &ctx;
120
121 fs::path binary_path = fs::executable_path(parser.app_name().c_str()).parent_path();
122 fs::add_path_protocol("binary", binary_path);
123
124 fs::path engine_data = binary_path / "data" / "engine";
125 fs::add_path_protocol("engine", engine_data);
126
127
129 .warning_logger = [](const std::string& log, const hpp::source_location& loc)
130 {
131 APPLOG_WARNING_LOC(loc.file_name(), int(loc.line()), loc.function_name(), "Serialization {}", log);
132 }
133 };
135
136 ctx.add<logging>();
137 ctx.add<loading_screen>();
138
139 // Install engine crash handlers immediately after logging is available
141 .interrupt_handler = engine_interrupt_handler,
142 .termination_handler = engine_termination_handler,
143 .crash_handler = engine_crash_handler,
144 .exception_handler = engine_exception_handler,
145 });
146
147 APPLOG_INFO("Engine crash handlers installed");
148
149 ctx.add<simulation>();
150 ctx.add<events>();
151 ctx.add<play_mode>();
152 ctx.add<threader>();
153 ctx.add<renderer>(ctx, parser);
154 ctx.add<audio_system>();
155 ctx.add<asset_manager>(ctx);
156 ctx.add<ecs>();
157 ctx.add<rendering_system>();
158 ctx.add<transform_system>();
159 ctx.add<camera_system>();
160 ctx.add<reflection_probe_system>();
161 ctx.add<skylight_system>();
162 ctx.add<model_system>();
163 ctx.add<animation_system>();
164 ctx.add<particle_system>();
165 ctx.add<physics_system>();
166 ctx.add<input_system>();
167 ctx.add<script_system>(ctx, parser);
168 ctx.add<ui_system>();
169 return true;
170}
171
172auto engine::init_core(const cmd_line::parser& parser) -> bool
173{
174 auto& ctx = engine::context();
175 auto& ls = ctx.get_cached<loading_screen>();
176
177 ls.begin_module("Threading");
178 if(!ls.check(ctx.get_cached<threader>().init(ctx)))
179 {
180 return false;
181 }
182
183 ls.begin_module("Renderer");
184 if(!ls.check(ctx.get_cached<renderer>().init(ctx, parser)))
185 {
186 return false;
187 }
188
189 ls.begin_module("Audio");
190 if(!ls.check(ctx.get_cached<audio_system>().init(ctx)))
191 {
192 return false;
193 }
194
195 ls.begin_module("Assets");
196 if(!ls.check(ctx.get_cached<asset_manager>().init(ctx)))
197 {
198 return false;
199 }
200
201 return true;
202}
203
204auto engine::init_systems(const cmd_line::parser& parser) -> bool
205{
206 auto& ctx = engine::context();
207 auto& ls = ctx.get_cached<loading_screen>();
208
209 ls.begin_module("ECS");
210 if(!ls.check(ctx.get_cached<ecs>().init(ctx)))
211 {
212 return false;
213 }
214
215 ls.begin_module("Rendering");
216 if(!ls.check(ctx.get_cached<rendering_system>().init(ctx)))
217 {
218 return false;
219 }
220
221 ls.begin_module("Transforms");
222 if(!ls.check(ctx.get_cached<transform_system>().init(ctx)))
223 {
224 return false;
225 }
226
227 ls.begin_module("Camera");
228 if(!ls.check(ctx.get_cached<camera_system>().init(ctx)))
229 {
230 return false;
231 }
232
233 ls.begin_module("Reflection Probes");
234 if(!ls.check(ctx.get_cached<reflection_probe_system>().init(ctx)))
235 {
236 return false;
237 }
238
239 ls.begin_module("Sky Lighting");
240 if(!ls.check(ctx.get_cached<skylight_system>().init(ctx)))
241 {
242 return false;
243 }
244
245 ls.begin_module("Models");
246 if(!ls.check(ctx.get_cached<model_system>().init(ctx)))
247 {
248 return false;
249 }
250
251 ls.begin_module("Animation");
252 if(!ls.check(ctx.get_cached<animation_system>().init(ctx)))
253 {
254 return false;
255 }
256
257 ls.begin_module("Physics");
258 if(!ls.check(ctx.get_cached<physics_system>().init(ctx)))
259 {
260 return false;
261 }
262
263 ls.begin_module("Particles");
264 if(!ls.check(ctx.get_cached<particle_system>().init(ctx)))
265 {
266 return false;
267 }
268
269 ls.begin_module("Input");
270 if(!ls.check(ctx.get_cached<input_system>().init(ctx)))
271 {
272 return false;
273 }
274
275 ls.begin_module("Scripting");
276 if(!ls.check(ctx.get_cached<script_system>().init(ctx, parser)))
277 {
278 return false;
279 }
280
281 ls.begin_module("UI");
282 if(!ls.check(ctx.get_cached<ui_system>().init(ctx)))
283 {
284 return false;
285 }
286
287 ls.begin_module("Play Mode");
288 if(!ls.check(ctx.get_cached<play_mode>().init(ctx)))
289 {
290 return false;
291 }
292
293 ls.begin_module("Defaults");
294 if(!ls.check(defaults::init(ctx)))
295 {
296 return false;
297 }
298
299 return true;
300}
301
302auto engine::deinit() -> bool
303{
304 auto& ctx = engine::context();
305
306 if(!defaults::deinit(ctx))
307 {
308 return false;
309 }
310
311 if(!ctx.get_cached<play_mode>().deinit(ctx))
312 {
313 return false;
314 }
315
316
317 if(!ctx.get_cached<ui_system>().deinit(ctx))
318 {
319 return false;
320 }
321
322 if(!ctx.get_cached<script_system>().deinit(ctx))
323 {
324 return false;
325 }
326
327
328 if(!ctx.get_cached<input_system>().deinit(ctx))
329 {
330 return false;
331 }
332
333 if(!ctx.get_cached<physics_system>().deinit(ctx))
334 {
335 return false;
336 }
337
338 if(!ctx.get_cached<animation_system>().deinit(ctx))
339 {
340 return false;
341 }
342
343 if(!ctx.get_cached<model_system>().deinit(ctx))
344 {
345 return false;
346 }
347
348 if(!ctx.get_cached<skylight_system>().deinit(ctx))
349 {
350 return false;
351 }
352
353 if(!ctx.get_cached<reflection_probe_system>().deinit(ctx))
354 {
355 return false;
356 }
357
358 if(!ctx.get_cached<camera_system>().deinit(ctx))
359 {
360 return false;
361 }
362
363 if(!ctx.get_cached<transform_system>().deinit(ctx))
364 {
365 return false;
366 }
367
368 if(!ctx.get_cached<rendering_system>().deinit(ctx))
369 {
370 return false;
371 }
372
373 if(!ctx.get_cached<ecs>().deinit(ctx))
374 {
375 return false;
376 }
377
378 if(!ctx.get_cached<particle_system>().deinit(ctx))
379 {
380 return false;
381 }
382
383 if(!ctx.get_cached<asset_manager>().deinit(ctx))
384 {
385 return false;
386 }
387
388 if(!ctx.get_cached<audio_system>().deinit(ctx))
389 {
390 return false;
391 }
392
393 if(!ctx.get_cached<renderer>().deinit(ctx))
394 {
395 return false;
396 }
397
398 if(!ctx.get_cached<threader>().deinit(ctx))
399 {
400 return false;
401 }
402
403 return true;
404}
405
406auto engine::destroy() -> bool
407{
408 auto& ctx = engine::context();
409
410 ctx.remove<defaults>();
411 ctx.remove<ui_system>();
412 ctx.remove<script_system>();
413 ctx.remove<particle_system>();
414 ctx.remove<input_system>();
415 ctx.remove<physics_system>();
416 ctx.remove<animation_system>();
417 ctx.remove<model_system>();
418 ctx.remove<skylight_system>();
419 ctx.remove<reflection_probe_system>();
420 ctx.remove<camera_system>();
421 ctx.remove<transform_system>();
422 ctx.remove<rendering_system>();
423 ctx.remove<ecs>();
424
425 ctx.remove<asset_manager>();
426 ctx.remove<audio_system>();
427 ctx.remove<renderer>();
428 ctx.remove<play_mode>();
429 ctx.remove<events>();
430 ctx.remove<simulation>();
431 ctx.remove<threader>();
432 ctx.remove<logging>();
433
434 ctx.remove<loading_screen>();
435
436 bool empty = ctx.empty();
437 if(!empty)
438 {
439 ctx.print_types();
440 }
441
442 context_ptr() = {};
443 return empty;
444}
445
446auto engine::process() -> int
447{
448 auto& ctx = engine::context();
449
450 auto& sim = ctx.get_cached<simulation>();
451 auto& ev = ctx.get_cached<events>();
452 auto& rend = ctx.get_cached<renderer>();
453 auto& thr = ctx.get_cached<threader>();
454 auto& input = ctx.get_cached<input_system>();
455
456 {
457 APP_SCOPE_PERF("Frame Loop");
458
459 {
460 APP_SCOPE_PERF("Threader Process");
461 thr.process();
462 }
463
464 sim.run_one_frame(true);
465
466 auto dt = sim.get_delta_time();
467 auto& play = ctx.get_cached<play_mode>();
468
469 // First simulation frame: zero dt so Start/init work cannot integrate
470 // a hitch. Increment frames_running at frame end so consumers can also
471 // detect this via frames_running() == 0 (e.g. mid-frame enter_running).
472 if(play.is_simulation_running() && play.frames_running() == 0)
473 {
474 dt = {};
475 }
476
477 if(play.is_paused())
478 {
479 dt = {};
480 }
481
482 update_input_zone(rend, input);
483
484 input.manager.before_events_update();
485
486 bool should_quit = false;
487
488 {
489 APP_SCOPE_PERF("Poll OS Events");
490 os::event e{};
491 while(os::poll_event(e))
492 {
493 ev.on_os_event(ctx, e);
494
495 input.manager.on_os_event(e);
496
497 should_quit = rend.get_main_window() == nullptr || is_shutting_down;
498 if(should_quit)
499 {
500 break;
501 }
502 }
503 }
504
505 {
506 APP_SCOPE_PERF("After Events Update");
507 input.manager.after_events_update();
508 }
509
510 if(should_quit)
511 {
512 ctx.get_cached<play_mode>().set_active(ctx, false);
513 is_shutting_down = false;
514 return 0;
515 }
516
517 {
518 APP_SCOPE_PERF("Frame Begin");
519 ev.on_frame_begin(ctx, dt);
520 }
521
522 {
523 APP_SCOPE_PERF("Seq Update");
524 seq::update(dt);
525 }
526
527
528 {
529 APP_SCOPE_PERF("Frame Update");
530 ev.on_frame_update(ctx, dt);
531 }
532
533 {
534 APP_SCOPE_PERF("Seq Update Zero");
535 seq::update(delta_t::zero());
536 }
537
538 {
539 APP_SCOPE_PERF("Frame Before Render");
540 ev.on_frame_before_render(ctx, dt);
541 }
542
543 {
544 APP_SCOPE_PERF("Frame Render");
545 ev.on_frame_render(ctx, dt);
546 }
547
548 {
549 APP_SCOPE_PERF("Frame End");
550 ev.on_frame_end(ctx, dt);
551 }
552
553 if(play.is_simulation_running())
554 {
555 play.on_simulation_frame();
556 }
557 }
558
559 get_app_profiler()->swap();
560
561 return 1;
562}
563auto engine::interrupt() -> bool
564{
565 is_shutting_down = true;
566 return true;
567}
568
569} // namespace unravel
auto init(rtti::context &ctx) -> bool
auto deinit(rtti::context &ctx) -> bool
Manages assets, including loading, unloading, and storage.
auto init(rtti::context &ctx) -> bool
Initializes the asset manager with the given context.
auto deinit(rtti::context &ctx) -> bool
Deinitializes the asset manager with the given context.
Manages the audio operations and integrates with the audio backend.
auto init(rtti::context &ctx) -> bool
Initializes the audio system with the given context.
auto deinit(rtti::context &ctx) -> bool
Deinitializes the audio system with the given context.
auto deinit(rtti::context &ctx) -> bool
auto init(rtti::context &ctx) -> bool
auto deinit(rtti::context &ctx) -> bool
auto init(rtti::context &ctx) -> bool
System that manages and updates particle emitters in the ECS.
auto deinit(rtti::context &ctx) -> bool
Deinitializes the particle system.
auto init(rtti::context &ctx) -> bool
Initializes the particle system.
Manages the physics operations using the specified backend.
auto deinit(rtti::context &ctx) -> bool
Deinitializes the physics system with the given context.
auto init(rtti::context &ctx) -> bool
Initializes the physics system with the given context.
auto deinit(rtti::context &ctx) -> bool
auto init(rtti::context &ctx) -> bool
Base class for different rendering paths in the ACE framework.
auto init(rtti::context &ctx) -> bool
Initializes the rendering path with the given context.
auto deinit(rtti::context &ctx) -> bool
Deinitializes the rendering path with the given context.
auto init(rtti::context &ctx) -> bool
auto deinit(rtti::context &ctx) -> bool
auto init(rtti::context &ctx) -> bool
auto deinit(rtti::context &ctx) -> bool
#define APPLOG_INFO(...)
Definition logging.h:18
#define APPLOG_FLUSH()
Definition logging.h:43
#define APPLOG_CRITICAL(...)
Definition logging.h:21
#define APPLOG_WARNING_LOC(FILE_LOC, LINE_LOC, FUNC_LOC,...)
Definition logging.h:36
bool add_path_protocol(const std::string &protocol, const path &dir)
Allows us to map a protocol to a specific directory. A path protocol gives the caller the ability to ...
void update(seq_id_t id, duration_t delta)
Updates the elapsed duration of a specific action.
Definition seq.cpp:100
void init(const init_data &data)
auto install_handlers(const crash_handlers &handlers) -> void
Install comprehensive crash handlers.
Definition crash.cpp:318
auto get_app_profiler() -> performance_profiler *
Definition profiler.cpp:99
emitter_sim_state sim
#define APP_SCOPE_PERF(name_literal)
Create a scoped performance timer that records to the timeline profiler. Only accepts string literals...
Definition profiler.h:675
Provides default initialization and creation functions for various entities and assets.
Definition defaults.h:26
static auto init(rtti::context &ctx) -> bool
Initializes default settings and assets.
Definition defaults.cpp:596
static auto deinit(rtti::context &ctx) -> bool
Deinitializes default settings and assets.
Definition defaults.cpp:603
Manages the entity-component-system (ECS) operations for the ACE framework.
Definition ecs.h:12
auto deinit(rtti::context &ctx) -> bool
Deinitializes the ECS with the given context.
Definition ecs.cpp:16
auto init(rtti::context &ctx) -> bool
Initializes the ECS with the given context.
Definition ecs.cpp:9
static auto process() -> int
Definition engine.cpp:446
static auto init_systems(const cmd_line::parser &parser) -> bool
Definition engine.cpp:204
static auto destroy() -> bool
Definition engine.cpp:406
static auto context() -> rtti::context &
Definition engine.cpp:111
static auto deinit() -> bool
Definition engine.cpp:302
static auto interrupt() -> bool
Definition engine.cpp:563
static auto create(rtti::context &ctx, cmd_line::parser &parser) -> bool
Definition engine.cpp:116
static auto init_core(const cmd_line::parser &parser) -> bool
Definition engine.cpp:172
auto init(rtti::context &ctx) -> bool
Definition input.cpp:49
auto deinit(rtti::context &ctx) -> bool
Definition input.cpp:57
void begin_module(const std::string &module_name)
Owns play-mode state and orchestrates the splash -> running lifecycle.
Definition play_mode.h:17
auto deinit(rtti::context &ctx) -> bool
Definition play_mode.cpp:23
auto init(rtti::context &ctx) -> bool
Definition play_mode.cpp:15
auto deinit(rtti::context &ctx) -> bool
Definition renderer.cpp:164
auto init(rtti::context &ctx, const cmd_line::parser &parser) -> bool
Definition renderer.cpp:121
auto deinit(rtti::context &ctx) -> bool
auto init(rtti::context &ctx, const cmd_line::parser &parser) -> bool
Class responsible for timers.
Definition simulation.h:20
auto init(rtti::context &ctx) -> bool
Definition threader.cpp:31
auto deinit(rtti::context &ctx) -> bool
Definition threader.cpp:38
System responsible for managing user interface components and rendering.
Definition ui_system.h:39
auto init(rtti::context &ctx) -> bool
Initializes the UI system with the given context.
Definition ui_system.cpp:68
auto deinit(rtti::context &ctx) -> bool
Deinitializes the UI system with the given context.