1 module dlangui.graphics.scene.transform;
2 
3 public import dlangui.core.config;
4 static if (ENABLE_OPENGL):
5 static if (BACKEND_GUI):
6 
7 import dlangui.core.math3d;
8 import dlangui.core.types;
9 
10 /// 3d transform: scale + translation + rotation
11 class Transform : RefCountedObject {
12     // transform flags
13     protected bool _dirtyTransform = true;
14     protected bool _hasScale = false;
15     protected bool _hasTranslation = false;
16     protected bool _hasRotation = false;
17     // transform parameters
18     protected vec3 _scale = vec3(1.0f, 1.0f, 1.0f);
19     protected vec3 _translation = vec3(0.0f, 0.0f, 0.0f);
20     protected mat4 _rotation = mat4.identity;
21     // resulting transform matrix
22     protected mat4 _matrix;
23 
24     this() {
25         setIdentity();
26     }
27 
28     protected void invalidateTransform() {
29         _dirtyTransform = true;
30     }
31 
32     /// get scale vector
33     public @property ref const(vec3) scaling() const { return _scale; }
34     /// get scale X
35     public @property float scalingX() const { return _scale.x; }
36     /// get scale Y
37     public @property float scalingY() const { return _scale.y; }
38     /// get scale Z
39     public @property float scalingZ() const { return _scale.z; }
40 
41     /// set scale vector
42     public @property void scaling(const ref vec3 value) { _scale = value; _hasScale = true; invalidateTransform(); }
43     /// set scale vector x, y, z to the same value
44     public @property void scaling(float value) { _scale.x = _scale.y = _scale.z = value; _hasScale = true; invalidateTransform(); }
45     /// set scale X
46     public @property void scalingX(float value) { _scale.x = value; _hasScale = true; invalidateTransform(); }
47     /// set scale Y
48     public @property void scalingY(float value) { _scale.y = value; _hasScale = true; invalidateTransform(); }
49     /// set scale Z
50     public @property void scalingZ(float value) { _scale.z = value; _hasScale = true; invalidateTransform(); }
51 
52     /// get translation vector
53     public @property ref const(vec3) translation() const { return _translation; }
54     /// get translation X
55     public @property float translationX() const { return _translation.x; }
56     /// get translation Y
57     public @property float translationY() const { return _translation.y; }
58     /// get translation Z
59     public @property float translationZ() const { return _translation.z; }
60 
61     /// set translation vector
62     public @property void translation(inout vec3 value) { _translation = value; _hasTranslation = true; invalidateTransform(); }
63     /// set translation vector x, y, z to the same value
64     public @property void translation(float value) { _translation.x = _translation.y = _translation.z = value; _hasTranslation = true; invalidateTransform(); }
65     /// set translation x
66     public @property void translationX(float value) { _translation.x = value; _hasTranslation = true; invalidateTransform(); }
67     /// set translation y
68     public @property void translationY(float value) { _translation.y = value; _hasTranslation = true; invalidateTransform(); }
69     /// set translation z
70     public @property void translationZ(float value) { _translation.z = value; _hasTranslation = true; invalidateTransform(); }
71 
72     /// translate by vector
73     public void translate(vec3 value) { _translation += value; _hasTranslation = true; invalidateTransform(); }
74     /// translate X
75     public void translateX(float value) { _translation.x += value; _hasTranslation = true; invalidateTransform(); }
76     /// translate Y
77     public void translateY(float value) { _translation.y += value; _hasTranslation = true; invalidateTransform(); }
78     /// translate Z
79     public void translateZ(float value) { _translation.z += value; _hasTranslation = true; invalidateTransform(); }
80 
81     /// scale by vector
82     public void scale(vec3 value) { _scale.x *= value.x; _scale.y *= value.y; _scale.z *= value.z; _hasScale = true; invalidateTransform(); }
83     /// scale all axis by the same values
84     public void scale(float value) { _scale *= value; _hasScale = true; invalidateTransform(); }
85     /// scale X
86     public void scaleX(float value) { _scale.x *= value; _hasScale = true; invalidateTransform(); }
87     /// scale Y
88     public void scaleY(float value) { _scale.y *= value; _hasScale = true; invalidateTransform(); }
89     /// scale Z
90     public void scaleZ(float value) { _scale.z *= value; _hasScale = true; invalidateTransform(); }
91 
92     /// rotate around X axis
93     public void rotateX(float angle) { _rotation.rotateX(angle); _hasRotation = true; invalidateTransform(); }
94     /// rotate around Y axis
95     public void rotateY(float angle) { _rotation.rotateY(angle); _hasRotation = true; invalidateTransform(); }
96     /// rotate around Z axis
97     public void rotateZ(float angle) { _rotation.rotateZ(angle); _hasRotation = true; invalidateTransform(); }
98     /// rotate around custom axis
99     public void rotate(float angle, const ref vec3 axis) { _rotation.rotate(angle, axis); _hasRotation = true; invalidateTransform(); }
100 
101     /// set transform to identity transform
102     public void setIdentity() {
103         _hasTranslation = _hasRotation = _hasScale = _dirtyTransform = false;
104         _scale = vec3(1.0f, 1.0f, 1.0f);
105         _translation = vec3(0.0f, 0.0f, 0.0f);
106         _rotation.setIdentity();
107         _matrix.setIdentity();
108     }
109 
110     /// get transform matrix, recalculates if needed
111     public @property ref const(mat4) matrix() {
112         if (_dirtyTransform) {
113             _matrix.setIdentity();
114             if (_hasTranslation)
115                 _matrix.translate(_translation);
116             if (_hasRotation)
117                 _matrix *= _rotation;
118             if (_hasScale)
119                 _matrix.scale(_scale);
120             _dirtyTransform = false;
121         }
122         return _matrix;
123     }
124 
125     @property void matrix(ref const(mat4) m) {
126         _matrix = m;
127         _dirtyTransform = false;
128     }
129 
130     void lookAt(const vec3 eye, const vec3 center, const vec3 up) {
131         _matrix.setIdentity();
132         _matrix.lookAt(eye, center, up);
133         _dirtyTransform = false;
134     }
135 }