Replace some per-frame physics loops with intrusive lists
[xonotic/xonotic-data.pk3dir.git] / qcsrc / ecs / lib.qh
1 #pragma once
2
3 IntrusiveList g_events;
4 IntrusiveList g_components;
5 STATIC_INIT(components) { g_events = IL_NEW(); g_components = IL_NEW(); }
6
7 /** Components always interpolate from the previous state */
8 #define COMPONENT(com) \
9         void com_##com##_interpolate(entity it, float a); \
10         .bool com_##com
11
12 #define FOREACH_COMPONENT(com, body) IL_EACH(g_components, it.com_##com, body)
13
14
15 #define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T
16
17 #define emit(T, ...) \
18         MACRO_BEGIN \
19         IL_EACH(g_events, it.evt_##T##_listener, it.evt_##T(__VA_ARGS__)); \
20         MACRO_END
21
22 #define subscribe(listener, T, fn) \
23         MACRO_BEGIN \
24         listener.evt_##T = (fn); \
25         listener.evt_##T##_listener = true; \
26         IL_PUSH(g_events, listener); \
27         MACRO_END
28
29
30 /**
31  * framelimit 0 is no limit, interpolation does not apply
32  * framerate below minfps will result in less than 100% speed
33  */
34 #define SYSTEM(sys, frameLimit, minfps) \
35         void sys_##sys##_update(entity this, float dt); \
36         noref float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
37         noref float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
38
39 #define SYSTEM_UPDATE(sys) \
40         MACRO_BEGIN \
41         static float t = 0; \
42         float dt = autocvar_xon_sys_##sys##_dt; \
43         float minfps = autocvar_xon_sys_##sys##_minfps; \
44         static float accumulator = 0; \
45         float a = 0; \
46         if (dt) { \
47                 accumulator += min(frametime, 1 / (minfps)); \
48         } else { \
49                 accumulator += frametime; \
50                 dt = accumulator; \
51                 a = 1; \
52         } \
53         while (accumulator >= dt) \
54         { \
55                 time = t; \
56                 FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \
57                 t += dt; \
58                 accumulator -= dt; \
59         } \
60         if (!a) a = accumulator / dt; \
61         FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \
62         MACRO_END