]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/lib/deglobalization.qh
comment
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / deglobalization.qh
1 #include "lib/misc.qh"
2 #include "lib/static.qh"
3 #include "lib/vector.qh"
4
5 // These macros wrap functions which use globals so mutation only occurs inside them and is not visible from outside.
6 // Functions for which all usages are replaced with these macros can be hidden inside our `*defs.qh` files
7 // to prevent anyone from using them accidentally.
8
9 // TODO stuff in the engine that uses the v_forward/v_right/v_up globals and is not wrapped yet:
10 //  - RF_USEAXIS, addentities, predraw,
11 //    - CL_GetEntityMatrix (in engine but is called from other functions so transitively any of them can use the globals - e.g. V_CalcRefdef, maybe others)
12 //    - however RF_USEAXIS is only used if MF_ROTATE is used which is only set in one place
13 //  - e.camera_transform / CL_VM_TransformView (in engine
14 //    - this is the only used function that both sets and gets the globals (aim does too but isn't used in our code)
15 //  - adddynamiclight
16 //  - makestatic
17
18 #define NEW_VECS(...) EVAL(OVERLOAD(NEW_VECS, __VA_ARGS__))
19 #define NEW_VECS_3(forward, right, up) vector forward = '0 0 0'; vector right = '0 0 0'; vector up = '0 0 0';
20 #define NEW_VECS_4(forward, right, up, origin) NEW_VECS_3(forward, right, up); vector origin = '0 0 0';
21
22 #define CLEAR_V_GLOBALS() v_forward = VEC_NAN; v_right = VEC_NAN; v_up = VEC_NAN;
23 #define GET_V_GLOBALS(forward, right, up) forward = v_forward; right = v_right; up = v_up;
24 #define SET_V_GLOBALS(forward, right, up) v_forward = forward; v_right = right; v_up = up;
25
26 #ifdef GAMEQC
27 STATIC_INIT(globals) {
28         // set to NaN to more easily detect uninitialized use
29         // TODO when all functions are wrapped and the raw functions are not used anymore,
30         // uncomment the defines in *progs.qh files that hide the raw functions
31         // and assert that the global vectors are NaN before calling the raw functions here
32         // to make sure nobody (even builtins) is accidentally using them - NaN is the most likely value to expose remaining usages
33
34         // TODO make sure `isnan` actually works - potential compiler bug:
35         //LOG_INFOF("%f\n", 0.0/0.0 == 0.0/0.0);
36         //LOG_INFOF("%f\n", 0.0/0.0 != 0.0/0.0);
37         //float x = 0.0/0.0;
38         //LOG_INFOF("%f\n", x == x);
39         //LOG_INFOF("%f\n", x != x);
40
41         CLEAR_V_GLOBALS();
42 }
43 #endif
44
45 /// Same as the `makevectors` builtin but uses the provided locals instead of the `v_*` globals.
46 /// Always use this instead of raw `makevectors` to make the data flow clear.
47 #define MAKE_VECTORS(angles, forward, right, up) MACRO_BEGIN { \
48         _makevectors_hidden(angles); \
49         GET_V_GLOBALS(forward, right, up); \
50         CLEAR_V_GLOBALS(); \
51 } MACRO_END
52
53 /// Same as `MAKE_VECTORS` but also creates the locals for convenience.
54 #define MAKE_VECTORS_NEW(angles, forward, right, up) \
55         NEW_VECS(forward, right, up); \
56         MAKE_VECTORS(angles, forward, right, up);
57
58 /// Returns all 4 vectors by assigning to them (instead of returning a value) for consistency (and sanity)
59 #define SKEL_GET_BONE_ABS(skel, bonenum, forward, right, up, origin) MACRO_BEGIN { \
60         origin = _skel_get_boneabs_hidden(skel, bonenum) \
61         GET_V_GLOBALS(forward, right, up); \
62         CLEAR_V_GLOBALS(); \
63 } MACRO_END
64
65 #define SKEL_GET_BONE_ABS_NEW(skel, bonenum, forward, right, up, origin) \
66         NEW_VECS(forward, right, up, origin); \
67         SKEL_GET_BONE_ABS(skel, bonenum, forward, right, up, origin)
68
69 #define SKEL_SET_BONE(skel, bonenum, org, forward, right, up) MACRO_BEGIN { \
70         SET_V_GLOBALS(forward, right, up); \
71         _skel_set_bone_hidden(skel, bonenum, org); \
72         CLEAR_V_GLOBALS(); \
73 } MACRO_END
74
75 #define VECTOR_VECTORS(forward_in, forward, right, up) MACRO_BEGIN { \
76         _vectorvectors_hidden(forward_in); \
77         GET_V_GLOBALS(forward, right, up); \
78         CLEAR_V_GLOBALS(); \
79 } MACRO_END
80
81 #define VECTOR_VECTORS_NEW(forward_in, forward, right, up) \
82         NEW_VECS(forward, right, up); \
83         VECTOR_VECTORS(forward_in, forward, right, up);
84
85 /// Note that this only avoids the v_* globals, not the gettaginfo_* ones
86 #define GET_TAG_INFO(ent, tagindex, forward, right, up, origin) MACRO_BEGIN {  \
87         origin = _gettaginfo_hidden(ent, tagindex); \
88         GET_V_GLOBALS(forward, right, up); \
89         CLEAR_V_GLOBALS(); \
90 } MACRO_END
91
92 #define GET_TAG_INFO_NEW(ent, tagindex, forward, right, up, origin) \
93         NEW_VECS(forward, right, up, origin); \
94         GET_TAG_INFO(ent, tagindex, forward, right, up, origin);