1 /**
2  * Copyright:       Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved
3  * Authors:         $(Gabriel Gheorghe)
4  * License:         $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007)
5  * Source:          $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/math/transform.d)
6  * Documentation:
7  * Coverage:
8 **/
9 module liberty.math.transform;
10 
11 import liberty.logger.impl;
12 import liberty.math.functions;
13 import liberty.math.vector;
14 import liberty.math.matrix;
15 import liberty.scene.component;
16 import liberty.scene.meta;
17 import liberty.scene.entity;
18 import liberty.framework.primitive.vertex;
19 import liberty.framework.terrain.vertex;
20 import liberty.framework.gui.widget;
21 import liberty.core.platform;
22 
23 /**
24  *
25 **/
26 final class Transform : IComponent {
27   private {
28     // getParent
29     Entity parent;
30     Matrix4F modelMatrix = Matrix4F.identity();
31     Matrix4F tempModelMatrix = Matrix4F.identity();
32     
33     Vector3F location = Vector3F.zero;
34     Vector3F rotation = Vector3F.zero;
35     Vector3F scale = Vector3F.one;
36 
37     Vector3F pivot = Vector3F.zero;
38   }
39 
40   /**
41    *
42   **/
43   this(Entity parent)   {
44     this.parent = parent;
45   }
46 
47   /**
48    *
49   **/
50   this(Entity parent, Transform transform) {
51     this(parent);
52     location = transform.location;
53 
54     tempModelMatrix.c[0][3] += location.x;
55     tempModelMatrix.c[1][3] += location.y;
56     tempModelMatrix.c[2][3] += location.z;
57 
58     updateModelMatrix();
59   }
60 
61   /**
62    * Translate location using x, y and z scalars as coordinates.
63    * Location is done in  space.
64   **/
65 	Transform setLocation(string op = "=")(float x, float y, float z)
66   if (op == "=" || op == "+=" || op == "-=")
67   do {
68 		return setLocation!(op)(Vector3F(x, y, z));
69 	}
70 
71   /**
72    * Translate location using a vector with x, y and z coordinates.
73    * Location is done in  space.
74    * Returns reference to this so it can be used in a stream.
75   **/
76 	Transform setLocation(string op = "=")(Vector3F location)
77   if (op == "=" || op == "+=" || op == "-=")
78   do {
79     static if (op == "=") {
80       mixin("tempModelMatrix.c[0][3] " ~ op ~ " this.location.x + location.x;");
81       mixin("tempModelMatrix.c[1][3] " ~ op ~ " this.location.y + location.y;");
82       mixin("tempModelMatrix.c[2][3] " ~ op ~ " this.location.z + location.z;");
83     } else {
84       mixin("tempModelMatrix.c[0][3] " ~ op ~ " location.x;");
85       mixin("tempModelMatrix.c[1][3] " ~ op ~ " location.y;");
86       mixin("tempModelMatrix.c[2][3] " ~ op ~ " location.z;");
87     }
88     mixin("this.location " ~ op ~ " location;");
89 
90     updateModelMatrix;
91 		return this;
92 	}
93 
94   /**
95    * Translate x-coordinate location.
96    * Location is done in  space.
97    * Returns reference to this so it can be used in a stream.
98   **/
99 	Transform setLocationX(string op = "=")(float value)
100   if (op == "=" || op == "+=" || op == "-=")
101   do {
102     static if (op == "=")
103       mixin("tempModelMatrix.c[0][3] " ~ op ~ " location.x + value;");
104     else
105       mixin("tempModelMatrix.c[0][3] " ~ op ~ " value;");
106     mixin("location.x " ~ op ~ " value;");
107 
108     updateModelMatrix;
109     return this;
110 	}
111   
112   /**
113    * Translate y-coordinate location.
114    * Location is done in  space.
115    * Returns reference to this so it can be used in a stream.
116   **/
117 	Transform setLocationY(string op = "=")(float value)
118   if (op == "=" || op == "+=" || op == "-=")
119   do {
120     static if (op == "=")
121       mixin("tempModelMatrix.c[1][3] " ~ op ~ " location.y + value;");
122     else
123       mixin("tempModelMatrix.c[1][3] " ~ op ~ " value;");
124     mixin("location.y " ~ op ~ " value;");
125 
126     updateModelMatrix;
127     return this;
128 	}
129   
130   /**
131    * Translate z-coordinate location.
132    * Location is done in  space.
133    * Returns reference to this so it can be used in a stream.
134   **/
135 	Transform setLocationZ(string op = "=")(float value)
136   if (op == "=" || op == "+=" || op == "-=")
137   do {
138     static if (op == "=")
139       mixin("tempModelMatrix.c[2][3] " ~ op ~ " location.z + value;");
140     else
141       mixin("tempModelMatrix.c[2][3] " ~ op ~ " value;");
142     mixin("location.z " ~ op ~ " value;");
143 
144     updateModelMatrix;
145     return this;
146 	}
147   
148   /**
149    * Rotate object specifying the rotation angle and rotation coordinates using scalars x, y and z.
150    * Returns reference to this so it can be used in a stream.
151   **/
152 	//Transform setRotation(string op = "=")(float angle, float rotX, float rotY, float rotZ) 
153   //if (op == "=" || op == "+=" || op == "-=")
154   //do {
155 	//	return setRotation!op(angle, Vector3F(rotX, rotY, rotZ));
156 	//}
157   
158   /**
159    * Rotate object specifying the rotation angle and a vector of three scalars for x, y and z.
160    * Returns reference to this so it can be used in a stream.
161   **/
162 	//Transform setRotation(string op = "=")(float angle, Vector3F rotation) 
163   //if (op == "=" || op == "+=" || op == "-=")
164   //do {  
165   //  return this;
166 	//}
167 
168   /*Transform setRotation(string op = "=")(Matrix3F rotation) 
169   if (op == "=" || op == "+=" || op == "-=")
170   do {
171     mixin("tempModelMatrix.c[0][0] " ~ op ~ " rotation.c[0][0];");
172     mixin("tempModelMatrix.c[0][1] " ~ op ~ " rotation.c[0][1];");
173     mixin("tempModelMatrix.c[0][2] " ~ op ~ " rotation.c[0][2];");
174     mixin("tempModelMatrix.c[1][0] " ~ op ~ " rotation.c[1][0];");
175     mixin("tempModelMatrix.c[1][1] " ~ op ~ " rotation.c[1][1];");
176     mixin("tempModelMatrix.c[1][2] " ~ op ~ " rotation.c[1][2];");
177     mixin("tempModelMatrix.c[2][0] " ~ op ~ " rotation.c[2][0];");
178     mixin("tempModelMatrix.c[2][1] " ~ op ~ " rotation.c[2][1];");
179     mixin("tempModelMatrix.c[2][2] " ~ op ~ " rotation.c[2][2];");
180     updateModelMatrix();
181     return this;
182 	}*/
183   
184   /**
185    * Rotate object specifying the rotation angle for pitch axis.
186    * Returns reference to this so it can be used in a stream.
187   **/
188 	Transform rotatePitch(string op = "=")(float angle) 
189   if (op == "=" || op == "+=" || op == "-=")
190   do {
191     mixin("rotation.x " ~ op ~ " angle;");
192 		tempModelMatrix.rotateX(rotation.x.radians);
193 
194     updateModelMatrix();
195     return this;
196 	}
197 
198   /**
199    * Rotate object specifying the rotation angle for yaw axis.
200    * Returns reference to this so it can be used in a stream.
201   **/
202 	Transform rotateYaw(string op = "=")(float angle) 
203   if (op == "=" || op == "+=" || op == "-=")
204   do {
205     mixin("rotation.y " ~ op ~ " angle;");
206 		tempModelMatrix.rotateY(rotation.y.radians);
207 
208     updateModelMatrix();
209     return this;
210 	}
211 
212   /**
213    * Rotate object specifying the rotation angle for roll axis.
214    * Returns reference to this so it can be used in a stream.
215   **/
216 	Transform rotateRoll(string op = "=")(float angle) 
217   if (op == "=" || op == "+=" || op == "-=")
218   do {
219     mixin("rotation.z " ~ op ~ " angle;");
220 		tempModelMatrix.rotateZ(rotation.z.radians);
221 
222     updateModelMatrix();
223     return this;
224 	}
225 
226   /**
227    * Scale object using same value for x, y and z coordinates.
228    * Returns reference to this so it can be used in a stream.
229   **/
230 	Transform setScale(string op = "=")(float value) 
231   if (op == "=" || op == "+=" || op == "-=")
232   do {
233     return setScale!op(Vector3F(value, value, value));
234 	}
235   
236   /**
237    * Scale object using x, y and z scalars for coordinates.
238    * Returns reference to this so it can be used in a stream.
239   **/
240 	Transform setScale(string op = "=")(float x, float y, float z) 
241   if (op == "=" || op == "+=" || op == "-=")
242   do {
243     return setScale!op(Vector3F(x, y, z));
244 	}
245   
246   /**
247    * Scale object using a vector with x, y and z scalars for coordinates.
248    * Returns reference to this so it can be used in a stream.
249   **/
250 	Transform setScale(string op = "=")(Vector3F scale) 
251   if (op == "=" || op == "+=" || op == "-=")
252   do {
253 		mixin("tempModelMatrix.c[0][0] " ~ op ~ " scale.x;");
254     mixin("tempModelMatrix.c[1][1] " ~ op ~ " scale.y;");
255     mixin("tempModelMatrix.c[2][2] " ~ op ~ " scale.z;");
256 
257     updateModelMatrix();
258     return this;
259 	}
260   
261   /**
262    * Scale object on x axis.
263    * Returns reference to this so it can be used in a stream.
264   **/
265 	Transform setScaleX(string op = "=")(float value) 
266   if (op == "=" || op == "+=" || op == "-=")
267   do {
268 		mixin("tempModelMatrix.c[0][0] " ~ op ~ " value;");
269 
270     updateModelMatrix();
271     return this;
272 	}
273   
274   /**
275    * Scale object on y axis.
276    * Returns reference to this so it can be used in a stream.
277   **/
278 	Transform setScaleY(string op = "=")(float value) 
279   if (op == "=" || op == "+=" || op == "-=")
280   do {
281 		mixin("tempModelMatrix.c[1][1] " ~ op ~ " value;");
282 
283     updateModelMatrix();
284     return this;
285 	}
286   
287   /**
288    * Scale object on z axis.
289    * Returns reference to this so it can be used in a stream.
290   **/
291 	Transform setScaleZ(string op = "=")(float value) 
292   if (op == "=" || op == "+=" || op == "-=")
293   do {
294 		mixin("tempModelMatrix.c[2][2] " ~ op ~ " value;");
295 
296     updateModelMatrix();
297     return this;
298 	}
299   
300   /**
301    * Returns object location in relative space.
302   **/
303 	ref const(Vector3F) getLocation()   const {
304 		return location;
305 	}
306   
307   /**
308    * Returns object rotation in relative space.
309   **/
310 	ref const(Vector3F) getRotation()   const {
311 		return rotation;
312 	}
313   
314   /**
315    * Returns object scale in relative space.
316   **/
317 	ref const(Vector3F) getScale()   const {
318 		return scale;
319 	}
320 
321   /**
322    *
323   **/
324   Transform setPivot(string op = "=")(float x, float y, float z) 
325   if (op == "=" || op == "+=" || op == "-=")
326   do {
327     return setPivot!op(Vector3F(x, y, z));
328   }
329 
330   /**
331    *
332    * Returns reference to this so it can be used in a stream.
333   **/
334   Transform setPivot(string op = "=")(Vector3F pivot) 
335   if (op == "=" || op == "+=" || op == "-=")
336   do {
337     mixin("this.pivot " ~ op ~ " pivot;");
338     updateModelMatrix();
339     return this;
340   }
341 
342   /**
343    *
344    * Returns reference to this so it can be used in a stream.
345   **/
346 	Transform setPivotX(string op = "=")(float value) 
347   if (op == "=" || op == "+=" || op == "-=")
348   do {
349     mixin("pivot.x " ~ op ~ " value;");
350     updateModelMatrix();
351     return this;
352 	}
353 
354   /**
355    *
356    * Returns reference to this so it can be used in a stream.
357   **/
358 	Transform setPivotY(string op = "=")(float value) 
359   if (op == "=" || op == "+=" || op == "-=")
360   do {
361     mixin("pivot.y " ~ op ~ " value;");
362     updateModelMatrix();
363     return this;
364 	}
365 
366   /**
367    *
368    * Returns reference to this so it can be used in a stream.
369   **/
370 	Transform setPivotZ(string op = "=")(float value) 
371   if (op == "=" || op == "+=" || op == "-=")
372   do {
373     mixin("pivot.z " ~ op ~ " value;");
374     updateModelMatrix();
375     return this;
376 	}
377 
378   /**
379    *
380   **/
381   ref const(Vector3F) getPivot()   const {
382     return pivot;
383   }
384   
385   /**
386    * Returns model matrix for the object representation.
387   **/
388 	ref const(Matrix4F) getModelMatrix()   const {
389 		return modelMatrix;
390 	}
391  
392   /**
393    *
394   **/
395   Entity getParent()   {
396     return parent;
397   }
398 
399   private void updateModelMatrix()   {
400     modelMatrix = tempModelMatrix;
401     modelMatrix.c[0][3] += pivot.x;
402     modelMatrix.c[1][3] -= pivot.y;
403     modelMatrix.c[2][3] += pivot.z;
404   }
405 }