1 module dlangui.graphics.scene.node;
2 
3 public import dlangui.core.config;
4 static if (ENABLE_OPENGL):
5 static if (BACKEND_GUI):
6 
7 import dlangui.core.math3d;
8 
9 import dlangui.graphics.scene.transform;
10 
11 /// 3D scene node
12 class Node3d : Transform {
13     import dlangui.core.collections;
14     import dlangui.graphics.scene.scene3d;
15     import dlangui.graphics.scene.drawableobject;
16     import dlangui.graphics.scene.light;
17     import dlangui.graphics.scene.camera;
18 
19     protected Node3d _parent;
20     protected Scene3d _scene;
21     protected string _id;
22     protected bool _visible = true;
23     protected DrawableObjectRef _drawable;
24     protected LightRef _light;
25 
26     protected mat4 _worldMatrix;
27 
28     protected ObjectList!Node3d _children;
29 
30     this(string id = null) {
31         super();
32         _id = id;
33     }
34 
35     this(string id, DrawableObject drawable) {
36         super();
37         _id = id;
38         _drawable = drawable;
39     }
40 
41     @property bool visible() { return _visible; }
42     @property Node3d visible(bool v) { _visible = v; return this; }
43 
44     /// drawable attached to node
45     @property ref DrawableObjectRef drawable() { return _drawable; }
46 
47     /// light attached to node
48     @property ref LightRef light() { return _light; }
49 
50     /// attach light to node
51     @property Node3d light(Light v) {
52         if (_light.get is v)
53             return this;
54         Node3d oldNode = v.node;
55         v.node = this;
56         _light = v;
57         if (oldNode)
58             oldNode._light = null;
59         return this;
60     }
61 
62     /// returns scene for node
63     @property Scene3d scene() {
64         if (_scene)
65             return _scene;
66         if (_parent)
67             return _parent.scene;
68         return cast(Scene3d) this;
69     }
70 
71     @property void scene(Scene3d v) { _scene = v; }
72 
73     /// returns child node count
74     @property int childCount() {
75         return _children.count;
76     }
77 
78     /// returns child node by index
79     Node3d child(int index) {
80         return _children[index];
81     }
82 
83     /// add child node, return current node
84     Node3d addChild(Node3d node) {
85         _children.add(node);
86         node.parent = this;
87         node.scene = scene;
88         return this;
89     }
90 
91     /// removes and destroys child node by index
92     void removeChild(int index) {
93         destroy(_children.remove(index));
94     }
95 
96     /// remove and destroy child node (returns true if child is found and removed)
97     bool removeChild(Node3d child) {
98         int index = findChild(child);
99         if (index >= 0) {
100             removeChild(index);
101             return true;
102         }
103         return false;
104     }
105 
106     /// find node index, returns -1 if not found
107     int findChild(Node3d node) {
108         if (node is null)
109             return -1;
110         for (int i = 0; i < childCount; i++) {
111             if (child(i) is node)
112                 return i;
113         }
114         return -1;
115     }
116 
117     @property ref ObjectList!Node3d children() { return _children; }
118 
119     /// parent node
120     @property Node3d parent() {
121         return _parent;
122     }
123 
124     @property Node3d parent(Node3d v) {
125         _parent = v;
126         _scene = v.scene;
127         return this;
128     }
129     /// id of node
130     @property string id() {
131         return _id;
132     }
133     /// set id for node
134     @property Node3d id(string v) {
135         _id = v;
136         return this;
137     }
138 
139     /// active camera or null of no camera
140     @property Camera activeCamera() {
141         if (!scene)
142             return null;
143         return scene.activeCamera;
144     }
145 
146     @property vec3 cameraPosition() {
147         auto cam = activeCamera;
148         if (cam)
149             return cam.translationWorld;
150         return vec3(0, 0, 0);
151     }
152 
153     /// get view matrix based on active camera
154     @property ref const(mat4) viewMatrix() {
155         auto cam = activeCamera;
156         if (cam)
157             return cam.viewMatrix;
158         return mat4.IDENTITY;
159     }
160 
161     /// get projection*view matrix based on active camera
162     @property ref const(mat4) projectionViewMatrix() {
163         auto cam = activeCamera;
164         if (cam)
165             return cam.projectionViewMatrix;
166         return mat4.IDENTITY;
167     }
168 
169     protected mat4 _projectionViewModelMatrix;
170 
171     /// returns projectionMatrix * viewMatrix * modelMatrix
172     @property ref const(mat4) projectionViewModelMatrix() {
173         // TODO: optimize
174         if (_parent)
175             _projectionViewModelMatrix = _scene.projectionViewMatrix * _parent.matrix * matrix;
176         else
177             _projectionViewModelMatrix = _scene.projectionViewMatrix * matrix;
178         return _projectionViewModelMatrix;
179     }
180 
181     /// returns world matrix
182     @property ref const(mat4) worldMatrix() {
183         if (!parent)
184             return matrix;
185         _worldMatrix = parent.worldMatrix * matrix;
186         return _worldMatrix;
187     }
188 
189     /**
190     * Gets the world view matrix corresponding to this node.
191     *
192     * @return The world view matrix of this node.
193     */
194     @property ref const(mat4) worldViewMatrix() {
195         static mat4 worldView;
196         worldView = viewMatrix * worldMatrix;
197         return worldView;
198     }
199 
200     /// returns translation vector (position) of this node in world space
201     @property vec3 translationWorld() {
202         vec3 translation;
203         worldMatrix.getTranslation(translation);
204         return translation;
205     }
206 
207     /// returns translation vector (position) of this node in view space
208     @property vec3 translationView() {
209         vec3 translation;
210         worldMatrix.getTranslation(translation);
211         viewMatrix.transformPoint(translation);
212         return translation;
213     }
214 
215     /**
216     * Gets the inverse transpose world matrix corresponding to this node.
217     *
218     * This matrix is typically used to transform normal vectors into world space.
219     *
220     * @return The inverse world matrix of this node.
221     */
222     @property ref const(mat4) inverseTransposeWorldMatrix() {
223         static __gshared mat4 invTransWorld;
224         invTransWorld = worldMatrix;
225         invTransWorld.invert();
226         invTransWorld.transpose();
227         return invTransWorld;
228     }
229 
230     /**
231     * Gets the inverse transpose world view matrix corresponding to this node.
232     *
233     * This matrix is typically used to transform normal vectors into view space.
234     *
235     * @return The inverse world view matrix of this node.
236     */
237     @property ref const(mat4) inverseTransposeWorldViewMatrix() {
238         static __gshared mat4 invTransWorldView;
239         invTransWorldView = viewMatrix * worldMatrix;
240         invTransWorldView.invert();
241         invTransWorldView.transpose();
242         return invTransWorldView;
243     }
244 
245 
246     /**
247     * Returns the forward vector of the Node in world space.
248     *
249     * @return The forward vector in world space.
250     */
251     @property vec3 forwardVectorWorld() {
252         return worldMatrix.forwardVector;
253     }
254     /**
255     * Returns the forward vector of the Node in view space.
256     *
257     * @return The forward vector in view space.
258     */
259     @property vec3 forwardVectorView() {
260         vec3 vector = worldMatrix.forwardVector;
261         viewMatrix.transformVector(vector);
262         return vector;
263     }
264 }