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/matrix.d)
6  * Documentation:
7  * Coverage:
8 **/
9 module liberty.math.matrix;
10 
11 import std.traits : isFloatingPoint;
12 
13 import liberty.math.traits;
14 import liberty.math.functions;
15 import liberty.math.vector;
16 
17 /// T = Type of elements.
18 /// R = Number of rows.
19 /// C = Number of columns.
20 /// O = Matrix order. It can be RowMajor or ColumnMajor.
21 struct Matrix(T, ubyte R, ubyte C = R) if (R >= 2 && R <= 4 && C >= 2 && C <= 4) {
22 	///
23 	alias type = T;
24 	///
25 	enum rowCount = R;
26 	///
27 	enum columnCount = C;
28 	///
29 	enum order = 0;
30 	///
31 	enum bool isSquare = (R == C);
32 	///
33 	alias RowType = Vector!(T, C) ;
34 	///
35 	alias ColumnType = Vector!(T, R);
36 	/// Fields definition.
37 	union {
38 		/// All elements.
39 		T[C * R] v;
40 		/// All rows.
41 		RowType[R] row;
42 		/// Components.
43 		T[C][R] c;
44 	}
45 
46   static if (R == 4 && C == 4) {
47     void setTranslation(string op = "=")(Vector3!T translation)  
48     if (op == "=" || op == "+=" || op == "-=")
49     do {
50       mixin("c[0][3] " ~ op ~ " translation.x;");
51       mixin("c[1][3] " ~ op ~ " translation.y;");
52       mixin("c[2][3] " ~ op ~ " translation.z;");
53     }
54 
55     void setScale(string op = "=")(Vector3!T scale)  
56     if (op == "=" || op == "+=" || op == "-=")
57     do {
58       mixin("c[0][0] " ~ op ~ " scale.x;");
59       mixin("c[1][1] " ~ op ~ " scale.y;");
60       mixin("c[2][2] " ~ op ~ " scale.z;");
61     }
62   }
63 
64 
65 	///
66 	this(U...)(U values)   {
67 		import std.meta : allSatisfy;
68 		import std.traits : isAssignable;
69 		enum bool isAsgn(U) = isAssignable!(T, U);
70 		static if ((U.length == C * R) && allSatisfy!(isAsgn, U)) {
71 			static foreach (i, x; values) {
72 				v[i] = x;
73 			}
74 		} else static if ((U.length == 1) && isAsgn!U && (!is(U[0] : Matrix))) {
75 			v[] = values[0];
76 		} else static if (U.length == 0) {
77 			v[] = cast(T)0;
78 		} else {
79 			static assert(false, "Cannot create a matrix from given arguments!");
80 		}
81 	}
82 	///
83 	  unittest {
84 		// Create a matrix using all values.
85 		const matrix1 = Matrix!(int, 2)(1, 2, 3, 4);
86 		assert(matrix1.v == [1, 2, /**/ 3, 4]);
87 		// Create a matrix from one value.
88 		const matrix2 = Matrix!(float, 2)(5.2f);
89 		assert(matrix2.v == [5.2f, 5.2f, /**/ 5.2f, 5.2f]);
90 		// Create a matrix with no value (implicit 0).
91 		const matrix3 = Matrix!(short, 2)();
92 		assert(matrix3.v == [0, 0, /**/ 0, 0]);
93 	}
94 	/// Construct a matrix from columns.
95 	static Matrix fromColumns(ColumnType[] columns)  
96 	in {
97 		assert(columns.length == C);
98 	} do {
99 		Matrix ret = void;
100 		// todo
101 		return ret;
102 	}
103 	///
104 	  unittest {
105 		// todo
106 	}
107 	/// Construct a matrix from rows.
108 	static Matrix fromRows(RowType[] rows)  
109 	in {
110 		assert(rows.length == R);
111 	} do {
112 		Matrix ret = void;
113 		ret.row[] = rows[];
114 		return ret;
115 	}
116 	///
117 	  unittest {
118 		auto row = Vector!(double, 2)(2.0, 4.5);
119 		const matrix = Matrix!(double, 2).fromRows([row, row]);
120 		assert(matrix.v == [2.0, 4.5, /**/ 2.0, 4.5]);
121 	}
122 	/// Returns an identity matrix.
123 	static Matrix identity()   {
124 		Matrix ret = void;
125 		static foreach (i; 0 .. R) {
126 			static foreach (j; 0 .. C) {
127 				static if (i == j) {
128 					ret.c[i][j] = 1;
129 				} else {
130 					ret.c[i][j] = 0;
131 				}
132 			}
133 		}
134 		return ret;
135 	}
136 	///
137 	  unittest {
138 		const matrix = Matrix!(uint, 3).identity();
139 		assert(matrix.v == [1, 0, 0, /**/ 0, 1, 0, /**/ 0, 0, 1]);
140 	}
141 	/// Returns a constant matrix.
142 	static Matrix constant(U)(U x)   {
143 		Matrix ret = void;
144 		static foreach (i; 0 .. R * C) {
145 			ret.v[i] = cast(T)x;
146 		}
147 		return ret;
148 	}
149 	///
150 	  unittest {
151 		const matrix = Matrix!(int, 2, 3).constant(7);
152 		assert(matrix.v == [7, 7, 7, /**/ 7, 7, 7]);
153 	}
154 	///
155 	ColumnType column(int j)   const {
156 		ColumnType ret = void;
157 		static foreach (i; 0..R) {
158 			ret.v[i] = c[i][j];
159 		}
160 		return ret;
161 	}
162 	///
163 	Matrix opBinary(string op)(T fprimitive)   const if (op == "*") {
164 		Matrix ret = void;
165 		static foreach (i; 0..R) {
166 			static foreach (j; 0..C) {
167 				ret.c[i][j] = c[i][j] * fprimitive;
168 			}
169 		}
170 		return ret;
171 	}
172 	///
173 	  unittest {
174 		const m1 = Matrix2I(3);
175 		const m2 = m1 * 4;
176 		assert(m2.v == [12, 12, /**/ 12, 12]);
177 	}
178 	///
179 	ColumnType opBinary(string op)(RowType x)   const if (op == "*") {
180 		ColumnType ret = void;
181 		static foreach (i; 0..R) {
182 			T sum = 0;
183 			static foreach (j; 0..C) {
184 				sum += c[i][j] * x.v[j];
185 			}
186 			res.v[i] = sum;
187 		}
188 		return ret;
189 	}
190 	///
191 	auto opBinary(string op, U)(U x)   const if (isMatrixInstance!U && (U.rowCount == C) && (op == "*")) {
192 		Matrix!(T, R, U.columnCount) ret = void;
193 		T sum = 0;
194 		static foreach (i; 0..R) {
195 			static foreach (j; 0..U.columnCount) {
196 				static foreach (k; 0..C) {
197 					sum += c[i][k] * x.c[k][j];
198 				}
199 				ret.c[i][j] = sum;
200 				sum = 0;
201 			}
202 		}
203 		return ret;
204 	}
205 	///
206 	  unittest {
207 		auto m1 = Matrix2I(2, 5, /**/ -1, 2);
208 		auto m2 = Matrix2x3I(3, 3, -2, /**/ 3, 4, 3);
209 		auto m3 = m1 * m2;
210 		assert(m3.v == [21, 26, 11, /**/ 3, 5, 8]);
211 	}
212 	///
213 	Matrix opBinary(string op, U)(U rhs)   const if (op == "+" || op == "-") {
214 		Matrix ret = void;
215 		static if (is (U : Matrix)) {
216 			static foreach (i; 0..R) {
217 				static foreach (j; 0..C) {
218 					mixin("ret.c[i][j] = c[i][j] " ~ op ~ " rhs.c[i][j];");
219 				}
220 			}
221 		} else static if (is (U : T)) {
222 			mixin("ret.v[] = this.v[] " ~ op ~ " rhs;");
223 		} else {
224 			static assert(0, "Cannot assign a variable of type " ~ U.stringof ~ " within a variable of type " ~ Matrix.stringof);
225 		}
226 		return ret;
227 	}
228 	///
229 	  unittest {
230 		const m1 = Matrix2I(1, 3, /**/ -1, 4);
231 		const m2 = Matrix2I(5, 2, /**/ 1, 0);
232 		const m3 = m1 + m2;
233 		assert(m3.v == [6, 5, /**/ 0, 4]);
234 		const m4 = m1 - 7;
235 		assert(m4.v == [-6, -4, /**/ -8, -3]);
236 	}
237 	///
238 	ref Matrix opOpAssign(string op, U)(U rhs)   {
239 		static if (is(U : Matrix) || is(U : T)) {
240 			mixin("this = this " ~ op ~ " rhs;");
241 		} else {
242 			static assert(0, "Cannot assign a variable of type " ~ U.stringof ~
243         " within a variable of type " ~ Matrix.stringof
244       );
245 		}
246 		return this;
247 	}
248 	///
249 	  unittest {
250 		auto m1 = Matrix2I(1, 3, /**/ -1, 4);
251 		const m2 = Matrix2I(5, 2, /**/ 1, 0);
252 		m1 += m2;
253 		assert(m1.v == [6, 5, /**/ 0, 4]);
254 		m1 -= 2;
255 		assert(m1.v == [4, 3, /**/ -2, 2]);
256 	}
257 	///
258 	Matrix opUnary(string op)()   const if (op == "+" || op == "-" || op == "~" || op == "!") {
259 		Matrix ret = void;
260 		static foreach (i; 0..R * C) {
261 			mixin("ret.v[i] = " ~ op ~ "v[i];");
262 		}
263 		return ret;
264 	}
265 	///
266 	  unittest {
267 		const m1 = Matrix2I(1, 3, /**/ -1, 0);
268 		assert((+m1).v == [1, 3, /**/ -1, 0]);
269 		assert((-m1).v == [-1, -3, /**/ 1, 0]);
270 		assert((~m1).v == [-2, -4, /**/ 0, -1]);
271 		// *** BUG ***
272 		//auto m2 = Matrix!(bool, 2)(true, true, /**/ false, false);
273 		//assert((!m2).v == [false, false, /**/ true, true]);
274 	}
275 	///
276 	U opCast(U)()   const if (isMatrixInstance!U && U.rowCount == rowCount && U.columnCount == columnCount) {
277 		U ret = U.identity();
278 		enum min_r = R < U.rowCount ? R : U.rowCount;
279 		enum min_c = C < U.columnCount ? C : U.columnCount;
280 		static foreach (i; 0..min_r) {
281 			static foreach (j; 0..min_c) {
282 				ret.c[i][j] = cast(U.type)(c[i][j]);
283 			}
284 		}
285 		return ret;
286 	}
287 	///
288 	  unittest {
289 		auto m1 = Matrix2F(3.2f, 4.5f, /**/ 3.8f, -7.2f);
290 		Matrix2I m2 = cast(Matrix2I)m1;
291 		assert(m2.v == [3, 4, /**/ 3, -7]);
292 	}
293 	///
294 	bool opEquals(U)(U rhs)   const {
295 		static if (is(U : Matrix)) {
296 			static foreach (i; 0..R * C) {
297 				if (v[i] != rhs.v[i]) {
298 					return false;
299 				}
300 			}
301 		} else static if (is(U : T)) {
302 			static foreach (i; 0..R * C) {
303 				if (v[i] != rhs) {
304 					return false;
305 				}
306 			}
307 		} else {
308 			static assert(0, "Cannot compare a variable of type " ~ 
309         U.stringof ~ " with a variable of type " ~ Matrix.stringof
310       );
311 		}
312 		return true;
313 	}
314 	///
315 	  unittest {
316 		const m1 = Matrix2I(6, 3, /**/ -1, 0);
317 		const m2 = Matrix2I(6, 3, /**/ -1, 0);
318 		const m3 = Matrix2I(1, 4, /**/ -1, 7);
319 		assert(m1 == m2);
320 		assert(m1 != m3);
321 		const m4 = Matrix2I(3, 3, /**/ 3, 3);
322 		assert(m4 == 3);
323 		assert(m4 != -3);
324 	}
325 	/// Returns a pointer to content.
326 	inout(T)* ptr()   inout {
327 		return v.ptr;
328 	}
329 	static if (isFloatingPoint!T && R == 2 && C == 2) {
330 		/// Returns inverse of matrix 2x2.
331 		Matrix inverse()   const {
332 			T invDet = 1 / (c[0][0] * c[1][1] - c[0][1] * c[1][0]);
333 			return Matrix(c[1][1] * invDet, -c[0][1] * invDet, -c[1][0] * invDet, c[0][0] * invDet);
334 		}
335 		///
336 		  unittest {
337 			import std.math : approxEqual;
338 			auto m1 = Matrix2D(2.0, 3.0, /**/ -1.0, 5.0);
339 			auto m2 = m1.inverse();
340 			assert(m2.v[0].approxEqual(0.384615));
341 			assert(m2.v[1].approxEqual(-0.230769));
342 			assert(m2.v[2].approxEqual(0.0769231));
343 			assert(m2.v[3].approxEqual(0.153846));
344 		}
345 	}
346 	static if (isFloatingPoint!T && R == 3 && C == 3) {
347 		/// Returns inverse of matrix 3x3.
348 		Matrix inverse()   const {
349 			const T det = c[0][0] * (c[1][1] * c[2][2] - c[2][1] * c[1][2])
350         - c[0][1] * (c[1][0] * c[2][2] - c[1][2] * c[2][0]) 
351         + c[0][2] * (c[1][0] * c[2][1] - c[1][1] * c[2][0]);
352 			const T invDet = 1 / det;
353 			Matrix ret = void;
354 			ret.c[0][0] =  (c[1][1] * c[2][2] - c[2][1] * c[1][2]) * invDet;
355 			ret.c[0][1] = -(c[0][1] * c[2][2] - c[0][2] * c[2][1]) * invDet;
356 			ret.c[0][2] =  (c[0][1] * c[1][2] - c[0][2] * c[1][1]) * invDet;
357 			ret.c[1][0] = -(c[1][0] * c[2][2] - c[1][2] * c[2][0]) * invDet;
358 			ret.c[1][1] =  (c[0][0] * c[2][2] - c[0][2] * c[2][0]) * invDet;
359 			ret.c[1][2] = -(c[0][0] * c[1][2] - c[1][0] * c[0][2]) * invDet;
360 			ret.c[2][0] =  (c[1][0] * c[2][1] - c[2][0] * c[1][1]) * invDet;
361 			ret.c[2][1] = -(c[0][0] * c[2][1] - c[2][0] * c[0][1]) * invDet;
362 			ret.c[2][2] =  (c[0][0] * c[1][1] - c[1][0] * c[0][1]) * invDet;
363 			return ret;
364 		}
365 		///
366 		  unittest {
367 		}
368 	}
369 	static if (isFloatingPoint!T && R == 4 && C == 4) {
370 		/// Returns inverse of matrix 4x4.
371 		Matrix inverse()   const {
372 			const T det2_01_01 = c[0][0] * c[1][1] - c[0][1] * c[1][0];
373 			const T det2_01_02 = c[0][0] * c[1][2] - c[0][2] * c[1][0];
374 			const T det2_01_03 = c[0][0] * c[1][3] - c[0][3] * c[1][0];
375 			const T det2_01_12 = c[0][1] * c[1][2] - c[0][2] * c[1][1];
376 			const T det2_01_13 = c[0][1] * c[1][3] - c[0][3] * c[1][1];
377 			const T det2_01_23 = c[0][2] * c[1][3] - c[0][3] * c[1][2];
378 			const T det3_201_012 = c[2][0] * det2_01_12 - c[2][1] * det2_01_02 + c[2][2] * det2_01_01;
379 			const T det3_201_013 = c[2][0] * det2_01_13 - c[2][1] * det2_01_03 + c[2][3] * det2_01_01;
380 			const T det3_201_023 = c[2][0] * det2_01_23 - c[2][2] * det2_01_03 + c[2][3] * det2_01_02;
381 			const T det3_201_123 = c[2][1] * det2_01_23 - c[2][2] * det2_01_13 + c[2][3] * det2_01_12;
382 			const T det = - det3_201_123 * c[3][0] + det3_201_023 * c[3][1] - det3_201_013 * c[3][2] + det3_201_012 * c[3][3];
383 			const T invDet = 1 / det;
384 			const T det2_03_01 = c[0][0] * c[3][1] - c[0][1] * c[3][0];
385 			const T det2_03_02 = c[0][0] * c[3][2] - c[0][2] * c[3][0];
386 			const T det2_03_03 = c[0][0] * c[3][3] - c[0][3] * c[3][0];
387 			const T det2_03_12 = c[0][1] * c[3][2] - c[0][2] * c[3][1];
388 			const T det2_03_13 = c[0][1] * c[3][3] - c[0][3] * c[3][1];
389 			const T det2_03_23 = c[0][2] * c[3][3] - c[0][3] * c[3][2];
390 			const T det2_13_01 = c[1][0] * c[3][1] - c[1][1] * c[3][0];
391 			const T det2_13_02 = c[1][0] * c[3][2] - c[1][2] * c[3][0];
392 			const T det2_13_03 = c[1][0] * c[3][3] - c[1][3] * c[3][0];
393 			const T det2_13_12 = c[1][1] * c[3][2] - c[1][2] * c[3][1];
394 			const T det2_13_13 = c[1][1] * c[3][3] - c[1][3] * c[3][1];
395 			const T det2_13_23 = c[1][2] * c[3][3] - c[1][3] * c[3][2];
396 			const T det3_203_012 = c[2][0] * det2_03_12 - c[2][1] * det2_03_02 + c[2][2] * det2_03_01;
397 			const T det3_203_013 = c[2][0] * det2_03_13 - c[2][1] * det2_03_03 + c[2][3] * det2_03_01;
398 			const T det3_203_023 = c[2][0] * det2_03_23 - c[2][2] * det2_03_03 + c[2][3] * det2_03_02;
399 			const T det3_203_123 = c[2][1] * det2_03_23 - c[2][2] * det2_03_13 + c[2][3] * det2_03_12;
400 			const T det3_213_012 = c[2][0] * det2_13_12 - c[2][1] * det2_13_02 + c[2][2] * det2_13_01;
401 			const T det3_213_013 = c[2][0] * det2_13_13 - c[2][1] * det2_13_03 + c[2][3] * det2_13_01;
402 			const T det3_213_023 = c[2][0] * det2_13_23 - c[2][2] * det2_13_03 + c[2][3] * det2_13_02;
403 			const T det3_213_123 = c[2][1] * det2_13_23 - c[2][2] * det2_13_13 + c[2][3] * det2_13_12;
404 			const T det3_301_012 = c[3][0] * det2_01_12 - c[3][1] * det2_01_02 + c[3][2] * det2_01_01;
405 			const T det3_301_013 = c[3][0] * det2_01_13 - c[3][1] * det2_01_03 + c[3][3] * det2_01_01;
406 			const T det3_301_023 = c[3][0] * det2_01_23 - c[3][2] * det2_01_03 + c[3][3] * det2_01_02;
407 			const T det3_301_123 = c[3][1] * det2_01_23 - c[3][2] * det2_01_13 + c[3][3] * det2_01_12;
408 			Matrix ret = void;
409 			ret.c[0][0] = - det3_213_123 * invDet;
410 			ret.c[1][0] = + det3_213_023 * invDet;
411 			ret.c[2][0] = - det3_213_013 * invDet;
412 			ret.c[3][0] = + det3_213_012 * invDet;
413 			ret.c[0][1] = + det3_203_123 * invDet;
414 			ret.c[1][1] = - det3_203_023 * invDet;
415 			ret.c[2][1] = + det3_203_013 * invDet;
416 			ret.c[3][1] = - det3_203_012 * invDet;
417 			ret.c[0][2] = + det3_301_123 * invDet;
418 			ret.c[1][2] = - det3_301_023 * invDet;
419 			ret.c[2][2] = + det3_301_013 * invDet;
420 			ret.c[3][2] = - det3_301_012 * invDet;
421 			ret.c[0][3] = - det3_201_123 * invDet;
422 			ret.c[1][3] = + det3_201_023 * invDet;
423 			ret.c[2][3] = - det3_201_013 * invDet;
424 			ret.c[3][3] = + det3_201_012 * invDet;
425 			return ret;
426 		}
427 		///
428 		  unittest {
429 		}
430 	}
431 	/// Returns transposed matrix.
432 	Matrix!(T, C, R) transposed()   const {
433 		Matrix!(T, C, R) ret = void;
434 		static foreach (i; 0..C) {
435 			static foreach (j; 0..R) {
436 				ret.c[i][j] = c[j][i];
437 			}
438 		}
439 		return ret;
440 	}
441 	///
442 	  unittest {
443 		auto m1 = Matrix2I(4, 5, /**/ -1, 0);
444 		assert(m1.transposed().v == [4, -1, /**/ 5, 0]);
445 	}
446 	static if (isSquare && R > 2) {
447 		/// Makes a diagonal matrix from a vector.
448 		static Matrix diag(Vector!(T, R) v)   {
449 			Matrix ret = void;
450 			static foreach (i; 0..R) {
451 				static foreach (j; 0..C) {
452 					ret.c[i][j] = (i == j) ? v.v[i] : 0;
453 				}
454 			}
455 			return ret;
456 		}
457 		///
458 		  unittest {
459 			const v1 = Vector!(int, 3)(4, 5, -1);
460 			const m1 = Matrix!(int, 3).diag(v1);
461 			assert(m1.v == [4, 0, 0, /**/ 0, 5, 0, /**/ 0, 0, -1]);
462 		}
463 		///
464 		  unittest {
465 		}
466 		/// Make a translation matrix.
467 		static Matrix translation(Vector!(T, R-1) v)   {
468 			Matrix ret = identity();
469 			static foreach (i; 0..R - 1) {
470 				ret.c[i][C - 1] += v.v[i];
471 			}
472 			return ret;
473 		}
474 		///
475 		  unittest {
476 		}
477 		/// Make a scaling matrix.
478 		static Matrix scaling(Vector!(T, R-1) v)   {
479 			Matrix ret = identity();
480 			static foreach (i; 0..R - 1) {
481 				ret.c[i][i] = v.v[i];
482 			}
483 			return ret;
484 		}
485 		///
486 		  unittest {
487 		}
488 	}
489 	static if (isSquare && (R == 3 || R == 4) && isFloatingPoint!T) {
490 		///
491 		static Matrix rotateAxis(int i, int j)(T angle)   {
492 			import liberty.math.functions : sin, cos;
493 			Matrix ret = identity();
494 			const T cosa = cos(angle);
495 			const T sina = sin(angle);
496 			ret.c[i][i] = cosa;
497 			ret.c[i][j] = -sina;
498 			ret.c[j][i] = sina;
499 			ret.c[j][j] = cosa;
500 			return ret;
501 		}
502 		///
503 		  unittest {
504 		}
505 		/// Returns rotation matrix along axis X.
506 		alias rotateXAxix = rotateAxis!(1, 2);
507 		/// Returns rotation matrix along axis Y.
508 		alias rotateYAxis = rotateAxis!(2, 0);
509 		/// Returns rotation matrix along axis Z.
510 		alias rotateZAxis = rotateAxis!(0, 1);
511 		/// In-place rotation by (v, 1)
512 		void rotate(T angle, Vector!(T, 3) axis)   {
513 			this = rotation(angle, axis, this);
514 		}
515 		///
516 		  unittest {
517 		}
518 		///
519 		void rotateX(T angle)   {
520 			this = rotation(angle, Vector!(T, 3)(1, 0, 0), this);
521 		}
522 		///
523 		  unittest {
524 		}
525 		///
526 		void rotateY(T angle)   {
527 			this = rotation(angle, Vector!(T, 3)(0, 1, 0), this);
528 		}
529 		///
530 		  unittest {
531 		}
532 		///
533 		void rotateZ(T angle)   {
534 			this = rotation(angle, Vector!(T, 3)(0, 0, 1), this);
535 		}
536 		///
537 		  unittest {
538 		}
539 		///
540 		static Matrix rotation(T angle, Vector!(T, 3) axis, Matrix m = identity())   {
541 			import liberty.math.functions : sin, cos;
542 			Matrix ret = m;
543 			const T c = cos(angle);
544 			const oneMinusC = 1 - c;
545 			const T s = sin(angle);
546 			axis = axis.normalized();
547 			const T x = axis.x,
548 			y = axis.y,
549 			z = axis.z;
550 			const T xy = x * y,
551 			yz = y * z,
552 			xz = x * z;
553 			ret.c[0][0] = x * x * oneMinusC + c;
554 			ret.c[0][1] = x * y * oneMinusC - z * s;
555 			ret.c[0][2] = x * z * oneMinusC + y * s;
556 			ret.c[1][0] = y * x * oneMinusC + z * s;
557 			ret.c[1][1] = y * y * oneMinusC + c;
558 			ret.c[1][2] = y * z * oneMinusC - x * s;
559 			ret.c[2][0] = z * x * oneMinusC - y * s;
560 			ret.c[2][1] = z * y * oneMinusC + x * s;
561 			ret.c[2][2] = z * z * oneMinusC + c;
562 			return ret;
563 		}
564 		///
565 		  unittest {
566 		}
567 	}
568 	static if (isSquare && R == 4 && isFloatingPoint!T) {
569 		/**
570 		 * Transform a Vector4 by a Matrix4.
571 		**/
572 		static Vector4!T transformation(Matrix lhs, Vector4!T rhs) {
573 			const T x = lhs.c[0][0] * rhs.x + lhs.c[1][0] * rhs.y + lhs.c[2][0] * rhs.z + lhs.c[3][0] * rhs.w;
574 			const T y = lhs.c[0][1] * rhs.x + lhs.c[1][1] * rhs.y + lhs.c[2][1] * rhs.z + lhs.c[3][1] * rhs.w;
575 			const T z = lhs.c[0][2] * rhs.x + lhs.c[1][2] * rhs.y + lhs.c[2][2] * rhs.z + lhs.c[3][2] * rhs.w;
576 			const T w = lhs.c[0][3] * rhs.x + lhs.c[1][3] * rhs.y + lhs.c[2][3] * rhs.z + lhs.c[3][3] * rhs.w;
577 
578 			return Vector4!T(x, y, z, w);
579 		}
580 		///
581 		//static Matrix orthographic(T left, T right, T bottom, T top)   {
582 		//  return Matrix(
583 		//    (2) / (right - left), 0, 0, 0,
584 		//    0, (2) / (top - bottom), 0, 0,
585 		//    0, 0, -1, 0,
586 		//    -(right + left) / (right - left), -(top + bottom) / (top - bottom), 0, 0
587 		//  );
588 		//}
589 
590 		///
591 		  unittest {
592 		}
593 		/// Returns perspective projection.
594 		static Matrix perspective(T FOVInRadians, T width, T height, T zNear, T zFar)   {
595 			import liberty.math.functions : tan;
596 			T f = 1 / tan(FOVInRadians / 2);
597 			T d = 1 / (zNear - zFar);
598 			return Matrix(
599         f / (width / height), 0, 0, 0,
600         0, f, 0, 0,
601         0, 0, (zFar + zNear) * d, 2 * d * zFar * zNear,
602         0, 0, -1, 0
603       );
604 		}
605 		///
606 		  unittest {
607 		}
608 		/// Returns lookAt projection.
609 		static Matrix lookAt(Vector!(T, 3) eye, Vector!(T, 3) target, Vector!(T, 3) up)   {
610 			import liberty.math.vector : dot, cross;
611 			Vector!(T, 3) Z = (eye - target).normalized();
612 			Vector!(T, 3) X = cross(-up, Z).normalized();
613 			Vector!(T, 3) Y = cross(Z, -X);
614 			return Matrix(-X.x, -X.y, -X.z, dot(X, eye), Y.x, Y.y, Y.z, -dot(Y, eye), Z.x, Z.y, Z.z, -dot(Z, eye), 0, 0, 0, 1);
615 		}
616 		/// Returns camera projection
617 		static Matrix camera(Vector!(T, 3) forward, Vector!(T, 3) up) {
618 			Vector!(T, 3) f = forward;
619 			f.normalize();
620 
621 			Vector!(T, 3) r = up;
622 			r.normalize();
623 			r = r.cross(f);
624 
625 			Vector!(T, 3) u = f.cross(r);
626 			
627 			return Matrix(
628 				r.x, r.y, r.z, 0.0f,
629 				u.x, u.y, u.z, 0.0f,
630 				f.x, f.y, f.z, 0.0f,
631 				0.0f, 0.0f, 0.0f, 1.0f
632 			);
633 		}
634 		///
635 		  unittest {
636 		}
637 	}
638 }
639 ///
640 template Matrix2(T) {
641 	alias Matrix2 = Matrix!(T, 2);
642 }
643 ///
644 template Matrix3(T) {
645 	alias Matrix3 = Matrix!(T, 3);
646 }
647 ///
648 template Matrix4(T) {
649 	alias Matrix4 = Matrix!(T, 4);
650 }
651 ///
652 template Matrix2x3(T) {
653 	alias Matrix2x3 = Matrix!(T, 2, 3);
654 }
655 ///
656 template Matrix2x4(T) {
657 	alias Matrix2x4 = Matrix!(T, 2, 4);
658 }
659 ///
660 template Matrix3x2(T) {
661 	alias Matrix3x2 = Matrix!(T, 3, 2);
662 }
663 ///
664 template Matrix3x4(T) {
665 	alias Matrix3x4 = Matrix!(T, 3, 4);
666 }
667 ///
668 template Matrix4x2(T) {
669 	alias Matrix4x2 = Matrix!(T, 4, 2);
670 }
671 ///
672 template Matrix4x3(T) {
673 	alias Matrix4x3 = Matrix!(T, 4, 3);
674 }
675 ///
676 alias Matrix2I = Matrix2!int;
677 ///
678 alias Matrix3I = Matrix3!int;
679 ///
680 alias Matrix4I = Matrix4!int;
681 ///
682 alias Matrix2F = Matrix2!float;
683 ///
684 alias Matrix3F = Matrix3!float;
685 ///
686 alias Matrix4F = Matrix4!float;
687 ///
688 alias Matrix2D = Matrix2!double;
689 ///
690 alias Matrix3D = Matrix3!double;
691 ///
692 alias Matrix4D = Matrix4!double;
693 ///
694 alias Matrix2x3I = Matrix2x3!int;
695 ///
696 alias Matrix2x4I = Matrix2x4!int;
697 ///
698 alias Matrix3x2I = Matrix3x2!int;
699 ///
700 alias Matrix2x3F = Matrix2x3!float;
701 ///
702 alias Matrix2x4F = Matrix2x4!float;
703 ///
704 alias Matrix3x2F = Matrix3x2!float;
705 ///
706 alias Matrix2x3D = Matrix2x3!double;
707 ///
708 alias Matrix2x4D = Matrix2x4!double;
709 ///
710 alias Matrix3x2D = Matrix3x2!double;
711 ///
712 alias Matrix3x4I = Matrix3x4!int;
713 ///
714 alias Matrix4x2I = Matrix4x2!int;
715 ///
716 alias Matrix4x3I = Matrix4x3!int;
717 ///
718 alias Matrix3x4F = Matrix3x4!float;
719 ///
720 alias Matrix4x2F = Matrix4x2!float;
721 ///
722 alias Matrix4x3F = Matrix4x3!float;
723 ///
724 alias Matrix3x4D = Matrix3x4!double;
725 ///
726 alias Matrix4x2D = Matrix4x2!double;
727 ///
728 alias Matrix4x3D = Matrix4x3!double;
729 ///
730 final class MatrixStack(int R, T) if (R == 3 || R == 4) {
731 	private {
732 		size_t _top;
733 		size_t _depth;
734 		MatrixType* _matrices;
735 		MatrixType* _invMatrices;
736 	}
737 	///
738 	alias MatrixType = Matrix!(T, R, R);
739 	/// Creates a matrix stack.
740 	this(size_t depth = 32) 
741 	in {
742 		assert(depth > 0);
743 	} do {
744 		import core.stdc.stdlib : malloc;
745 		size_t memory_needed = MatrixType.sizeof * depth * 2;
746 		const void* data = malloc(memory_needed * 2);
747 		_matrices = cast(MatrixType*)data;
748 		_invMatrices = cast(MatrixType*)(data + memory_needed);
749 		_top = 0;
750 		_depth = depth;
751 		loadIdentity();
752 	}
753 	/// Relases the matrix stack memory.
754 	~this() {
755 		if (_matrices !is null) {
756 			import core.stdc.stdlib : free;
757 			free(_matrices);
758 			_matrices = null;
759 		}
760 	}
761 	///
762 	void loadIdentity()   {
763 		_matrices[_top] = MatrixType.identity();
764 		_invMatrices[_top] = MatrixType.identity();
765 	}
766 	///
767 	void push()   {
768 		if(_top + 1 >= _depth) {
769 			assert(false, "Matrix stack is full!");
770 		}
771 		_matrices[_top + 1] = _matrices[_top];
772 		_invMatrices[_top + 1] = _invMatrices[_top];
773 		_top++;
774 	}
775 	/// Replacement for $(D glPopMatrix).
776 	void pop()   {
777 		if (_top <= 0) {
778 			assert(false, "Matrix stack is empty!");
779 		}
780 		_top--;
781 	}
782 	///
783 	MatrixType top()  const  {
784 		return _matrices[_top];
785 	}
786 	///
787 	MatrixType invTop()  const  {
788 		return _invMatrices[_top];
789 	}
790 	///
791 	void top(MatrixType m)   {
792 		_matrices[_top] = m;
793 		_invMatrices[_top] = m.inverse();
794 	}
795 	///
796 	void mult(MatrixType m)   {
797 		mult(m, m.inverse());
798 	}
799 	///
800 	void mult(MatrixType m, MatrixType invM)   {
801 		_matrices[_top] = _matrices[_top] * m;
802 		_invMatrices[_top] = invM *_invMatrices[_top];
803 	}
804 	///
805 	void translate(Vector!(T, R-1) v)   {
806 		mult(MatrixType.translation(v), MatrixType.translation(-v));
807 	}
808 	///
809 	void scale(Vector!(T, R-1) v)   {
810 		mult(MatrixType.scaling(v), MatrixType.scaling(1 / v));
811 	}
812 	static if (R == 4) {
813 		///
814 		void rotate(T angle, Vector!(T, 3) axis)   {
815 			MatrixType rot = MatrixType.rotation(angle, axis);
816 			mult(rot, rot.transposed());
817 		}
818 		///
819 		void perspective(T FOVInRadians, T width, T height, T zNear, T zFar)   {
820 			mult(MatrixType.perspective(FOVInRadians, width, height, zNear, zFar));
821 		}
822 		///
823 		//void orthographic(T left, T right, T bottom, T top, T near, T far)   {
824 		//	mult(MatrixType.orthographic(left, right, bottom, top, near, far));
825 		//}
826 		///
827 		void lookAt(Vector!(T, 3) eye, Vector!(T, 3) target, Vector!(T, 3) up)   {
828 			mult(MatrixType.lookAt(eye, target, up));
829 		}
830 	}
831 }
832 ///
833 unittest {
834     auto m = new MatrixStack!(4, double)();
835     scope(exit) destroy(m);
836     m.loadIdentity();
837     m.push();
838     m.pop();
839     m.translate(Vector!(double, 3)(2.4, 3.3, 7.5));
840     m.scale(Vector!(double, 3)(0.7));
841     auto t = new MatrixStack!(3, float)();
842     scope(exit) destroy(t);
843     t.loadIdentity();
844     t.push();
845     t.pop();
846     t.translate(Vector!(float, 2)(1, -8));
847     t.scale(Vector!(float, 2)(0.2));
848 }