1// tLinearAlgebra.h 
2// 
3// POD types for Vectors, Matrices and a function library to manipulate them. Includes geometrical transformations, 
4// cross/dot products, inversion functions, projections, normalization etc. These POD types are used as superclasses 
5// for the more object-oriented and complete derived types. eg. tVector3 derives from the POD type tVec2 found here. 
6// 
7// Copyright (c) 2004-2006, 2015, 2017, 2019 Tristan Grimmer. 
8// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
9// granted, provided that the above copyright notice and this permission notice appear in all copies. 
10// 
11// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
12// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
13// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
14// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
15// PERFORMANCE OF THIS SOFTWARE. 
16 
17#pragma once 
18#include <Foundation/tStandard.h> 
19#include <Foundation/tFundamentals.h> 
20namespace tMath 
21
22 
23 
24// These can be ORed together if necessary and are generally passed around using the tComponents type. 
25enum tComponent 
26
27 tComponent_X = 0x00000001
28 tComponent_Y = 0x00000002
29 tComponent_Z = 0x00000004
30 tComponent_W = 0x00000008
31 tComponent_XY = tComponent_X | tComponent_Y
32 tComponent_YZ = tComponent_Y | tComponent_Z
33 tComponent_ZX = tComponent_Z | tComponent_X
34 tComponent_XYZ = tComponent_X | tComponent_Y | tComponent_Z
35 tComponent_XYZW = tComponent_X | tComponent_Y | tComponent_Z | tComponent_W
36 
37 // For matrices the notation Amn means the component at row m and column n (like in linear algebra). 
38 tComponent_A11 = 0x00000010
39 tComponent_A21 = 0x00000020
40 tComponent_A31 = 0x00000040
41 tComponent_A41 = 0x00000080
42 tComponent_A12 = 0x00000100
43 tComponent_A22 = 0x00000200
44 tComponent_A32 = 0x00000400
45 tComponent_A42 = 0x00000800
46 tComponent_A13 = 0x00001000
47 tComponent_A23 = 0x00002000
48 tComponent_A33 = 0x00004000
49 tComponent_A43 = 0x00008000
50 tComponent_A14 = 0x00010000
51 tComponent_A24 = 0x00020000
52 tComponent_A34 = 0x00040000
53 tComponent_A44 = 0x00080000
54 tComponent_C1 = tComponent_A11 | tComponent_A21 | tComponent_A31 | tComponent_A41
55 tComponent_C2 = tComponent_A12 | tComponent_A22 | tComponent_A32 | tComponent_A42
56 tComponent_C3 = tComponent_A13 | tComponent_A23 | tComponent_A33 | tComponent_A43
57 tComponent_C4 = tComponent_A14 | tComponent_A24 | tComponent_A34 | tComponent_A44
58 tComponent_R1 = tComponent_A11 | tComponent_A12 | tComponent_A13 | tComponent_A14
59 tComponent_R2 = tComponent_A21 | tComponent_A22 | tComponent_A23 | tComponent_A24
60 tComponent_R3 = tComponent_A31 | tComponent_A32 | tComponent_A33 | tComponent_A34
61 tComponent_R4 = tComponent_A41 | tComponent_A42 | tComponent_A43 | tComponent_A44
62 
63 tComponent_All = 0xFFFFFFFF 
64}; 
65 
66 
67// Since it is awkward to do bitwise operations on the enum and enum class types we simply use a uint32 for components. 
68typedef uint32 tComponents
69 
70 
71#pragma pack(push, 4) 
72 
73 
74// Note that points are not implemented separately since in linear algebra "A vector is a point is a vector". At the 
75// very least they have the same behaviour, even if they are conceptually different. All vectors are column vectors. 
76struct tVec2 
77
78 union 
79
80 struct { float x, y; }; 
81 struct { float u, v; }; 
82 struct { float a, b; }; 
83 float E[2]; // E for elements. 
84 }; 
85}; 
86 
87 
88struct tVec3 
89
90 union 
91
92 struct { float x, y, z; }; 
93 struct { float t, u, v; }; 
94 struct { float a, b, c; }; 
95 float E[3]; 
96 }; 
97}; 
98 
99 
100struct tVec4 
101
102 union 
103
104 struct { float x, y, z, w; }; 
105 struct { float s, t, u, v; }; 
106 struct { float a, b, c, d; }; 
107 struct { float L, R, T, B; }; 
108 float E[4]; 
109 }; 
110}; 
111 
112 
113struct tQuat 
114
115 union 
116
117 struct { float x, y, z, w; }; // W comes last unlike white-papers on quaternions. 
118 struct { tVec3 v; float r; }; 
119 float E[4]; 
120 }; 
121}; 
122 
123 
124struct tMat2 
125
126 union 
127
128 struct 
129
130 float a11, a21; // Convention is A_rc where r = row and c = col. 
131 float a12, a22
132 }; 
133 struct { tVec2 C1, C2; }; // C for column. 
134 float A[2][2]; // A for array. 
135 float E[4]; 
136 }; 
137}; 
138 
139 
140// tMat4 is a 4x4 (16 dimensional) homogeneous matrix plain-old-data type. Components are stored inmemory column major. 
141// 
142// For example, the translation matrix: 
143// 1 0 0 tx 
144// 0 1 0 ty 
145// 0 0 1 tz 
146// 0 0 0 1 
147// is stored in memory in memory as 1 0 0 0 0 1 0 0 0 0 1 0 tx ty tz 1 with lower addresses on the left. Column 4 (C4) 
148// is therefore the column vector (tx, ty, tz, 1). 
149struct tMat4 
150
151 union 
152
153 struct 
154
155 float a11, a21, a31, a41
156 float a12, a22, a32, a42
157 float a13, a23, a33, a43
158 float a14, a24, a34, a44
159 }; 
160 
161 struct { tVec4 C1, C2, C3, C4; }; 
162 tVec4 C[4]; 
163 float A[4][4]; 
164 float E[16]; 
165 }; 
166}; 
167 
168 
169#pragma pack(pop) 
170 
171 
172// For the functions below we generally use d for destination and s for source. When a non-const v, m, or q is used, the 
173// parameter is both input and output. s should be different to d for overloads that use them. 
174inline void tSet(tVec2& d, const tVec2& s) { d.x = s.x; d.y = s.y; } 
175inline void tSet(tVec2& d, const tVec3& s) { d.x = s.x; d.y = s.y; } 
176inline void tSet(tVec2& d, const tVec4& s) { d.x = s.x; d.y = s.y; } 
177inline void tSet(tVec2& d, float xy) { d.x = xy; d.y = xy; } 
178inline void tSet(tVec2& d, float x, float y) { d.x = x; d.y = y; } 
179inline void tSet(tVec2& d, const float* a) { d.x = a[0]; d.y = a[1]; } 
180inline void tSet(tVec3& d, const tVec2& s, float z = 0.0f) { d.x = s.x; d.y = s.y; d.z = z; } 
181inline void tSet(tVec3& d, const tVec3& s) { d.x = s.x; d.y = s.y; d.z = s.z; } 
182inline void tSet(tVec3& d, const tVec4& s) { d.x = s.x; d.y = s.y; d.z = s.z; } 
183inline void tSet(tVec3& d, float xyz) { d.x = xyz; d.y = xyz; d.z = xyz; } 
184inline void tSet(tVec3& d, float x, float y, float z) { d.x = x; d.y = y; d.z = z; } 
185inline void tSet(tVec3& d, const float* a) { d.x = a[0]; d.y = a[1]; d.z = a[2]; } 
186inline void tSet(tVec4& d, const tVec2& s, float z = 0.0f, float w = 0.0f) { d.x = s.x; d.y = s.y; d.z = z; d.w = w; } 
187inline void tSet(tVec4& d, const tVec3& s, float w = 0.0f) { d.x = s.x; d.y = s.y; d.z = s.z; d.w = w; } 
188inline void tSet(tVec4& d, const tVec4& s) { d.x = s.x; d.y = s.y; d.z = s.z; d.w = s.w; } 
189inline void tSet(tVec4& d, float xyzw) { d.x = xyzw; d.y = xyzw; d.z = xyzw; d.w = xyzw; } 
190inline void tSet(tVec4& d, float x, float y, float z, float w) { d.x = x; d.y = y; d.z = z; d.w = w; } 
191inline void tSet(tVec4& d, const float* a) { d.x = a[0]; d.y = a[1]; d.z = a[2]; d.w = a[3]; } 
192inline void tSet(tQuat& d, const tQuat& s) { d.v = s.v; d.r = s.r; } 
193inline void tSet(tQuat& d, float x, float y, float z, float w) { d.x = x; d.y = y; d.z = z; d.w = w; } 
194inline void tSet(tQuat& d, const float* a) { d.x = a[0]; d.y = a[1]; d.z = a[2]; d.w = a[3]; } 
195 void tSet(tQuat& d, const tMat4&); // Creates a unit quaternion from a rotation matrix. 
196inline void tSet(tQuat& d, float r, const tVec3& v) /* Not axis-angle. */ { d.v = v; d.r = r; } 
197 void tSet(tQuat& d, const tVec3& axis, float angle); // Assumes axis is normalized. 
198inline void tSet(tQuat& d, const tVec3& v) { d.v = v; d.r = 0.0f; } 
199inline void tSet(tMat2& d, const tMat2& s) { d.C1 = s.C1; d.C2 = s.C2; } 
200inline void tSet(tMat2& d, const tVec2& c1, const tVec2& c2) { d.C1 = c1; d.C2 = c2; } 
201inline void tSet(tMat2& d, float a11, float a21, float a12, float a22) { d.a11 = a11; d.a21 = a21; d.a12 = a12; d.a22 = a22; } 
202inline void tSet(tMat2& d, const float* a) { d.a11 = a[0]; d.a21 = a[1]; d.a12 = a[2]; d.a22 = a[3]; } 
203inline void tSet(tMat4& d, const tMat4& s) { for (int e = 0; e < 16; e++) d.E[e] = s.E[e]; } 
204inline void tSet(tMat4& d, const tVec4& c1, const tVec4& c2, const tVec4& c3, const tVec4& c4) { d.C1 = c1; d.C2 = c2; d.C3 = c3; d.C4 = c4; } 
205inline void tSet(tMat4& d, const tVec3& c1, const tVec3& c2, const tVec3& c3, const tVec3& c4) { tSet(d.C1, c1, 0.0f); tSet(d.C2, c2, 0.0f); tSet(d.C3, c3, 0.0f); tSet(d.C4, c4, 1.0f); } 
206inline void tSet 
207
208 tMat4& d
209 float a11, float a21, float a31, float a41
210 float a12, float a22, float a32, float a42
211 float a13, float a23, float a33, float a43
212 float a14, float a24, float a34, float a44 
213); 
214inline void tSet(tMat4& d, const float* a) { for (int e = 0; e < 16; e++) d.E[e] = a[e]; } 
215 void tSet(tMat4& d, const tQuat& s); 
216 
217// Similar to the tSet functions except generally used only for decomposing the pod type rather than conversions. 
218inline void tGet(float& x, float& y, const tVec2& s) { x = s.x; y = s.y; } 
219inline void tGet(float* a, const tVec2& s) { a[0] = s.x; a[1] = s.y; } 
220inline void tGet(float& x, float& y, float& z, const tVec3& s) { x = s.x; y = s.y; z = s.z; } 
221inline void tGet(float* a, const tVec3& s) { a[0] = s.x; a[1] = s.y; a[2] = s.z; } 
222inline void tGet(float& x, float& y, float& z, float& w, const tVec4& s) { x = s.x; y = s.y; z = s.z; w = s.w; } 
223inline void tGet(float* a, const tVec4& s) { a[0] = s.x; a[1] = s.y; a[2] = s.z; a[3] = s.w; } 
224inline void tGet(float& x, float& y, float& z, float& w, const tQuat& s) { x = s.x; y = s.y; z = s.z; w = s.w; } 
225inline void tGet(float* a, const tQuat& s) { a[0] = s.x; a[1] = s.y; a[2] = s.z; a[3] = s.w; } 
226 void tGet(tVec3& axis, float& angle, const tQuat&); // Angle always returned E [0,Pi]. 
227inline void tGet(float& a11, float& a21, float& a12, float& a22, const tMat2& s) { a11 = s.a11; a21 = s.a21; a12 = s.a12; a22 = s.a22; } 
228inline void tGet(float* a, const tMat2& m) { a[0] = m.E[0]; a[1] = m.E[1]; a[2] = m.E[2]; a[3] = m.E[3]; } 
229inline void tGet 
230
231 float& a11, float& a21, float& a31, float& a41
232 float& a12, float& a22, float& a32, float& a42
233 float& a13, float& a23, float& a33, float& a43
234 float& a14, float& a24, float& a34, float& a44
235 const tMat4& s 
236); 
237inline void tGet(float* a, const tMat4& m) { for (int e = 0; e < 16; e++) a[e] = m.E[e]; } 
238 
239inline void tZero(tVec2& d) { d.x = 0.0f; d.y = 0.0f; } 
240inline void tZero(tVec2& d, tComponents c) { if (c & tComponent_X) d.x = 0.0f; if (c & tComponent_Y) d.y = 0.0f; } 
241inline void tZero(tVec3& d) { d.x = 0.0f; d.y = 0.0f; d.z = 0.0f; } 
242inline void tZero(tVec3& d, tComponents c) { if (c & tComponent_X) d.x = 0.0f; if (c & tComponent_Y) d.y = 0.0f; if (c & tComponent_Z) d.z = 0.0f; } 
243inline void tZero(tVec4& d) { d.x = 0.0f; d.y = 0.0f; d.z = 0.0f; d.w = 0.0f; } 
244inline void tZero(tVec4& d, tComponents c) { if (c & tComponent_X) d.x = 0.0f; if (c & tComponent_Y) d.y = 0.0f; if (c & tComponent_Z) d.z = 0.0f; if (c & tComponent_W) d.w = 0.0f; } 
245inline void tZero(tQuat& d) { d.x = 0.0f; d.y = 0.0f; d.z = 0.0f; d.w = 0.0f; } 
246inline void tZero(tQuat& d, tComponents c) { if (c & tComponent_X) d.x = 0.0f; if (c & tComponent_Y) d.y = 0.0f; if (c & tComponent_Z) d.z = 0.0f; if (c & tComponent_W) d.w = 0.0f; } 
247inline void tZero(tMat2& d) { tZero(d.C1); tZero(d.C2); } 
248inline void tZero(tMat2& d, tComponents c) { if (c & tComponent_A11) d.a11 = 0.0f; if (c & tComponent_A21) d.a21 = 0.0f; if (c & tComponent_A12) d.a12 = 0.0f; if (c & tComponent_A22) d.a22 = 0.0f; } 
249inline void tZero(tMat4& d) { for (int e = 0; e < 16; e++) d.E[e] = 0.0f; } 
250inline void tZero(tMat4& d, tComponents c); 
251 
252inline bool tIsZero(const tVec2& v) { return (v.x == 0.0f) && (v.y == 0.0f); } 
253inline bool tIsZero(const tVec2& v, tComponents c) { return (!(c & tComponent_X) || (v.x == 0.0f)) && (!(c & tComponent_Y) || (v.y == 0.0f)); } 
254inline bool tIsZero(const tVec3& v) { return (v.x == 0.0f) && (v.y == 0.0f) && (v.z == 0.0f); } 
255inline bool tIsZero(const tVec3& v, tComponents c) { return (!(c & tComponent_X) || (v.x == 0.0f)) && (!(c & tComponent_Y) || (v.y == 0.0f)) && (!(c & tComponent_Z) || (v.z == 0.0f)); } 
256inline bool tIsZero(const tVec4& v) { return (v.x == 0.0f) && (v.y == 0.0f) && (v.z == 0.0f) && (v.w == 0.0f); } 
257inline bool tIsZero(const tVec4& v, tComponents c) { return (!(c & tComponent_X) || (v.x == 0.0f)) && (!(c & tComponent_Y) || (v.y == 0.0f)) && (!(c & tComponent_Z) || (v.z == 0.0f)) && (!(c & tComponent_W) || (v.w == 0.0f)); } 
258inline bool tIsZero(const tQuat& q) { return (q.x == 0.0f) && (q.y == 0.0f) && (q.z == 0.0f) && (q.w == 0.0f); } 
259inline bool tIsZero(const tQuat& q, tComponents c) { return (!(c & tComponent_X) || (q.x == 0.0f)) && (!(c & tComponent_Y) || (q.y == 0.0f)) && (!(c & tComponent_Z) || (q.z == 0.0f)) && (!(c & tComponent_W) || (q.w == 0.0f)); } 
260inline bool tIsZero(const tMat2& m) { return tIsZero(m.C1) && tIsZero(m.C2); } 
261inline bool tIsZero(const tMat2& m, tComponents c) { return (!(c & tComponent_A11) || (m.a11 == 0.0f)) && (!(c & tComponent_A21) || (m.a21 == 0.0f)) && (!(c & tComponent_A12) || (m.a12 == 0.0f)) && (!(c & tComponent_A22) || (m.a22 == 0.0f)); } 
262inline bool tIsZero(const tMat4& m) { return tIsZero(m.C1) && tIsZero(m.C2) && tIsZero(m.C3) && tIsZero(m.C4); } 
263inline bool tIsZero(const tMat4& m, tComponents c); 
264 
265// Test for equality within epsilon. Each basis component is tested independently. A relative error metric would behave 
266// better: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm 
267inline bool tApproxEqual(const tVec2& a, const tVec2& b, float e = Epsilon) { return (tAbs(a.x-b.x) < e) && (tAbs(a.y-b.y) < e); } 
268inline bool tApproxEqual(const tVec2& a, const tVec2& b, tComponents c, float e = Epsilon) { return (!(c & tComponent_X) || (tAbs(a.x-b.x) < e)) && (!(c & tComponent_Y) || (tAbs(a.y-b.y) < e)); } 
269inline bool tApproxEqual(const tVec3& a, const tVec3& b, float e = Epsilon) { return (tAbs(a.x-b.x) < e) && (tAbs(a.y-b.y) < e) && (tAbs(a.z-b.z) < e); } 
270inline bool tApproxEqual(const tVec3& a, const tVec3& b, tComponents c, float e = Epsilon) { return (!(c & tComponent_X) || (tAbs(a.x-b.x) < e)) && (!(c & tComponent_Y) || (tAbs(a.y-b.y) < e)) && (!(c & tComponent_Z) || (tAbs(a.z-b.z) < e)); } 
271inline bool tApproxEqual(const tVec4& a, const tVec4& b, float e = Epsilon) { return (tAbs(a.x-b.x) < e) && (tAbs(a.y-b.y) < e) && (tAbs(a.z-b.z) < e) && (tAbs(a.w-b.w) < e); } 
272inline bool tApproxEqual(const tVec4& a, const tVec4& b, tComponents c, float e = Epsilon) { return (!(c & tComponent_X) || (tAbs(a.x-b.x) < e)) && (!(c & tComponent_Y) || (tAbs(a.y-b.y) < e)) && (!(c & tComponent_Z) || (tAbs(a.z-b.z) < e)) && (!(c & tComponent_W) || (tAbs(a.w-b.w) < e)); } 
273inline bool tApproxEqual(const tQuat& a, const tQuat& b, float e = Epsilon) { return (tAbs(a.x-b.x) < e) && (tAbs(a.y-b.y) < e) && (tAbs(a.z-b.z) < e) && (tAbs(a.w-b.w) < e); } 
274inline bool tApproxEqual(const tQuat& a, const tQuat& b, tComponents c, float e = Epsilon) { return (!(c & tComponent_X) || (tAbs(a.x-b.x) < e)) && (!(c & tComponent_Y) || (tAbs(a.y-b.y) < e)) && (!(c & tComponent_Z) || (tAbs(a.z-b.z) < e)) && (!(c & tComponent_W) || (tAbs(a.w-b.w) < e)); } 
275inline bool tApproxEqual(const tMat2& a, const tMat2& b, float e = Epsilon) { return tApproxEqual(a.C1, b.C1, e) && tApproxEqual(a.C2, b.C2, e); } 
276inline bool tApproxEqual(const tMat2& a, const tMat2& b, tComponents c, float e = Epsilon); 
277inline bool tApproxEqual(const tMat4& a, const tMat4& b, float e = Epsilon) { return tApproxEqual(a.C1, b.C1, e) && tApproxEqual(a.C2, b.C2, e) && tApproxEqual(a.C3, b.C3, e) && tApproxEqual(a.C4, b.C4, e); } 
278inline bool tApproxEqual(const tMat4& a, const tMat4& b, tComponents c, float e = Epsilon); 
279 
280inline bool tEqual(const tVec2& a, const tVec2& b) { return (a.x == b.x) && (a.y == b.y); } 
281inline bool tEqual(const tVec2& a, const tVec2& b, tComponents c) { return (!(c & tComponent_X) || (a.x == b.x)) && (!(c & tComponent_Y) || (a.y == b.y)); } 
282inline bool tEqual(const tVec3& a, const tVec3& b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); } 
283inline bool tEqual(const tVec3& a, const tVec3& b, tComponents c) { return (!(c & tComponent_X) || (a.x == b.x)) && (!(c & tComponent_Y) || (a.y == b.y)) && (!(c & tComponent_Z) || (a.z == b.z)); } 
284inline bool tEqual(const tVec4& a, const tVec4& b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); } 
285inline bool tEqual(const tVec4& a, const tVec4& b, tComponents c) { return (!(c & tComponent_X) || (a.x == b.x)) && (!(c & tComponent_Y) || (a.y == b.y)) && (!(c & tComponent_Z) || (a.z == b.z)) && (!(c & tComponent_W) || (a.w == b.w)); } 
286inline bool tEqual(const tQuat& a, const tQuat& b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); } 
287inline bool tEqual(const tQuat& a, const tQuat& b, tComponents c) { return (!(c & tComponent_X) || (a.x == b.x)) && (!(c & tComponent_Y) || (a.y == b.y)) && (!(c & tComponent_Z) || (a.z == b.z)) && (!(c & tComponent_W) || (a.w == b.w)); } 
288inline bool tEqual(const tMat2& a, const tMat2& b) { return tEqual(a.C1, b.C1) && tEqual(a.C2, b.C2); } 
289inline bool tEqual(const tMat2& a, const tMat2& b, tComponents c) { return (!(c & tComponent_A11) || (a.a11 == b.a11)) && (!(c & tComponent_A21) || (a.a21 == b.a21)) && (!(c & tComponent_A12) || (a.a12 == b.a12)) && (!(c & tComponent_A22) || (a.a22 == b.a22)); } 
290inline bool tEqual(const tMat4& a, const tMat4& b) { return tEqual(a.C1, b.C1) && tEqual(a.C2, b.C2) && tEqual(a.C3, b.C3) && tEqual(a.C4, b.C4); } 
291inline bool tEqual(const tMat4& a, const tMat4& b, tComponents c); 
292 
293inline bool tNotEqual(const tVec2& a, const tVec2& b) { return (a.x != b.x) || (a.y != b.y); } 
294inline bool tNotEqual(const tVec2& a, const tVec2& b, tComponents c) { return ((c & tComponent_X) && (a.x != b.x)) || ((c & tComponent_Y) && (a.y != b.y)); } 
295inline bool tNotEqual(const tVec3& a, const tVec3& b) { return (a.x != b.x) || (a.y != b.y) || (a.z != b.z); } 
296inline bool tNotEqual(const tVec3& a, const tVec3& b, tComponents c) { return ((c & tComponent_X) && (a.x != b.x)) || ((c & tComponent_Y) && (a.y != b.y)) || ((c & tComponent_Z) && (a.z != b.z)); } 
297inline bool tNotEqual(const tVec4& a, const tVec4& b) { return (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); } 
298inline bool tNotEqual(const tVec4& a, const tVec4& b, tComponents c) { return ((c & tComponent_X) && (a.x != b.x)) || ((c & tComponent_Y) && (a.y != b.y)) || ((c & tComponent_Z) && (a.z != b.z)) || ((c & tComponent_W) && (a.w != b.w)); } 
299inline bool tNotEqual(const tQuat& a, const tQuat& b) { return (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); } 
300inline bool tNotEqual(const tQuat& a, const tQuat& b, tComponents c) { return ((c & tComponent_X) && (a.x != b.x)) || ((c & tComponent_Y) && (a.y != b.y)) || ((c & tComponent_Z) && (a.z != b.z)) || ((c & tComponent_W) && (a.w != b.w)); } 
301inline bool tNotEqual(const tMat2& a, const tMat2& b) { return tNotEqual(a.C1, b.C1) || tNotEqual(a.C2, b.C2); } 
302inline bool tNotEqual(const tMat2& a, const tMat2& b, tComponents c) { return ((c & tComponent_A11) && (a.a11 != b.a11)) || ((c & tComponent_A21) && (a.a21 != b.a21)) || ((c & tComponent_A12) && (a.a12 != b.a12)) || ((c & tComponent_A22) && (a.a22 != b.a22)); } 
303inline bool tNotEqual(const tMat4& a, const tMat4& b) { return tNotEqual(a.C1, b.C1) || tNotEqual(a.C2, b.C2) || tNotEqual(a.C3, b.C3) || tNotEqual(a.C4, b.C4); } 
304inline bool tNotEqual(const tMat4& a, const tMat4& b, tComponents c); 
305 
306inline float tLengthSq(const tVec2& v) { return v.x*v.x + v.y*v.y; } 
307inline float tLengthSq(const tVec3& v) { return v.x*v.x + v.y*v.y + v.z*v.z; } 
308inline float tLengthSq(const tVec4& v) { return v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; } 
309inline float tLengthSq(const tQuat& q) { return q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; } 
310 
311inline float tLength(const tVec2& v) { return tSqrt(tLengthSq(v)); } 
312inline float tLength(const tVec3& v) { return tSqrt(tLengthSq(v)); } 
313inline float tLength(const tVec4& v) { return tSqrt(tLengthSq(v)); } 
314inline float tLength(const tQuat& q) { return tSqrt(tLengthSq(q)); } 
315 
316inline float tLengthFast(const tVec2& v) { return tSqrtFast(tLengthSq(v)); } 
317inline float tLengthFast(const tVec3& v) { return tSqrtFast(tLengthSq(v)); } 
318inline float tLengthFast(const tVec4& v) { return tSqrtFast(tLengthSq(v)); } 
319inline float tLengthFast(const tQuat& q) { return tSqrtFast(tLengthSq(q)); } 
320 
321inline void tNormalize(tVec2& v) { float l = tLength(v); v.x /= l; v.y /= l; } 
322inline void tNormalize(tVec3& v) { float l = tLength(v); v.x /= l; v.y /= l; v.z /= l; } 
323inline void tNormalize(tVec4& v) { float l = tLength(v); v.x /= l; v.y /= l; v.z /= l; v.w /= l; } 
324inline void tNormalize(tQuat& q) { float l = tLength(q); q.x /= l; q.y /= l; q.z /= l; q.w /= l; } 
325 
326inline float tNormalizeGetLength(tVec2& v) /* Returns pre-normalized length. */ { float l = tLength(v); v.x /= l; v.y /= l; return l; } 
327inline float tNormalizeGetLength(tVec3& v) /* Returns pre-normalized length. */ { float l = tLength(v); v.x /= l; v.y /= l; v.z /= l; return l; } 
328inline float tNormalizeGetLength(tVec4& v) /* Returns pre-normalized length. */ { float l = tLength(v); v.x /= l; v.y /= l; v.z /= l; v.w /= l; return l; } 
329inline float tNormalizeGetLength(tQuat& q) /* Returns pre-normalized length. */ { float l = tLength(q); q.x /= l; q.y /= l; q.z /= l; q.w /= l; return l; } 
330 
331inline bool tNormalizeSafe(tVec2& v) /* Returns success. */ { float l = tLength(v); if (l == 0.0f) return false; v.x /= l; v.y /= l; return true; } 
332inline bool tNormalizeSafe(tVec3& v) /* Returns success. */ { float l = tLength(v); if (l == 0.0f) return false; v.x /= l; v.y /= l; v.z /= l; return true; } 
333inline bool tNormalizeSafe(tVec4& v) /* Returns success. */ { float l = tLength(v); if (l == 0.0f) return false; v.x /= l; v.y /= l; v.z /= l; v.w /= l; return true; } 
334inline bool tNormalizeSafe(tQuat& q) /* Returns success. */ { float l = tLength(q); if (l == 0.0f) return false; q.x /= l; q.y /= l; q.z /= l; q.w /= l; return true; } 
335 
336inline float tNormalizeSafeGetLength(tVec2& v) /* Returns pre-normalized length. 0.0f if no go. */ { float l = tLength(v); if (l == 0.0f) return l; v.x /= l; v.y /= l; return l; } 
337inline float tNormalizeSafeGetLength(tVec3& v) /* Returns pre-normalized length. 0.0f if no go. */ { float l = tLength(v); if (l == 0.0f) return l; v.x /= l; v.y /= l; v.z /= l; return l; } 
338inline float tNormalizeSafeGetLength(tVec4& v) /* Returns pre-normalized length. 0.0f if no go. */ { float l = tLength(v); if (l == 0.0f) return l; v.x /= l; v.y /= l; v.z /= l; v.w /= l; return l; } 
339inline float tNormalizeSafeGetLength(tQuat& q) /* Returns pre-normalized length. 0.0f if no go. */ { float l = tLength(q); if (l == 0.0f) return l; q.x /= l; q.y /= l; q.z /= l; q.w /= l; return l; } 
340 
341inline void tNormalizeScale(tVec2& v, float s) /* Normalize then scale. Resizes the vector. */ { float l = tLength(v); v.x *= s/l; v.y *= s/l; } 
342inline void tNormalizeScale(tVec3& v, float s) /* Normalize then scale. Resizes the vector. */ { float l = tLength(v); v.x *= s/l; v.y *= s/l; v.z *= s/l; } 
343inline void tNormalizeScale(tVec4& v, float s) /* Normalize then scale. Resizes the vector. */ { float l = tLength(v); v.x *= s/l; v.y *= s/l; v.z *= s/l; v.w *= s/l; } 
344 
345inline bool tNormalizeScaleSafe(tVec2& v, float s) { float l = tLength(v); if (l == 0.0f) return false; v.x *= s/l; v.y *= s/l; return true; } 
346inline bool tNormalizeScaleSafe(tVec3& v, float s) { float l = tLength(v); if (l == 0.0f) return false; v.x *= s/l; v.y *= s/l; v.z *= s/l; return true; } 
347inline bool tNormalizeScaleSafe(tVec4& v, float s) { float l = tLength(v); if (l == 0.0f) return false; v.x *= s/l; v.y *= s/l; v.z *= s/l; v.w *= s/l; return true; } 
348 
349inline void tNormalizeFast(tVec2& v) { float s = tLengthSq(v); s = tRecipSqrtFast(s); v.x *= s; v.y *= s; } 
350inline void tNormalizeFast(tVec3& v) { float s = tLengthSq(v); s = tRecipSqrtFast(s); v.x *= s; v.y *= s; v.z *= s; } 
351inline void tNormalizeFast(tVec4& v) { float s = tLengthSq(v); s = tRecipSqrtFast(s); v.x *= s; v.y *= s; v.z *= s; v.w *= s; } 
352inline void tNormalizeFast(tQuat& q) { float s = tLengthSq(q); s = tRecipSqrtFast(s); q.x *= s; q.y *= s; q.z *= s; q.w *= s; } 
353 
354inline bool tNormalizeSafeFast(tVec2& v) { float s = tLengthSq(v); if (s == 0.0f) return false; s = tRecipSqrtFast(s); v.x *= s; v.y *= s; return true; } 
355inline bool tNormalizeSafeFast(tVec3& v) { float s = tLengthSq(v); if (s == 0.0f) return false; s = tRecipSqrtFast(s); v.x *= s; v.y *= s; v.z *= s; return true; } 
356inline bool tNormalizeSafeFast(tVec4& v) { float s = tLengthSq(v); if (s == 0.0f) return false; s = tRecipSqrtFast(s); v.x *= s; v.y *= s; v.z *= s; v.w *= s; return true; } 
357inline bool tNormalizeSafeFast(tQuat& q) { float s = tLengthSq(q); if (s == 0.0f) return false; s = tRecipSqrtFast(s); q.x *= s; q.y *= s; q.z *= s; q.w *= s; return true; } 
358 
359// Addition. Computes d = a + b or vqm += a. 
360inline void tAdd(tVec2& v, const tVec2& a) { v.x += a.x; v.y += a.y; } 
361inline void tAdd(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x + b.x; d.y = a.y + b.y; } 
362inline void tAdd(tVec3& v, const tVec3& a) { v.x += a.x; v.y += a.y; v.z += a.z; } 
363inline void tAdd(tVec3& d, const tVec3& a, const tVec3& b) { d.x = a.x + b.x; d.y = a.y + b.y; d.z = a.z + b.z; } 
364inline void tAdd(tVec4& v, const tVec4& a) { v.x += a.x; v.y += a.y; v.z += a.z; v.w += a.w; } 
365inline void tAdd(tVec4& d, const tVec4& a, const tVec4& b) { d.x = a.x + b.x; d.y = a.y + b.y; d.z = a.z + b.z; d.w = a.w + b.w; } 
366inline void tAdd(tQuat& q, const tQuat& a) { q.x += a.x; q.y += a.y; q.z += a.z; q.w += a.w; } 
367inline void tAdd(tQuat& d, const tQuat& a, const tQuat& b) { d.x = a.x + b.x; d.y = a.y + b.y; d.z = a.z + b.z; d.w = a.w + b.w; } 
368inline void tAdd(tMat2& m, const tMat2& a) { for (int c = 0; c < 4; c++) m.E[c] += a.E[c]; } 
369inline void tAdd(tMat2& d, const tMat2& a, const tMat2& b) { for (int c = 0; c < 4; c++) d.E[c] = a.E[c] + b.E[c]; } 
370inline void tAdd(tMat4& m, const tMat4& a) { for (int c = 0; c < 16; c++) m.E[c] += a.E[c]; } 
371inline void tAdd(tMat4& d, const tMat4& a, const tMat4& b) { for (int c = 0; c < 16; c++) d.E[c] = a.E[c] + b.E[c]; } 
372 
373// Subtraction. Computes d = a - b or vqm -= a. 
374inline void tSub(tVec2& v, const tVec2& a) { v.x -= a.x; v.y -= a.y; } 
375inline void tSub(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x - b.x; d.y = a.y - b.y; } 
376inline void tSub(tVec3& v, const tVec3& a) { v.x -= a.x; v.y -= a.y; v.z -= a.z; } 
377inline void tSub(tVec3& d, const tVec3& a, const tVec3& b) { d.x = a.x - b.x; d.y = a.y - b.y; d.z = a.z - b.z; } 
378inline void tSub(tVec4& v, const tVec4& a) { v.x -= a.x; v.y -= a.y; v.z -= a.z; v.w -= a.w; } 
379inline void tSub(tVec4& d, const tVec4& a, const tVec4& b) { d.x = a.x - b.x; d.y = a.y - b.y; d.z = a.z - b.z; d.w = a.w - b.w; } 
380inline void tSub(tQuat& q, const tQuat& a) { q.x -= a.x; q.y -= a.y; q.z -= a.z; q.w -= a.w; } 
381inline void tSub(tQuat& d, const tQuat& a, const tQuat& b) { d.x = a.x - b.x; d.y = a.y - b.y; d.z = a.z - b.z; d.w = a.w - b.w; } 
382inline void tSub(tMat2& m, const tMat2& a) { for (int c = 0; c < 4; c++) m.E[c] -= a.E[c]; } 
383inline void tSub(tMat2& d, const tMat2& a, const tMat2& b) { for (int c = 0; c < 4; c++) d.E[c] = a.E[c] - b.E[c]; } 
384inline void tSub(tMat4& m, const tMat4& a) { for (int c = 0; c < 16; c++) m.E[c] -= a.E[c]; } 
385inline void tSub(tMat4& d, const tMat4& a, const tMat4& b) { for (int c = 0; c < 16; c++) d.E[c] = a.E[c] - b.E[c]; } 
386 
387// Negation. Computes d = -a or -vqm. 
388inline void tNeg(tVec2& v) { v.x = -v.x; v.y = -v.y; } 
389inline void tNeg(tVec2& d, const tVec2& a) { d.x = -a.x; d.y = -a.y; } 
390inline void tNeg(tVec3& v) { v.x = -v.x; v.y = -v.y; v.z = -v.z; } 
391inline void tNeg(tVec3& d, const tVec3& a) { d.x = -a.x; d.y = -a.y; d.z = -a.z; } 
392inline void tNeg(tVec4& v) { v.x = -v.x; v.y = -v.y; v.z = -v.z; v.w = -v.w; } 
393inline void tNeg(tVec4& d, const tVec4& a) { d.x = -a.x; d.y = -a.y; d.z = -a.z; d.w = -a.w; } 
394inline void tNeg(tQuat& q) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; } 
395inline void tNeg(tQuat& d, const tQuat& a) { d.x = -a.x; d.y = -a.y; d.z = -a.z; d.w = -a.w; } 
396inline void tNeg(tMat2& m) { m.a11 = -m.a11; m.a21 = -m.a21; m.a12 = -m.a12; m.a22 = -m.a22; } 
397inline void tNeg(tMat2& d, const tMat2& a) { d.a11 = -a.a11; d.a21 = -a.a21; d.a12 = -a.a12; d.a22 = -a.a22; } 
398inline void tNeg(tMat4& m) { for (int c = 0; c < 16; c++) m.E[c] = -m.E[c]; } 
399inline void tNeg(tMat4& d, const tMat4& a) { for (int c = 0; c < 16; c++) d.E[c] = -a.E[c]; } 
400 
401// Conjugation. Computes d = a* or q*. 
402inline void tConjugate(tQuat& q) { q.x = -q.x; q.y = -q.y; q.z = -q.z; } 
403inline void tConjugate(tQuat& d, const tQuat& a) { d.x = -a.x; d.y = -a.y; d.z = -a.z; d.w = a.w; } 
404 
405// Multiply. Computes d = a * b or vq *= a. 
406inline void tMul(tVec2& v, float a) { v.x *= a; v.y *= a; } 
407inline void tMul(tVec2& d, const tVec2& a, float b) { d.x = a.x*b; d.y = a.y*b; } 
408inline void tMul(tVec2& d, float a, const tVec2& b) { d.x = a*b.x; d.y = a*b.y; } 
409inline void tMul(tVec2& d, const tMat2& a, const tVec2& b) { d.x = b.x*a.a11 + b.y*a.a12; d.y = b.x*a.a21 + b.y*a.a22; } 
410 
411// Multiplies a 4x4 matrix by a 3x1 vector. Not mathematically defined but convenient for homogeneous coordinates. The 
412// vector is interpreted as a 4x1 with the w = 1. If the 4x4 is an affine matrix, it simply transforms the point. 
413 void tMul(tVec3& d, const tMat4& a, const tVec3& b); 
414inline void tMul(tVec3& v, float a) { v.x *= a; v.y *= a; v.z *= a; } 
415inline void tMul(tVec3& d, const tVec3& a, float b) { d.x = a.x*b; d.y = a.y*b; d.z = a.z*b; } 
416inline void tMul(tVec3& d, float a, const tVec3& b) { d.x = a*b.x; d.y = a*b.y; d.z = a*b.z; } 
417 void tMul(tVec4& d, const tMat4& a, const tVec4& b); 
418inline void tMul(tVec4& v, float a) { v.x *= a; v.y *= a; v.z *= a; v.w *= a; } 
419inline void tMul(tVec4& d, const tVec4& a, float b) { d.x = a.x*b; d.y = a.y*b; d.z = a.z*b; d.w = a.w*b;} 
420inline void tMul(tVec4& d, float a, const tVec4& b) { d.x = a*b.x; d.y = a*b.y; d.z = a*b.z; d.w = a*b.w; } 
421inline void tMul(tQuat& q, float a) { q.x *= a; q.y *= a; q.z *= a; q.w *= a; } 
422inline void tMul(tQuat& d, const tQuat& a, float b) { d.x = a.x*b; d.y = a.y*b; d.z = a.z*b; d.w = a.w*b; } 
423inline void tMul(tQuat& d, float a, const tQuat& b) { d.x = a*b.x; d.y = a*b.y; d.z = a*b.z; d.w = a*b.w; } 
424inline void tMul(tQuat& q, const tQuat& a); 
425inline void tMul(tQuat& d, const tQuat& a, const tQuat& b); 
426inline void tMul(tQuat& q, const tVec3& a); // Treats 'a' as an augmented (pure) quaternion. w = 0. 
427inline void tMul(tQuat& d, const tQuat& a, const tVec3& b); // Treats 'b' as an augmented (pure) quaternion. w = 0. 
428inline void tMul(tMat2& m, float a) { m.a11 *= a; m.a21 *= a; m.a12 *= a; m.a22 *= a; } 
429inline void tMul(tMat2& d, const tMat2& a, float b) { d.a11 = a.a11*b; d.a21 = a.a21*b; d.a12 = a.a12*b; d.a22 = a.a22*b; } 
430inline void tMul(tMat2& d, float a, const tMat2& b) { d.a11 = a*b.a11; d.a21 = a*b.a21; d.a12 = a*b.a12; d.a22 = a*b.a22; } 
431inline void tMul(tMat2& m, const tMat2& a); 
432inline void tMul(tMat2& d, const tMat2& a, const tMat2& b); 
433inline void tMul(tMat4& m, float a) { for (int c = 0; c < 16; c++) m.E[c] *= a; } 
434inline void tMul(tMat4& d, const tMat4& a, float b) { for (int c = 0; c < 16; c++) d.E[c] = a.E[c]*b; } 
435inline void tMul(tMat4& d, float a, const tMat4& b) { for (int c = 0; c < 16; c++) d.E[c] = a*b.E[c]; } 
436inline void tMul(tMat4& m, const tMat4& a); 
437 void tMul(tMat4& d, const tMat4& a, const tMat4& b); 
438 
439// Vectors in Tacent are column vectors. If you want to multiply a column vector a by the transpose of another vector b, 
440// to produce a matrix, use these functions. Note that a row vector by a column is just a dot product. With these 
441// functions it is always b that gets transposed. The versions that take tVec3s get interpreted as tVec4s with w = 0. 
442inline void tMulByTranspose(tMat4& d, const tVec3& a, const tVec3& b); 
443inline void tMulByTranspose(tMat4& d, const tVec4& a, const tVec4& b); 
444 
445// Hadamard or entry-wise product. Both matrices must have same dimension. Each position is multiplied independently. 
446// Computes d = a * b or vm *= a. 
447inline void tMulE(tVec2& v, const tVec2& a) { v.x *= a.x; v.y *= a.y; } 
448inline void tMulE(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x*b.x; d.y = a.y*b.y; } 
449inline void tMulE(tVec3& v, const tVec3& a) { v.x *= a.x; v.y *= a.y; v.z *= a.z; } 
450inline void tMulE(tVec3& d, const tVec3& a, const tVec3& b) { d.x = a.x*b.x; d.y = a.y*b.y; d.z = a.z*b.z; } 
451inline void tMulE(tVec4& v, const tVec4& a) { v.x *= a.x; v.y *= a.y; v.z *= a.z; v.w *= a.w; } 
452inline void tMulE(tVec4& d, const tVec4& a, const tVec4& b) { d.x = a.x*b.x; d.y = a.y*b.y; d.z = a.z*b.z; d.w = a.w*b.w; } 
453inline void tMulE(tMat2& m, const tMat2& a) { tMulE(m.C1, a.C1); tMulE(m.C2, a.C2); } 
454inline void tMulE(tMat2& d, const tMat2& a, const tMat2& b) { tMulE(d.C1, a.C1, b.C1); tMulE(d.C2, a.C2, b.C2); } 
455inline void tMulE(tMat4& m, const tMat4& a) { tMulE(m.C1, a.C1); tMulE(m.C2, a.C2); tMulE(m.C3, a.C3); tMulE(m.C4, a.C4); } 
456inline void tMulE(tMat4& d, const tMat4& a, const tMat4& b) { tMulE(d.C1, a.C1, b.C1); tMulE(d.C2, a.C2, b.C2); tMulE(d.C3, a.C3, b.C3); tMulE(d.C4, a.C4, b.C4); } 
457 
458// Divide. Computes d = a / b or vqm /= a. 
459inline void tDiv(tVec2& v, float a) { v.x /= a; v.y /= a; } 
460inline void tDiv(tVec2& d, const tVec2& a, float b) { d.x = a.x/b; d.y = a.y/b; } 
461inline void tDiv(tVec3& v, float a) { v.x /= a; v.y /= a; v.z /= a; } 
462inline void tDiv(tVec3& d, const tVec3& a, float b) { d.x = a.x/b; d.y = a.y/b; d.z = a.z/b; } 
463inline void tDiv(tVec4& v, float a) { v.x /= a; v.y /= a; v.z /= a; v.w /= a; } 
464inline void tDiv(tVec4& d, const tVec4& a, float b) { d.x = a.x/b; d.y = a.y/b; d.z = a.z/b; d.w = a.w/b; } 
465inline void tDiv(tQuat& q, float a) { q.x /= a; q.y /= a; q.z /= a; q.w /= a; } 
466inline void tDiv(tQuat& d, const tQuat& a, float b) { d.x = a.x/b; d.y = a.y/b; d.z = a.z/b; d.w = a.w/b; } 
467inline void tDiv(tMat2& m, float a) { m.a11 /= a; m.a21 /= a; m.a12 /= a; m.a22 /= a; } 
468inline void tDiv(tMat2& d, const tMat2& a, float b) { d.a11 = a.a11/b; d.a21 = a.a21/b; d.a12 = a.a12/b; d.a22 = a.a22/b; } 
469inline void tDiv(tMat4& m, float a) { for (int c = 0; c < 16; c++) m.E[c] /= a; } 
470inline void tDiv(tMat4& d, const tMat4& a, float b) { for (int c = 0; c < 16; c++) d.E[c] = a.E[c]/b; } 
471 
472// Component-wise divide. d = a / b or vm /= a. 
473inline void tDivE(tVec2& v, const tVec2& a) { v.x /= a.x; v.y /= a.y; } 
474inline void tDivE(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x/b.x; d.y = a.y/b.y; } 
475inline void tDivE(tVec3& v, const tVec3& a) { v.x /= a.x; v.y /= a.y; v.z /= a.z; } 
476inline void tDivE(tVec3& d, const tVec3& a, const tVec3& b) { d.x = a.x/b.x; d.y = a.y/b.y; d.z = a.z/b.z; } 
477inline void tDivE(tVec4& v, const tVec4& a) { v.x /= a.x; v.y /= a.y; v.z /= a.z; v.w /= a.w; } 
478inline void tDivE(tVec4& d, const tVec4& a, const tVec4& b) { d.x = a.x/b.x; d.y = a.y/b.y; d.z = a.z/b.z; d.w = a.w/b.w; } 
479inline void tDivE(tMat2& m, const tMat2& a) { m.a11 /= a.a11; m.a21 /= a.a21; m.a12 /= a.a12; m.a22 /= a.a22; } 
480inline void tDivE(tMat2& d, const tMat2& a, const tMat2& b) { d.a11 = a.a11/b.a11; d.a21 = a.a21/b.a21; d.a12 = a.a12/b.a12; d.a22 = a.a22/b.a22; } 
481inline void tDivE(tMat4& m, const tMat4& a) { for (int c = 0; c < 16; c++) m.E[c] /= a.E[c]; } 
482inline void tDivE(tMat4& d, const tMat4& a, const tMat4& b) { for (int c = 0; c < 16; c++) d.E[c] = a.E[c]/b.E[c]; } 
483 
484inline float tDot(const tVec2& a, const tVec2& b) { return a.x*b.x + a.y*b.y; } 
485inline float tDot(const tVec3& a, const tVec3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; } 
486inline float tDot(const tVec4& a, const tVec4& b) { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; } 
487inline float tDot(const tQuat& a, const tQuat& b) { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; } 
488 
489// Linear interpolate/extrapolate. d stores the result. 
490// t in [0.0, 1.0] results in interpolation between a and b with a and b being the endpoints. 
491// t < 0.0 results in extrapolation to values less than a. t > 1.0 results in extrapolation to values greater than b. 
492inline void tLerp(tVec2& d, const tVec2& a, const tVec2& b, float t) { float t0 = 1.0f - t; d.x = t0*a.x + t*b.x; d.y = t0*a.y + t*b.y; } 
493inline void tLerp(tVec3& d, const tVec3& a, const tVec3& b, float t) { float t0 = 1.0f - t; d.x = t0*a.x + t*b.x; d.y = t0*a.y + t*b.y; d.z = t0*a.z + t*b.z; } 
494inline void tLerp(tVec4& d, const tVec4& a, const tVec4& b, float t) { float t0 = 1.0f - t; d.x = t0*a.x + t*b.x; d.y = t0*a.y + t*b.y; d.z = t0*a.z + t*b.z; d.w = t0*a.w + t*b.w; } 
495 
496inline void tIdentity(tMat2& m) { m.a11 = 1.0f; m.a21 = 0.0f; m.a12 = 0.0f; m.a22 = 1.0f; } 
497inline void tIdentity(tMat4& m) { tZero(m); m.a11 = 1.0f; m.a22 = 1.0f; m.a33 = 1.0f; m.a44 = 1.0f; } 
498 
499inline void tTranspose(tMat2& m) { tStd::tSwap(m.a12, m.a21); } 
500inline void tTranspose(tMat2& d, const tMat2& a) { d.a11 = a.a11; d.a21 = a.a12; d.a12 = a.a21; d.a22 = a.a22; } 
501inline void tTranspose(tMat4& m); 
502inline void tTranspose(tMat4& d, const tMat4& a) { tSet(d, a); tTranspose(d); } 
503 
504inline float tDeterminant(const tMat2& m) { return m.a11*m.a22 - m.a12*m.a21; } 
505 float tDeterminant(const tMat4& m); 
506 
507inline float tTrace(const tMat2& m) { return m.a11 + m.a22; } 
508inline float tTrace(const tMat4& m) { return m.a11 + m.a22 + m.a33 + m.a44; } 
509 
510inline bool tInvert(tMat2& m); 
511inline bool tInvert(tMat2& d, const tMat2& a); 
512 bool tInvert(tMat4& m); 
513 bool tInvert(tMat4& d, const tMat4& a); 
514 
515// Faster if inverting a matrix where the 4th column is the translation, and the upper-left 3x3 is the 
516// rotation/scale/skew. 
517inline void tInvertAffine(tMat4& m); 
518 void tInvertAffine(tMat4& d, const tMat4& a); 
519 
520inline float tDistBetween(const tVec2& a, const tVec2& b) { tVec2 d; tSub(d, b, a); return tLength(d); } 
521inline float tDistBetweenSq(const tVec2& a, const tVec2& b) { tVec2 d; tSub(d, b, a); return tLengthSq(d); } 
522inline float tDistBetween(const tVec3& a, const tVec3& b) { tVec3 d; tSub(d, b, a); return tLength(d); } 
523inline float tDistBetweenSq(const tVec3& a, const tVec3& b) { tVec3 d; tSub(d, b, a); return tLengthSq(d); } 
524 
525// Cross Product. Computes d = a X b or v X= a. 
526inline void tCross(tVec3& v, const tVec3& a); 
527inline void tCross(tVec3& d, const tVec3& a, const tVec3& b); 
528inline void tCross(tVec4& v, const tVec4& a); 
529inline void tCross(tVec4& d, const tVec4& a, const tVec4& b); 
530inline void tProject(tVec3& d, const tVec3& a, const tVec3& b) /* Orthogonally projects b onto a. */ { tMul(d, a, tDot(a, b)/tDot(a, a)); } 
531 
532enum class tOrientationPath 
533
534 Shortest
535 Longest
536 Clockwise
537 CounterClockwise 
538}; 
539 
540// Spherical (great circle) linear interpolation. Const velocity but not-commutative. t = 0 yields a. t = 1 yields b. 
541// The version without the tOrientationPath is a bit faster than choosing shortest in the latter function. a and b may 
542// be the same quaternion as d for the lerp functions. 
543void tSlerp(tQuat& d, const tQuat& a, const tQuat& b, float t); 
544void tSlerp(tQuat& d, const tQuat& a, const tQuat& b, float t, tOrientationPath); 
545 
546// Normalized linear interpolation. Shortest path through the sphere. Faster than slerp and commutative. Rotation 
547// sequences may be applied in any order with same results (order independent). 
548void tNlerp(tQuat& d, const tQuat& a, const tQuat& b, float t, tOrientationPath = tOrientationPath::Shortest); 
549 
550float tRotationAngle(const tQuat& a); 
551void tRotate(tVec3& v, const tQuat& q); 
552void tRotate(tVec4& v, const tQuat& q); 
553 
554inline void tMakeTranslate(tMat4& d, float x, float y, float z) { tIdentity(d); d.a14 = x; d.a24 = y; d.a34 = z; } 
555inline void tMakeTranslate(tMat4& d, const tVec3& t) { tIdentity(d); d.a14 = t.x; d.a24 = t.y; d.a34 = t.z; } 
556 
557void tMakeRotateX(tMat4& d, float angle); 
558void tMakeRotateY(tMat4& d, float angle); 
559void tMakeRotateZ(tMat4& d, float angle); 
560void tMakeRotateZ(tMat2& d, float angle); 
561void tMakeRotate(tMat4& d, const tVec3& axis, float angle); 
562void tMakeRotate(tMat4& d, const tVec3& a, const tVec3& b); // Rotates from from a to b. Normalize a and b first. 
563 
564// The Euler angle functions make rotation matrices that are essentially concatenations of the RotateX, RotateY, and 
565// RotateZ calls above. There are 6 possible ways the successive rotations may be applied, and they are all implemented. 
566// The function tMakeRotateXYZ rotates by the x-angle first, then y, then z. That is, it generates RzRyRx. Remember 
567// v' = Mv. In all cases the angles are in radians and the rotations are specified about the 3 cardinal axes: x, y, z. 
568// An excellent reference can be found here: http://www.songho.ca/opengl/gl_anglestoaxes.html. I suggest using the XYZ 
569// more often than not as it is Maya's default. eulerX is sometimes referred to as Psi, AngleX or pitch, eulerY as 
570// Theta, Ay, or yaw, and eulerZ as Phi, Az, or roll. 
571void tMakeRotateXYZ(tMat4& d, float eulerX, float eulerY, float eulerZ); // RzRyRx. Default for Maya. 
572void tMakeRotateYZX(tMat4& d, float eulerX, float eulerY, float eulerZ); // RxRzRy 
573void tMakeRotateZXY(tMat4& d, float eulerX, float eulerY, float eulerZ); // RyRxRz 
574void tMakeRotateZYX(tMat4& d, float eulerX, float eulerY, float eulerZ); // RxRyRz 
575void tMakeRotateXZY(tMat4& d, float eulerX, float eulerY, float eulerZ); // RyrzRx 
576void tMakeRotateYXZ(tMat4& d, float eulerX, float eulerY, float eulerZ); // RzrxRy 
577inline void tMakeRotateXYZ(tMat4& d, const tVec3& euler) { tMakeRotateXYZ(d, euler.x, euler.y, euler.z); } 
578inline void tMakeRotateYZX(tMat4& d, const tVec3& euler) { tMakeRotateYZX(d, euler.x, euler.y, euler.z); } 
579inline void tMakeRotateZXY(tMat4& d, const tVec3& euler) { tMakeRotateZXY(d, euler.x, euler.y, euler.z); } 
580inline void tMakeRotateZYX(tMat4& d, const tVec3& euler) { tMakeRotateZYX(d, euler.x, euler.y, euler.z); } 
581inline void tMakeRotateXZY(tMat4& d, const tVec3& euler) { tMakeRotateXZY(d, euler.x, euler.y, euler.z); } 
582inline void tMakeRotateYXZ(tMat4& d, const tVec3& euler) { tMakeRotateYXZ(d, euler.x, euler.y, euler.z); } 
583 
584inline void tMakeScale(tMat4& d, float scale) { tIdentity(d); d.a11 = d.a22 = d.a33 = scale; } 
585inline void tMakeScale(tMat4& d, float scaleX, float scaleY, float scaleZ) { tIdentity(d); d.a11 = scaleX; d.a22 = scaleY; d.a33 = scaleZ; } 
586inline void tMakeScale(tMat4& d, const tVec3& scale) { tIdentity(d); d.a11 = scale.x; d.a22 = scale.y; d.a33 = scale.z; } 
587 
588inline void tMakeReflectXY(tMat4& d) { tIdentity(d); d.a33 = -1.0f; } 
589inline void tMakeReflectXZ(tMat4& d) { tIdentity(d); d.a22 = -1.0f; } 
590inline void tMakeReflectYZ(tMat4& d) { tIdentity(d); d.a11 = -1.0f; } 
591 
592void tMakeLookAt(tMat4& d, const tVec3& eye, const tVec3& look, const tVec3& up); 
593 
594// Functions to make various types of projection matrix. Persp for perspective. Sym for symmetric. FovV for vertical 
595// field-of-view, FovH for field-of-view horizontal. The functions below all generate projection matrices that 
596// transform points to a clip space with z E [-1, 1] rather than the DX convention starting at 0. 
597void tMakeProjPersp(tMat4& d, float left, float right, float bottom, float top, float nearPlane, float farPlane); 
598void tMakeProjPersp(tMat4& d, const tVec3& boxMin, const tVec3& boxMax); 
599void tMakeProjPerspSym(tMat4& d, float right, float top, float nearPlane, float farPlane); 
600 
601// Angles are named using the axis about which they rotate, so vertical FovV may also be written FovX, and horizontal 
602// FovH may be written FovY. 
603void tMakeProjPerspSymFovV(tMat4& d, float fovX, float aspect, float nearPlane, float farPlane); 
604void tMakeProjPerspSymFovH(tMat4& d, float fovY, float aspect, float nearPlane, float farPlane); 
605 
606// The offsets in these functions allow creation of oblique (asymmetric) projection matrices. A (1, 1) offset will 
607// puts the camera at the upper right corner of the near/far planes. The visual effect of changing offsets is to pan 
608// the image around as if it were a big poster _without_ affecting the apparent perspective. This is useful if you want 
609// to offset an object on the screen without having it distort. 
610void tMakeProjPerspOffset 
611
612 tMat4& d, float right, float top
613 float nearPlane, float farPlane
614 float offsetX, float offsetY 
615); 
616void tMakeProjPerspFovVOffset 
617
618 tMat4& d, float fovX, float aspect
619 float nearPlane, float farPlane
620 float offsetX, float offsetY 
621); 
622void tMakeProjPerspFovHOffset 
623
624 tMat4& d, float fovY, float aspect
625 float nearPlane, float farPlane
626 float offsetX, float offsetY 
627); 
628 
629// There is no 'orthogonal' projection matrix creation function since an ortho projection is a type of parallel 
630// projection. It is the view matrix that determines the direction in the world. i.e. What is colloquially known as an 
631// ortho projection is actually a parallel projection with an appropriate view matrix to align to a basis axis. 
632void tMakeProjParallel(tMat4& d, const tVec3& boxMin, const tVec3& boxMax); 
633 
634// MakeOrthoNormal ensures the upper 3x3 matrix has orthogonal columns AND that they each have length one. 
635// MakeOrthoUniform yields orthogonal columns and equalizes (rather than normalizes) their lengths. Uniform scale safe. 
636// MakeOrthoNonUniform ensures orthogonal columns AND preserves each columns length separately. Non-uniform scale safe. 
637// MakeOrtho is synonymous with MakeOrthoNonUniform which preserves the most information (the safest). 
638void tMakeOrthoNormal(tMat4& m); 
639void tMakeOrthoUniform(tMat4& m); 
640void tMakeOrthoNonUniform(tMat4& m); 
641inline void tMakeOrtho(tMat4& m) { tMakeOrthoNonUniform(m); } 
642 
643// The following functions are used to extract information from various types of homogeneous matrix. We use the word 
644// extract here rather than decompose since decomposition of a matrix usually means factorizing (finding BC in A = BC). 
645// The naming generally follows tExtract_MatrixType_PropertiesExtracted. 
646void tExtractAffineScale(tVec3& scale, const tMat4& affine); 
647 
648// This set of functions deal with projection 
649// matrices -- extracting FOVs, aspect ratios, clip planes etc. The tExtractProjectionPlanes returns vectors that 
650// represent the coefficients of the plane equation ax + by + cz + d = 0. The abcd members of the tVec4 class may be 
651// used as a convenience. The plane array is filled in the order Right, Left, Top, Bottom, Near, Far which matches 
652// the same order as the tFrustum class (+x,-x,+y,-y,+z,-z). The vectors may also be used to construct tPlane objects. 
653// If normalizePlanes is true, the plane normal length |(a,b,c)| = 1 and d is the distance from the origin. 
654void tExtractProjectionPlanes 
655
656 tVec4 planes[6], const tMat4& projection
657 bool outwardNormals = false, bool normalizePlanes = true 
658); 
659 
660// These work with generic (perspective, oblique, and parallel) projections. 
661float tExtractProjectionNear(const tMat4&); // Returns near plane dist (assumes frustum is not oblique). 
662float tExtractProjectionFar(const tMat4&); // Returns far plane dist (assumes frustum is not oblique). 
663inline float tExtractProjectionAspect(const tMat4& m) /* Returns aspect ratio, the width / height. */ { tAssert(m.a11 != 0.0f); return m.a22 / m.a11; } 
664inline float tExtractProjectionOffsetX(const tMat4& m) /* Returns offsetX, the horizontal oblique pan offset. */ { return -m.a13; } 
665inline float tExtractProjectionOffsetY(const tMat4& m) /* Returns offsetY, the vertical oblique pan offset. */ { return -m.a23; } 
666 
667// These are specific to perspective transforms. 
668inline float tExtractPerspectiveFovV(const tMat4& m) /* Returns FovX. */ { tAssert(m.a22 != 0.0f); return 2.0f * tArcTan(1.0f, m.a22); } 
669inline float tExtractPerspectiveFovH(const tMat4& m) /* Returns FovY. */ { tAssert(m.a11 != 0.0f); return 2.0f * tArcTan(1.0f, m.a11); } 
670void tExtractPerspective(float& fovV, float& fovH, float& aspect, float& nearPlane, float& farPlane, const tMat4&); 
671void tExtractPerspective 
672
673 float& fovV, float& fovH, float& aspect
674 float& nearPlane, float& farPlane
675 float& offsetX, float& offsetY
676 const tMat4
677); 
678 
679// This function extracts Euler angles from a rotation matrix. It assumes a particular order of rotations were applied. 
680// tExtractRotationEulerXYZ assumes an X, Y, Z order meaning the rotation matrix is RzRyRx. The other orders are not yet 
681// implemented. 
682// 
683// tExtractAffineEulerXYZ can extract rotations for affine transformations that do NOT include shear because the basis 
684// vectors aren't orthogonal. i.e. tExtractAffineEulerXYZ can handle non-uniform scale -- affine transforms preserve 
685// parallel lines and include Euclidean rotation/translation, non-uniform scale, and shear (which we are excluding). 
686// 
687// If you know the matrix is orthonormal (columns are orthogonal AND of unit length), use the Euclidian version: 
688// tExtractRotationEulerXYZ). It will be faster. 
689// 
690// Any particular orientation can be achieved by at least 2 sets of Euler rotations, so there are 2 sets of Euler angles 
691// returned. When the middle rotation (eulerY) satisfies Cos(eulerY) = 0 (the middle one is Y for the XYZ order, which 
692// we will now assume for the rest of this comment) there are an infinite number of solutions. This is called gimbal 
693// lock. 
694// 
695// In gimbal lock you usually want to choose one of the infinity of solutions. In particular the eulerZ angle may be 
696// anything, eulerY will be +- Pi/2 (cos == 0), and eulerX depends on your choice of eulerZ. This is what gimbalZValue 
697// is for, it allows EulerX to be calculated for you -- it is your 'choice' of the Z rotation when in gimbal lock. Note 
698// that both sol1 and sol2 are equal when in gimbal lock. They both represent the chosen solution. IF you want to know 
699// what ALL solutions are, just leave gimbalZValue at zero. Choose any value for EulerZ (myZ). If EulerY > 0, then 
700// EulerZ = EulerX + myZ. If EulerY < 0, then EulerZ = EulerX - myZ. 
701// 
702// All returned angles are in [(-Pi, Pi)]. See comment by tIntervalBias for a description of my bias notation. This 
703// function Returns true if in gimbal lock or if it's close to gimbal lock as determined by an internal epsilon on 
704// Cos(eulerY). The extraction algorithm is based on this paper: 
705// http://staff.city.ac.uk/~sbbh653/publications/euler.pdf by Gregory G. Slabaugh. That's it. Simple, right? 
706bool tExtractRotationEulerXYZ 
707
708 tVec3& sol1, tVec3& sol2
709 const tMat4& rot
710 float gimbalZValue = 0.0f, tIntervalBias = tIntervalBias::Low 
711); 
712 
713bool tExtractAffineEulerXYZ 
714
715 tVec3& sol1, tVec3& sol2
716 const tMat4& aff
717 float gimbalZValue = 0.0f, tIntervalBias = tIntervalBias::Low 
718); 
719 
720// Linearly interpolate value towards dest at rate. t is delta time. Value is updated. Returns if got to dest. 
721bool tApproach(float& value, float dest, float rate, float dt); 
722 
723// Angle approaches destination via shortest angular direction. Angle gets modified and will be E [0, 2Pi]. 
724bool tApproachAngle(float& angle, float dest, float rate, float dt); 
725bool tApproachOrientation(tQuat& orientation, const tQuat& dest, float rate, float dt); 
726 
727// Linear scale. t = 0 returns min. t = 1 returns max. No clamping. Works for non-pod vector and matrix types, but not 
728// the pod-types as they don't have the necessary operator overloading. 
729template <typename T> inline T tLinearScale(float t, T min, T max) { return min + (max - min)*t; } 
730template <typename T> inline T tLisc(float t, T min, T max) { return min + (max - min)*t; } 
731 
732// Many libraries have a, perhaps badly-named, Lerp (linear interpolation) function that does a linear scale. It's a bit 
733// of a misnomer because in general it also extrapolates. In any case, the synonym is included here. Does same as tLisc. 
734template <typename T> inline T tLerp(float t, T min, T max) { return min + (max - min)*t; } 
735 
736// Linear interpolation and extrapolation. Requires 2 points on the line. Input the domain values (d) and it'll give you 
737// the looked-up range value (r). No clamping. 
738template <typename T> inline T tLinearLookup(float d, float d0, float d1, T r0, T r1) { return tLinearScale((d-d0)/(d1-d0), r0, r1); } 
739template <typename T> inline T tLilo(float d, float d0, float d1, T r0, T r1) { return tLisc((d-d0)/(d1-d0), r0, r1); } 
740 
741// Linear interpolate. Same as tLinearLookup except that it clamps d to [d0, d1]. 
742template <typename T> inline T tLinearInterp(float d, float d0, float d1, T r0, T r1) { return tLinearScale(tSaturate((d-d0)/(d1-d0)), r0, r1); } 
743template <typename T> inline T tLiin(float d, float d0, float d1, T r0, T r1) { return tLisc(tSaturate((d-d0)/(d1-d0)), r0, r1); } 
744 
745 
746
747 
748 
749// Implementation below this line. 
750 
751 
752inline void tMath::tSet 
753
754 tMat4& d
755 float a11, float a21, float a31, float a41
756 float a12, float a22, float a32, float a42
757 float a13, float a23, float a33, float a43
758 float a14, float a24, float a34, float a44 
759
760
761 d.a11 = a11; d.a21 = a21; d.a31 = a31; d.a41 = a41
762 d.a12 = a12; d.a22 = a22; d.a32 = a32; d.a42 = a42
763 d.a13 = a13; d.a23 = a23; d.a33 = a33; d.a43 = a43
764 d.a14 = a14; d.a24 = a24; d.a34 = a34; d.a44 = a44
765
766 
767 
768inline void tMath::tGet 
769
770 float& a11, float& a21, float& a31, float& a41
771 float& a12, float& a22, float& a32, float& a42
772 float& a13, float& a23, float& a33, float& a43
773 float& a14, float& a24, float& a34, float& a44
774 const tMat4& s 
775
776
777 a11 = s.a11; a21 = s.a21; a31 = s.a31; a41 = s.a41
778 a12 = s.a12; a22 = s.a22; a32 = s.a32; a42 = s.a42
779 a13 = s.a13; a23 = s.a23; a33 = s.a33; a43 = s.a43
780 a14 = s.a14; a24 = s.a24; a34 = s.a34; a44 = s.a44
781
782 
783 
784inline void tMath::tZero(tMat4& d, tComponents c
785
786 if (c & tComponent_A11) d.a11 = 0.0f
787 if (c & tComponent_A21) d.a21 = 0.0f
788 if (c & tComponent_A31) d.a31 = 0.0f
789 if (c & tComponent_A41) d.a41 = 0.0f
790 
791 if (c & tComponent_A12) d.a12 = 0.0f
792 if (c & tComponent_A22) d.a22 = 0.0f
793 if (c & tComponent_A32) d.a32 = 0.0f
794 if (c & tComponent_A42) d.a42 = 0.0f
795 
796 if (c & tComponent_A13) d.a13 = 0.0f
797 if (c & tComponent_A23) d.a23 = 0.0f
798 if (c & tComponent_A33) d.a33 = 0.0f
799 if (c & tComponent_A43) d.a43 = 0.0f
800 
801 if (c & tComponent_A14) d.a14 = 0.0f
802 if (c & tComponent_A24) d.a24 = 0.0f
803 if (c & tComponent_A34) d.a34 = 0.0f
804 if (c & tComponent_A44) d.a44 = 0.0f
805
806 
807 
808inline bool tMath::tIsZero(const tMat4& m, tComponents c
809
810 return 
811 (!(c & tComponent_A11) || (m.a11 == 0.0f)) && 
812 (!(c & tComponent_A21) || (m.a21 == 0.0f)) && 
813 (!(c & tComponent_A31) || (m.a31 == 0.0f)) && 
814 (!(c & tComponent_A41) || (m.a41 == 0.0f)) && 
815 
816 (!(c & tComponent_A12) || (m.a12 == 0.0f)) && 
817 (!(c & tComponent_A22) || (m.a22 == 0.0f)) && 
818 (!(c & tComponent_A32) || (m.a32 == 0.0f)) && 
819 (!(c & tComponent_A42) || (m.a42 == 0.0f)) && 
820 
821 (!(c & tComponent_A13) || (m.a13 == 0.0f)) && 
822 (!(c & tComponent_A23) || (m.a23 == 0.0f)) && 
823 (!(c & tComponent_A33) || (m.a33 == 0.0f)) && 
824 (!(c & tComponent_A43) || (m.a43 == 0.0f)) && 
825 
826 (!(c & tComponent_A14) || (m.a14 == 0.0f)) && 
827 (!(c & tComponent_A24) || (m.a24 == 0.0f)) && 
828 (!(c & tComponent_A34) || (m.a34 == 0.0f)) && 
829 (!(c & tComponent_A44) || (m.a44 == 0.0f)); 
830
831 
832 
833inline bool tMath::tApproxEqual(const tMat2& a, const tMat2& b, tComponents c, float e
834
835 return 
836 (!(c & tComponent_A11) || (tAbs(a.a11-b.a11) < e)) && 
837 (!(c & tComponent_A21) || (tAbs(a.a21-b.a21) < e)) && 
838 
839 (!(c & tComponent_A12) || (tAbs(a.a12-b.a12) < e)) && 
840 (!(c & tComponent_A22) || (tAbs(a.a22-b.a22) < e)); 
841
842 
843 
844inline bool tMath::tApproxEqual(const tMat4& a, const tMat4& b, tComponents c, float e
845
846 return 
847 (!(c & tComponent_A11) || (tAbs(a.a11-b.a11) < e)) && 
848 (!(c & tComponent_A21) || (tAbs(a.a21-b.a21) < e)) && 
849 (!(c & tComponent_A31) || (tAbs(a.a31-b.a31) < e)) && 
850 (!(c & tComponent_A41) || (tAbs(a.a41-b.a41) < e)) && 
851 
852 (!(c & tComponent_A12) || (tAbs(a.a12-b.a12) < e)) && 
853 (!(c & tComponent_A22) || (tAbs(a.a22-b.a22) < e)) && 
854 (!(c & tComponent_A32) || (tAbs(a.a32-b.a32) < e)) && 
855 (!(c & tComponent_A42) || (tAbs(a.a42-b.a42) < e)) && 
856 
857 (!(c & tComponent_A13) || (tAbs(a.a13-b.a13) < e)) && 
858 (!(c & tComponent_A23) || (tAbs(a.a23-b.a23) < e)) && 
859 (!(c & tComponent_A33) || (tAbs(a.a33-b.a33) < e)) && 
860 (!(c & tComponent_A43) || (tAbs(a.a43-b.a43) < e)) && 
861 
862 (!(c & tComponent_A14) || (tAbs(a.a14-b.a14) < e)) && 
863 (!(c & tComponent_A24) || (tAbs(a.a24-b.a24) < e)) && 
864 (!(c & tComponent_A34) || (tAbs(a.a34-b.a34) < e)) && 
865 (!(c & tComponent_A44) || (tAbs(a.a44-b.a44) < e)); 
866
867 
868 
869inline bool tMath::tEqual(const tMat4& a, const tMat4& b, tComponents c
870
871 return 
872 (!(c & tComponent_A11) || (a.a11 == b.a11)) && 
873 (!(c & tComponent_A21) || (a.a21 == b.a21)) && 
874 (!(c & tComponent_A31) || (a.a31 == b.a31)) && 
875 (!(c & tComponent_A41) || (a.a41 == b.a41)) && 
876 
877 (!(c & tComponent_A12) || (a.a12 == b.a12)) && 
878 (!(c & tComponent_A22) || (a.a22 == b.a22)) && 
879 (!(c & tComponent_A32) || (a.a32 == b.a32)) && 
880 (!(c & tComponent_A42) || (a.a42 == b.a42)) && 
881 
882 (!(c & tComponent_A13) || (a.a13 == b.a13)) && 
883 (!(c & tComponent_A23) || (a.a23 == b.a23)) && 
884 (!(c & tComponent_A33) || (a.a33 == b.a33)) && 
885 (!(c & tComponent_A43) || (a.a43 == b.a43)) && 
886 
887 (!(c & tComponent_A14) || (a.a14 == b.a14)) && 
888 (!(c & tComponent_A24) || (a.a24 == b.a24)) && 
889 (!(c & tComponent_A34) || (a.a34 == b.a34)) && 
890 (!(c & tComponent_A44) || (a.a44 == b.a44)); 
891
892 
893 
894inline bool tMath::tNotEqual(const tMat4& a, const tMat4& b, tComponents c
895
896 return 
897 ((c & tComponent_A11) && (a.a11 != b.a11)) || 
898 ((c & tComponent_A21) && (a.a21 != b.a21)) || 
899 ((c & tComponent_A31) && (a.a31 != b.a31)) || 
900 ((c & tComponent_A41) && (a.a41 != b.a41)) || 
901 
902 ((c & tComponent_A12) && (a.a12 != b.a12)) || 
903 ((c & tComponent_A22) && (a.a22 != b.a22)) || 
904 ((c & tComponent_A32) && (a.a32 != b.a32)) || 
905 ((c & tComponent_A42) && (a.a42 != b.a42)) || 
906 
907 ((c & tComponent_A13) && (a.a13 != b.a13)) || 
908 ((c & tComponent_A23) && (a.a23 != b.a23)) || 
909 ((c & tComponent_A33) && (a.a33 != b.a33)) || 
910 ((c & tComponent_A43) && (a.a43 != b.a43)) || 
911 
912 ((c & tComponent_A14) && (a.a14 != b.a14)) || 
913 ((c & tComponent_A24) && (a.a24 != b.a24)) || 
914 ((c & tComponent_A34) && (a.a34 != b.a34)) || 
915 ((c & tComponent_A44) && (a.a44 != b.a44)); 
916
917 
918 
919inline float tMath::tRotationAngle(const tQuat& q
920
921 float a = tMod(2.0f*tMath::tArcCos(q.w), tMath::TwoPi); 
922 if (a > 0.0f
923 a *= -1.0f
924 if (a < 0.0f
925 a += tMath::TwoPi
926 
927 return a
928
929 
930 
931inline void tMath::tRotate(tVec3& v, const tQuat& q
932
933 tQuat c; tConjugate(c, q); 
934 tQuat p; tSet(p, q.v); 
935 tQuat r; tMul(r, q, p); tMul(r, c); // r = qpc. 
936 tSet(v, r.x, r.y, r.z); 
937
938 
939 
940inline void tMath::tRotate(tVec4& v, const tQuat& q
941
942 float x = q.w*v.x + q.y*v.z - q.z*v.y
943 float y = q.w*v.y + q.z*v.x - q.x*v.z
944 float z = q.w*v.z + q.x*v.y - q.y*v.x
945 float w = -q.x*v.x - q.y*v.y - q.z*v.z
946 tSet(v, x, y, z, w); 
947
948 
949 
950inline void tMath::tMul(tQuat& q, const tQuat& a
951
952 float x = q.w*a.x + q.x*a.w + q.y*a.z - q.z*a.y
953 float y = q.w*a.y + q.y*a.w + q.z*a.x - q.x*a.z
954 float z = q.w*a.z + q.z*a.w + q.x*a.y - q.y*a.x
955 float w = q.w*a.w - q.x*a.x - q.y*a.y - q.z*a.z
956 tSet(q, x, y, z, w); 
957
958 
959 
960inline void tMath::tMul(tQuat& d, const tQuat& a, const tQuat& b
961
962 d.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y
963 d.y = a.w*b.y + a.y*b.w + a.z*b.x - a.x*b.z
964 d.z = a.w*b.z + a.z*b.w + a.x*b.y - a.y*b.x
965 d.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z
966
967 
968 
969inline void tMath::tMul(tQuat& q, const tVec3& a
970
971 float x = q.w*a.x + q.y*a.z - q.z*a.y
972 float y = q.w*a.y + q.z*a.x - q.x*a.z
973 float z = q.w*a.z + q.x*a.y - q.y*a.x
974 float w = -q.x*a.x - q.y*a.y - q.z*a.z
975 tSet(q, x, y, z, w); 
976
977 
978 
979inline void tMath::tMul(tQuat& d, const tQuat& a, const tVec3& b
980
981 float x = a.w*b.x + a.y*b.z - a.z*b.y
982 float y = a.w*b.y + a.z*b.x - a.x*b.z
983 float z = a.w*b.z + a.x*b.y - a.y*b.x
984 float w = -a.x*b.x - a.y*b.y - a.z*b.z
985 tSet(d, x, y, z, w); 
986
987 
988 
989inline void tMath::tMul(tMat2& m, const tMat2& b
990
991 tMat2 a
992 tSet(a, m); 
993 tMul(m, a, b); 
994
995 
996 
997inline void tMath::tMul(tMat2& d, const tMat2& a, const tMat2& b
998
999 d.a11 = a.a11*b.a11 + a.a12*b.a21
1000 d.a21 = a.a21*b.a11 + a.a22*b.a21
1001 d.a12 = a.a11*b.a12 + a.a12*b.a22
1002 d.a22 = a.a21*b.a12 + a.a22*b.a22
1003
1004 
1005 
1006inline void tMath::tMul(tMat4& m, const tMat4& b
1007
1008 tMat4 a
1009 tSet(a, m); 
1010 tMul(m, a, b); 
1011
1012 
1013 
1014inline void tMath::tMulByTranspose(tMat4& d, const tVec3& a, const tVec3& b
1015
1016 tZero(d); 
1017 d.a11 = a.x * b.x
1018 d.a21 = a.y * b.x
1019 d.a31 = a.z * b.x
1020 
1021 d.a12 = a.x * b.y
1022 d.a22 = a.y * b.y
1023 d.a32 = a.z * b.y
1024 
1025 d.a13 = a.x * b.z
1026 d.a23 = a.y * b.z
1027 d.a33 = a.z * b.z
1028
1029 
1030 
1031inline void tMath::tMulByTranspose(tMat4& d, const tVec4& a, const tVec4& b
1032
1033 tZero(d); 
1034 d.a11 = a.x * b.x; d.a21 = a.y * b.x; d.a31 = a.z * b.x; d.a41 = a.w * b.x
1035 d.a12 = a.x * b.y; d.a22 = a.y * b.y; d.a32 = a.z * b.y; d.a42 = a.w * b.y
1036 d.a13 = a.x * b.z; d.a23 = a.y * b.z; d.a33 = a.z * b.z; d.a43 = a.w * b.z
1037 d.a14 = a.x * b.w; d.a24 = a.y * b.w; d.a34 = a.z * b.w; d.a44 = a.w * b.w
1038
1039 
1040 
1041inline void tMath::tTranspose(tMat4& m
1042
1043 #if defined(PLATFORM_WINDOWS) 
1044 __m128* a = (__m128*)m.E; 
1045 if (tIsAligned16(a)) 
1046
1047 _MM_TRANSPOSE4_PS(a[0], a[1], a[2], a[3]); 
1048
1049 else 
1050 #endif 
1051
1052 tStd::tSwap(m.a21, m.a12); 
1053 tStd::tSwap(m.a31, m.a13); 
1054 tStd::tSwap(m.a41, m.a14); 
1055 tStd::tSwap(m.a32, m.a23); 
1056 tStd::tSwap(m.a42, m.a24); 
1057 tStd::tSwap(m.a43, m.a34); 
1058
1059
1060 
1061 
1062inline bool tMath::tInvert(tMat2& d, const tMat2& s
1063
1064 // We leave the matrix alone if it's not invertible. 
1065 float det = tDeterminant(s); 
1066 if (det == 0.0f
1067 return false
1068 
1069 d.a11 = s.a22
1070 d.a21 = -s.a21
1071 d.a12 = -s.a12
1072 d.a22 = s.a11
1073 
1074 tDiv(d, det); 
1075 return true
1076
1077 
1078 
1079inline bool tMath::tInvert(tMat2& m
1080
1081 tMat2 s
1082 tSet(s, m); 
1083 return tInvert(m, s); 
1084
1085 
1086 
1087inline void tMath::tInvertAffine(tMat4& m
1088
1089 tMat4 s
1090 tSet(s, m); 
1091 tInvertAffine(m, s); 
1092
1093 
1094 
1095inline void tMath::tCross(tVec3& v, const tVec3& a
1096
1097 float x = v.y*a.z - v.z*a.y
1098 float y = v.z*a.x - v.x*a.z
1099 float z = v.x*a.y - v.y*a.x
1100 tSet(v, x, y, z); 
1101
1102 
1103 
1104inline void tMath::tCross(tVec3& d, const tVec3& a, const tVec3& b
1105
1106 d.x = a.y*b.z - a.z*b.y
1107 d.y = a.z*b.x - a.x*b.z
1108 d.z = a.x*b.y - a.y*b.x
1109
1110 
1111 
1112inline void tMath::tCross(tVec4& v, const tVec4& a
1113
1114 float x = v.y*a.z - v.z*a.y
1115 float y = v.z*a.x - v.x*a.z
1116 float z = v.x*a.y - v.y*a.x
1117 tSet(v, x, y, z, 1.0f); 
1118
1119 
1120 
1121inline void tMath::tCross(tVec4& d, const tVec4& a, const tVec4& b
1122
1123 d.x = a.y*b.z - a.z*b.y
1124 d.y = a.z*b.x - a.x*b.z
1125 d.z = a.x*b.y - a.y*b.x
1126 d.w = 1.0f
1127
1128 
1129 
1130inline void tMath::tMakeRotateX(tMat4& d, float a
1131
1132 float cos = tCos(a); 
1133 float sin = tSin(a); 
1134 
1135 // Matrix is being populated column major so it looks like the transpose of a math text but it's correct. 
1136 d.a11 = 1.0f; d.a21 = 0.0f; d.a31 = 0.0f; d.a41 = 0.0f
1137 d.a12 = 0.0f; d.a22 = cos; d.a32 = sin; d.a42 = 0.0f
1138 d.a13 = 0.0f; d.a23 = -sin; d.a33 = cos; d.a43 = 0.0f
1139 d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f
1140
1141 
1142 
1143inline void tMath::tMakeRotateY(tMat4& d, float a
1144
1145 float cos = tCos(a); 
1146 float sin = tSin(a); 
1147 
1148 d.a11 = cos; d.a21 = 0.0f; d.a31 = -sin; d.a41 = 0.0f
1149 d.a12 = 0.0f; d.a22 = 1.0f; d.a32 = 0.0f; d.a42 = 0.0f
1150 d.a13 = sin; d.a23 = 0.0f; d.a33 = cos; d.a43 = 0.0f
1151 d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f
1152
1153 
1154 
1155inline void tMath::tMakeRotateZ(tMat4& d, float a
1156
1157 float cos = tCos(a); 
1158 float sin = tSin(a); 
1159 
1160 d.a11 = cos; d.a21 = sin; d.a31 = 0.0f; d.a41 = 0.0f
1161 d.a12 = -sin; d.a22 = cos; d.a32 = 0.0f; d.a42 = 0.0f
1162 d.a13 = 0.0f; d.a23 = 0.0f; d.a33 = 1.0f; d.a43 = 0.0f
1163 d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f
1164
1165 
1166 
1167inline void tMath::tMakeRotateZ(tMat2& d, float a
1168
1169 float cos = tCos(a); 
1170 float sin = tSin(a); 
1171 
1172 d.a11 = cos; d.a21 = sin
1173 d.a12 = -sin; d.a22 = cos
1174
1175 
1176 
1177inline void tMath::tExtractAffineScale(tVec3& scale, const tMat4& affine
1178
1179 scale.x = tLength(affine.C1); 
1180 scale.y = tLength(affine.C2); 
1181 scale.z = tLength(affine.C3); 
1182
1183 
1184 
1185inline float tMath::tExtractProjectionNear(const tMat4& m
1186
1187 // To describe how this works we need to do a little math. For a general projection matrix 
1188 // a33 = -(f+n)/(f-n) (eq1) and 
1189 // a34 = -2fn/(f-n) (eq2) 
1190 // So we now have a system of 2 equations with 2 unknowns. Perfect. We're in simple algebra-land. Let a=a33, b=a34. 
1191 // Eq1) -(f+n)=(f-n)a -> -af-f=-an+n -> f(a+1)=n(a-1) -> f=n(a-1)/(a+1) -> f=nc where c is now a known constant. 
1192 // Subs nc for f in Eq2) ncn/(nc-n)=b/-2 -> cn/(c-1)=b/-2 -> n=(c-1)b/-2c. There's our near plane. For the far replce 
1193 // n with f/c to get f=(c-1)b/-2. Done. 
1194 float c = (m.a33 - 1.0f)/(m.a33 + 1.0f); 
1195 return (c - 1.0f)*m.a34/(-2.0f*c); 
1196
1197 
1198 
1199inline float tMath::tExtractProjectionFar(const tMat4& m
1200
1201 // See math for tExtractProjectionNear. 
1202 float c = (m.a33 - 1.0f)/(m.a33 + 1.0f); 
1203 return (c - 1.0f)*m.a34/(-2.0f); 
1204
1205 
1206 
1207inline void tMath::tExtractPerspective(float& fovV, float& fovH, float& aspect, float& nearPlane, float& farPlane, const tMat4& persp
1208
1209 fovV = tExtractPerspectiveFovV(persp); 
1210 fovH = tExtractPerspectiveFovH(persp); 
1211 aspect = tExtractProjectionAspect(persp); 
1212 nearPlane = tExtractProjectionNear(persp); 
1213 farPlane = tExtractProjectionFar(persp); 
1214
1215 
1216 
1217inline void tMath::tExtractPerspective(float& fovV, float& fovH, float& aspect, float& nearPlane, float& farPlane, float& offsetX, float& offsetY, const tMat4& persp
1218
1219 tExtractPerspective(fovV, fovH, aspect, nearPlane, farPlane, persp); 
1220 offsetX = tExtractProjectionOffsetX(persp); 
1221 offsetY = tExtractProjectionOffsetY(persp); 
1222
1223 
1224 
1225inline bool tMath::tApproach(float& value, float dest, float rate, float t
1226
1227 float diff = tAbs(dest - value); 
1228 float delta = rate * t
1229 
1230 if (diff <= delta
1231
1232 value = dest
1233 return true
1234
1235 
1236 value += (value < dest) ? delta : -delta
1237 return false
1238
1239