1 /**
2 3D Transformation. 3x4 matrix.
3 
4 Copyright:
5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.  
6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)  
7 Copyright (c) 2017-2018 Godot-D contributors  
8 
9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License)
10 
11 
12 */
13 module godot.core.transform;
14 
15 import godot.core.defs;
16 import godot.core.vector3;
17 import godot.core.quat;
18 import godot.core.basis;
19 import godot.core.aabb;
20 import godot.core.plane;
21 
22 /**
23 Represents one or many transformations in 3D space such as translation, rotation, or scaling. It is similar to a 3x4 matrix.
24 */
25 struct Transform
26 {
27 	@nogc nothrow:
28 	
29 	Basis basis; /// 
30 	Vector3 origin; /// 
31 	
32 	this(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz,
33 		 real_t zx, real_t zy, real_t zz,real_t tx, real_t ty, real_t tz) {
34 		set(xx, xy, xz, yx, yy, yz, zx, zy, zz,tx, ty, tz);
35 	}
36 	
37 	this(in Basis basis, in Vector3 origin) { this.basis = basis; this.origin = origin; }
38 	
39 	
40 	Transform inverseXform(in Transform t) const
41 	{
42 		Vector3 v = t.origin - origin;
43 		return Transform(basis.transposeXform(t.basis),
44 			basis.xform(v));
45 	}
46 	
47 	void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz,real_t tx, real_t ty, real_t tz)
48 	{
49 		basis.elements[0][0]=xx;
50 		basis.elements[0][1]=xy;
51 		basis.elements[0][2]=xz;
52 		basis.elements[1][0]=yx;
53 		basis.elements[1][1]=yy;
54 		basis.elements[1][2]=yz;
55 		basis.elements[2][0]=zx;
56 		basis.elements[2][1]=zy;
57 		basis.elements[2][2]=zz;
58 		origin.x=tx;
59 		origin.y=ty;
60 		origin.z=tz;
61 	}
62 	
63 	
64 	
65 	Vector3 xform(in Vector3 p_vector) const
66 	{
67 		return Vector3(
68 			basis[0].dot(p_vector)+origin.x,
69 			basis[1].dot(p_vector)+origin.y,
70 			basis[2].dot(p_vector)+origin.z
71 		);
72 	}
73 	Vector3 xformInv(in Vector3 p_vector) const
74 	{
75 		Vector3 v = p_vector - origin;
76 		
77 		return Vector3(
78 			(basis.elements[0][0]*v.x ) + ( basis.elements[1][0]*v.y ) + ( basis.elements[2][0]*v.z ),
79 			(basis.elements[0][1]*v.x ) + ( basis.elements[1][1]*v.y ) + ( basis.elements[2][1]*v.z ),
80 			(basis.elements[0][2]*v.x ) + ( basis.elements[1][2]*v.y ) + ( basis.elements[2][2]*v.z )
81 		);
82 	}
83 	
84 	Plane xform(in Plane p_plane) const
85 	{
86 		Vector3 point=p_plane.normal*p_plane.d;
87 		Vector3 point_dir=point+p_plane.normal;
88 		point=xform(point);
89 		point_dir=xform(point_dir);
90 	
91 		Vector3 normal=point_dir-point;
92 		normal.normalize();
93 		real_t d=normal.dot(point);
94 	
95 		return Plane(normal,d);
96 	
97 	}
98 	Plane xformInv(in Plane p_plane) const
99 	{
100 		Vector3 point=p_plane.normal*p_plane.d;
101 		Vector3 point_dir=point+p_plane.normal;
102 		point = xformInv(point);
103 		point_dir = xformInv(point_dir);
104 	
105 		Vector3 normal=point_dir-point;
106 		normal.normalize();
107 		real_t d=normal.dot(point);
108 	
109 		return Plane(normal,d);
110 	
111 	}
112 	
113 	AABB xform(in AABB p_aabb) const
114 	{
115 		/* define vertices */
116 		Vector3 x=basis.getAxis(0)*p_aabb.size.x;
117 		Vector3 y=basis.getAxis(1)*p_aabb.size.y;
118 		Vector3 z=basis.getAxis(2)*p_aabb.size.z;
119 		Vector3 pos = xform( p_aabb.pos );
120 		//could be even further optimized
121 		AABB new_aabb;
122 		new_aabb.pos=pos;
123 		new_aabb.expandTo( pos+x );
124 		new_aabb.expandTo( pos+y );
125 		new_aabb.expandTo( pos+z );
126 		new_aabb.expandTo( pos+x+y );
127 		new_aabb.expandTo( pos+x+z );
128 		new_aabb.expandTo( pos+y+z );
129 		new_aabb.expandTo( pos+x+y+z );
130 		return new_aabb;
131 	}
132 	AABB xformInv(in AABB p_aabb) const
133 	{
134 		/* define vertices */
135 		Vector3[8] vertices=[
136 				Vector3(p_aabb.pos.x+p_aabb.size.x,	p_aabb.pos.y+p_aabb.size.y,	p_aabb.pos.z+p_aabb.size.z),
137 				Vector3(p_aabb.pos.x+p_aabb.size.x,	p_aabb.pos.y+p_aabb.size.y,	p_aabb.pos.z),
138 				Vector3(p_aabb.pos.x+p_aabb.size.x,	p_aabb.pos.y,		p_aabb.pos.z+p_aabb.size.z),
139 				Vector3(p_aabb.pos.x+p_aabb.size.x,	p_aabb.pos.y,		p_aabb.pos.z),
140 				Vector3(p_aabb.pos.x,	p_aabb.pos.y+p_aabb.size.y,	p_aabb.pos.z+p_aabb.size.z),
141 				Vector3(p_aabb.pos.x,	p_aabb.pos.y+p_aabb.size.y,	p_aabb.pos.z),
142 				Vector3(p_aabb.pos.x,	p_aabb.pos.y,		p_aabb.pos.z+p_aabb.size.z),
143 				Vector3(p_aabb.pos.x,	p_aabb.pos.y,		p_aabb.pos.z)
144 		];
145 		AABB ret;
146 		ret.pos=xformInv(vertices[0]);
147 		for(int i=1;i<8;i++)
148 		{
149 			ret.expandTo( xformInv(vertices[i]) );
150 		}
151 		return ret;
152 	
153 	}
154 	
155 	void affineInvert()
156 	{
157 		basis.invert();
158 		origin = basis.xform(-origin);
159 	}
160 	
161 	Transform affineInverse() const
162 	{
163 		Transform ret=this;
164 		ret.affineInvert();
165 		return ret;
166 	
167 	}
168 	
169 	
170 	void invert()
171 	{
172 		basis.transpose();
173 		origin = basis.xform(-origin);
174 	}
175 	
176 	Transform inverse() const
177 	{
178 		// FIXME: this function assumes the basis is a rotation matrix, with no scaling.
179 		// affine_inverse can handle matrices with scaling, so GDScript should eventually use that.
180 		Transform ret=this;
181 		ret.invert();
182 		return ret;
183 	}
184 	
185 	
186 	void rotate(in Vector3 p_axis,real_t p_phi)
187 	{
188 		this = rotated(p_axis, p_phi);
189 	}
190 	
191 	Transform rotated(in Vector3 p_axis,real_t p_phi) const
192 	{
193 		return Transform(Basis( p_axis, p_phi ), Vector3()) * (this);
194 	}
195 	
196 	void rotateBasis(in Vector3 p_axis,real_t p_phi)
197 	{
198 		basis.rotate(p_axis,p_phi);
199 	}
200 	
201 	Transform lookingAt( in Vector3 p_target, in Vector3 p_up ) const
202 	{
203 		Transform t = this;
204 		t.setLookAt(origin,p_target,p_up);
205 		return t;
206 	}
207 	
208 	void setLookAt( in Vector3 p_eye, in Vector3 p_target, in Vector3 p_up )
209 	{
210 		// Reference: MESA source code
211 		Vector3 v_x, v_y, v_z;
212 		/* Make rotation matrix */
213 		
214 		/* Z vector */
215 		v_z = p_eye - p_target;
216 		
217 		v_z.normalize();
218 		
219 		v_y = p_up;
220 		
221 		
222 		v_x=v_y.cross(v_z);
223 		
224 		/* Recompute Y = Z cross X */
225 		v_y=v_z.cross(v_x);
226 		
227 		v_x.normalize();
228 		v_y.normalize();
229 		
230 		basis.setAxis(0,v_x);
231 		basis.setAxis(1,v_y);
232 		basis.setAxis(2,v_z);
233 		origin=p_eye;
234 	}
235 	
236 	Transform interpolateWith(in Transform p_transform, real_t p_c) const
237 	{
238 		/* not sure if very "efficient" but good enough? */
239 		Vector3 src_scale = basis.getScale();
240 		Quat src_rot = basis.quat;
241 		Vector3 src_loc = origin;
242 		
243 		Vector3 dst_scale = p_transform.basis.getScale();
244 		Quat dst_rot = p_transform.basis.quat;
245 		Vector3 dst_loc = p_transform.origin;
246 		
247 		Transform dst;
248 		dst.basis = Basis(src_rot.slerp(dst_rot,p_c));
249 		dst.basis.scale(src_scale.linearInterpolate(dst_scale,p_c));
250 		dst.origin=src_loc.linearInterpolate(dst_loc,p_c);
251 		
252 		return dst;
253 	}
254 	
255 	void scale(in Vector3 p_scale)
256 	{
257 		basis.scale(p_scale);
258 		origin*=p_scale;
259 	}
260 	
261 	Transform scaled(in Vector3 p_scale) const
262 	{
263 		Transform t = this;
264 		t.scale(p_scale);
265 		return t;
266 	}
267 	
268 	void scaleBasis(in Vector3 p_scale)
269 	{
270 		basis.scale(p_scale);
271 	}
272 	
273 	void translate(real_t p_tx, real_t p_ty, real_t p_tz)
274 	{
275 		translate( Vector3(p_tx,p_ty,p_tz) );
276 	}
277 	void translate(in Vector3 p_translation)
278 	{
279 		for( int i = 0; i < 3; i++ )
280 		{
281 			origin[i] += basis[i].dot(p_translation);
282 		}
283 	}
284 	
285 	Transform translated(in Vector3 p_translation) const
286 	{
287 		Transform t=this;
288 		t.translate(p_translation);
289 		return t;
290 	}
291 	
292 	void orthonormalize()
293 	{
294 		basis.orthonormalize();
295 	}
296 	
297 	Transform orthonormalized() const
298 	{
299 		Transform _copy = this;
300 		_copy.orthonormalize();
301 		return _copy;
302 	}
303 	
304 	void opOpAssign(string op : "*")(in Transform p_transform)
305 	{
306 		origin=xform(p_transform.origin);
307 		basis*=p_transform.basis;
308 	}
309 	
310 	Transform opBinary(string op : "*")(in Transform p_transform) const
311 	{
312 		Transform t=this;
313 		t*=p_transform;
314 		return t;
315 	}
316 }
317