1 /**
2     inmath.linalg
3 
4     Special thanks to:
5     $(UL
6         $(LI Tomasz Stachowiak (h3r3tic): allowed me to use parts of $(LINK2 https://bitbucket.org/h3r3tic/boxen/src/default/src/xf/omg, omg).)
7         $(LI Jakob Øvrum (jA_cOp): improved the code a lot!)
8         $(LI Florian Boesch (___doc__): helps me to understand opengl/complex maths better, see: $(LINK http://codeflow.org/).)
9         $(LI #D on freenode: answered general questions about D.)
10     )
11 
12     Authors: David Herberth, Inochi2D Project
13     License: MIT
14 
15     Note: All methods marked with pure are weakly pure since, they all access an instance member.
16     All static methods are strongly pure.
17 */
18 
19 
20 module inmath.linalg;
21 
22 private {
23     import std.math : isNaN, isInfinity;
24     import std.conv : to;
25     import std.traits : isIntegral, isFloatingPoint, isStaticArray, isDynamicArray, isImplicitlyConvertible, isArray;
26     import std.string : format, rightJustify;
27     import std.array : join;
28     import std.algorithm : max, min, reduce;
29     import inmath.math : clamp, PI, sqrt, sin, cos, acos, tan, asin, atan2, almostEqual;
30     import inmath.util : isVector, isMatrix, isQuaternion, isRect, TupleRange;
31 }
32 
33 version(NoReciprocalMul) {
34     private enum rmul = false;
35 } else {
36     private enum rmul = true;
37 }
38 
39 /// Base template for all vector-types.
40 /// Params:
41 /// type = all values get stored as this type
42 /// dimension = specifies the dimension of the vector, can be 1, 2, 3 or 4
43 /// Examples:
44 /// ---
45 /// alias Vector!(int, 3) vec3i;
46 /// alias Vector!(float, 4) vec4;
47 /// alias Vector!(real, 2) vec2r;
48 /// ---
49 struct Vector(type, int dimension_) {
50 static assert(dimension > 0, "0 dimensional vectors don't exist.");
51 
52     alias vt = type; /// Holds the internal type of the vector.
53     static const int dimension = dimension_; ///Holds the dimension of the vector.
54 
55     vt[dimension] vector; /// Holds all coordinates, length conforms dimension.
56 
57     /// Returns a pointer to the coordinates.
58     auto ptr() const { return vector.ptr; }
59 
60     /// Returns the current vector formatted as string, useful for printing the vector.
61     const(string) toString() const {
62         return format("%s", vector);
63     }
64 
65     /// Gets a hash of this item
66     size_t toHash() const { return typeid(this).getHash(&this); }
67 
68 @safe pure nothrow:
69 
70     /**
71         A vector with all zeroes
72     */
73     static auto zero() {
74         return Vector!(type, dimension_)(0); 
75     }
76 
77     /**
78         A vector with all ones
79     */
80     static auto one() {
81         return Vector!(type, dimension_)(1); 
82     }
83     
84     /**
85         Up vector (0, -1) OR (0, 1, 0)
86     */
87     static auto up() {
88         static if (dimension_ == 2) return Vector!(type, dimension_)(cast(type)0, cast(type)-1); 
89         else static if (dimension_ == 3) return Vector!(type, dimension_)(cast(type)0, cast(type)1, cast(type)0); 
90         else static if (dimension_ == 4) return Vector!(type, dimension_)(cast(type)0, cast(type)1, cast(type)0, cast(type)0); 
91         else return Vector!(type, dimension_).init;
92     }
93     
94     /**
95         Down vector (0, 1) OR (0, -1, 0)
96     */
97     static auto down() {
98         static if (dimension_ == 2) return Vector!(type, dimension_)(cast(type)0, cast(type)1); 
99         else static if (dimension_ == 3) return Vector!(type, dimension_)(cast(type)0, cast(type)-1, cast(type)0); 
100         else static if (dimension_ == 4) return Vector!(type, dimension_)(cast(type)0, cast(type)-1, cast(type)0, cast(type)0); 
101         else return Vector!(type, dimension_).init;
102     }
103     
104     /**
105         Left vector (-1, 0, 0)
106     */
107     static auto left() {
108         static if (dimension_ == 2) return Vector!(type, dimension_)(cast(type)-1, cast(type)0); 
109         else static if (dimension_ == 3) return Vector!(type, dimension_)(cast(type)-1, cast(type)0, cast(type)0); 
110         else static if (dimension_ == 4) return Vector!(type, dimension_)(cast(type)-1, cast(type)0, cast(type)0, cast(type)0); 
111         else return Vector!(type, dimension_).init;
112     }
113     
114     /**
115         Right vector (1, 0, 0)
116     */
117     static auto right() {
118         static if (dimension_ == 2) return Vector!(type, dimension_)(cast(type)1, cast(type)0); 
119         else static if (dimension_ == 3) return Vector!(type, dimension_)(cast(type)1, cast(type)0, cast(type)0); 
120         else static if (dimension_ == 4) return Vector!(type, dimension_)(cast(type)1, cast(type)0, cast(type)0, cast(type)0);
121         else return Vector!(type, dimension_).init;
122     }
123 
124     static if (dimension_ >= 3) {
125 
126         /**
127             Forward vector (0, 0, 1)
128         */
129         static auto forward() {
130             static if (dimension_ == 3) return Vector!(type, dimension_)(cast(type)0, cast(type)0, cast(type)1); 
131             else static if (dimension_ == 4) return Vector!(type, dimension_)(cast(type)0, cast(type)0, cast(type)1, cast(type)0);
132             else return Vector!(type, dimension_).init;
133         }
134         
135         /**
136             Back vector (0, 0, -1)
137         */
138         static auto back() {
139             static if (dimension_ == 3) return Vector!(type, dimension_)(cast(type)0, cast(type)0, cast(type)-1); 
140             else static if (dimension_ == 4) return Vector!(type, dimension_)(cast(type)0, cast(type)0, cast(type)-1, cast(type)0); 
141             else return Vector!(type, dimension_).init;
142         }
143     }
144 
145     ///
146     ref inout(vt) get_(char coord)() inout {
147         return vector[coordToIndex!coord];
148     }
149 
150     alias x = get_!'x'; /// static properties to access the values.
151     alias u = x; /// ditto
152     alias s = x; /// ditto
153     alias r = x; /// ditto
154     static if(dimension >= 2) {
155         alias y = get_!'y'; /// ditto
156         alias v = y; /// ditto
157         alias t = y; /// ditto
158         alias g = y; /// ditto
159     }
160     static if(dimension >= 3) {
161         alias z = get_!'z'; /// ditto
162         alias b = z; /// ditto
163         alias p = z; /// ditto
164     }
165     static if(dimension >= 4) {
166         alias w = get_!'w'; /// ditto
167         alias a = w; /// ditto
168         alias q = w; /// ditto
169     }
170 
171     static if(dimension == 2) {
172         enum Vector e1 = Vector(1.to!vt, 0.to!vt); /// canonical basis for Euclidian space
173         enum Vector e2 = Vector(0.to!vt, 1.to!vt); /// ditto
174     } else static if(dimension == 3) {
175         enum Vector e1 = Vector(1.to!vt, 0.to!vt, 0.to!vt); /// canonical basis for Euclidian space
176         enum Vector e2 = Vector(0.to!vt, 1.to!vt, 0.to!vt); /// ditto
177         enum Vector e3 = Vector(0.to!vt, 0.to!vt, 1.to!vt); /// ditto
178     } else static if(dimension == 4) {
179         enum Vector e1 = Vector(1.to!vt, 0.to!vt, 0.to!vt, 0.to!vt); /// canonical basis for Euclidian space
180         enum Vector e2 = Vector(0.to!vt, 1.to!vt, 0.to!vt, 0.to!vt); /// ditto
181         enum Vector e3 = Vector(0.to!vt, 0.to!vt, 1.to!vt, 0.to!vt); /// ditto
182         enum Vector e4 = Vector(0.to!vt, 0.to!vt, 0.to!vt, 1.to!vt); /// ditto
183     }
184 
185     unittest {
186         assert(vec2.e1.vector == [1.0, 0.0]);
187         assert(vec2.e2.vector == [0.0, 1.0]);
188 
189         assert(vec3.e1.vector == [1.0, 0.0, 0.0]);
190         assert(vec3.e2.vector == [0.0, 1.0, 0.0]);
191         assert(vec3.e3.vector == [0.0, 0.0, 1.0]);
192 
193         assert(vec4.e1.vector == [1.0, 0.0, 0.0, 0.0]);
194         assert(vec4.e2.vector == [0.0, 1.0, 0.0, 0.0]);
195         assert(vec4.e3.vector == [0.0, 0.0, 1.0, 0.0]);
196         assert(vec4.e4.vector == [0.0, 0.0, 0.0, 1.0]);
197     }
198 
199     static void isCompatibleVectorImpl(int d)(Vector!(vt, d) vec) if(d <= dimension) {
200     }
201 
202     template isCompatibleVector(T) {
203         enum isCompatibleVector = is(typeof(isCompatibleVectorImpl(T.init)));
204     }
205 
206     static void isCompatibleMatrixImpl(int r, int c)(Matrix!(vt, r, c) m) {
207     }
208 
209     template isCompatibleMatrix(T) {
210         enum isCompatibleMatrix = is(typeof(isCompatibleMatrixImpl(T.init)));
211     }
212 
213     private void construct(int i, T, Tail...)(T head, Tail tail) {
214         static if(i >= dimension) {
215             static assert(false, "Too many arguments passed to constructor");
216         } else static if(is(T : vt)) {
217             vector[i] = head;
218             construct!(i + 1)(tail);
219         } else static if(isDynamicArray!T) {
220             static assert((Tail.length == 0) && (i == 0), "dynamic array can not be passed together with other arguments");
221             vector[] = head[];
222         } else static if(isStaticArray!T) {
223             vector[i .. i + T.length] = head[];
224             construct!(i + T.length)(tail);
225         } else static if(isCompatibleVector!T) {
226             vector[i .. i + T.dimension] = head.vector[];
227             construct!(i + T.dimension)(tail);
228         } else {
229             static assert(false, "Vector constructor argument must be of type " ~ vt.stringof ~ " or Vector, not " ~ T.stringof);
230         }
231     }
232 
233     private void construct(int i)() { // terminate
234         static assert(i == dimension, "Not enough arguments passed to constructor");
235     }
236 
237     /// Constructs the vector.
238     /// If a single value is passed the vector, the vector will be cleared with this value.
239     /// If a vector with a higher dimension is passed the vector will hold the first values up to its dimension.
240     /// If mixed types are passed they will be joined together (allowed types: vector, static array, $(I vt)).
241     /// Examples:
242     /// ---
243     /// vec4 v4 = vec4(1.0f, vec2(2.0f, 3.0f), 4.0f);
244     /// vec3 v3 = vec3(v4); // v3 = vec3(1.0f, 2.0f, 3.0f);
245     /// vec2 v2 = v3.xy; // swizzling returns a static array.
246     /// vec3 v3_2 = vec3(1.0f); // vec3 v3_2 = vec3(1.0f, 1.0f, 1.0f);
247     /// ---
248     this(Args...)(Args args) {
249         construct!(0)(args);
250     }
251 
252     /// ditto
253     this(T)(T vec) if(isVector!T && is(T.vt : vt) && (T.dimension >= dimension)) {
254         foreach(i; TupleRange!(0, dimension)) {
255             vector[i] = vec.vector[i];
256         }
257     }
258 
259     /// ditto
260     this()(vt value) {
261         clear(value);
262     }
263 
264     /// Returns true if all values are not nan and finite, otherwise false.
265     bool isFinite() const {
266         static if(isIntegral!type) {
267             return true;
268         }
269         else {
270             foreach(v; vector) {
271                 if(isNaN(v) || isInfinity(v)) {
272                     return false;
273                 }
274             }
275             return true;
276         }
277     }
278 
279     /// Sets all values of the vector to value.
280     void clear(vt value) {
281         foreach(i; TupleRange!(0, dimension)) {
282             vector[i] = value;
283         }
284     }
285 
286     unittest {
287         vec3 vec_clear;
288         assert(!vec_clear.isFinite);
289         vec_clear.clear(1.0f);
290         assert(vec_clear.isFinite);
291         assert(vec_clear.vector == [1.0f, 1.0f, 1.0f]);
292         assert(vec_clear.vector == vec3(1.0f).vector);
293         vec_clear.clear(float.infinity);
294         assert(!vec_clear.isFinite);
295         vec_clear.clear(float.nan);
296         assert(!vec_clear.isFinite);
297         vec_clear.clear(1.0f);
298         assert(vec_clear.isFinite);
299 
300         vec4 b = vec4(1.0f, vec_clear);
301         assert(b.isFinite);
302         assert(b.vector == [1.0f, 1.0f, 1.0f, 1.0f]);
303         assert(b.vector == vec4(1.0f).vector);
304 
305         vec2 v2_1 = vec2(vec2(0.0f, 1.0f));
306         assert(v2_1.vector == [0.0f, 1.0f]);
307 
308         vec2 v2_2 = vec2(1.0f, 1.0f);
309         assert(v2_2.vector == [1.0f, 1.0f]);
310 
311         vec3 v3 = vec3(v2_1, 2.0f);
312         assert(v3.vector == [0.0f, 1.0f, 2.0f]);
313 
314         vec4 v4_1 = vec4(1.0f, vec2(2.0f, 3.0f), 4.0f);
315         assert(v4_1.vector == [1.0f, 2.0f, 3.0f, 4.0f]);
316         assert(vec3(v4_1).vector == [1.0f, 2.0f, 3.0f]);
317         assert(vec2(vec3(v4_1)).vector == [1.0f, 2.0f]);
318         assert(vec2(vec3(v4_1)).vector == vec2(v4_1).vector);
319         assert(v4_1.vector == vec4([1.0f, 2.0f, 3.0f, 4.0f]).vector);
320 
321         vec4 v4_2 = vec4(vec2(1.0f, 2.0f), vec2(3.0f, 4.0f));
322         assert(v4_2.vector == [1.0f, 2.0f, 3.0f, 4.0f]);
323         assert(vec3(v4_2).vector == [1.0f, 2.0f, 3.0f]);
324         assert(vec2(vec3(v4_2)).vector == [1.0f, 2.0f]);
325         assert(vec2(vec3(v4_2)).vector == vec2(v4_2).vector);
326         assert(v4_2.vector == vec4([1.0f, 2.0f, 3.0f, 4.0f]).vector);
327 
328         float[2] f2 = [1.0f, 2.0f];
329         float[3] f3 = [1.0f, 2.0f, 3.0f];
330         float[4] f4 = [1.0f, 2.0f, 3.0f, 4.0f];
331         assert(vec2(1.0f, 2.0f).vector == vec2(f2).vector);
332         assert(vec3(1.0f, 2.0f, 3.0f).vector == vec3(f3).vector);
333         assert(vec3(1.0f, 2.0f, 3.0f).vector == vec3(f2, 3.0f).vector);
334         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f).vector == vec4(f4).vector);
335         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f).vector == vec4(f3, 4.0f).vector);
336         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f).vector == vec4(f2, 3.0f, 4.0f).vector);
337         // useful for: "vec4 v4 = […]" or "vec4 v4 = other_vector.rgba"
338 
339         assert(vec3(vec3i(1, 2, 3)) == vec3(1.0, 2.0, 3.0));
340         assert(vec3d(vec3(1.0, 2.0, 3.0)) == vec3d(1.0, 2.0, 3.0));
341 
342         static assert(!__traits(compiles, vec3(0.0f, 0.0f)));
343         static assert(!__traits(compiles, vec4(0.0f, 0.0f, 0.0f)));
344         static assert(!__traits(compiles, vec4(0.0f, vec2(0.0f, 0.0f))));
345         static assert(!__traits(compiles, vec4(vec3(0.0f, 0.0f, 0.0f))));
346     }
347 
348     template coordToIndex(char c) {
349         static if((c == 'x') || (c == 'r') || (c == 'u') || (c == 's')) {
350             enum coordToIndex = 0;
351         } else static if((c == 'y') || (c == 'g') || (c == 'v') || (c == 't')) {
352             enum coordToIndex = 1;
353         } else static if((c == 'z') || (c == 'b') || (c == 'p')) {
354             static assert(dimension >= 3, "the " ~ c ~ " property is only available on vectors with a third dimension.");
355             enum coordToIndex = 2;
356         } else static if((c == 'w') || (c == 'a') || (c == 'q')) {
357             static assert(dimension >= 4, "the " ~ c ~ " property is only available on vectors with a fourth dimension.");
358             enum coordToIndex = 3;
359         } else {
360             static assert(false, "accepted coordinates are x, s, r, u, y, g, t, v, z, p, b, w, q and a not " ~ c ~ ".");
361         }
362     }
363 
364     static if(dimension == 2) { void set(vt x, vt y) { vector[0] = x; vector[1] = y; } }
365     static if(dimension == 3) { void set(vt x, vt y, vt z) { vector[0] = x; vector[1] = y; vector[2] = z; } }
366     static if(dimension == 4) { void set(vt x, vt y, vt z, vt w) { vector[0] = x; vector[1] = y; vector[2] = z; vector[3] = w; } }
367 
368     /// Updates the vector with the values from other.
369     void update(Vector!(vt, dimension) other) {
370         vector = other.vector;
371     }
372 
373     unittest {
374         vec2 v2 = vec2(1.0f, 2.0f);
375         assert(v2.x == 1.0f);
376         assert(v2.y == 2.0f);
377         v2.x = 3.0f;
378         v2.x += 1;
379         v2.x -= 1;
380         assert(v2.vector == [3.0f, 2.0f]);
381         v2.y = 4.0f;
382         v2.y += 1;
383         v2.y -= 1;
384         assert(v2.vector == [3.0f, 4.0f]);
385         assert((v2.x == 3.0f) && (v2.x == v2.u) && (v2.x == v2.s) && (v2.x == v2.r));
386         assert(v2.y == 4.0f);
387         assert((v2.y == 4.0f) && (v2.y == v2.v) && (v2.y == v2.t) && (v2.y == v2.g));
388         v2.set(0.0f, 1.0f);
389         assert(v2.vector == [0.0f, 1.0f]);
390         v2.update(vec2(3.0f, 4.0f));
391         assert(v2.vector == [3.0f, 4.0f]);
392 
393         vec3 v3 = vec3(1.0f, 2.0f, 3.0f);
394         assert(v3.x == 1.0f);
395         assert(v3.y == 2.0f);
396         assert(v3.z == 3.0f);
397         v3.x = 3.0f;
398         v3.x += 1;
399         v3.x -= 1;
400         assert(v3.vector == [3.0f, 2.0f, 3.0f]);
401         v3.y = 4.0f;
402         v3.y += 1;
403         v3.y -= 1;
404         assert(v3.vector == [3.0f, 4.0f, 3.0f]);
405         v3.z = 5.0f;
406         v3.z += 1;
407         v3.z -= 1;
408         assert(v3.vector == [3.0f, 4.0f, 5.0f]);
409         assert((v3.x == 3.0f) && (v3.x == v3.s) && (v3.x == v3.r));
410         assert((v3.y == 4.0f) && (v3.y == v3.t) && (v3.y == v3.g));
411         assert((v3.z == 5.0f) && (v3.z == v3.p) && (v3.z == v3.b));
412         v3.set(0.0f, 1.0f, 2.0f);
413         assert(v3.vector == [0.0f, 1.0f, 2.0f]);
414         v3.update(vec3(3.0f, 4.0f, 5.0f));
415         assert(v3.vector == [3.0f, 4.0f, 5.0f]);
416 
417         vec4 v4 = vec4(1.0f, 2.0f, vec2(3.0f, 4.0f));
418         assert(v4.x == 1.0f);
419         assert(v4.y == 2.0f);
420         assert(v4.z == 3.0f);
421         assert(v4.w == 4.0f);
422         v4.x = 3.0f;
423         v4.x += 1;
424         v4.x -= 1;
425         assert(v4.vector == [3.0f, 2.0f, 3.0f, 4.0f]);
426         v4.y = 4.0f;
427         v4.y += 1;
428         v4.y -= 1;
429         assert(v4.vector == [3.0f, 4.0f, 3.0f, 4.0f]);
430         v4.z = 5.0f;
431         v4.z += 1;
432         v4.z -= 1;
433         assert(v4.vector == [3.0f, 4.0f, 5.0f, 4.0f]);
434         v4.w = 6.0f;
435         v4.w += 1;
436         v4.w -= 1;
437         assert(v4.vector == [3.0f, 4.0f, 5.0f, 6.0f]);
438         assert((v4.x == 3.0f) && (v4.x == v4.s) && (v4.x == v4.r));
439         assert((v4.y == 4.0f) && (v4.y == v4.t) && (v4.y == v4.g));
440         assert((v4.z == 5.0f) && (v4.z == v4.p) && (v4.z == v4.b));
441         assert((v4.w == 6.0f) && (v4.w == v4.q) && (v4.w == v4.a));
442         v4.set(0.0f, 1.0f, 2.0f, 3.0f);
443         assert(v4.vector == [0.0f, 1.0f, 2.0f, 3.0f]);
444         v4.update(vec4(3.0f, 4.0f, 5.0f, 6.0f));
445         assert(v4.vector == [3.0f, 4.0f, 5.0f, 6.0f]);
446     }
447 
448     private void dispatchImpl(int i, string s, int size)(ref vt[size] result) const {
449         static if(s.length > 0) {
450             result[i] = vector[coordToIndex!(s[0])];
451             dispatchImpl!(i + 1, s[1..$])(result);
452         }
453     }
454 
455     /// Implements dynamic swizzling.
456     /// Returns: a Vector
457     Vector!(vt, s.length) opDispatch(string s)() const {
458         vt[s.length] ret;
459         dispatchImpl!(0, s)(ret);
460         Vector!(vt, s.length) ret_vec;
461         ret_vec.vector = ret;
462         return ret_vec;
463     }
464 
465     unittest {
466         vec2 v2 = vec2(1.0f, 2.0f);
467         assert(v2.xytsy == [1.0f, 2.0f, 2.0f, 1.0f, 2.0f]);
468 
469         assert(vec3(1.0f, 2.0f, 3.0f).xybzyr == [1.0f, 2.0f, 3.0f, 3.0f, 2.0f, 1.0f]);
470         assert(vec4(v2, 3.0f, 4.0f).xyzwrgbastpq == [1.0f, 2.0f, 3.0f, 4.0f,
471                                                      1.0f, 2.0f, 3.0f, 4.0f,
472                                                      1.0f, 2.0f, 3.0f, 4.0f]);
473         assert(vec4(v2, 3.0f, 4.0f).wgyzax == [4.0f, 2.0f, 2.0f, 3.0f, 4.0f, 1.0f]);
474         assert(vec4(v2.xyst).vector == [1.0f, 2.0f, 1.0f, 2.0f]);
475     }
476 
477     /// Returns the squared magnitude of the vector.
478     real lengthSquared() const {
479         real temp = 0;
480 
481         foreach(index; TupleRange!(0, dimension)) {
482             temp += vector[index]^^2;
483         }
484 
485         return temp;
486     }
487 
488     /// Returns the magnitude of the vector.
489     real length() const {
490         return sqrt(lengthSquared);
491     }
492 
493     /// Normalizes the vector.
494     void normalize() {
495         real len = length;
496 
497         if(len != 0) {
498             foreach(index; TupleRange!(0, dimension)) {
499                 vector[index] = cast(type)(vector[index]/len);
500             }
501         }
502     }
503 
504     /// Returns a normalized copy of the current vector.
505     Vector normalized() const {
506         Vector ret;
507         ret.update(this);
508         ret.normalize();
509         return ret;
510     }
511 
512     Vector opUnary(string op : "-")() const {
513         Vector ret;
514 
515         foreach(index; TupleRange!(0, dimension)) {
516             ret.vector[index] = -vector[index];
517         }
518 
519         return ret;
520     }
521 
522     unittest {
523         assert(vec2(1.0f, 1.0f) == -vec2(-1.0f, -1.0f));
524         assert(vec2(-1.0f, 1.0f) == -vec2(1.0f, -1.0f));
525 
526         assert(-vec3(1.0f, 1.0f, 1.0f) == vec3(-1.0f, -1.0f, -1.0f));
527         assert(-vec3(-1.0f, 1.0f, -1.0f) == vec3(1.0f, -1.0f, 1.0f));
528 
529         assert(vec4(1.0f, 1.0f, 1.0f, 1.0f) == -vec4(-1.0f, -1.0f, -1.0f, -1.0f));
530         assert(vec4(-1.0f, 1.0f, -1.0f, 1.0f) == -vec4(1.0f, -1.0f, 1.0f, -1.0f));
531     }
532 
533     // let the math begin!
534     Vector opBinary(string op : "*")(vt r) const {
535         Vector ret;
536 
537         static foreach(index; TupleRange!(0, dimension)) {
538             ret.vector[index] = vector[index] * r;
539         }
540 
541         return ret;
542     }
543 
544     Vector opBinary(string op : "/")(vt r) const {
545         Vector ret;
546 
547         static foreach(index; TupleRange!(0, dimension)) {
548             ret.vector[index] = cast(vt)(vector[index] / r);
549         }
550 
551         return ret;
552     }
553 
554     Vector opBinary(string op)(Vector r) const if((op == "+") || (op == "-")) {
555         Vector ret;
556 
557         static foreach(index; TupleRange!(0, dimension)) {
558             ret.vector[index] = mixin("cast(vt)(vector[index]" ~ op ~ "r.vector[index])");
559         }
560 
561         return ret;
562     }
563 
564     Vector opBinary(string op : "*")(Vector r) const {
565         Vector ret;
566 
567         static foreach(index; 0..dimension) {
568             ret.vector[index] = vector[index] * r.vector[index];
569         }
570 
571         return ret;
572     }
573 
574     // vector * matrix (for matrix * vector -> struct Matrix)
575     Vector!(vt, T.cols) opBinary(string op : "*", T)(T inp) const if(isCompatibleMatrix!T && (T.rows == dimension)) {
576         Vector!(vt, T.cols) ret;
577         ret.clear(0);
578 
579         foreach(c; TupleRange!(0, T.cols)) {
580             foreach(r; TupleRange!(0, T.rows)) {
581                 ret.vector[c] += vector[r] * inp.matrix[r][c];
582             }
583         }
584 
585         return ret;
586     }
587 
588     auto opBinaryRight(string op, T)(T inp) const if(!isVector!T && !isMatrix!T && !isQuaternion!T) {
589         return this.opBinary!(op)(inp);
590     }
591 
592     unittest {
593         // vec2 v2 = vec2(1.0f, 3.0f);
594         // auto v2times2 = 2 * v2;
595         // assert((v2*2.5f).vector == [2.5f, 7.5f]);
596         // assert((v2+vec2(3.0f, 1.0f)).vector == [4.0f, 4.0f]);
597         // assert((v2-vec2(1.0f, 3.0f)).vector == [0.0f, 0.0f]);
598         // assert((v2*vec2(2.0f, 2.0f)) == 8.0f);
599 
600         // vec3 v3 = vec3(1.0f, 3.0f, 5.0f);
601         // assert((v3*2.5f).vector == [2.5f, 7.5f, 12.5f]);
602         // assert((v3+vec3(3.0f, 1.0f, -1.0f)).vector == [4.0f, 4.0f, 4.0f]);
603         // assert((v3-vec3(1.0f, 3.0f, 5.0f)).vector == [0.0f, 0.0f, 0.0f]);
604         // assert((v3*vec3(2.0f, 2.0f, 2.0f)) == 18.0f);
605 
606         // vec4 v4 = vec4(1.0f, 3.0f, 5.0f, 7.0f);
607         // assert((v4*2.5f).vector == [2.5f, 7.5f, 12.5f, 17.5]);
608         // assert((v4+vec4(3.0f, 1.0f, -1.0f, -3.0f)).vector == [4.0f, 4.0f, 4.0f, 4.0f]);
609         // assert((v4-vec4(1.0f, 3.0f, 5.0f, 7.0f)).vector == [0.0f, 0.0f, 0.0f, 0.0f]);
610         // assert((v4*vec4(2.0f, 2.0f, 2.0f, 2.0f)) == 32.0f);
611 
612         // mat2 m2 = mat2(1.0f, 2.0f, 3.0f, 4.0f);
613         // vec2 v2_2 = vec2(2.0f, 2.0f);
614         // assert((v2_2*m2).vector == [8.0f, 12.0f]);
615 
616         // mat3 m3 = mat3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f);
617         // vec3 v3_2 = vec3(2.0f, 2.0f, 2.0f);
618         // assert((v3_2*m3).vector == [24.0f, 30.0f, 36.0f]);
619     }
620 
621     void opOpAssign(string op : "*")(vt r) {
622         foreach(index; TupleRange!(0, dimension)) {
623             vector[index] *= r;
624         }
625     }
626 
627     void opOpAssign(string op : "/")(vt r) {
628         foreach(index; TupleRange!(0, dimension)) {
629             vector[index] /= r;
630         }
631     }
632 
633     void opOpAssign(string op)(Vector r) if((op == "+") || (op == "-")) {
634         foreach(index; TupleRange!(0, dimension)) {
635             mixin("vector[index]" ~ op ~ "= r.vector[index];");
636         }
637     }
638 
639     unittest {
640         vec2 v2 = vec2(1.0f, 3.0f);
641         v2 *= 2.5f;
642         assert(v2.vector == [2.5f, 7.5f]);
643         v2 -= vec2(2.5f, 7.5f);
644         assert(v2.vector == [0.0f, 0.0f]);
645         v2 += vec2(1.0f, 3.0f);
646         assert(v2.vector == [1.0f, 3.0f]);
647         assert(almostEqual(v2.length, sqrt(10.0f)));
648         assert(v2.lengthSquared == 10.0f);
649         assert((v2.length == v2.length) && (v2.lengthSquared == v2.lengthSquared));
650         v2 /= 2.0f;
651         assert(v2.vector == [0.5f, 1.5f]);
652         assert(almostEqual(v2.normalized, vec2(1.0f/sqrt(10.0f), 3.0f/sqrt(10.0f))));
653 
654         vec3 v3 = vec3(1.0f, 3.0f, 5.0f);
655         v3 *= 2.5f;
656         assert(v3.vector == [2.5f, 7.5f, 12.5f]);
657         v3 -= vec3(2.5f, 7.5f, 12.5f);
658         assert(v3.vector == [0.0f, 0.0f, 0.0f]);
659         v3 += vec3(1.0f, 3.0f, 5.0f);
660         assert(v3.vector == [1.0f, 3.0f, 5.0f]);
661         assert(almostEqual(v3.length, sqrt(35.0f)));
662         assert(v3.lengthSquared == 35.0f);
663         assert((v3.length == v3.length) && (v3.lengthSquared == v3.lengthSquared));
664         v3 /= 2.0f;
665         assert(v3.vector == [0.5f, 1.5f, 2.5f]);
666         assert(almostEqual(v3.normalized, vec3(1.0f/sqrt(35.0f), 3.0f/sqrt(35.0f), 5.0f/sqrt(35.0f))));
667 
668         vec4 v4 = vec4(1.0f, 3.0f, 5.0f, 7.0f);
669         v4 *= 2.5f;
670         assert(v4.vector == [2.5f, 7.5f, 12.5f, 17.5]);
671         v4 -= vec4(2.5f, 7.5f, 12.5f, 17.5f);
672         assert(v4.vector == [0.0f, 0.0f, 0.0f, 0.0f]);
673         v4 += vec4(1.0f, 3.0f, 5.0f, 7.0f);
674         assert(v4.vector == [1.0f, 3.0f, 5.0f, 7.0f]);
675         assert(almostEqual(v4.length, sqrt(84.0f)));
676         assert(v4.lengthSquared == 84.0f);
677         assert((v4.length == v4.length) && (v4.lengthSquared == v4.lengthSquared));
678         v4 /= 2.0f;
679         assert(v4.vector == [0.5f, 1.5f, 2.5f, 3.5f]);
680         assert(almostEqual(v4.normalized, vec4(1.0f/sqrt(84.0f), 3.0f/sqrt(84.0f), 5.0f/sqrt(84.0f), 7.0f/sqrt(84.0f))));
681     }
682 
683     int opCmp(ref const Vector vec) const {
684         foreach(i, a; vector) {
685             if(a < vec.vector[i]) {
686                 return -1;
687             } else if(a > vec.vector[i]) {
688                 return 1;
689             }
690         }
691 
692         // Vectors are the same
693         return 0;
694     }
695 
696     bool opEquals(T)(const T vec) const if(!isArray!T && T.dimension == dimension) {
697         return vector == vec.vector;
698     }
699 
700     bool opEquals(T)(const(T)[] array) const if(!isArray!T && !isVector!T) {
701         if(array.length != dimension) {
702             return false;
703         }
704 
705         foreach(index; TupleRange!(0, dimension)) {
706             if(vector[index] != array[index]) {
707                 return false;
708             }
709         }
710 
711         return true;
712     }
713 
714     unittest {
715         assert(vec2(1.0f, 2.0f) == vec2(1.0f, 2.0f));
716         assert(vec2(1.0f, 2.0f) != vec2(1.0f, 1.0f));
717         assert(vec2(1.0f, 2.0f) == vec2d(1.0, 2.0));
718         assert(vec2(1.0f, 2.0f) != vec2d(1.0, 1.0));
719         assert(vec2(1.0f, 2.0f) == vec2(1.0f, 2.0f).vector);
720         assert(vec2(1.0f, 2.0f) != vec2(1.0f, 1.0f).vector);
721         assert(vec2(1.0f, 2.0f) == vec2d(1.0, 2.0).vector);
722         assert(vec2(1.0f, 2.0f) != vec2d(1.0, 1.0).vector);
723 
724         assert(vec3(1.0f, 2.0f, 3.0f) == vec3(1.0f, 2.0f, 3.0f));
725         assert(vec3(1.0f, 2.0f, 3.0f) != vec3(1.0f, 2.0f, 2.0f));
726         assert(vec3(1.0f, 2.0f, 3.0f) == vec3d(1.0, 2.0, 3.0));
727         assert(vec3(1.0f, 2.0f, 3.0f) != vec3d(1.0, 2.0, 2.0));
728         assert(vec3(1.0f, 2.0f, 3.0f) == vec3(1.0f, 2.0f, 3.0f).vector);
729         assert(vec3(1.0f, 2.0f, 3.0f) != vec3(1.0f, 2.0f, 2.0f).vector);
730         assert(vec3(1.0f, 2.0f, 3.0f) == vec3d(1.0, 2.0, 3.0).vector);
731         assert(vec3(1.0f, 2.0f, 3.0f) != vec3d(1.0, 2.0, 2.0).vector);
732 
733         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) == vec4(1.0f, 2.0f, 3.0f, 4.0f));
734         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) != vec4(1.0f, 2.0f, 3.0f, 3.0f));
735         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) == vec4d(1.0, 2.0, 3.0, 4.0));
736         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) != vec4d(1.0, 2.0, 3.0, 3.0));
737         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) == vec4(1.0f, 2.0f, 3.0f, 4.0f).vector);
738         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) != vec4(1.0f, 2.0f, 3.0f, 3.0f).vector);
739         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) == vec4d(1.0, 2.0, 3.0, 4.0).vector);
740         assert(vec4(1.0f, 2.0f, 3.0f, 4.0f) != vec4d(1.0, 2.0, 3.0, 3.0).vector);
741 
742         assert(!vec4(float.nan).isFinite);
743         if(vec4(1.0f).isFinite) { }
744         else { assert(false); }
745     }
746 }
747 
748 /// Calculates the product between two vectors.
749 T.vt dot(T)(const T veca, const T vecb) @safe pure nothrow if(isVector!T) {
750     T.vt temp = 0;
751 
752     foreach(index; TupleRange!(0, T.dimension)) {
753         temp += veca.vector[index] * vecb.vector[index];
754     }
755 
756     return temp;
757 }
758 
759 /// Calculates the cross product of two 3-dimensional vectors.
760 T cross(T)(const T veca, const T vecb) @safe pure nothrow if(isVector!T && (T.dimension == 3)) {
761    return T(veca.y * vecb.z - vecb.y * veca.z,
762             veca.z * vecb.x - vecb.z * veca.x,
763             veca.x * vecb.y - vecb.x * veca.y);
764 }
765 
766 /// Calculates the distance between two vectors.
767 T.vt distance(T)(const T veca, const T vecb) @safe pure nothrow if(isVector!T) {
768     return (veca - vecb).length;
769 }
770 
771 @("vector dot product")
772 unittest {
773     // dot is already tested in Vector.opBinary, so no need for testing with more vectors
774     vec3 v1 = vec3(1.0f, 2.0f, -3.0f);
775     vec3 v2 = vec3(1.0f, 3.0f, 2.0f);
776 
777     assert(dot(v1, v2) == 1.0f);
778     assert(dot(v1, v2) == dot(v2, v1));
779     assert((v1 * v2) == (v1 * v2));
780 
781     assert(cross(v1, v2).vector == [13.0f, -5.0f, 1.0f]);
782     assert(cross(v2, v1).vector == [-13.0f, 5.0f, -1.0f]);
783 
784     assert(distance(vec2(0.0f, 0.0f), vec2(0.0f, 10.0f)) == 10.0);
785 }
786 
787 /// reflect a vector using a surface normal
788 T reflect(T)(const T vec, const T norm) @safe pure nothrow if(isVector!T) {
789     return (2 * (vec * norm) * norm) - vec;
790 }
791 
792 @("vector reflect")
793 unittest
794 {
795     assert(vec2(1,1).reflect(vec2(0,1)) == vec2(-1,1));
796     assert(vec2(-1,1).reflect(vec2(0,1)) == vec2(1,1));
797     assert(vec2(2,1).reflect(vec2(0,1)) == vec2(-2,1));
798 
799     assert(vec3(1,1,1).reflect(vec3(0,1,0)) == vec3(-1,1,-1));
800 }
801 
802 /// Pre-defined vector types, the number represents the dimension and the last letter the type (none = float, d = double, i = int).
803 alias vec2 = Vector!(float, 2);
804 alias vec3 = Vector!(float, 3); /// ditto
805 alias vec4 = Vector!(float, 4); /// ditto
806 
807 alias vec2d = Vector!(double, 2); /// ditto
808 alias vec3d = Vector!(double, 3); /// ditto
809 alias vec4d = Vector!(double, 4); /// ditto
810 
811 alias vec2i = Vector!(int, 2); /// ditto
812 alias vec3i = Vector!(int, 3); /// ditto
813 alias vec4i = Vector!(int, 4); /// ditto
814 
815 alias vec2u = Vector!(uint, 2); /// ditto
816 alias vec3u = Vector!(uint, 3); /// ditto
817 alias vec4u = Vector!(uint, 4); /// ditto
818 
819 /*alias Vector!(ubyte, 2) vec2ub;
820 alias Vector!(ubyte, 3) vec3ub;
821 alias Vector!(ubyte, 4) vec4ub;*/
822 
823 
824 /// Base template for all matrix-types.
825 /// Params:
826 ///  type = all values get stored as this type
827 ///  rows_ = rows of the matrix
828 ///  cols_ = columns of the matrix
829 /// Examples:
830 /// ---
831 /// alias Matrix!(float, 4, 4) mat4;
832 /// alias Matrix!(double, 3, 4) mat34d;
833 /// alias Matrix!(real, 2, 2) mat2r;
834 /// ---
835 struct Matrix(type, int rows_, int cols_) if((rows_ > 0) && (cols_ > 0)) {
836     alias mt = type; /// Holds the internal type of the matrix;
837     static const int rows = rows_; /// Holds the number of rows;
838     static const int cols = cols_; /// Holds the number of columns;
839 
840     /// Holds the matrix $(RED row-major) in memory.
841     mt[cols][rows] matrix; // In C it would be mt[rows][cols], D does it like this: (mt[foo])[bar]
842     alias matrix this;
843 
844     unittest {
845         mat2 m2 = mat2(0.0f, 1.0f, 2.0f, 3.0f);
846         assert(m2[0][0] == 0.0f);
847         assert(m2[0][1] == 1.0f);
848         assert(m2[1][0] == 2.0f);
849         assert(m2[1][1] == 3.0f);
850         m2[0..1] = [2.0f, 2.0f];
851         assert(m2 == [[2.0f, 2.0f], [2.0f, 3.0f]]);
852 
853         mat3 m3 = mat3(0.0f, 0.1f, 0.2f, 1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f);
854         assert(m3[0][1] == 0.1f);
855         assert(m3[2][0] == 2.0f);
856         assert(m3[1][2] == 1.2f);
857         m3[0][0..$] = 0.0f;
858         assert(m3 == [[0.0f, 0.0f, 0.0f],
859                       [1.0f, 1.1f, 1.2f],
860                       [2.0f, 2.1f, 2.2f]]);
861 
862         mat4 m4 = mat4(0.0f, 0.1f, 0.2f, 0.3f,
863                        1.0f, 1.1f, 1.2f, 1.3f,
864                        2.0f, 2.1f, 2.2f, 2.3f,
865                        3.0f, 3.1f, 3.2f, 3.3f);
866        assert(m4[0][3] == 0.3f);
867        assert(m4[1][1] == 1.1f);
868        assert(m4[2][0] == 2.0f);
869        assert(m4[3][2] == 3.2f);
870        m4[2][1..3] = [1.0f, 2.0f];
871        assert(m4 == [[0.0f, 0.1f, 0.2f, 0.3f],
872                      [1.0f, 1.1f, 1.2f, 1.3f],
873                      [2.0f, 1.0f, 2.0f, 2.3f],
874                      [3.0f, 3.1f, 3.2f, 3.3f]]);
875 
876     }
877 
878     /// Returns the pointer to the stored values as OpenGL requires it.
879     /// Note this will return a pointer to a $(RED row-major) matrix,
880     /// $(RED this means you've to set the transpose argument to GL_TRUE when passing it to OpenGL).
881     /// Examples:
882     /// ---
883     /// // 3rd argument = GL_TRUE
884     /// glUniformMatrix4fv(programs.main.model, 1, GL_TRUE, mat4.translation(-0.5f, -0.5f, 1.0f).ptr);
885     /// ---
886     auto ptr() const { return matrix[0].ptr; }
887 
888     /// Returns the current matrix formatted as flat string.
889     string toString() const {
890         return format("%s", matrix);
891     }
892 
893     /// Returns the current matrix as pretty formatted string.
894     string toPrettyString() {
895         string fmtr = "%s";
896 
897         size_t rjust = max(format(fmtr, reduce!(max)(matrix[])).length,
898                            format(fmtr, reduce!(min)(matrix[])).length) - 1;
899 
900         string[] outer_parts;
901         foreach(mt[] row; matrix) {
902             string[] inner_parts;
903             foreach(mt col; row) {
904                 inner_parts ~= rightJustify(format(fmtr, col), rjust);
905             }
906             outer_parts ~= " [" ~ join(inner_parts, ", ") ~ "]";
907         }
908 
909         return "[" ~ join(outer_parts, "\n")[1..$] ~ "]";
910     }
911 
912 @safe pure nothrow:
913     static void isCompatibleMatrixImpl(int r, int c)(Matrix!(mt, r, c) m) {
914     }
915 
916     template isCompatibleMatrix(T) {
917         enum isCompatibleMatrix = is(typeof(isCompatibleMatrixImpl(T.init)));
918     }
919 
920     static void isCompatibleVectorImpl(int d)(Vector!(mt, d) vec) {
921     }
922 
923     template isCompatibleVector(T) {
924         enum isCompatibleVector = is(typeof(isCompatibleVectorImpl(T.init)));
925     }
926 
927     private void construct(int i, T, Tail...)(T head, Tail tail) {
928         static if(i >= rows*cols) {
929             static assert(false, "Too many arguments passed to constructor");
930         } else static if(is(T : mt)) {
931             matrix[i / cols][i % cols] = head;
932             construct!(i + 1)(tail);
933         } else static if(is(T == Vector!(mt, cols))) {
934             static if(i % cols == 0) {
935                 matrix[i / cols] = head.vector;
936                 construct!(i + T.dimension)(tail);
937             } else {
938                 static assert(false, "Can't convert Vector into the matrix. Maybe it doesn't align to the columns correctly or dimension doesn't fit");
939             }
940         } else static if(isDynamicArray!T) {
941             foreach(j; 0..cols*rows)
942                 matrix[j / cols][j % cols] = head[j];
943         } else {
944             static assert(false, "Matrix constructor argument must be of type " ~ mt.stringof ~ " or Vector, not " ~ T.stringof);
945         }
946     }
947 
948     private void construct(int i)() { // terminate
949         static assert(i == rows*cols, "Not enough arguments passed to constructor");
950     }
951 
952     /// Constructs the matrix:
953     /// If a single value is passed, the matrix will be cleared with this value (each column in each row will contain this value).
954     /// If a matrix with more rows and columns is passed, the matrix will be the upper left nxm matrix.
955     /// If a matrix with less rows and columns is passed, the passed matrix will be stored in the upper left of an identity matrix.
956     /// It's also allowed to pass vectors and scalars at a time, but the vectors dimension must match the number of columns and align correctly.
957     /// Examples:
958     /// ---
959     /// mat2 m2 = mat2(0.0f); // mat2 m2 = mat2(0.0f, 0.0f, 0.0f, 0.0f);
960     /// mat3 m3 = mat3(m2); // mat3 m3 = mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
961     /// mat3 m3_2 = mat3(vec3(1.0f, 2.0f, 3.0f), 4.0f, 5.0f, 6.0f, vec3(7.0f, 8.0f, 9.0f));
962     /// mat4 m4 = mat4.identity; // just an identity matrix
963     /// mat3 m3_3 = mat3(m4); // mat3 m3_3 = mat3.identity
964     /// ---
965     this(Args...)(Args args) {
966         construct!(0)(args);
967     }
968 
969     /// ditto
970     this(T)(T mat) if(isMatrix!T && (T.cols >= cols) && (T.rows >= rows)) {
971         foreach(r; TupleRange!(0, rows)) {
972             foreach(c; TupleRange!(0, cols)) {
973                 matrix[r][c] = mat.matrix[r][c];
974             }
975         }
976     }
977 
978     /// ditto
979     this(T)(T mat) if(isMatrix!T && (T.cols < cols) && (T.rows < rows)) {
980         makeIdentity();
981 
982         foreach(r; TupleRange!(0, T.rows)) {
983             foreach(c; TupleRange!(0, T.cols)) {
984                 matrix[r][c] = mat.matrix[r][c];
985             }
986         }
987     }
988 
989     /// ditto
990     this()(mt value) {
991         clear(value);
992     }
993 
994     /// Returns true if all values are not nan and finite, otherwise false.
995     bool isFinite() const {
996         static if(isIntegral!type) {
997             return true;
998         }
999         else {
1000             foreach(row; matrix) {
1001                 foreach(col; row) {
1002                     if(isNaN(col) || isInfinity(col)) {
1003                         return false;
1004                     }
1005                 }
1006             }
1007             return true;
1008         }
1009 
1010     }
1011     deprecated("Use isFinite instead of ok") alias ok = isFinite;
1012 
1013     /// Sets all values of the matrix to value (each column in each row will contain this value).
1014     void clear(mt value) {
1015         foreach(r; TupleRange!(0, rows)) {
1016             foreach(c; TupleRange!(0, cols)) {
1017                 matrix[r][c] = value;
1018             }
1019         }
1020     }
1021 
1022     unittest {
1023         mat2 m2 = mat2(1.0f, 1.0f, vec2(2.0f, 2.0f));
1024         assert(m2.matrix == [[1.0f, 1.0f], [2.0f, 2.0f]]);
1025         m2.clear(3.0f);
1026         assert(m2.matrix == [[3.0f, 3.0f], [3.0f, 3.0f]]);
1027         assert(m2.isFinite);
1028         m2.clear(float.nan);
1029         assert(!m2.isFinite);
1030         m2.clear(float.infinity);
1031         assert(!m2.isFinite);
1032         m2.clear(0.0f);
1033         assert(m2.isFinite);
1034 
1035         mat3 m3 = mat3(1.0f);
1036         assert(m3.matrix == [[1.0f, 1.0f, 1.0f],
1037                              [1.0f, 1.0f, 1.0f],
1038                              [1.0f, 1.0f, 1.0f]]);
1039 
1040         mat4 m4 = mat4(vec4(1.0f, 1.0f, 1.0f, 1.0f),
1041                             2.0f, 2.0f, 2.0f, 2.0f,
1042                             3.0f, 3.0f, 3.0f, 3.0f,
1043                        vec4(4.0f, 4.0f, 4.0f, 4.0f));
1044         assert(m4.matrix == [[1.0f, 1.0f, 1.0f, 1.0f],
1045                              [2.0f, 2.0f, 2.0f, 2.0f],
1046                              [3.0f, 3.0f, 3.0f, 3.0f],
1047                              [4.0f, 4.0f, 4.0f, 4.0f]]);
1048         assert(mat3(m4).matrix == [[1.0f, 1.0f, 1.0f],
1049                                    [2.0f, 2.0f, 2.0f],
1050                                    [3.0f, 3.0f, 3.0f]]);
1051         assert(mat2(mat3(m4)).matrix == [[1.0f, 1.0f], [2.0f, 2.0f]]);
1052         assert(mat2(m4).matrix == mat2(mat3(m4)).matrix);
1053         assert(mat4(mat3(m4)).matrix == [[1.0f, 1.0f, 1.0f, 0.0f],
1054                                          [2.0f, 2.0f, 2.0f, 0.0f],
1055                                          [3.0f, 3.0f, 3.0f, 0.0f],
1056                                          [0.0f, 0.0f, 0.0f, 1.0f]]);
1057 
1058         Matrix!(float, 2, 3) mt1 = Matrix!(float, 2, 3)(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f);
1059         Matrix!(float, 3, 2) mt2 = Matrix!(float, 3, 2)(6.0f, -1.0f, 3.0f, 2.0f, 0.0f, -3.0f);
1060 
1061         assert(mt1.matrix == [[1.0f, 2.0f, 3.0f], [4.0f, 5.0f, 6.0f]]);
1062         assert(mt2.matrix == [[6.0f, -1.0f], [3.0f, 2.0f], [0.0f, -3.0f]]);
1063 
1064         static assert(!__traits(compiles, mat2(1, 2, 1)));
1065         static assert(!__traits(compiles, mat3(1, 2, 3, 1, 2, 3, 1, 2)));
1066         static assert(!__traits(compiles, mat4(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3)));
1067 
1068         auto m5 = mat2([0.0f,1,2,3]);
1069         assert(m5.matrix == [[0.0f, 1.0f], [2.0f, 3.0f]]);
1070 
1071         auto m6 = Matrix!(int, 2, 3)([0,1,2,3,4,5]);
1072         assert(m6.matrix == [[0, 1, 2], [3, 4, 5]]);
1073     }
1074 
1075     static if(rows == cols) {
1076         /// Makes the current matrix an identity matrix.
1077         void makeIdentity() {
1078             clear(0);
1079             foreach(r; TupleRange!(0, rows)) {
1080                 matrix[r][r] = 1;
1081             }
1082         }
1083 
1084         /// Returns a identity matrix.
1085         static Matrix identity() {
1086             Matrix ret;
1087             ret.clear(0);
1088 
1089             foreach(r; TupleRange!(0, rows)) {
1090                 ret.matrix[r][r] = 1;
1091             }
1092 
1093             return ret;
1094         }
1095 
1096         /// Transposes the current matrix;
1097         void transpose() {
1098             matrix = transposed().matrix;
1099         }
1100 
1101         unittest {
1102             mat2 m2 = mat2(1.0f);
1103             m2.transpose();
1104             assert(m2.matrix == mat2(1.0f).matrix);
1105             m2.makeIdentity();
1106             assert(m2.matrix == [[1.0f, 0.0f],
1107                                  [0.0f, 1.0f]]);
1108             m2.transpose();
1109             assert(m2.matrix == [[1.0f, 0.0f],
1110                                  [0.0f, 1.0f]]);
1111             assert(m2.matrix == m2.identity.matrix);
1112 
1113             mat3 m3 = mat3(1.1f, 1.2f, 1.3f,
1114                            2.1f, 2.2f, 2.3f,
1115                            3.1f, 3.2f, 3.3f);
1116             m3.transpose();
1117             assert(m3.matrix == [[1.1f, 2.1f, 3.1f],
1118                                  [1.2f, 2.2f, 3.2f],
1119                                  [1.3f, 2.3f, 3.3f]]);
1120 
1121             mat4 m4 = mat4(2.0f);
1122             m4.transpose();
1123             assert(m4.matrix == mat4(2.0f).matrix);
1124             m4.makeIdentity();
1125             assert(m4.matrix == [[1.0f, 0.0f, 0.0f, 0.0f],
1126                                  [0.0f, 1.0f, 0.0f, 0.0f],
1127                                  [0.0f, 0.0f, 1.0f, 0.0f],
1128                                  [0.0f, 0.0f, 0.0f, 1.0f]]);
1129             assert(m4.matrix == m4.identity.matrix);
1130         }
1131 
1132     }
1133 
1134     /// Returns a transposed copy of the matrix.
1135     Matrix!(mt, cols, rows) transposed() const {
1136         typeof(return) ret;
1137 
1138         foreach(r; TupleRange!(0, rows)) {
1139             foreach(c; TupleRange!(0, cols)) {
1140                 ret.matrix[c][r] = matrix[r][c];
1141             }
1142         }
1143 
1144         return ret;
1145     }
1146 
1147     // transposed already tested in last unittest
1148 
1149 
1150     static if((rows == 2) && (cols == 2)) {
1151         mt det() const {
1152             return (matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]);
1153         }
1154 
1155         private Matrix invert(ref Matrix mat) const {
1156             static if(isFloatingPoint!mt && rmul) {
1157                 mt d = 1 / det;
1158 
1159                 mat.matrix = [[matrix[1][1]*d, -matrix[0][1]*d],
1160                               [-matrix[1][0]*d, matrix[0][0]*d]];
1161             } else {
1162                 mt d = det;
1163 
1164                 mat.matrix = [[matrix[1][1]/d, -matrix[0][1]/d],
1165                               [-matrix[1][0]/d, matrix[0][0]/d]];
1166             }
1167 
1168             return mat;
1169         }
1170 
1171         static Matrix scaling(mt x, mt y) {
1172             Matrix ret = Matrix.identity;
1173 
1174             ret.matrix[0][0] = x;
1175             ret.matrix[1][1] = y;
1176 
1177             return ret;
1178         }
1179 
1180         Matrix scale(mt x, mt y) {
1181             this = Matrix.scaling(x, y) * this;
1182             return this;
1183         }
1184 
1185         unittest {
1186             assert(mat2.scaling(3, 3).matrix == mat2.identity.scale(3, 3).matrix);
1187             assert(mat2.scaling(3, 3).matrix == [[3.0f, 0.0f], [0.0f, 3.0f]]);
1188         }
1189 
1190     } else static if((rows == 3) && (cols == 3)) {
1191         mt det() const {
1192             return (matrix[0][0] * matrix[1][1] * matrix[2][2]
1193                   + matrix[0][1] * matrix[1][2] * matrix[2][0]
1194                   + matrix[0][2] * matrix[1][0] * matrix[2][1]
1195                   - matrix[0][2] * matrix[1][1] * matrix[2][0]
1196                   - matrix[0][1] * matrix[1][0] * matrix[2][2]
1197                   - matrix[0][0] * matrix[1][2] * matrix[2][1]);
1198         }
1199 
1200         private Matrix invert(ref Matrix mat) const {
1201             static if(isFloatingPoint!mt && rmul) {
1202                 mt d = 1 / det;
1203                 enum op = "*";
1204             } else {
1205                 mt d = det;
1206                 enum op = "/";
1207             }
1208 
1209             mixin(`
1210             mat.matrix = [[(matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])`~op~`d,
1211                            (matrix[0][2] * matrix[2][1] - matrix[0][1] * matrix[2][2])`~op~`d,
1212                            (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])`~op~`d],
1213                           [(matrix[1][2] * matrix[2][0] - matrix[1][0] * matrix[2][2])`~op~`d,
1214                            (matrix[0][0] * matrix[2][2] - matrix[0][2] * matrix[2][0])`~op~`d,
1215                            (matrix[0][2] * matrix[1][0] - matrix[0][0] * matrix[1][2])`~op~`d],
1216                           [(matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0])`~op~`d,
1217                            (matrix[0][1] * matrix[2][0] - matrix[0][0] * matrix[2][1])`~op~`d,
1218                            (matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0])`~op~`d]];
1219             `);
1220 
1221             return mat;
1222         }
1223     } else static if((rows == 4) && (cols == 4)) {
1224         /// Returns the determinant of the current matrix (2x2, 3x3 and 4x4 matrices).
1225         mt det() const {
1226             return (matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0]
1227                   - matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0]
1228                   + matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0]
1229                   - matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1]
1230                   + matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1]
1231                   - matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1]
1232                   + matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2]
1233                   - matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2]
1234                   + matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2]
1235                   - matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3]
1236                   + matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3]
1237                   - matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3]);
1238         }
1239 
1240         private Matrix invert(ref Matrix mat) const {
1241             static if(isFloatingPoint!mt && rmul) {
1242                 mt d = 1 / det;
1243                 enum op = "*";
1244             } else {
1245                 mt d = det;
1246                 enum op = "/";
1247             }
1248 
1249             mixin(`
1250             mat.matrix = [[(matrix[1][1] * matrix[2][2] * matrix[3][3] + matrix[1][2] * matrix[2][3] * matrix[3][1] + matrix[1][3] * matrix[2][1] * matrix[3][2]
1251                           - matrix[1][1] * matrix[2][3] * matrix[3][2] - matrix[1][2] * matrix[2][1] * matrix[3][3] - matrix[1][3] * matrix[2][2] * matrix[3][1])`~op~`d,
1252                            (matrix[0][1] * matrix[2][3] * matrix[3][2] + matrix[0][2] * matrix[2][1] * matrix[3][3] + matrix[0][3] * matrix[2][2] * matrix[3][1]
1253                           - matrix[0][1] * matrix[2][2] * matrix[3][3] - matrix[0][2] * matrix[2][3] * matrix[3][1] - matrix[0][3] * matrix[2][1] * matrix[3][2])`~op~`d,
1254                            (matrix[0][1] * matrix[1][2] * matrix[3][3] + matrix[0][2] * matrix[1][3] * matrix[3][1] + matrix[0][3] * matrix[1][1] * matrix[3][2]
1255                           - matrix[0][1] * matrix[1][3] * matrix[3][2] - matrix[0][2] * matrix[1][1] * matrix[3][3] - matrix[0][3] * matrix[1][2] * matrix[3][1])`~op~`d,
1256                            (matrix[0][1] * matrix[1][3] * matrix[2][2] + matrix[0][2] * matrix[1][1] * matrix[2][3] + matrix[0][3] * matrix[1][2] * matrix[2][1]
1257                           - matrix[0][1] * matrix[1][2] * matrix[2][3] - matrix[0][2] * matrix[1][3] * matrix[2][1] - matrix[0][3] * matrix[1][1] * matrix[2][2])`~op~`d],
1258                           [(matrix[1][0] * matrix[2][3] * matrix[3][2] + matrix[1][2] * matrix[2][0] * matrix[3][3] + matrix[1][3] * matrix[2][2] * matrix[3][0]
1259                           - matrix[1][0] * matrix[2][2] * matrix[3][3] - matrix[1][2] * matrix[2][3] * matrix[3][0] - matrix[1][3] * matrix[2][0] * matrix[3][2])`~op~`d,
1260                            (matrix[0][0] * matrix[2][2] * matrix[3][3] + matrix[0][2] * matrix[2][3] * matrix[3][0] + matrix[0][3] * matrix[2][0] * matrix[3][2]
1261                           - matrix[0][0] * matrix[2][3] * matrix[3][2] - matrix[0][2] * matrix[2][0] * matrix[3][3] - matrix[0][3] * matrix[2][2] * matrix[3][0])`~op~`d,
1262                            (matrix[0][0] * matrix[1][3] * matrix[3][2] + matrix[0][2] * matrix[1][0] * matrix[3][3] + matrix[0][3] * matrix[1][2] * matrix[3][0]
1263                           - matrix[0][0] * matrix[1][2] * matrix[3][3] - matrix[0][2] * matrix[1][3] * matrix[3][0] - matrix[0][3] * matrix[1][0] * matrix[3][2])`~op~`d,
1264                            (matrix[0][0] * matrix[1][2] * matrix[2][3] + matrix[0][2] * matrix[1][3] * matrix[2][0] + matrix[0][3] * matrix[1][0] * matrix[2][2]
1265                           - matrix[0][0] * matrix[1][3] * matrix[2][2] - matrix[0][2] * matrix[1][0] * matrix[2][3] - matrix[0][3] * matrix[1][2] * matrix[2][0])`~op~`d],
1266                           [(matrix[1][0] * matrix[2][1] * matrix[3][3] + matrix[1][1] * matrix[2][3] * matrix[3][0] + matrix[1][3] * matrix[2][0] * matrix[3][1]
1267                           - matrix[1][0] * matrix[2][3] * matrix[3][1] - matrix[1][1] * matrix[2][0] * matrix[3][3] - matrix[1][3] * matrix[2][1] * matrix[3][0])`~op~`d,
1268                            (matrix[0][0] * matrix[2][3] * matrix[3][1] + matrix[0][1] * matrix[2][0] * matrix[3][3] + matrix[0][3] * matrix[2][1] * matrix[3][0]
1269                           - matrix[0][0] * matrix[2][1] * matrix[3][3] - matrix[0][1] * matrix[2][3] * matrix[3][0] - matrix[0][3] * matrix[2][0] * matrix[3][1])`~op~`d,
1270                            (matrix[0][0] * matrix[1][1] * matrix[3][3] + matrix[0][1] * matrix[1][3] * matrix[3][0] + matrix[0][3] * matrix[1][0] * matrix[3][1]
1271                           - matrix[0][0] * matrix[1][3] * matrix[3][1] - matrix[0][1] * matrix[1][0] * matrix[3][3] - matrix[0][3] * matrix[1][1] * matrix[3][0])`~op~`d,
1272                            (matrix[0][0] * matrix[1][3] * matrix[2][1] + matrix[0][1] * matrix[1][0] * matrix[2][3] + matrix[0][3] * matrix[1][1] * matrix[2][0]
1273                           - matrix[0][0] * matrix[1][1] * matrix[2][3] - matrix[0][1] * matrix[1][3] * matrix[2][0] - matrix[0][3] * matrix[1][0] * matrix[2][1])`~op~`d],
1274                           [(matrix[1][0] * matrix[2][2] * matrix[3][1] + matrix[1][1] * matrix[2][0] * matrix[3][2] + matrix[1][2] * matrix[2][1] * matrix[3][0]
1275                           - matrix[1][0] * matrix[2][1] * matrix[3][2] - matrix[1][1] * matrix[2][2] * matrix[3][0] - matrix[1][2] * matrix[2][0] * matrix[3][1])`~op~`d,
1276                            (matrix[0][0] * matrix[2][1] * matrix[3][2] + matrix[0][1] * matrix[2][2] * matrix[3][0] + matrix[0][2] * matrix[2][0] * matrix[3][1]
1277                           - matrix[0][0] * matrix[2][2] * matrix[3][1] - matrix[0][1] * matrix[2][0] * matrix[3][2] - matrix[0][2] * matrix[2][1] * matrix[3][0])`~op~`d,
1278                            (matrix[0][0] * matrix[1][2] * matrix[3][1] + matrix[0][1] * matrix[1][0] * matrix[3][2] + matrix[0][2] * matrix[1][1] * matrix[3][0]
1279                           - matrix[0][0] * matrix[1][1] * matrix[3][2] - matrix[0][1] * matrix[1][2] * matrix[3][0] - matrix[0][2] * matrix[1][0] * matrix[3][1])`~op~`d,
1280                            (matrix[0][0] * matrix[1][1] * matrix[2][2] + matrix[0][1] * matrix[1][2] * matrix[2][0] + matrix[0][2] * matrix[1][0] * matrix[2][1]
1281                           - matrix[0][0] * matrix[1][2] * matrix[2][1] - matrix[0][1] * matrix[1][0] * matrix[2][2] - matrix[0][2] * matrix[1][1] * matrix[2][0])`~op~`d]];
1282             `);
1283 
1284             return mat;
1285         }
1286 
1287         // some static fun ...
1288         // (1) glprogramming.com/red/appendixf.html - ortographic is broken!
1289         // (2) http://fly.cc.fer.hr/~unreal/theredbook/appendixg.html
1290         // (3) http://en.wikipedia.org/wiki/Orthographic_projection_(geometry)
1291 
1292         static if(isFloatingPoint!mt) {
1293             static private mt[6] cperspective(mt width, mt height, mt fov, mt near, mt far)
1294                 in { assert(height != 0); }
1295                 do {
1296                     mt aspect = width/height;
1297                     mt top = near * tan(fov*(PI/360.0));
1298                     mt bottom = -top;
1299                     mt right = top * aspect;
1300                     mt left = -right;
1301 
1302                     return [left, right, bottom, top, near, far];
1303                 }
1304 
1305             /// Returns a perspective matrix (4x4 and floating-point matrices only).
1306             static Matrix perspective(mt width, mt height, mt fov, mt near, mt far) {
1307                 mt[6] cdata = cperspective(width, height, fov, near, far);
1308                 return perspective(cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5]);
1309             }
1310 
1311             /// ditto
1312             static Matrix perspective(mt left, mt right, mt bottom, mt top, mt near, mt far)
1313                 in {
1314                     assert(right-left != 0);
1315                     assert(top-bottom != 0);
1316                     assert(far-near != 0);
1317                 }
1318                 do {
1319                     Matrix ret;
1320                     ret.clear(0);
1321 
1322                     ret.matrix[0][0] = (2*near)/(right-left);
1323                     ret.matrix[0][2] = (right+left)/(right-left);
1324                     ret.matrix[1][1] = (2*near)/(top-bottom);
1325                     ret.matrix[1][2] = (top+bottom)/(top-bottom);
1326                     ret.matrix[2][2] = -(far+near)/(far-near);
1327                     ret.matrix[2][3] = -(2*far*near)/(far-near);
1328                     ret.matrix[3][2] = -1;
1329 
1330                     return ret;
1331                 }
1332 
1333             /// Returns an inverse perspective matrix (4x4 and floating-point matrices only).
1334             static Matrix persperctiveInverse(mt width, mt height, mt fov, mt near, mt far) {
1335                 mt[6] cdata = cperspective(width, height, fov, near, far);
1336                 return persperctiveInverse(cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5]);
1337             }
1338 
1339             /// ditto
1340             static Matrix persperctiveInverse(mt left, mt right, mt bottom, mt top, mt near, mt far)
1341                 in {
1342                     assert(near != 0);
1343                     assert(far != 0);
1344                 }
1345                 do {
1346                     Matrix ret;
1347                     ret.clear(0);
1348 
1349                     ret.matrix[0][0] = (right-left)/(2*near);
1350                     ret.matrix[0][3] = (right+left)/(2*near);
1351                     ret.matrix[1][1] = (top-bottom)/(2*near);
1352                     ret.matrix[1][3] = (top+bottom)/(2*near);
1353                     ret.matrix[2][3] = -1;
1354                     ret.matrix[3][2] = -(far-near)/(2*far*near);
1355                     ret.matrix[3][3] = (far+near)/(2*far*near);
1356 
1357                     return ret;
1358                 }
1359 
1360             // (2) and (3) say this one is correct
1361             /// Returns an orthographic matrix (4x4 and floating-point matrices only).
1362             static Matrix orthographic(mt left, mt right, mt bottom, mt top, mt near, mt far)
1363                 in {
1364                     assert(right-left != 0);
1365                     assert(top-bottom != 0);
1366                     assert(far-near != 0);
1367                 }
1368                 do {
1369                     Matrix ret;
1370                     ret.clear(0);
1371 
1372                     ret.matrix[0][0] = 2/(right-left);
1373                     ret.matrix[0][3] = -(right+left)/(right-left);
1374                     ret.matrix[1][1] = 2/(top-bottom);
1375                     ret.matrix[1][3] = -(top+bottom)/(top-bottom);
1376                     ret.matrix[2][2] = -2/(far-near);
1377                     ret.matrix[2][3] = -(far+near)/(far-near);
1378                     ret.matrix[3][3] = 1;
1379 
1380                     return ret;
1381                 }
1382 
1383             // (1) and (2) say this one is correct
1384             /// Returns an inverse ortographic matrix (4x4 and floating-point matrices only).
1385             static Matrix orthographicInverse(mt left, mt right, mt bottom, mt top, mt near, mt far) {
1386                 Matrix ret;
1387                 ret.clear(0);
1388 
1389                 ret.matrix[0][0] = (right-left)/2;
1390                 ret.matrix[0][3] = (right+left)/2;
1391                 ret.matrix[1][1] = (top-bottom)/2;
1392                 ret.matrix[1][3] = (top+bottom)/2;
1393                 ret.matrix[2][2] = (far-near)/-2;
1394                 ret.matrix[2][3] = (far+near)/2;
1395                 ret.matrix[3][3] = 1;
1396 
1397                 return ret;
1398             }
1399 
1400             /// Returns a look at matrix (4x4 and floating-point matrices only).
1401             static Matrix lookAt(Vector!(mt, 3) eye, Vector!(mt, 3) target, Vector!(mt, 3) up) {
1402                 alias vec3mt = Vector!(mt, 3);
1403                 vec3mt look_dir = (target - eye).normalized;
1404                 vec3mt up_dir = up.normalized;
1405 
1406                 vec3mt right_dir = cross(look_dir, up_dir).normalized;
1407                 vec3mt perp_up_dir = cross(right_dir, look_dir);
1408 
1409                 Matrix ret = Matrix.identity;
1410                 ret.matrix[0][0..3] = right_dir.vector[];
1411                 ret.matrix[1][0..3] = perp_up_dir.vector[];
1412                 ret.matrix[2][0..3] = (-look_dir).vector[];
1413 
1414                 ret.matrix[0][3] = -dot(eye, right_dir);
1415                 ret.matrix[1][3] = -dot(eye, perp_up_dir);
1416                 ret.matrix[2][3] = dot(eye, look_dir);
1417 
1418                 return ret;
1419             }
1420 
1421             unittest {
1422                 mt[6] cp = cperspective(600f, 900f, 60f, 1f, 100f);
1423                 assert(cp[4] == 1.0f);
1424                 assert(cp[5] == 100.0f);
1425                 assert(cp[0] == -cp[1]);
1426                 assert((cp[0] < -0.38489f) && (cp[0] > -0.38491f));
1427                 assert(cp[2] == -cp[3]);
1428                 assert((cp[2] < -0.577349f) && (cp[2] > -0.577351f));
1429 
1430                 assert(mat4.perspective(600f, 900f, 60.0, 1.0, 100.0) == mat4.perspective(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]));
1431                 float[4][4] m4p = mat4.perspective(600f, 900f, 60.0, 1.0, 100.0).matrix;
1432                 assert((m4p[0][0] < 2.598077f) && (m4p[0][0] > 2.598075f));
1433                 assert(m4p[0][2] == 0.0f);
1434                 assert((m4p[1][1] < 1.732052) && (m4p[1][1] > 1.732050));
1435                 assert(m4p[1][2] == 0.0f);
1436                 assert((m4p[2][2] < -1.020201) && (m4p[2][2] > -1.020203));
1437                 assert((m4p[2][3] < -2.020201) && (m4p[2][3] > -2.020203));
1438                 assert((m4p[3][2] < -0.9f) && (m4p[3][2] > -1.1f));
1439 
1440                 float[4][4] m4pi = mat4.persperctiveInverse(600f, 900f, 60.0, 1.0, 100.0).matrix;
1441                 assert((m4pi[0][0] < 0.384901) && (m4pi[0][0] > 0.384899));
1442                 assert(m4pi[0][3] == 0.0f);
1443                 assert((m4pi[1][1] < 0.577351) && (m4pi[1][1] > 0.577349));
1444                 assert(m4pi[1][3] == 0.0f);
1445                 assert(m4pi[2][3] == -1.0f);
1446                 assert((m4pi[3][2] < -0.494999) && (m4pi[3][2] > -0.495001));
1447                 assert((m4pi[3][3] < 0.505001) && (m4pi[3][3] > 0.504999));
1448 
1449                 // maybe the next tests should be improved
1450                 float[4][4] m4o = mat4.orthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f).matrix;
1451                 assert(m4o == [[1.0f, 0.0f, 0.0f, 0.0f],
1452                                [0.0f, 1.0f, 0.0f, 0.0f],
1453                                [0.0f, 0.0f, -1.0f, 0.0f],
1454                                [0.0f, 0.0f, 0.0f, 1.0f]]);
1455 
1456                 float[4][4] m4oi = mat4.orthographicInverse(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f).matrix;
1457                 assert(m4oi == [[1.0f, 0.0f, 0.0f, 0.0f],
1458                                 [0.0f, 1.0f, 0.0f, 0.0f],
1459                                 [0.0f, 0.0f, -1.0f, 0.0f],
1460                                 [0.0f, 0.0f, 0.0f, 1.0f]]);
1461 
1462                 //TODO: lookAt tests
1463             }
1464         }
1465     }
1466 
1467     static if((rows == cols) && (rows >= 3) && (rows <= 4)) {
1468         /// Returns a translation matrix (3x3 and 4x4 matrices).
1469         static Matrix translation(mt x, mt y, mt z) {
1470             Matrix ret = Matrix.identity;
1471 
1472             ret.matrix[0][cols-1] = x;
1473             ret.matrix[1][cols-1] = y;
1474             ret.matrix[2][cols-1] = z;
1475 
1476             return ret;
1477         }
1478 
1479         /// ditto
1480         static Matrix translation(Vector!(mt, 3) v) {
1481             Matrix ret = Matrix.identity;
1482             
1483             ret.matrix[0][cols-1] = v.x;
1484             ret.matrix[1][cols-1] = v.y;
1485             ret.matrix[2][cols-1] = v.z;
1486             
1487             return ret;
1488         }
1489 
1490         /// Applys a translation on the current matrix and returns $(I this) (3x3 and 4x4 matrices).
1491         Matrix translate(mt x, mt y, mt z) {
1492             this = Matrix.translation(x, y, z) * this;
1493             return this;
1494         }
1495 
1496         /// ditto
1497         Matrix translate(Vector!(mt, 3) v) {
1498             this = Matrix.translation(v) * this;
1499             return this;
1500         }
1501 
1502         /// Returns a scaling matrix (3x3 and 4x4 matrices);
1503         static Matrix scaling(mt x, mt y, mt z) {
1504             Matrix ret = Matrix.identity;
1505 
1506             ret.matrix[0][0] = x;
1507             ret.matrix[1][1] = y;
1508             ret.matrix[2][2] = z;
1509 
1510             return ret;
1511         }
1512 
1513         /// Applys a scale to the current matrix and returns $(I this) (3x3 and 4x4 matrices).
1514         Matrix scale(mt x, mt y, mt z) {
1515             this = Matrix.scaling(x, y, z) * this;
1516             return this;
1517         }
1518 
1519         unittest {
1520             mat3 m3 = mat3.identity;
1521             assert(m3.translate(1.0f, 2.0f, 3.0f).matrix == mat3.translation(1.0f, 2.0f, 3.0f).matrix);
1522             assert(mat3.translation(1.0f, 2.0f, 3.0f).matrix == [[1.0f, 0.0f, 1.0f],
1523                                                                  [0.0f, 1.0f, 2.0f],
1524                                                                  [0.0f, 0.0f, 3.0f]]);
1525             assert(mat3.identity.translate(0.0f, 1.0f, 2.0f).matrix == mat3.translation(0.0f, 1.0f, 2.0f).matrix);
1526 
1527             mat3 m31 = mat3.identity;
1528             assert(m31.translate(vec3(1.0f, 2.0f, 3.0f)).matrix == mat3.translation(vec3(1.0f, 2.0f, 3.0f)).matrix);
1529             assert(mat3.translation(vec3(1.0f, 2.0f, 3.0f)).matrix == [[1.0f, 0.0f, 1.0f],
1530                     [0.0f, 1.0f, 2.0f],
1531                     [0.0f, 0.0f, 3.0f]]);
1532             assert(mat3.identity.translate(vec3(0.0f, 1.0f, 2.0f)).matrix == mat3.translation(vec3(0.0f, 1.0f, 2.0f)).matrix);
1533 
1534             assert(m3.scaling(0.0f, 1.0f, 2.0f).matrix == mat3.scaling(0.0f, 1.0f, 2.0f).matrix);
1535             assert(mat3.scaling(0.0f, 1.0f, 2.0f).matrix == [[0.0f, 0.0f, 0.0f],
1536                                                              [0.0f, 1.0f, 0.0f],
1537                                                              [0.0f, 0.0f, 2.0f]]);
1538             assert(mat3.identity.scale(0.0f, 1.0f, 2.0f).matrix == mat3.scaling(0.0f, 1.0f, 2.0f).matrix);
1539 
1540             // same tests for 4x4
1541 
1542             mat4 m4 = mat4(1.0f);
1543             assert(m4.translation(1.0f, 2.0f, 3.0f).matrix == mat4.translation(1.0f, 2.0f, 3.0f).matrix);
1544             assert(mat4.translation(1.0f, 2.0f, 3.0f).matrix == [[1.0f, 0.0f, 0.0f, 1.0f],
1545                                                                  [0.0f, 1.0f, 0.0f, 2.0f],
1546                                                                  [0.0f, 0.0f, 1.0f, 3.0f],
1547                                                                  [0.0f, 0.0f, 0.0f, 1.0f]]);
1548             assert(mat4.identity.translate(0.0f, 1.0f, 2.0f).matrix == mat4.translation(0.0f, 1.0f, 2.0f).matrix);
1549 
1550             assert(m4.scaling(0.0f, 1.0f, 2.0f).matrix == mat4.scaling(0.0f, 1.0f, 2.0f).matrix);
1551             assert(mat4.scaling(0.0f, 1.0f, 2.0f).matrix == [[0.0f, 0.0f, 0.0f, 0.0f],
1552                                                              [0.0f, 1.0f, 0.0f, 0.0f],
1553                                                              [0.0f, 0.0f, 2.0f, 0.0f],
1554                                                              [0.0f, 0.0f, 0.0f, 1.0f]]);
1555             assert(mat4.identity.scale(0.0f, 1.0f, 2.0f).matrix == mat4.scaling(0.0f, 1.0f, 2.0f).matrix);
1556         }
1557     }
1558 
1559 
1560     static if((rows == cols) && (rows >= 3)) {
1561         static if(isFloatingPoint!mt) {
1562             /// Returns an identity matrix with an applied rotateAxis around an arbitrary axis (nxn matrices, n >= 3).
1563             static Matrix rotation(real alpha, Vector!(mt, 3) axis) {
1564                 Matrix mult = Matrix.identity;
1565 
1566                 if(axis.length != 1) {
1567                     axis.normalize();
1568                 }
1569 
1570                 real cosa = cos(alpha);
1571                 real sina = sin(alpha);
1572 
1573                 Vector!(mt, 3) temp = (1 - cosa)*axis;
1574 
1575                 mult.matrix[0][0] = to!mt(cosa + temp.x * axis.x);
1576                 mult.matrix[0][1] = to!mt(       temp.x * axis.y + sina * axis.z);
1577                 mult.matrix[0][2] = to!mt(       temp.x * axis.z - sina * axis.y);
1578                 mult.matrix[1][0] = to!mt(       temp.y * axis.x - sina * axis.z);
1579                 mult.matrix[1][1] = to!mt(cosa + temp.y * axis.y);
1580                 mult.matrix[1][2] = to!mt(       temp.y * axis.z + sina * axis.x);
1581                 mult.matrix[2][0] = to!mt(       temp.z * axis.x + sina * axis.y);
1582                 mult.matrix[2][1] = to!mt(       temp.z * axis.y - sina * axis.x);
1583                 mult.matrix[2][2] = to!mt(cosa + temp.z * axis.z);
1584 
1585                 return mult;
1586             }
1587 
1588             /// ditto
1589             static Matrix rotation(real alpha, mt x, mt y, mt z) {
1590                 return Matrix.rotation(alpha, Vector!(mt, 3)(x, y, z));
1591             }
1592 
1593             /// Returns an identity matrix with an applied rotation around the x-axis (nxn matrices, n >= 3).
1594             static Matrix xRotation(real alpha) {
1595                 Matrix mult = Matrix.identity;
1596 
1597                 mt cosamt = to!mt(cos(alpha));
1598                 mt sinamt = to!mt(sin(alpha));
1599 
1600                 mult.matrix[1][1] = cosamt;
1601                 mult.matrix[1][2] = -sinamt;
1602                 mult.matrix[2][1] = sinamt;
1603                 mult.matrix[2][2] = cosamt;
1604 
1605                 return mult;
1606             }
1607 
1608             /// Returns an identity matrix with an applied rotation around the y-axis (nxn matrices, n >= 3).
1609             static Matrix yRotation(real alpha) {
1610                 Matrix mult = Matrix.identity;
1611 
1612                 mt cosamt = to!mt(cos(alpha));
1613                 mt sinamt = to!mt(sin(alpha));
1614 
1615                 mult.matrix[0][0] = cosamt;
1616                 mult.matrix[0][2] = sinamt;
1617                 mult.matrix[2][0] = -sinamt;
1618                 mult.matrix[2][2] = cosamt;
1619 
1620                 return mult;
1621             }
1622 
1623             /// Returns an identity matrix with an applied rotation around the z-axis (nxn matrices, n >= 3).
1624             static Matrix zRotation(real alpha) {
1625                 Matrix mult = Matrix.identity;
1626 
1627                 mt cosamt = to!mt(cos(alpha));
1628                 mt sinamt = to!mt(sin(alpha));
1629 
1630                 mult.matrix[0][0] = cosamt;
1631                 mult.matrix[0][1] = -sinamt;
1632                 mult.matrix[1][0] = sinamt;
1633                 mult.matrix[1][1] = cosamt;
1634 
1635                 return mult;
1636             }
1637 
1638             Matrix rotate(real alpha, Vector!(mt, 3) axis) {
1639                 this = rotation(alpha, axis) * this;
1640                 return this;
1641             }
1642 
1643             /// Rotates the current matrix around the x-axis and returns $(I this) (nxn matrices, n >= 3).
1644             Matrix rotateX(real alpha) {
1645                 this = xRotation(alpha) * this;
1646                 return this;
1647             }
1648 
1649             /// Rotates the current matrix around the y-axis and returns $(I this) (nxn matrices, n >= 3).
1650             Matrix rotateY(real alpha) {
1651                 this = yRotation(alpha) * this;
1652                 return this;
1653             }
1654 
1655             /// Rotates the current matrix around the z-axis and returns $(I this) (nxn matrices, n >= 3).
1656             Matrix rotateZ(real alpha) {
1657                 this = zRotation(alpha) * this;
1658                 return this;
1659             }
1660 
1661             unittest {
1662                 assert(mat4.xRotation(0).matrix == [[1.0f, 0.0f, 0.0f, 0.0f],
1663                                                     [0.0f, 1.0f, -0.0f, 0.0f],
1664                                                     [0.0f, 0.0f, 1.0f, 0.0f],
1665                                                     [0.0f, 0.0f, 0.0f, 1.0f]]);
1666                 assert(mat4.yRotation(0).matrix == [[1.0f, 0.0f, 0.0f, 0.0f],
1667                                                     [0.0f, 1.0f, 0.0f, 0.0f],
1668                                                     [0.0f, 0.0f, 1.0f, 0.0f],
1669                                                     [0.0f, 0.0f, 0.0f, 1.0f]]);
1670                 assert(mat4.zRotation(0).matrix == [[1.0f, -0.0f, 0.0f, 0.0f],
1671                                                     [0.0f, 1.0f, 0.0f, 0.0f],
1672                                                     [0.0f, 0.0f, 1.0f, 0.0f],
1673                                                     [0.0f, 0.0f, 0.0f, 1.0f]]);
1674                 mat4 xro = mat4.identity;
1675                 xro.rotateX(0);
1676                 assert(mat4.xRotation(0).matrix == xro.matrix);
1677                 assert(xro.matrix == mat4.identity.rotateX(0).matrix);
1678                 assert(xro.matrix == mat4.rotation(0, vec3(1.0f, 0.0f, 0.0f)).matrix);
1679                 mat4 yro = mat4.identity;
1680                 yro.rotateY(0);
1681                 assert(mat4.yRotation(0).matrix == yro.matrix);
1682                 assert(yro.matrix == mat4.identity.rotateY(0).matrix);
1683                 assert(yro.matrix == mat4.rotation(0, vec3(0.0f, 1.0f, 0.0f)).matrix);
1684                 mat4 zro = mat4.identity;
1685                 xro.rotateZ(0);
1686                 assert(mat4.zRotation(0).matrix == zro.matrix);
1687                 assert(zro.matrix == mat4.identity.rotateZ(0).matrix);
1688                 assert(zro.matrix == mat4.rotation(0, vec3(0.0f, 0.0f, 1.0f)).matrix);
1689             }
1690         } // isFloatingPoint
1691 
1692 
1693         /// Sets the translation of the matrix (nxn matrices, n >= 3).
1694         void translation(mt[] values...) // intended to be a property
1695             in { assert(values.length >= (rows-1)); }
1696             do {
1697                 foreach(r; TupleRange!(0, rows-1)) {
1698                     matrix[r][rows-1] = values[r];
1699                 }
1700             }
1701 
1702         /// Copyies the translation from mat to the current matrix (nxn matrices, n >= 3).
1703         void translation(Matrix mat) {
1704             foreach(r; TupleRange!(0, rows-1)) {
1705                 matrix[r][rows-1] = mat.matrix[r][rows-1];
1706             }
1707         }
1708 
1709         /// Returns an identity matrix with the current translation applied (nxn matrices, n >= 3)..
1710         Matrix translation() {
1711             Matrix ret = Matrix.identity;
1712 
1713             foreach(r; TupleRange!(0, rows-1)) {
1714                 ret.matrix[r][rows-1] = matrix[r][rows-1];
1715             }
1716 
1717             return ret;
1718         }
1719 
1720         unittest {
1721             mat3 m3 = mat3(0.0f, 1.0f, 2.0f,
1722                            3.0f, 4.0f, 5.0f,
1723                            6.0f, 7.0f, 1.0f);
1724             assert(m3.translation().matrix == [[1.0f, 0.0f, 2.0f], [0.0f, 1.0f, 5.0f], [0.0f, 0.0f, 1.0f]]);
1725             m3.translation(mat3.identity);
1726             assert(mat3.identity.matrix == m3.translation().matrix);
1727             m3.translation([2.0f, 5.0f]);
1728             assert(m3.translation().matrix == [[1.0f, 0.0f, 2.0f], [0.0f, 1.0f, 5.0f], [0.0f, 0.0f, 1.0f]]);
1729             assert(mat3.identity.matrix == mat3.identity.translation().matrix);
1730 
1731             mat4 m4 = mat4(0.0f, 1.0f, 2.0f, 3.0f,
1732                            4.0f, 5.0f, 6.0f, 7.0f,
1733                            8.0f, 9.0f, 10.0f, 11.0f,
1734                            12.0f, 13.0f, 14.0f, 1.0f);
1735             assert(m4.translation().matrix == [[1.0f, 0.0f, 0.0f, 3.0f],
1736                                        [0.0f, 1.0f, 0.0f, 7.0f],
1737                                        [0.0f, 0.0f, 1.0f, 11.0f],
1738                                        [0.0f, 0.0f, 0.0f, 1.0f]]);
1739             m4.translation(mat4.identity);
1740             assert(mat4.identity.matrix == m4.translation().matrix);
1741             m4.translation([3.0f, 7.0f, 11.0f]);
1742             assert(m4.translation().matrix == [[1.0f, 0.0f, 0.0f, 3.0f],
1743                                        [0.0f, 1.0f, 0.0f, 7.0f],
1744                                        [0.0f, 0.0f, 1.0f, 11.0f],
1745                                        [0.0f, 0.0f, 0.0f, 1.0f]]);
1746             assert(mat4.identity.matrix == mat4.identity.translation().matrix);
1747         }
1748 
1749         /// Sets the scale of the matrix (nxn matrices, n >= 3).
1750         void scale(mt[] values...)
1751             in { assert(values.length >= (rows-1)); }
1752             do {
1753                 foreach(r; TupleRange!(0, rows-1)) {
1754                     matrix[r][r] = values[r];
1755                 }
1756             }
1757 
1758         /// Copyies the scale from mat to the current matrix (nxn matrices, n >= 3).
1759         void scale(Matrix mat) {
1760             foreach(r; TupleRange!(0, rows-1)) {
1761                 matrix[r][r] = mat.matrix[r][r];
1762             }
1763         }
1764 
1765         /// Returns an identity matrix with the current scale applied (nxn matrices, n >= 3).
1766         Matrix scale() {
1767             Matrix ret = Matrix.identity;
1768 
1769             foreach(r; TupleRange!(0, rows-1)) {
1770                 ret.matrix[r][r] = matrix[r][r];
1771             }
1772 
1773             return ret;
1774         }
1775 
1776         unittest {
1777             mat3 m3 = mat3(0.0f, 1.0f, 2.0f,
1778                            3.0f, 4.0f, 5.0f,
1779                            6.0f, 7.0f, 1.0f);
1780             assert(m3.scale().matrix == [[0.0f, 0.0f, 0.0f], [0.0f, 4.0f, 0.0f], [0.0f, 0.0f, 1.0f]]);
1781             m3.scale(mat3.identity);
1782             assert(mat3.identity.matrix == m3.scale().matrix);
1783             m3.scale([0.0f, 4.0f]);
1784             assert(m3.scale().matrix == [[0.0f, 0.0f, 0.0f], [0.0f, 4.0f, 0.0f], [0.0f, 0.0f, 1.0f]]);
1785             assert(mat3.identity.matrix == mat3.identity.scale().matrix);
1786 
1787             mat4 m4 = mat4(0.0f, 1.0f, 2.0f, 3.0f,
1788                            4.0f, 5.0f, 6.0f, 7.0f,
1789                            8.0f, 9.0f, 10.0f, 11.0f,
1790                            12.0f, 13.0f, 14.0f, 1.0f);
1791             assert(m4.scale().matrix == [[0.0f, 0.0f, 0.0f, 0.0f],
1792                                        [0.0f, 5.0f, 0.0f, 0.0f],
1793                                        [0.0f, 0.0f, 10.0f, 0.0f],
1794                                        [0.0f, 0.0f, 0.0f, 1.0f]]);
1795             m4.scale(mat4.identity);
1796             assert(mat4.identity.matrix == m4.scale().matrix);
1797             m4.scale([0.0f, 5.0f, 10.0f]);
1798             assert(m4.scale().matrix == [[0.0f, 0.0f, 0.0f, 0.0f],
1799                                        [0.0f, 5.0f, 0.0f, 0.0f],
1800                                        [0.0f, 0.0f, 10.0f, 0.0f],
1801                                        [0.0f, 0.0f, 0.0f, 1.0f]]);
1802             assert(mat4.identity.matrix == mat4.identity.scale().matrix);
1803         }
1804 
1805         /// Copies rot into the upper left corner, the translation (nxn matrices, n >= 3).
1806         void rotation(Matrix!(mt, 3, 3) rot) {
1807             foreach(r; TupleRange!(0, 3)) {
1808                 foreach(c; TupleRange!(0, 3)) {
1809                     matrix[r][c] = rot[r][c];
1810                 }
1811             }
1812         }
1813 
1814         /// Returns an identity matrix with the current rotation applied (nxn matrices, n >= 3).
1815         Matrix!(mt, 3, 3) rotation() {
1816             Matrix!(mt, 3, 3) ret = Matrix!(mt, 3, 3).identity;
1817 
1818             foreach(r; TupleRange!(0, 3)) {
1819                 foreach(c; TupleRange!(0, 3)) {
1820                     ret.matrix[r][c] = matrix[r][c];
1821                 }
1822             }
1823 
1824             return ret;
1825         }
1826 
1827         unittest {
1828             mat3 m3 = mat3(0.0f, 1.0f, 2.0f,
1829                            3.0f, 4.0f, 5.0f,
1830                            6.0f, 7.0f, 1.0f);
1831             assert(m3.rotation().matrix == [[0.0f, 1.0f, 2.0f], [3.0f, 4.0f, 5.0f], [6.0f, 7.0f, 1.0f]]);
1832             m3.rotation(mat3.identity);
1833             assert(mat3.identity.matrix == m3.rotation().matrix);
1834             m3.rotation(mat3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 1.0f));
1835             assert(m3.rotation().matrix == [[0.0f, 1.0f, 2.0f], [3.0f, 4.0f, 5.0f], [6.0f, 7.0f, 1.0f]]);
1836             assert(mat3.identity.matrix == mat3.identity.rotation().matrix);
1837 
1838             mat4 m4 = mat4(0.0f, 1.0f, 2.0f, 3.0f,
1839                            4.0f, 5.0f, 6.0f, 7.0f,
1840                            8.0f, 9.0f, 10.0f, 11.0f,
1841                            12.0f, 13.0f, 14.0f, 1.0f);
1842             assert(m4.rotation().matrix == [[0.0f, 1.0f, 2.0f], [4.0f, 5.0f, 6.0f], [8.0f, 9.0f, 10.0f]]);
1843             m4.rotation(mat3.identity);
1844             assert(mat3.identity.matrix == m4.rotation().matrix);
1845             m4.rotation(mat3(0.0f, 1.0f, 2.0f, 4.0f, 5.0f, 6.0f, 8.0f, 9.0f, 10.0f));
1846             assert(m4.rotation().matrix == [[0.0f, 1.0f, 2.0f], [4.0f, 5.0f, 6.0f], [8.0f, 9.0f, 10.0f]]);
1847             assert(mat3.identity.matrix == mat4.identity.rotation().matrix);
1848         }
1849 
1850     }
1851 
1852     static if((rows == cols) && (rows >= 2) && (rows <= 4)) {
1853         /// Returns an inverted copy of the current matrix (nxn matrices, 2 >= n <= 4).
1854         Matrix inverse() const {
1855             Matrix mat;
1856             invert(mat);
1857             return mat;
1858         }
1859 
1860         /// Inverts the current matrix (nxn matrices, 2 >= n <= 4).
1861         void invert() {
1862             // workaround Issue #11238
1863             // uses a temporary instead of invert(this)
1864             Matrix temp;
1865             invert(temp);
1866             this.matrix = temp.matrix;
1867         }
1868     }
1869 
1870     unittest {
1871         mat2 m2 = mat2(1.0f, 2.0f, vec2(3.0f, 4.0f));
1872         assert(m2.det == -2.0f);
1873         assert(m2.inverse.matrix == [[-2.0f, 1.0f], [1.5f, -0.5f]]);
1874 
1875         mat3 m3 = mat3(1.0f, -2.0f, 3.0f,
1876                        7.0f, -1.0f, 0.0f,
1877                        3.0f, 2.0f, -4.0f);
1878         assert(m3.det == -1.0f);
1879         assert(m3.inverse.matrix == [[-4.0f, 2.0f, -3.0f],
1880                                      [-28.0f, 13.0f, -21.0f],
1881                                      [-17.0f, 8.0f, -13.0f]]);
1882 
1883         mat4 m4 = mat4(1.0f, 2.0f, 3.0f, 4.0f,
1884                        -2.0f, 1.0f, 5.0f, -2.0f,
1885                        2.0f, -1.0f, 7.0f, 1.0f,
1886                        3.0f, -3.0f, 2.0f, 0.0f);
1887         assert(m4.det == -8.0f);
1888         assert(m4.inverse.matrix == [[6.875f, 7.875f, -11.75f, 11.125f],
1889                                      [6.625f, 7.625f, -11.25f, 10.375f],
1890                                      [-0.375f, -0.375f, 0.75f, -0.625f],
1891                                      [-4.5f, -5.5f, 8.0f, -7.5f]]);
1892     }
1893 
1894     private void mms(mt inp, ref Matrix mat) const { // mat * scalar
1895         for(int r = 0; r < rows; r++) {
1896             for(int c = 0; c < cols; c++) {
1897                 mat.matrix[r][c] = matrix[r][c] * inp;
1898             }
1899         }
1900     }
1901 
1902     private void masm(string op)(Matrix inp, ref Matrix mat) const { // mat + or - mat
1903         foreach(r; TupleRange!(0, rows)) {
1904             foreach(c; TupleRange!(0, cols)) {
1905                 mat.matrix[r][c] = mixin("inp.matrix[r][c]" ~ op ~ "matrix[r][c]");
1906             }
1907         }
1908     }
1909 
1910     Matrix!(mt, rows, T.cols) opBinary(string op : "*", T)(T inp) const if(isCompatibleMatrix!T && (T.rows == cols)) {
1911         Matrix!(mt, rows, T.cols) ret;
1912 
1913         foreach(r; TupleRange!(0, rows)) {
1914             foreach(c; TupleRange!(0, T.cols)) {
1915                 ret.matrix[r][c] = 0;
1916 
1917                 foreach(c2; TupleRange!(0, cols)) {
1918                     ret.matrix[r][c] += matrix[r][c2] * inp.matrix[c2][c];
1919                 }
1920             }
1921         }
1922 
1923         return ret;
1924     }
1925 
1926     Vector!(mt, rows) opBinary(string op : "*", T : Vector!(mt, cols))(T inp) const {
1927         Vector!(mt, rows) ret;
1928         ret.clear(0);
1929 
1930         foreach(c; TupleRange!(0, cols)) {
1931             foreach(r; TupleRange!(0, rows)) {
1932                 ret.vector[r] += matrix[r][c] * inp.vector[c];
1933             }
1934         }
1935 
1936         return ret;
1937     }
1938 
1939     Matrix opBinary(string op : "*")(mt inp) const {
1940         Matrix ret;
1941         mms(inp, ret);
1942         return ret;
1943     }
1944 
1945     Matrix opBinaryRight(string op : "*")(mt inp) const {
1946         return this.opBinary!(op)(inp);
1947     }
1948 
1949     Matrix opBinary(string op)(Matrix inp) const if((op == "+") || (op == "-")) {
1950         Matrix ret;
1951         masm!(op)(inp, ret);
1952         return ret;
1953     }
1954 
1955     void opOpAssign(string op : "*")(mt inp) {
1956         mms(inp, this);
1957     }
1958 
1959     void opOpAssign(string op)(Matrix inp) if((op == "+") || (op == "-")) {
1960         masm!(op)(inp, this);
1961     }
1962 
1963     void opOpAssign(string op)(Matrix inp) if(op == "*") {
1964         this = this * inp;
1965     }
1966 
1967     unittest {
1968         mat2 m2 = mat2(1.0f, 2.0f, 3.0f, 4.0f);
1969         vec2 v2 = vec2(2.0f, 2.0f);
1970         assert((m2*2).matrix == [[2.0f, 4.0f], [6.0f, 8.0f]]);
1971         assert((2*m2).matrix == (m2*2).matrix);
1972         m2 *= 2;
1973         assert(m2.matrix == [[2.0f, 4.0f], [6.0f, 8.0f]]);
1974         assert((m2*v2).vector == [12.0f, 28.0f]);
1975         assert((v2*m2).vector == [16.0f, 24.0f]);
1976         assert((m2*m2).matrix == [[28.0f, 40.0f], [60.0f, 88.0f]]);
1977         assert((m2-m2).matrix == [[0.0f, 0.0f], [0.0f, 0.0f]]);
1978         assert((m2+m2).matrix == [[4.0f, 8.0f], [12.0f, 16.0f]]);
1979         m2 += m2;
1980         assert(m2.matrix == [[4.0f, 8.0f], [12.0f, 16.0f]]);
1981         m2 -= m2;
1982         assert(m2.matrix == [[0.0f, 0.0f], [0.0f, 0.0f]]);
1983 
1984         mat3 m3 = mat3(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f);
1985         vec3 v3 = vec3(2.0f, 2.0f, 2.0f);
1986         assert((m3*2).matrix == [[2.0f, 4.0f, 6.0f], [8.0f, 10.0f, 12.0f], [14.0f, 16.0f, 18.0f]]);
1987         assert((2*m3).matrix == (m3*2).matrix);
1988         m3 *= 2;
1989         assert(m3.matrix == [[2.0f, 4.0f, 6.0f], [8.0f, 10.0f, 12.0f], [14.0f, 16.0f, 18.0f]]);
1990         assert((m3*v3).vector == [24.0f, 60.0f, 96.0f]);
1991         assert((v3*m3).vector == [48.0f, 60.0f, 72.0f]);
1992         assert((m3*m3).matrix == [[120.0f, 144.0f, 168.0f], [264.0f, 324.0f, 384.0f], [408.0f, 504.0f, 600.0f]]);
1993         assert((m3-m3).matrix == [[0.0f, 0.0f, 0.0f], [0.0f, 0.0f, 0.0f], [0.0f, 0.0f, 0.0f]]);
1994         assert((m3+m3).matrix == [[4.0f, 8.0f, 12.0f], [16.0f, 20.0f, 24.0f], [28.0f, 32.0f, 36.0f]]);
1995         m3 += m3;
1996         assert(m3.matrix == [[4.0f, 8.0f, 12.0f], [16.0f, 20.0f, 24.0f], [28.0f, 32.0f, 36.0f]]);
1997         m3 -= m3;
1998         assert(m3.matrix == [[0.0f, 0.0f, 0.0f], [0.0f, 0.0f, 0.0f], [0.0f, 0.0f, 0.0f]]);
1999 
2000         // test opOpAssign for matrix multiplication
2001         auto m4 = mat4.translation(0,1,2);
2002         m4 *= mat4.translation(0,-1,2);
2003         assert(m4 == mat4.translation(0,0,4));
2004 
2005         //TODO: tests for mat4, mat34
2006     }
2007 
2008     unittest {
2009         assert(mat2(1.0f, 2.0f, 1.0f, 1.0f) == mat2(1.0f, 2.0f, 1.0f, 1.0f));
2010         assert(mat2(1.0f, 2.0f, 1.0f, 1.0f) != mat2(1.0f, 1.0f, 1.0f, 1.0f));
2011 
2012         assert(mat3(1.0f) == mat3(1.0f));
2013         assert(mat3(1.0f) != mat3(2.0f));
2014 
2015         assert(mat4(1.0f) == mat4(1.0f));
2016         assert(mat4(1.0f) != mat4(2.0f));
2017 
2018         assert(!mat4(float.nan).isFinite);
2019         if(mat4(1.0f).isFinite) { }
2020         else { assert(false); }
2021     }
2022 }
2023 
2024 /// Pre-defined matrix types, the first number represents the number of rows
2025 /// and the second the number of columns, if there's just one it's a nxn matrix.
2026 /// All of these matrices are floating-point matrices.
2027 alias mat2 = Matrix!(float, 2, 2);
2028 alias mat3 = Matrix!(float, 3, 3);
2029 alias mat34 = Matrix!(float, 3, 4);
2030 alias mat4 = Matrix!(float, 4, 4);
2031 
2032 private unittest {
2033     Matrix!(float,  1, 1) A = 1;
2034     Matrix!(double, 1, 1) B = 1;
2035     Matrix!(real,   1, 1) C = 1;
2036     Matrix!(int,    1, 1) D = 1;
2037     Matrix!(float,  5, 1) E = 1;
2038     Matrix!(double, 5, 1) F = 1;
2039     Matrix!(real,   5, 1) G = 1;
2040     Matrix!(int,    5, 1) H = 1;
2041     Matrix!(float,  1, 5) I = 1;
2042     Matrix!(double, 1, 5) J = 1;
2043     Matrix!(real,   1, 5) K = 1;
2044     Matrix!(int,    1, 5) L = 1;
2045 }
2046 
2047 /// Base template for all quaternion-types.
2048 /// Params:
2049 ///  type = all values get stored as this type
2050 struct Quaternion(type) {
2051     alias qt = type; /// Holds the internal type of the quaternion.
2052 
2053     qt[4] quaternion; /// Holds the w, x, y and z coordinates.
2054 
2055     /// Returns a pointer to the quaternion in memory, it starts with the w coordinate.
2056     auto ptr() const { return quaternion.ptr; }
2057 
2058     /// Returns the current vector formatted as string, useful for printing the quaternion.
2059     string toString() const {
2060         return format("%s", quaternion);
2061     }
2062 
2063     /// Gets a hash of this item
2064     size_t toHash() const { return typeid(this).getHash(&this); }
2065 
2066 @safe pure nothrow:
2067     qt get_(char coord)() const {
2068         return quaternion[coordToIndex!coord];
2069     }
2070     void set_(char coord)(qt value) {
2071         quaternion[coordToIndex!coord] = value;
2072     }
2073 
2074     alias w = get_!'w'; /// static properties to access the values.
2075     alias w = set_!'w';
2076     alias x = get_!'x'; /// ditto
2077     alias x = set_!'x';
2078     alias y = get_!'y'; /// ditto
2079     alias y = set_!'y';
2080     alias z = get_!'z'; /// ditto
2081     alias z = set_!'z';
2082 
2083     /// Constructs the quaternion.
2084     /// Takes a 4-dimensional vector, where vector.x = the quaternions w coordinate,
2085     /// or a w coordinate of type $(I qt) and a 3-dimensional vector representing the imaginary part,
2086     /// or 4 values of type $(I qt).
2087     this(qt w_, qt x_, qt y_, qt z_) {
2088         w = w_;
2089         x = x_;
2090         y = y_;
2091         z = z_;
2092     }
2093 
2094     /// ditto
2095     this(qt w_, Vector!(qt, 3) vec) {
2096         w = w_;
2097         quaternion[1..4] = vec.vector[];
2098     }
2099 
2100     /// ditto
2101     this(Vector!(qt, 4) vec) {
2102         quaternion[] = vec.vector[];
2103     }
2104 
2105     /// Returns true if all values are not nan and finite, otherwise false.
2106     bool isFinite() const {
2107         foreach(q; quaternion) {
2108             if(isNaN(q) || isInfinity(q)) {
2109                 return false;
2110             }
2111         }
2112         return true;
2113     }
2114     deprecated("Use isFinite instead of ok") alias ok = isFinite;
2115 
2116     unittest {
2117         quat q1 = quat(0.0f, 0.0f, 0.0f, 1.0f);
2118         assert(q1.quaternion == [0.0f, 0.0f, 0.0f, 1.0f]);
2119         assert(q1.quaternion == quat(0.0f, 0.0f, 0.0f, 1.0f).quaternion);
2120         assert(q1.quaternion == quat(0.0f, vec3(0.0f, 0.0f, 1.0f)).quaternion);
2121         assert(q1.quaternion == quat(vec4(0.0f, 0.0f, 0.0f, 1.0f)).quaternion);
2122 
2123         assert(q1.isFinite);
2124         q1.x = float.infinity;
2125         assert(!q1.isFinite);
2126         q1.x = float.nan;
2127         assert(!q1.isFinite);
2128         q1.x = 0.0f;
2129         assert(q1.isFinite);
2130     }
2131 
2132     template coordToIndex(char c) {
2133         static if(c == 'w') {
2134             enum coordToIndex = 0;
2135         } else static if(c == 'x') {
2136             enum coordToIndex = 1;
2137         } else static if(c == 'y') {
2138             enum coordToIndex = 2;
2139         } else static if(c == 'z') {
2140             enum coordToIndex = 3;
2141         } else {
2142             static assert(false, "accepted coordinates are x, y, z and w not " ~ c ~ ".");
2143         }
2144     }
2145 
2146     /// Returns the squared magnitude of the quaternion.
2147     real magnitudeSquared() const {
2148         return to!real(w^^2 + x^^2 + y^^2 + z^^2);
2149     }
2150 
2151     /// Returns the magnitude of the quaternion.
2152     real magnitude() const {
2153         return sqrt(magnitudeSquared);
2154     }
2155 
2156     /// Returns an identity quaternion (w=1, x=0, y=0, z=0).
2157     static Quaternion identity() {
2158         return Quaternion(1, 0, 0, 0);
2159     }
2160 
2161     /// Makes the current quaternion an identity quaternion.
2162     void makeIdentity() {
2163         w = 1;
2164         x = 0;
2165         y = 0;
2166         z = 0;
2167     }
2168 
2169     /// Inverts the quaternion.
2170     void invert() {
2171         x = -x;
2172         y = -y;
2173         z = -z;
2174     }
2175     alias conjugate = invert; /// ditto
2176 
2177     /// Returns an inverted copy of the current quaternion.
2178     Quaternion inverse() const {
2179         return Quaternion(w, -x, -y, -z);
2180     }
2181     alias conjugated = inverse; /// ditto
2182 
2183     unittest {
2184         quat q1 = quat(1.0f, 1.0f, 1.0f, 1.0f);
2185 
2186         assert(q1.magnitude == 2.0f);
2187         assert(q1.magnitudeSquared == 4.0f);
2188         assert(q1.magnitude == quat(0.0f, 0.0f, 2.0f, 0.0f).magnitude);
2189 
2190         quat q2 = quat.identity;
2191         assert(q2.quaternion == [1.0f, 0.0f, 0.0f, 0.0f]);
2192         assert(q2.x == 0.0f);
2193         assert(q2.y == 0.0f);
2194         assert(q2.z == 0.0f);
2195         assert(q2.w == 1.0f);
2196 
2197         assert(q1.inverse.quaternion == [1.0f, -1.0f, -1.0f, -1.0f]);
2198         q1.invert();
2199         assert(q1.quaternion == [1.0f, -1.0f, -1.0f, -1.0f]);
2200 
2201         q1.makeIdentity();
2202         assert(q1.quaternion == q2.quaternion);
2203 
2204     }
2205 
2206     /// Creates a quaternion from a 3x3 matrix.
2207     /// Params:
2208     ///  matrix = 3x3 matrix (rotation)
2209     /// Returns: A quaternion representing the rotation (3x3 matrix)
2210     static Quaternion fromMatrix(Matrix!(qt, 3, 3) matrix) {
2211         Quaternion ret;
2212 
2213         auto mat = matrix.matrix;
2214         qt trace = mat[0][0] + mat[1][1] + mat[2][2];
2215 
2216         if(trace > 0) {
2217             real s = 0.5 / sqrt(trace + 1.0f);
2218 
2219             ret.w = to!qt(0.25 / s);
2220             ret.x = to!qt((mat[2][1] - mat[1][2]) * s);
2221             ret.y = to!qt((mat[0][2] - mat[2][0]) * s);
2222             ret.z = to!qt((mat[1][0] - mat[0][1]) * s);
2223         } else if((mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2])) {
2224             real s = 2.0 * sqrt(1.0 + mat[0][0] - mat[1][1] - mat[2][2]);
2225 
2226             ret.w = to!qt((mat[2][1] - mat[1][2]) / s);
2227             ret.x = to!qt(0.25f * s);
2228             ret.y = to!qt((mat[0][1] + mat[1][0]) / s);
2229             ret.z = to!qt((mat[0][2] + mat[2][0]) / s);
2230         } else if(mat[1][1] > mat[2][2]) {
2231             real s = 2.0 * sqrt(1 + mat[1][1] - mat[0][0] - mat[2][2]);
2232 
2233             ret.w = to!qt((mat[0][2] - mat[2][0]) / s);
2234             ret.x = to!qt((mat[0][1] + mat[1][0]) / s);
2235             ret.y = to!qt(0.25f * s);
2236             ret.z = to!qt((mat[1][2] + mat[2][1]) / s);
2237         } else {
2238             real s = 2.0 * sqrt(1 + mat[2][2] - mat[0][0] - mat[1][1]);
2239 
2240             ret.w = to!qt((mat[1][0] - mat[0][1]) / s);
2241             ret.x = to!qt((mat[0][2] + mat[2][0]) / s);
2242             ret.y = to!qt((mat[1][2] + mat[2][1]) / s);
2243             ret.z = to!qt(0.25f * s);
2244         }
2245 
2246         return ret;
2247     }
2248 
2249     /// Returns the quaternion as matrix.
2250     /// Params:
2251     ///  rows = number of rows of the resulting matrix (min 3)
2252     ///  cols = number of columns of the resulting matrix (min 3)
2253     Matrix!(qt, rows, cols) toMatrix(int rows, int cols)() const if((rows >= 3) && (cols >= 3)) {
2254         static if((rows == 3) && (cols == 3)) {
2255             Matrix!(qt, rows, cols) ret;
2256         } else {
2257             Matrix!(qt, rows, cols) ret = Matrix!(qt, rows, cols).identity;
2258         }
2259 
2260         qt xx = x^^2;
2261         qt xy = x * y;
2262         qt xz = x * z;
2263         qt xw = x * w;
2264         qt yy = y^^2;
2265         qt yz = y * z;
2266         qt yw = y * w;
2267         qt zz = z^^2;
2268         qt zw = z * w;
2269 
2270         ret.matrix[0][0] = 1 - 2 * (yy + zz);
2271         ret.matrix[0][1] = 2 * (xy - zw);
2272         ret.matrix[0][2] = 2 * (xz + yw);
2273 
2274         ret.matrix[1][0] = 2 * (xy + zw);
2275         ret.matrix[1][1] = 1 - 2 * (xx + zz);
2276         ret.matrix[1][2] = 2 * (yz - xw);
2277 
2278         ret.matrix[2][0] = 2 * (xz - yw);
2279         ret.matrix[2][1] = 2 * (yz + xw);
2280         ret.matrix[2][2] = 1 - 2 * (xx + yy);
2281 
2282         return ret;
2283     }
2284 
2285     unittest {
2286         quat q1 = quat(4.0f, 1.0f, 2.0f, 3.0f);
2287 
2288         assert(q1.toMatrix!(3, 3).matrix == [[-25.0f, -20.0f, 22.0f], [28.0f, -19.0f, 4.0f], [-10.0f, 20.0f, -9.0f]]);
2289         assert(q1.toMatrix!(4, 4).matrix == [[-25.0f, -20.0f, 22.0f, 0.0f],
2290                                               [28.0f, -19.0f, 4.0f, 0.0f],
2291                                               [-10.0f, 20.0f, -9.0f, 0.0f],
2292                                               [0.0f, 0.0f, 0.0f, 1.0f]]);
2293         assert(quat.identity.toMatrix!(3, 3).matrix == Matrix!(qt, 3, 3).identity.matrix);
2294         assert(q1.quaternion == quat.fromMatrix(q1.toMatrix!(3, 3)).quaternion);
2295 
2296         assert(quat(1.0f, 0.0f, 0.0f, 0.0f).quaternion == quat.fromMatrix(mat3.identity).quaternion);
2297 
2298         quat q2 = quat.fromMatrix(mat3(1.0f, 3.0f, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
2299         assert(q2.x == 0.0f);
2300         assert(almostEqual(q2.y, 0.7071067f));
2301         assert(almostEqual(q2.z, -1.060660));
2302         assert(almostEqual(q2.w, 0.7071067f));
2303     }
2304     
2305     /// Returns the quaternion as a vec3 (axis / angle representation).
2306     vec3 toAxisAngle() {
2307         vec3 ret;
2308         quat this_normalized = this.normalized();
2309         real angle = 2 * acos(this_normalized.w);
2310         real denominator = sqrt(1.0 - (this_normalized.w)^^2);
2311 
2312         if (almostEqual(denominator, 0)) { // Avoid divide by 0
2313             ret.x = 1;
2314             ret.y = ret.z = 0;
2315         }
2316         else {
2317             ret.x = x / denominator;
2318             ret.y = y / denominator;
2319             ret.z = z / denominator;
2320         }
2321 
2322         return ret * angle;
2323     }
2324     unittest {
2325         // See https://www.energid.com/resources/orientation-calculator
2326 
2327         void testPair(quat q, vec3 v) {
2328             vec3 q2v = q.toAxisAngle();
2329             assert(almostEqual(q2v.x, q2v.x) // epsilon = 0.000001f
2330                    && almostEqual(q2v.y, q2v.y)
2331                    && almostEqual(q2v.z, q2v.z),
2332                    "to_axisAngle does not yield a correct vector.");
2333         }
2334 
2335         quat q1 = quat(0.5, 0.5, 0.5, 0.5);
2336         vec3 v1 = vec3(1.2091996);
2337         testPair(q1, v1);
2338 
2339         q1 = quat(0.1825742, 0.3651484, 0.5477226, 0.7302967);
2340         v1 = vec3(1.030380653, 1.54557098, 2.060761024);
2341         testPair(q1, v1);
2342 
2343         q1 = quat(0, 0, 0, 1);
2344         v1 = vec3(0, 0, 0);
2345         testPair(q1, v1);
2346 
2347         q1 = quat(-0.1961161, 0.4358136, 0.8716273, 0.1089534);
2348         v1 = vec3(-1.220800604, -2.441601488, -0.305200151);
2349         testPair(q1, v1);
2350     }
2351 
2352     /// Normalizes the current quaternion.
2353     void normalize() {
2354         qt m = to!qt(magnitude);
2355 
2356         if(m != 0) {
2357             w = w / m;
2358             x = x / m;
2359             y = y / m;
2360             z = z / m;
2361         }
2362     }
2363 
2364     /// Returns a normalized copy of the current quaternion.
2365     Quaternion normalized() const {
2366         Quaternion ret;
2367         qt m = to!qt(magnitude);
2368 
2369         if(m != 0) {
2370             ret.w = w / m;
2371             ret.x = x / m;
2372             ret.y = y / m;
2373             ret.z = z / m;
2374         } else {
2375             ret = Quaternion(w, x, y, z);
2376         }
2377 
2378         return ret;
2379     }
2380 
2381     unittest {
2382         quat q1 = quat(1.0f, 2.0f, 3.0f, 4.0f);
2383         quat q2 = quat(1.0f, 2.0f, 3.0f, 4.0f);
2384 
2385         q1.normalize();
2386         assert(q1.quaternion == q2.normalized.quaternion);
2387         //assert(q1.quaternion == q1.normalized.quaternion);
2388         assert(almostEqual(q1.magnitude, 1.0));
2389     }
2390 
2391     /// Returns the yaw.
2392     real yaw() const {
2393         return atan2(to!real(2.0*(w*z + x*y)), to!real(1.0 - 2.0*(y*y + z*z)));
2394     }
2395 
2396     /// Returns the pitch.
2397     real pitch() const {
2398         return asin(to!real(2.0*(w*y - z*x)));
2399     }
2400 
2401     /// Returns the roll.
2402     real roll() const {
2403         return atan2(to!real(2.0*(w*x + y*z)), to!real(1.0 - 2.0*(x*x + y*y)));
2404     }
2405 
2406     unittest {
2407         quat q1 = quat.identity;
2408         assert(q1.pitch == 0.0f);
2409         assert(q1.yaw == 0.0f);
2410         assert(q1.roll == 0.0f);
2411 
2412         quat q2 = quat(1.0f, 1.0f, 1.0f, 1.0f);
2413         assert(almostEqual(q2.yaw, q2.roll));
2414         //assert(almostEqual(q2.yaw, 1.570796f));
2415         assert(q2.pitch == 0.0f);
2416 
2417         quat q3 = quat(0.1f, 1.9f, 2.1f, 1.3f);
2418         //assert(almostEqual(q3.yaw, 2.4382f));
2419         assert(isNaN(q3.pitch));
2420         //assert(almostEqual(q3.roll, 1.67719f));
2421     }
2422 
2423     /// Returns a quaternion with applied rotation around the x-axis.
2424     static Quaternion xRotation(real alpha) {
2425         Quaternion ret;
2426 
2427         alpha /= 2;
2428         ret.w = to!qt(cos(alpha));
2429         ret.x = to!qt(sin(alpha));
2430         ret.y = 0;
2431         ret.z = 0;
2432 
2433         return ret;
2434     }
2435 
2436     /// Returns a quaternion with applied rotation around the y-axis.
2437     static Quaternion yRotation(real alpha) {
2438         Quaternion ret;
2439 
2440         alpha /= 2;
2441         ret.w = to!qt(cos(alpha));
2442         ret.x = 0;
2443         ret.y = to!qt(sin(alpha));
2444         ret.z = 0;
2445 
2446         return ret;
2447     }
2448 
2449     /// Returns a quaternion with applied rotation around the z-axis.
2450     static Quaternion zRotation(real alpha) {
2451         Quaternion ret;
2452 
2453         alpha /= 2;
2454         ret.w = to!qt(cos(alpha));
2455         ret.x = 0;
2456         ret.y = 0;
2457         ret.z = to!qt(sin(alpha));
2458 
2459         return ret;
2460     }
2461 
2462     /// Returns a quaternion with applied rotation around an axis.
2463     static Quaternion axisRotation(real alpha, Vector!(qt, 3) axis) {
2464         if(alpha == 0) {
2465             return Quaternion.identity;
2466         }
2467         Quaternion ret;
2468 
2469         alpha /= 2;
2470         qt sinaqt = to!qt(sin(alpha));
2471 
2472         ret.w = to!qt(cos(alpha));
2473         ret.x = axis.x * sinaqt;
2474         ret.y = axis.y * sinaqt;
2475         ret.z = axis.z * sinaqt;
2476 
2477         return ret;
2478     }
2479 
2480     /// Creates a quaternion from an euler rotation.
2481     static Quaternion eulerRotation(real roll, real pitch, real yaw) {
2482         Quaternion ret;
2483 
2484         auto cr = cos(roll / 2.0);
2485         auto cp = cos(pitch / 2.0);
2486         auto cy = cos(yaw / 2.0);
2487         auto sr = sin(roll / 2.0);
2488         auto sp = sin(pitch / 2.0);
2489         auto sy = sin(yaw / 2.0);
2490 
2491         ret.w = cr * cp * cy + sr * sp * sy;
2492         ret.x = sr * cp * cy - cr * sp * sy;
2493         ret.y = cr * sp * cy + sr * cp * sy;
2494         ret.z = cr * cp * sy - sr * sp * cy;
2495 
2496         return ret;
2497     }
2498 
2499     @("quat eulerRotation")
2500     unittest {
2501         enum startPitch = 0.1;
2502         enum startYaw = -0.2;
2503         enum startRoll = 0.6;
2504         
2505         auto q = quat.eulerRotation(startRoll,startPitch,startYaw);
2506         
2507         assert(almostEqual(q.pitch,startPitch));
2508         assert(almostEqual(q.yaw,startYaw));
2509         assert(almostEqual(q.roll,startRoll));
2510     }
2511 
2512     /**
2513         Makes a quaternion with the specified forward and upwards directions in a Unity compatible manner.
2514         Implementation from http://answers.unity3d.com/questions/467614/what-is-the-source-code-of-quaternionlookrotation.html
2515     */
2516     static Quaternion lookRotation(vec3 forward, vec3 up) {
2517         forward = forward.normalized;
2518         vec3 right = cross(up, forward).normalized;
2519         up = cross(forward, right);
2520 
2521         qt m00 = right.x;
2522         qt m01 = right.y;
2523         qt m02 = right.z;
2524         qt m10 = up.x;
2525         qt m11 = up.y;
2526         qt m12 = up.z;
2527         qt m20 = forward.x;
2528         qt m21 = forward.y;
2529         qt m22 = forward.z;
2530 
2531         qt num8 = (m00 + m11) + m22;
2532         Quaternion!qt quat = Quaternion!qt.identity;
2533         if (num8 > 0) {
2534             qt num = sqrt(num8 + 1.0);
2535             quat.w = num * 0.5f;
2536             num = 0.5f/num;
2537 			quat.x = (m12 - m21) * num;
2538 			quat.y = (m20 - m02) * num;
2539 			quat.z = (m01 - m10) * num;
2540             return quat;
2541         }
2542         if ((m00 >= m11) && (m00 >= m22)) {
2543             qt num7 = sqrt(((1f + m00) - m11) - m22);
2544 			qt num4 = 0.5f / num7;
2545 			quat.x = 0.5f * num7;
2546 			quat.y = (m01 + m10) * num4;
2547 			quat.z = (m02 + m20) * num4;
2548 			quat.w = (m12 - m21) * num4;
2549 			return quat;
2550         }
2551 		if (m11 > m22)
2552 		{
2553 			qt num6 = sqrt(((1f + m11) - m00) - m22);
2554 			qt num3 = 0.5f / num6;
2555 			quat.x = (m10 + m01) * num3;
2556 			quat.y = 0.5f * num6;
2557 			quat.z = (m21 + m12) * num3;
2558 			quat.w = (m20 - m02) * num3;
2559 			return quat;
2560 		}
2561 		qt num5 = sqrt(((1f + m22) - m00) - m11);
2562 		qt num2 = 0.5f / num5;
2563 		quat.x = (m20 + m02) * num2;
2564 		quat.y = (m21 + m12) * num2;
2565 		quat.z = 0.5f * num5;
2566 		quat.w = (m01 - m10) * num2;
2567 		return quat;
2568     }
2569 
2570     @("quat lookRotation")
2571     unittest {
2572         // TODO: add unittest
2573     }
2574 
2575     /// Rotates the current quaternion around the x-axis and returns $(I this).
2576     Quaternion rotateX(real alpha) {
2577         this = xRotation(alpha) * this;
2578         return this;
2579     }
2580 
2581     /// Rotates the current quaternion around the y-axis and returns $(I this).
2582     Quaternion rotateY(real alpha) {
2583         this = yRotation(alpha) * this;
2584         return this;
2585     }
2586 
2587     /// Rotates the current quaternion around the z-axis and returns $(I this).
2588     Quaternion rotateZ(real alpha) {
2589         this = zRotation(alpha) * this;
2590         return this;
2591     }
2592 
2593     /// Rotates the current quaternion around an axis and returns $(I this).
2594     Quaternion rotateAxis(real alpha, Vector!(qt, 3) axis) {
2595         this = axisRotation(alpha, axis) * this;
2596         return this;
2597     }
2598 
2599     /// Applies an euler rotation to the current quaternion and returns $(I this).
2600     Quaternion rotateEuler(real heading, real attitude, real bank) {
2601         this = eulerRotation(heading, attitude, bank) * this;
2602         return this;
2603     }
2604 
2605     @("quat x/y/z/axis rotation")
2606     unittest {
2607         assert(quat.xRotation(PI).quaternion[1..4] == [1.0f, 0.0f, 0.0f]);
2608         assert(quat.yRotation(PI).quaternion[1..4] == [0.0f, 1.0f, 0.0f]);
2609         assert(quat.zRotation(PI).quaternion[1..4] == [0.0f, 0.0f, 1.0f]);
2610         assert((quat.xRotation(PI).w == quat.yRotation(PI).w) && (quat.yRotation(PI).w == quat.zRotation(PI).w));
2611         //assert(quat.rotateX(PI).w == to!(quat.qt)(cos(PI)));
2612         assert(quat.xRotation(PI).quaternion == quat.identity.rotateX(PI).quaternion);
2613         assert(quat.yRotation(PI).quaternion == quat.identity.rotateY(PI).quaternion);
2614         assert(quat.zRotation(PI).quaternion == quat.identity.rotateZ(PI).quaternion);
2615 
2616         assert(quat.axisRotation(PI, vec3(1.0f, 1.0f, 1.0f)).quaternion[1..4] == [1.0f, 1.0f, 1.0f]);
2617         assert(quat.axisRotation(PI, vec3(1.0f, 1.0f, 1.0f)).w == quat.xRotation(PI).w);
2618         assert(quat.axisRotation(PI, vec3(1.0f, 1.0f, 1.0f)).quaternion ==
2619                quat.identity.rotateAxis(PI, vec3(1.0f, 1.0f, 1.0f)).quaternion);
2620 
2621         quat q1 = quat.eulerRotation(PI, PI, PI);
2622         assert((q1.x > -1e-16) && (q1.x < 1e-16));
2623         assert((q1.y > -1e-16) && (q1.y < 1e-16));
2624         assert((q1.z > -1e-16) && (q1.z < 1e-16));
2625         //assert(q1.w == -1.0f);
2626         assert(quat.eulerRotation(PI, PI, PI).quaternion == quat.identity.rotateEuler(PI, PI, PI).quaternion);
2627     }
2628 
2629     Quaternion opBinary(string op : "*")(Quaternion inp) const {
2630         Quaternion ret;
2631 
2632         ret.w = -x * inp.x - y * inp.y - z * inp.z + w * inp.w;
2633         ret.x = x * inp.w + y * inp.z - z * inp.y + w * inp.x;
2634         ret.y = -x * inp.z + y * inp.w + z * inp.x + w * inp.y;
2635         ret.z = x * inp.y - y * inp.x + z * inp.w + w * inp.z;
2636 
2637         return ret;
2638     }
2639 
2640     auto opBinaryRight(string op, T)(T inp) const if(!isQuaternion!T) {
2641         return this.opBinary!(op)(inp);
2642     }
2643 
2644     Quaternion opBinary(string op)(Quaternion inp) const  if((op == "+") || (op == "-")) {
2645         Quaternion ret;
2646 
2647         mixin("ret.w = w" ~ op ~ "inp.w;");
2648         mixin("ret.x = x" ~ op ~ "inp.x;");
2649         mixin("ret.y = y" ~ op ~ "inp.y;");
2650         mixin("ret.z = z" ~ op ~ "inp.z;");
2651 
2652         return ret;
2653     }
2654 
2655     Vector!(qt, 3) opBinary(string op : "*")(Vector!(qt, 3) inp) const {
2656         Vector!(qt, 3) ret;
2657 
2658         qt ww = w^^2;
2659         qt w2 = w * 2;
2660         qt wx2 = w2 * x;
2661         qt wy2 = w2 * y;
2662         qt wz2 = w2 * z;
2663         qt xx = x^^2;
2664         qt x2 = x * 2;
2665         qt xy2 = x2 * y;
2666         qt xz2 = x2 * z;
2667         qt yy = y^^2;
2668         qt yz2 = 2 * y * z;
2669         qt zz = z * z;
2670 
2671         ret.vector =  [ww * inp.x + wy2 * inp.z - wz2 * inp.y + xx * inp.x +
2672                        xy2 * inp.y + xz2 * inp.z - zz * inp.x - yy * inp.x,
2673                        xy2 * inp.x + yy * inp.y + yz2 * inp.z + wz2 * inp.x -
2674                        zz * inp.y + ww * inp.y - wx2 * inp.z - xx * inp.y,
2675                        xz2 * inp.x + yz2 * inp.y + zz * inp.z - wy2 * inp.x -
2676                        yy * inp.z + wx2 * inp.y - xx * inp.z + ww * inp.z];
2677 
2678        return ret;
2679     }
2680 
2681     Quaternion opBinary(string op : "*")(qt inp) const {
2682         return Quaternion(w*inp, x*inp, y*inp, z*inp);
2683     }
2684 
2685     void opOpAssign(string op : "*")(Quaternion inp) {
2686         qt w2 = -x * inp.x - y * inp.y - z * inp.z + w * inp.w;
2687         qt x2 = x * inp.w + y * inp.z - z * inp.y + w * inp.x;
2688         qt y2 = -x * inp.z + y * inp.w + z * inp.x + w * inp.y;
2689         qt z2 = x * inp.y - y * inp.x + z * inp.w + w * inp.z;
2690         w = w2; x = x2; y = y2; z = z2;
2691     }
2692 
2693     void opOpAssign(string op)(Quaternion inp) if((op == "+") || (op == "-")) {
2694         mixin("w = w" ~ op ~ "inp.w;");
2695         mixin("x = x" ~ op ~ "inp.x;");
2696         mixin("y = y" ~ op ~ "inp.y;");
2697         mixin("z = z" ~ op ~ "inp.z;");
2698     }
2699 
2700     void opOpAssign(string op : "*")(qt inp) {
2701         quaternion[0] *= inp;
2702         quaternion[1] *= inp;
2703         quaternion[2] *= inp;
2704         quaternion[3] *= inp;
2705     }
2706 
2707     unittest {
2708         quat q1 = quat.identity;
2709         quat q2 = quat(3.0f, 0.0f, 1.0f, 2.0f);
2710         quat q3 = quat(3.4f, 0.1f, 1.2f, 2.3f);
2711 
2712         assert((q1 * q1).quaternion == q1.quaternion);
2713         assert((q1 * q2).quaternion == q2.quaternion);
2714         assert((q2 * q1).quaternion == q2.quaternion);
2715         quat q4 = q3 * q2;
2716         assert((q2 * q3).quaternion != q4.quaternion);
2717         q3 *= q2;
2718         assert(q4.quaternion == q3.quaternion);
2719         assert(almostEqual(q4.x, 0.4f));
2720         assert(almostEqual(q4.y, 6.8f));
2721         assert(almostEqual(q4.z, 13.8f));
2722         assert(almostEqual(q4.w, 4.4f));
2723 
2724         quat q5 = quat(1.0f, 2.0f, 3.0f, 4.0f);
2725         quat q6 = quat(3.0f, 1.0f, 6.0f, 2.0f);
2726 
2727         assert((q5 - q6).quaternion == [-2.0f, 1.0f, -3.0f, 2.0f]);
2728         assert((q5 + q6).quaternion == [4.0f, 3.0f, 9.0f, 6.0f]);
2729         assert((q6 - q5).quaternion == [2.0f, -1.0f, 3.0f, -2.0f]);
2730         assert((q6 + q5).quaternion == [4.0f, 3.0f, 9.0f, 6.0f]);
2731         q5 += q6;
2732         assert(q5.quaternion == [4.0f, 3.0f, 9.0f, 6.0f]);
2733         q6 -= q6;
2734         assert(q6.quaternion == [0.0f, 0.0f, 0.0f, 0.0f]);
2735 
2736         quat q7 = quat(2.0f, 2.0f, 2.0f, 2.0f);
2737         assert((q7 * 2).quaternion == [4.0f, 4.0f, 4.0f, 4.0f]);
2738         assert((2 * q7).quaternion == (q7 * 2).quaternion);
2739         q7 *= 2;
2740         assert(q7.quaternion == [4.0f, 4.0f, 4.0f, 4.0f]);
2741 
2742         vec3 v1 = vec3(1.0f, 2.0f, 3.0f);
2743         assert((q1 * v1).vector == v1.vector);
2744         assert((v1 * q1).vector == (q1 * v1).vector);
2745         assert((q2 * v1).vector == [-2.0f, 36.0f, 38.0f]);
2746     }
2747 
2748     int opCmp(ref const Quaternion qua) const {
2749         foreach(i, a; quaternion) {
2750             if(a < qua.quaternion[i]) {
2751                 return -1;
2752             } else if(a > qua.quaternion[i]) {
2753                 return 1;
2754             }
2755         }
2756 
2757         // Quaternions are the same
2758         return 0;
2759     }
2760 
2761     bool opEquals(const Quaternion qu) const {
2762         return quaternion == qu.quaternion;
2763     }
2764 
2765     unittest {
2766         assert(quat(1.0f, 2.0f, 3.0f, 4.0f) == quat(1.0f, 2.0f, 3.0f, 4.0f));
2767         assert(quat(1.0f, 2.0f, 3.0f, 4.0f) != quat(1.0f, 2.0f, 3.0f, 3.0f));
2768 
2769         assert(!quat(float.nan, float.nan, float.nan, float.nan).isFinite);
2770         if(quat(1.0f, 1.0f, 1.0f, 1.0f).isFinite) { }
2771         else { assert(false); }
2772     }
2773 }
2774 
2775 /// Pre-defined quaternion of type float.
2776 alias quat = Quaternion!(float);
2777 
2778 struct Rect(type) {
2779     alias rt = type; /// Holds the internal type of the rect.
2780     alias RectT = Rect!type;
2781 
2782     union {
2783         struct {
2784             rt x;
2785             rt y;
2786             rt width;
2787             rt height;
2788         }
2789         rt[4] elements; /// Holds the x, y, width and height
2790     }
2791 
2792     /// Returns a pointer to the quaternion in memory, it starts with the w coordinate.
2793     auto ptr() const { return elements.ptr; }
2794 @safe pure nothrow:
2795 
2796     /**
2797         returns identity rect
2798     */
2799     static auto identity() {
2800         return RectT(0, 0, 0, 0);
2801     }
2802 
2803     /**
2804         Left coordinate of the rect
2805     */
2806     rt left() const {
2807         return x;
2808     }
2809 
2810     /**
2811         Right coordinate of the rect
2812     */
2813     rt right() const {
2814         return x+width;
2815     }
2816 
2817     /**
2818         Top coordinate of the rect
2819     */
2820     rt top() const {
2821         return y;
2822     }
2823 
2824     /**
2825         Bottom coordinate of the rect
2826     */
2827     rt bottom() const {
2828         return y+height;
2829     }
2830 
2831     /**
2832         Gets the center of a rect
2833     */
2834     Vector!(rt, 2) center() const {
2835         return Vector!(rt, 2)(this.x + (this.width/2), this.y + (this.height/2));
2836     }
2837 
2838     /**
2839         Gets the corner of a rect
2840     */
2841     Vector!(rt, 2) corner() const {
2842         return Vector!(rt, 2)(this.x, this.y);
2843     }
2844 
2845     /**
2846         Gets the dimensions of a rect
2847     */
2848     Vector!(rt, 2) dimensions() const {
2849         return Vector!(rt, 2)(this.width, this.height);
2850     }
2851 
2852     /**
2853         Gets whether this rect intersects another rect
2854     */
2855     bool intersects(rtype)(rtype other) const if (isRect!rtype) {
2856         return !(other.left >= this.right || other.right <= this.left || other.top >= this.bottom || other.bottom <= this.top);
2857     }
2858 
2859     /**
2860         Gets whether this rect intersects a vector
2861     */
2862     bool intersects(vtype)(vtype other) const if (isVector!vtype) {
2863         return !(other.x >= this.right || other.x <= this.left || other.y >= this.bottom || other.y <= this.top);
2864     }
2865 
2866     /**
2867         Displaces the rect by the specified amount
2868     */
2869     void displace(vtype)(vtype other) const if (isVector!vtype && vtype.dimension == 2) {
2870         this.x += other.x;
2871         this.y += other.y;
2872     }
2873 
2874     /**
2875         Gets a rect that has been displaced by the specified amount
2876     */
2877     RectT displaced(vtype)(vtype other) const if (isVector!vtype && vtype.dimension == 2) {
2878         return RectT(this.x+other.x, this.y+other.y, this.width, this.height);
2879     }
2880 
2881     /**
2882         Expands the rect by the specified amount from the center
2883     */
2884     void expand(vtype)(vtype other) const if (isVector!vtype && vtype.dimension == 2) {
2885         this.x -= other.x;
2886         this.y -= other.y;
2887         this.width += other.x*2;
2888         this.height += other.y*2;
2889     }
2890 
2891     /**
2892         Expands the rect by the specified amount from the corner
2893     */
2894     void expandSize(vtype)(vtype other) const if (isVector!vtype && vtype.dimension == 2) {
2895         this.width += other.x;
2896         this.height += other.y;
2897     }
2898 
2899     /**
2900         Gets a rect that has been expanded by the specified amount from the center
2901     */
2902     RectT expanded(vtype)(vtype other) const if (isVector!vtype && vtype.dimension == 2) {
2903         return RectT(this.x-other.x, this.y-other.y, this.width+(other.x*2), this.height+(other.y*2));
2904     }
2905 
2906     /**
2907         Expands the rect by the specified amount from the corner
2908     */
2909     RectT expandedSize(vtype)(vtype other) const if (isVector!vtype && vtype.dimension == 2) {
2910         return RectT(this.x, this.y, this.width+other.x, this.height+other.y);
2911     }
2912 
2913     /**
2914         Gets the UV coordinates of each corner and returns them as a vec4 of the rect's type
2915     */
2916     Vector!(rt, 4) uvs() const {
2917         return Vector!(rt, 4)(this.left, this.top, this.right, this.bottom);
2918     }
2919 }
2920 
2921 alias rect = Rect!(float);
2922 alias rectd = Rect!(double);
2923 
2924 @("rect intersects")
2925 unittest {
2926     rect a = rect(0, 0, 32, 32);
2927     rectd b = rectd(16, 16, 32, 32);
2928     rect c = rect(0, 32, 32, 32);
2929     vec2 p = vec2(8, 8);
2930 
2931     assert(a.intersects(b));
2932     assert(b.intersects(c));
2933     assert(!a.intersects(c));
2934     
2935     assert(a.intersects(p));
2936     assert(!b.intersects(p));
2937     assert(!c.intersects(p));
2938 }
2939 
2940 @("rect uvs")
2941 unittest {
2942     assert(rect(16, 16, 32, 64).uvs == vec4(16, 16, 16+32, 16+64));
2943 }
2944 
2945 @("rect center")
2946 unittest {
2947     rect a = rect(0, 0, 32, 32);
2948     assert(a.center == vec2(16, 16));
2949 }