1 module re.math.transform;
2 
3 import re.math;
4 
5 struct Transform {
6     private bool _dirty;
7     private Vector3 _position = Vector3(0, 0, 0);
8     private Vector3 _scale = Vector3(1, 1, 1);
9     private float _rotation = 0;
10     private Matrix4 _localToWorldTransform;
11     private Matrix4 _worldToLocalTransform;
12 
13     // 2d wrappers
14 
15     /// gets 2d position
16     @property Vector2 position2() {
17         auto pos = position;
18         return Vector2(pos.x, pos.y);
19     }
20 
21     /// sets 2d position
22     @property Vector2 position2(Vector2 value) {
23         position = Vector3(value.x, value.y, 0);
24         return value;
25     }
26 
27     /// gets 2d scale
28     @property Vector2 scale2() {
29         auto scl = scale;
30         return Vector2(scl.x, scl.y);
31     }
32 
33     /// sets 2d scale
34     @property Vector2 scale2(Vector2 value) {
35         scale = Vector3(value.x, value.y, 1);
36         return value;
37     }
38 
39     // main sub-transforms
40 
41     /// gets 3d position
42     @property ref Vector3 position() return {
43         update_transform();
44         return _position;
45     }
46 
47     /// sets 3d position
48     @property Vector3 position(Vector3 value) {
49         _dirty = true;
50         return _position = value;
51     }
52 
53     /// gets 3d scale
54     @property Vector3 scale() {
55         update_transform();
56         return _scale;
57     }
58 
59     /// sets 3d scale
60     @property Vector3 scale(Vector3 value) {
61         _dirty = true;
62         return _scale = value;
63     }
64 
65     /// gets Z-axis rotation
66     @property float rotation() {
67         update_transform();
68         return _rotation;
69     }
70 
71     /// sets Z-axis rotation
72     @property float rotation(float radians) {
73         _dirty = true;
74         return _rotation = radians;
75     }
76 
77     /// gets local-to-world transform
78     @property Matrix4 local_to_world_transform() {
79         update_transform();
80         return _localToWorldTransform;
81     }
82 
83     /// gets world-to-local transform
84     @property Matrix4 world_to_local_transform() {
85         update_transform();
86         return _worldToLocalTransform;
87     }
88 
89     private void update_transform() {
90         if (!_dirty)
91             return;
92 
93         // recompute matrices
94         auto translation_mat = raymath.MatrixTranslate(_position.x, _position.y, _position.z);
95         auto rotation_mat = raymath.MatrixRotateZ(_rotation);
96         auto scale_mat = raymath.MatrixScale(_scale.x, _scale.y, _scale.z);
97 
98         auto tmp1 = raymath.MatrixMultiply(scale_mat, rotation_mat);
99         auto tmp2 = raymath.MatrixMultiply(tmp1, translation_mat);
100 
101         _localToWorldTransform = tmp2;
102         _worldToLocalTransform = raymath.MatrixInvert(_localToWorldTransform);
103 
104         _dirty = false;
105 
106     }
107 }