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>  |
20 | namespace tMath  |
21 | {  |
22 |   |
23 |   |
24 | // These can be ORed together if necessary and are generally passed around using the tComponents type.  |
25 | enum 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.  |
68 | typedef 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.  |
76 | struct 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 |   |
88 | struct 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 |   |
100 | struct 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 |   |
113 | struct 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 |   |
124 | struct 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).  |
149 | struct 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.  |
174 | inline void tSet(tVec2& d, const tVec2& s) { d.x = s.x; d.y = s.y; }  |
175 | inline void tSet(tVec2& d, const tVec3& s) { d.x = s.x; d.y = s.y; }  |
176 | inline void tSet(tVec2& d, const tVec4& s) { d.x = s.x; d.y = s.y; }  |
177 | inline void tSet(tVec2& d, float xy) { d.x = xy; d.y = xy; }  |
178 | inline void tSet(tVec2& d, float x, float y) { d.x = x; d.y = y; }  |
179 | inline void tSet(tVec2& d, const float* a) { d.x = a[0]; d.y = a[1]; }  |
180 | inline void tSet(tVec3& d, const tVec2& s, float z = 0.0f) { d.x = s.x; d.y = s.y; d.z = z; }  |
181 | inline void tSet(tVec3& d, const tVec3& s) { d.x = s.x; d.y = s.y; d.z = s.z; }  |
182 | inline void tSet(tVec3& d, const tVec4& s) { d.x = s.x; d.y = s.y; d.z = s.z; }  |
183 | inline void tSet(tVec3& d, float xyz) { d.x = xyz; d.y = xyz; d.z = xyz; }  |
184 | inline void tSet(tVec3& d, float x, float y, float z) { d.x = x; d.y = y; d.z = z; }  |
185 | inline void tSet(tVec3& d, const float* a) { d.x = a[0]; d.y = a[1]; d.z = a[2]; }  |
186 | inline 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; }  |
187 | inline 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; }  |
188 | inline void tSet(tVec4& d, const tVec4& s) { d.x = s.x; d.y = s.y; d.z = s.z; d.w = s.w; }  |
189 | inline void tSet(tVec4& d, float xyzw) { d.x = xyzw; d.y = xyzw; d.z = xyzw; d.w = xyzw; }  |
190 | inline void tSet(tVec4& d, float x, float y, float z, float w) { d.x = x; d.y = y; d.z = z; d.w = w; }  |
191 | inline void tSet(tVec4& d, const float* a) { d.x = a[0]; d.y = a[1]; d.z = a[2]; d.w = a[3]; }  |
192 | inline void tSet(tQuat& d, const tQuat& s) { d.v = s.v; d.r = s.r; }  |
193 | inline void tSet(tQuat& d, float x, float y, float z, float w) { d.x = x; d.y = y; d.z = z; d.w = w; }  |
194 | inline 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.  |
196 | inline 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.  |
198 | inline void tSet(tQuat& d, const tVec3& v) { d.v = v; d.r = 0.0f; }  |
199 | inline void tSet(tMat2& d, const tMat2& s) { d.C1 = s.C1; d.C2 = s.C2; }  |
200 | inline void tSet(tMat2& d, const tVec2& c1, const tVec2& c2) { d.C1 = c1; d.C2 = c2; }  |
201 | inline void tSet(tMat2& d, float a11, float a21, float a12, float a22) { d.a11 = a11; d.a21 = a21; d.a12 = a12; d.a22 = a22; }  |
202 | inline void tSet(tMat2& d, const float* a) { d.a11 = a[0]; d.a21 = a[1]; d.a12 = a[2]; d.a22 = a[3]; }  |
203 | inline void tSet(tMat4& d, const tMat4& s) { for (int e = 0; e < 16; e++) d.E[e] = s.E[e]; }  |
204 | inline 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; }  |
205 | inline 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); }  |
206 | inline 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 | );  |
214 | inline 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.  |
218 | inline void tGet(float& x, float& y, const tVec2& s) { x = s.x; y = s.y; }  |
219 | inline void tGet(float* a, const tVec2& s) { a[0] = s.x; a[1] = s.y; }  |
220 | inline void tGet(float& x, float& y, float& z, const tVec3& s) { x = s.x; y = s.y; z = s.z; }  |
221 | inline void tGet(float* a, const tVec3& s) { a[0] = s.x; a[1] = s.y; a[2] = s.z; }  |
222 | inline 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; }  |
223 | inline void tGet(float* a, const tVec4& s) { a[0] = s.x; a[1] = s.y; a[2] = s.z; a[3] = s.w; }  |
224 | inline 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; }  |
225 | inline 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].  |
227 | inline 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; }  |
228 | inline 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]; }  |
229 | inline 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 | );  |
237 | inline void tGet(float* a, const tMat4& m) { for (int e = 0; e < 16; e++) a[e] = m.E[e]; }  |
238 |   |
239 | inline void tZero(tVec2& d) { d.x = 0.0f; d.y = 0.0f; }  |
240 | inline void tZero(tVec2& d, tComponents c) { if (c & tComponent_X) d.x = 0.0f; if (c & tComponent_Y) d.y = 0.0f; }  |
241 | inline void tZero(tVec3& d) { d.x = 0.0f; d.y = 0.0f; d.z = 0.0f; }  |
242 | inline 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; }  |
243 | inline void tZero(tVec4& d) { d.x = 0.0f; d.y = 0.0f; d.z = 0.0f; d.w = 0.0f; }  |
244 | inline 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; }  |
245 | inline void tZero(tQuat& d) { d.x = 0.0f; d.y = 0.0f; d.z = 0.0f; d.w = 0.0f; }  |
246 | inline 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; }  |
247 | inline void tZero(tMat2& d) { tZero(d.C1); tZero(d.C2); }  |
248 | inline 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; }  |
249 | inline void tZero(tMat4& d) { for (int e = 0; e < 16; e++) d.E[e] = 0.0f; }  |
250 | inline void tZero(tMat4& d, tComponents c);  |
251 |   |
252 | inline bool tIsZero(const tVec2& v) { return (v.x == 0.0f) && (v.y == 0.0f); }  |
253 | inline bool tIsZero(const tVec2& v, tComponents c) { return (!(c & tComponent_X) || (v.x == 0.0f)) && (!(c & tComponent_Y) || (v.y == 0.0f)); }  |
254 | inline bool tIsZero(const tVec3& v) { return (v.x == 0.0f) && (v.y == 0.0f) && (v.z == 0.0f); }  |
255 | inline 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)); }  |
256 | inline bool tIsZero(const tVec4& v) { return (v.x == 0.0f) && (v.y == 0.0f) && (v.z == 0.0f) && (v.w == 0.0f); }  |
257 | inline 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)); }  |
258 | inline bool tIsZero(const tQuat& q) { return (q.x == 0.0f) && (q.y == 0.0f) && (q.z == 0.0f) && (q.w == 0.0f); }  |
259 | inline 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)); }  |
260 | inline bool tIsZero(const tMat2& m) { return tIsZero(m.C1) && tIsZero(m.C2); }  |
261 | inline 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)); }  |
262 | inline bool tIsZero(const tMat4& m) { return tIsZero(m.C1) && tIsZero(m.C2) && tIsZero(m.C3) && tIsZero(m.C4); }  |
263 | inline 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  |
267 | inline bool tApproxEqual(const tVec2& a, const tVec2& b, float e = Epsilon) { return (tAbs(a.x-b.x) < e) && (tAbs(a.y-b.y) < e); }  |
268 | inline 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)); }  |
269 | inline 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); }  |
270 | inline 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)); }  |
271 | inline 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); }  |
272 | inline 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)); }  |
273 | inline 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); }  |
274 | inline 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)); }  |
275 | inline bool tApproxEqual(const tMat2& a, const tMat2& b, float e = Epsilon) { return tApproxEqual(a.C1, b.C1, e) && tApproxEqual(a.C2, b.C2, e); }  |
276 | inline bool tApproxEqual(const tMat2& a, const tMat2& b, tComponents c, float e = Epsilon);  |
277 | inline 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); }  |
278 | inline bool tApproxEqual(const tMat4& a, const tMat4& b, tComponents c, float e = Epsilon);  |
279 |   |
280 | inline bool tEqual(const tVec2& a, const tVec2& b) { return (a.x == b.x) && (a.y == b.y); }  |
281 | inline 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)); }  |
282 | inline bool tEqual(const tVec3& a, const tVec3& b) { return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); }  |
283 | inline 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)); }  |
284 | inline 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); }  |
285 | inline 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)); }  |
286 | inline 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); }  |
287 | inline 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)); }  |
288 | inline bool tEqual(const tMat2& a, const tMat2& b) { return tEqual(a.C1, b.C1) && tEqual(a.C2, b.C2); }  |
289 | inline 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)); }  |
290 | inline 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); }  |
291 | inline bool tEqual(const tMat4& a, const tMat4& b, tComponents c);  |
292 |   |
293 | inline bool tNotEqual(const tVec2& a, const tVec2& b) { return (a.x != b.x) || (a.y != b.y); }  |
294 | inline 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)); }  |
295 | inline bool tNotEqual(const tVec3& a, const tVec3& b) { return (a.x != b.x) || (a.y != b.y) || (a.z != b.z); }  |
296 | inline 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)); }  |
297 | inline 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); }  |
298 | inline 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)); }  |
299 | inline 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); }  |
300 | inline 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)); }  |
301 | inline bool tNotEqual(const tMat2& a, const tMat2& b) { return tNotEqual(a.C1, b.C1) || tNotEqual(a.C2, b.C2); }  |
302 | inline 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)); }  |
303 | inline 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); }  |
304 | inline bool tNotEqual(const tMat4& a, const tMat4& b, tComponents c);  |
305 |   |
306 | inline float tLengthSq(const tVec2& v) { return v.x*v.x + v.y*v.y; }  |
307 | inline float tLengthSq(const tVec3& v) { return v.x*v.x + v.y*v.y + v.z*v.z; }  |
308 | inline float tLengthSq(const tVec4& v) { return v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; }  |
309 | inline float tLengthSq(const tQuat& q) { return q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; }  |
310 |   |
311 | inline float tLength(const tVec2& v) { return tSqrt(tLengthSq(v)); }  |
312 | inline float tLength(const tVec3& v) { return tSqrt(tLengthSq(v)); }  |
313 | inline float tLength(const tVec4& v) { return tSqrt(tLengthSq(v)); }  |
314 | inline float tLength(const tQuat& q) { return tSqrt(tLengthSq(q)); }  |
315 |   |
316 | inline float tLengthFast(const tVec2& v) { return tSqrtFast(tLengthSq(v)); }  |
317 | inline float tLengthFast(const tVec3& v) { return tSqrtFast(tLengthSq(v)); }  |
318 | inline float tLengthFast(const tVec4& v) { return tSqrtFast(tLengthSq(v)); }  |
319 | inline float tLengthFast(const tQuat& q) { return tSqrtFast(tLengthSq(q)); }  |
320 |   |
321 | inline void tNormalize(tVec2& v) { float l = tLength(v); v.x /= l; v.y /= l; }  |
322 | inline void tNormalize(tVec3& v) { float l = tLength(v); v.x /= l; v.y /= l; v.z /= l; }  |
323 | inline void tNormalize(tVec4& v) { float l = tLength(v); v.x /= l; v.y /= l; v.z /= l; v.w /= l; }  |
324 | inline void tNormalize(tQuat& q) { float l = tLength(q); q.x /= l; q.y /= l; q.z /= l; q.w /= l; }  |
325 |   |
326 | inline float tNormalizeGetLength(tVec2& v) /* Returns pre-normalized length. */ { float l = tLength(v); v.x /= l; v.y /= l; return l; }  |
327 | inline float tNormalizeGetLength(tVec3& v) /* Returns pre-normalized length. */ { float l = tLength(v); v.x /= l; v.y /= l; v.z /= l; return l; }  |
328 | inline 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; }  |
329 | inline 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 |   |
331 | inline bool tNormalizeSafe(tVec2& v) /* Returns success. */ { float l = tLength(v); if (l == 0.0f) return false; v.x /= l; v.y /= l; return true; }  |
332 | inline 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; }  |
333 | inline 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; }  |
334 | inline 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 |   |
336 | inline 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; }  |
337 | inline 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; }  |
338 | inline 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; }  |
339 | inline 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 |   |
341 | inline void tNormalizeScale(tVec2& v, float s) /* Normalize then scale. Resizes the vector. */ { float l = tLength(v); v.x *= s/l; v.y *= s/l; }  |
342 | inline 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; }  |
343 | inline 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 |   |
345 | inline 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; }  |
346 | inline 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; }  |
347 | inline 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 |   |
349 | inline void tNormalizeFast(tVec2& v) { float s = tLengthSq(v); s = tRecipSqrtFast(s); v.x *= s; v.y *= s; }  |
350 | inline void tNormalizeFast(tVec3& v) { float s = tLengthSq(v); s = tRecipSqrtFast(s); v.x *= s; v.y *= s; v.z *= s; }  |
351 | inline void tNormalizeFast(tVec4& v) { float s = tLengthSq(v); s = tRecipSqrtFast(s); v.x *= s; v.y *= s; v.z *= s; v.w *= s; }  |
352 | inline void tNormalizeFast(tQuat& q) { float s = tLengthSq(q); s = tRecipSqrtFast(s); q.x *= s; q.y *= s; q.z *= s; q.w *= s; }  |
353 |   |
354 | inline 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; }  |
355 | inline 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; }  |
356 | inline 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; }  |
357 | inline 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.  |
360 | inline void tAdd(tVec2& v, const tVec2& a) { v.x += a.x; v.y += a.y; }  |
361 | inline void tAdd(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x + b.x; d.y = a.y + b.y; }  |
362 | inline void tAdd(tVec3& v, const tVec3& a) { v.x += a.x; v.y += a.y; v.z += a.z; }  |
363 | inline 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; }  |
364 | inline void tAdd(tVec4& v, const tVec4& a) { v.x += a.x; v.y += a.y; v.z += a.z; v.w += a.w; }  |
365 | inline 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; }  |
366 | inline void tAdd(tQuat& q, const tQuat& a) { q.x += a.x; q.y += a.y; q.z += a.z; q.w += a.w; }  |
367 | inline 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; }  |
368 | inline void tAdd(tMat2& m, const tMat2& a) { for (int c = 0; c < 4; c++) m.E[c] += a.E[c]; }  |
369 | inline 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]; }  |
370 | inline void tAdd(tMat4& m, const tMat4& a) { for (int c = 0; c < 16; c++) m.E[c] += a.E[c]; }  |
371 | inline 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.  |
374 | inline void tSub(tVec2& v, const tVec2& a) { v.x -= a.x; v.y -= a.y; }  |
375 | inline void tSub(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x - b.x; d.y = a.y - b.y; }  |
376 | inline void tSub(tVec3& v, const tVec3& a) { v.x -= a.x; v.y -= a.y; v.z -= a.z; }  |
377 | inline 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; }  |
378 | inline void tSub(tVec4& v, const tVec4& a) { v.x -= a.x; v.y -= a.y; v.z -= a.z; v.w -= a.w; }  |
379 | inline 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; }  |
380 | inline void tSub(tQuat& q, const tQuat& a) { q.x -= a.x; q.y -= a.y; q.z -= a.z; q.w -= a.w; }  |
381 | inline 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; }  |
382 | inline void tSub(tMat2& m, const tMat2& a) { for (int c = 0; c < 4; c++) m.E[c] -= a.E[c]; }  |
383 | inline 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]; }  |
384 | inline void tSub(tMat4& m, const tMat4& a) { for (int c = 0; c < 16; c++) m.E[c] -= a.E[c]; }  |
385 | inline 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.  |
388 | inline void tNeg(tVec2& v) { v.x = -v.x; v.y = -v.y; }  |
389 | inline void tNeg(tVec2& d, const tVec2& a) { d.x = -a.x; d.y = -a.y; }  |
390 | inline void tNeg(tVec3& v) { v.x = -v.x; v.y = -v.y; v.z = -v.z; }  |
391 | inline void tNeg(tVec3& d, const tVec3& a) { d.x = -a.x; d.y = -a.y; d.z = -a.z; }  |
392 | inline void tNeg(tVec4& v) { v.x = -v.x; v.y = -v.y; v.z = -v.z; v.w = -v.w; }  |
393 | inline void tNeg(tVec4& d, const tVec4& a) { d.x = -a.x; d.y = -a.y; d.z = -a.z; d.w = -a.w; }  |
394 | inline void tNeg(tQuat& q) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; }  |
395 | inline void tNeg(tQuat& d, const tQuat& a) { d.x = -a.x; d.y = -a.y; d.z = -a.z; d.w = -a.w; }  |
396 | inline void tNeg(tMat2& m) { m.a11 = -m.a11; m.a21 = -m.a21; m.a12 = -m.a12; m.a22 = -m.a22; }  |
397 | inline void tNeg(tMat2& d, const tMat2& a) { d.a11 = -a.a11; d.a21 = -a.a21; d.a12 = -a.a12; d.a22 = -a.a22; }  |
398 | inline void tNeg(tMat4& m) { for (int c = 0; c < 16; c++) m.E[c] = -m.E[c]; }  |
399 | inline 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*.  |
402 | inline void tConjugate(tQuat& q) { q.x = -q.x; q.y = -q.y; q.z = -q.z; }  |
403 | inline 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.  |
406 | inline void tMul(tVec2& v, float a) { v.x *= a; v.y *= a; }  |
407 | inline void tMul(tVec2& d, const tVec2& a, float b) { d.x = a.x*b; d.y = a.y*b; }  |
408 | inline void tMul(tVec2& d, float a, const tVec2& b) { d.x = a*b.x; d.y = a*b.y; }  |
409 | inline 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);  |
414 | inline void tMul(tVec3& v, float a) { v.x *= a; v.y *= a; v.z *= a; }  |
415 | inline void tMul(tVec3& d, const tVec3& a, float b) { d.x = a.x*b; d.y = a.y*b; d.z = a.z*b; }  |
416 | inline 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);  |
418 | inline void tMul(tVec4& v, float a) { v.x *= a; v.y *= a; v.z *= a; v.w *= a; }  |
419 | inline 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;}  |
420 | inline 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; }  |
421 | inline void tMul(tQuat& q, float a) { q.x *= a; q.y *= a; q.z *= a; q.w *= a; }  |
422 | inline 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; }  |
423 | inline 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; }  |
424 | inline void tMul(tQuat& q, const tQuat& a);  |
425 | inline void tMul(tQuat& d, const tQuat& a, const tQuat& b);  |
426 | inline void tMul(tQuat& q, const tVec3& a); // Treats 'a' as an augmented (pure) quaternion. w = 0.  |
427 | inline void tMul(tQuat& d, const tQuat& a, const tVec3& b); // Treats 'b' as an augmented (pure) quaternion. w = 0.  |
428 | inline void tMul(tMat2& m, float a) { m.a11 *= a; m.a21 *= a; m.a12 *= a; m.a22 *= a; }  |
429 | inline 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; }  |
430 | inline 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; }  |
431 | inline void tMul(tMat2& m, const tMat2& a);  |
432 | inline void tMul(tMat2& d, const tMat2& a, const tMat2& b);  |
433 | inline void tMul(tMat4& m, float a) { for (int c = 0; c < 16; c++) m.E[c] *= a; }  |
434 | inline void tMul(tMat4& d, const tMat4& a, float b) { for (int c = 0; c < 16; c++) d.E[c] = a.E[c]*b; }  |
435 | inline void tMul(tMat4& d, float a, const tMat4& b) { for (int c = 0; c < 16; c++) d.E[c] = a*b.E[c]; }  |
436 | inline 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.  |
442 | inline void tMulByTranspose(tMat4& d, const tVec3& a, const tVec3& b);  |
443 | inline 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.  |
447 | inline void tMulE(tVec2& v, const tVec2& a) { v.x *= a.x; v.y *= a.y; }  |
448 | inline void tMulE(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x*b.x; d.y = a.y*b.y; }  |
449 | inline void tMulE(tVec3& v, const tVec3& a) { v.x *= a.x; v.y *= a.y; v.z *= a.z; }  |
450 | inline 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; }  |
451 | inline void tMulE(tVec4& v, const tVec4& a) { v.x *= a.x; v.y *= a.y; v.z *= a.z; v.w *= a.w; }  |
452 | inline 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; }  |
453 | inline void tMulE(tMat2& m, const tMat2& a) { tMulE(m.C1, a.C1); tMulE(m.C2, a.C2); }  |
454 | inline void tMulE(tMat2& d, const tMat2& a, const tMat2& b) { tMulE(d.C1, a.C1, b.C1); tMulE(d.C2, a.C2, b.C2); }  |
455 | inline 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); }  |
456 | inline 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.  |
459 | inline void tDiv(tVec2& v, float a) { v.x /= a; v.y /= a; }  |
460 | inline void tDiv(tVec2& d, const tVec2& a, float b) { d.x = a.x/b; d.y = a.y/b; }  |
461 | inline void tDiv(tVec3& v, float a) { v.x /= a; v.y /= a; v.z /= a; }  |
462 | inline void tDiv(tVec3& d, const tVec3& a, float b) { d.x = a.x/b; d.y = a.y/b; d.z = a.z/b; }  |
463 | inline void tDiv(tVec4& v, float a) { v.x /= a; v.y /= a; v.z /= a; v.w /= a; }  |
464 | inline 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; }  |
465 | inline void tDiv(tQuat& q, float a) { q.x /= a; q.y /= a; q.z /= a; q.w /= a; }  |
466 | inline 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; }  |
467 | inline void tDiv(tMat2& m, float a) { m.a11 /= a; m.a21 /= a; m.a12 /= a; m.a22 /= a; }  |
468 | inline 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; }  |
469 | inline void tDiv(tMat4& m, float a) { for (int c = 0; c < 16; c++) m.E[c] /= a; }  |
470 | inline 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.  |
473 | inline void tDivE(tVec2& v, const tVec2& a) { v.x /= a.x; v.y /= a.y; }  |
474 | inline void tDivE(tVec2& d, const tVec2& a, const tVec2& b) { d.x = a.x/b.x; d.y = a.y/b.y; }  |
475 | inline void tDivE(tVec3& v, const tVec3& a) { v.x /= a.x; v.y /= a.y; v.z /= a.z; }  |
476 | inline 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; }  |
477 | inline void tDivE(tVec4& v, const tVec4& a) { v.x /= a.x; v.y /= a.y; v.z /= a.z; v.w /= a.w; }  |
478 | inline 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; }  |
479 | inline void tDivE(tMat2& m, const tMat2& a) { m.a11 /= a.a11; m.a21 /= a.a21; m.a12 /= a.a12; m.a22 /= a.a22; }  |
480 | inline 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; }  |
481 | inline void tDivE(tMat4& m, const tMat4& a) { for (int c = 0; c < 16; c++) m.E[c] /= a.E[c]; }  |
482 | inline 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 |   |
484 | inline float tDot(const tVec2& a, const tVec2& b) { return a.x*b.x + a.y*b.y; }  |
485 | inline float tDot(const tVec3& a, const tVec3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; }  |
486 | inline 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; }  |
487 | inline 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.  |
492 | inline 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; }  |
493 | inline 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; }  |
494 | inline 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 |   |
496 | inline void tIdentity(tMat2& m) { m.a11 = 1.0f; m.a21 = 0.0f; m.a12 = 0.0f; m.a22 = 1.0f; }  |
497 | inline void tIdentity(tMat4& m) { tZero(m); m.a11 = 1.0f; m.a22 = 1.0f; m.a33 = 1.0f; m.a44 = 1.0f; }  |
498 |   |
499 | inline void tTranspose(tMat2& m) { tStd::tSwap(m.a12, m.a21); }  |
500 | inline void tTranspose(tMat2& d, const tMat2& a) { d.a11 = a.a11; d.a21 = a.a12; d.a12 = a.a21; d.a22 = a.a22; }  |
501 | inline void tTranspose(tMat4& m);  |
502 | inline void tTranspose(tMat4& d, const tMat4& a) { tSet(d, a); tTranspose(d); }  |
503 |   |
504 | inline float tDeterminant(const tMat2& m) { return m.a11*m.a22 - m.a12*m.a21; }  |
505 | float tDeterminant(const tMat4& m);  |
506 |   |
507 | inline float tTrace(const tMat2& m) { return m.a11 + m.a22; }  |
508 | inline float tTrace(const tMat4& m) { return m.a11 + m.a22 + m.a33 + m.a44; }  |
509 |   |
510 | inline bool tInvert(tMat2& m);  |
511 | inline 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.  |
517 | inline void tInvertAffine(tMat4& m);  |
518 | void tInvertAffine(tMat4& d, const tMat4& a);  |
519 |   |
520 | inline float tDistBetween(const tVec2& a, const tVec2& b) { tVec2 d; tSub(d, b, a); return tLength(d); }  |
521 | inline float tDistBetweenSq(const tVec2& a, const tVec2& b) { tVec2 d; tSub(d, b, a); return tLengthSq(d); }  |
522 | inline float tDistBetween(const tVec3& a, const tVec3& b) { tVec3 d; tSub(d, b, a); return tLength(d); }  |
523 | inline 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.  |
526 | inline void tCross(tVec3& v, const tVec3& a);  |
527 | inline void tCross(tVec3& d, const tVec3& a, const tVec3& b);  |
528 | inline void tCross(tVec4& v, const tVec4& a);  |
529 | inline void tCross(tVec4& d, const tVec4& a, const tVec4& b);  |
530 | inline 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 |   |
532 | enum 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.  |
543 | void tSlerp(tQuat& d, const tQuat& a, const tQuat& b, float t);  |
544 | void 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).  |
548 | void tNlerp(tQuat& d, const tQuat& a, const tQuat& b, float t, tOrientationPath = tOrientationPath::Shortest);  |
549 |   |
550 | float tRotationAngle(const tQuat& a);  |
551 | void tRotate(tVec3& v, const tQuat& q);  |
552 | void tRotate(tVec4& v, const tQuat& q);  |
553 |   |
554 | inline void tMakeTranslate(tMat4& d, float x, float y, float z) { tIdentity(d); d.a14 = x; d.a24 = y; d.a34 = z; }  |
555 | inline void tMakeTranslate(tMat4& d, const tVec3& t) { tIdentity(d); d.a14 = t.x; d.a24 = t.y; d.a34 = t.z; }  |
556 |   |
557 | void tMakeRotateX(tMat4& d, float angle);  |
558 | void tMakeRotateY(tMat4& d, float angle);  |
559 | void tMakeRotateZ(tMat4& d, float angle);  |
560 | void tMakeRotateZ(tMat2& d, float angle);  |
561 | void tMakeRotate(tMat4& d, const tVec3& axis, float angle);  |
562 | void 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.  |
571 | void tMakeRotateXYZ(tMat4& d, float eulerX, float eulerY, float eulerZ); // RzRyRx. Default for Maya.  |
572 | void tMakeRotateYZX(tMat4& d, float eulerX, float eulerY, float eulerZ); // RxRzRy  |
573 | void tMakeRotateZXY(tMat4& d, float eulerX, float eulerY, float eulerZ); // RyRxRz  |
574 | void tMakeRotateZYX(tMat4& d, float eulerX, float eulerY, float eulerZ); // RxRyRz  |
575 | void tMakeRotateXZY(tMat4& d, float eulerX, float eulerY, float eulerZ); // RyrzRx  |
576 | void tMakeRotateYXZ(tMat4& d, float eulerX, float eulerY, float eulerZ); // RzrxRy  |
577 | inline void tMakeRotateXYZ(tMat4& d, const tVec3& euler) { tMakeRotateXYZ(d, euler.x, euler.y, euler.z); }  |
578 | inline void tMakeRotateYZX(tMat4& d, const tVec3& euler) { tMakeRotateYZX(d, euler.x, euler.y, euler.z); }  |
579 | inline void tMakeRotateZXY(tMat4& d, const tVec3& euler) { tMakeRotateZXY(d, euler.x, euler.y, euler.z); }  |
580 | inline void tMakeRotateZYX(tMat4& d, const tVec3& euler) { tMakeRotateZYX(d, euler.x, euler.y, euler.z); }  |
581 | inline void tMakeRotateXZY(tMat4& d, const tVec3& euler) { tMakeRotateXZY(d, euler.x, euler.y, euler.z); }  |
582 | inline void tMakeRotateYXZ(tMat4& d, const tVec3& euler) { tMakeRotateYXZ(d, euler.x, euler.y, euler.z); }  |
583 |   |
584 | inline void tMakeScale(tMat4& d, float scale) { tIdentity(d); d.a11 = d.a22 = d.a33 = scale; }  |
585 | inline void tMakeScale(tMat4& d, float scaleX, float scaleY, float scaleZ) { tIdentity(d); d.a11 = scaleX; d.a22 = scaleY; d.a33 = scaleZ; }  |
586 | inline void tMakeScale(tMat4& d, const tVec3& scale) { tIdentity(d); d.a11 = scale.x; d.a22 = scale.y; d.a33 = scale.z; }  |
587 |   |
588 | inline void tMakeReflectXY(tMat4& d) { tIdentity(d); d.a33 = -1.0f; }  |
589 | inline void tMakeReflectXZ(tMat4& d) { tIdentity(d); d.a22 = -1.0f; }  |
590 | inline void tMakeReflectYZ(tMat4& d) { tIdentity(d); d.a11 = -1.0f; }  |
591 |   |
592 | void 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.  |
597 | void tMakeProjPersp(tMat4& d, float left, float right, float bottom, float top, float nearPlane, float farPlane);  |
598 | void tMakeProjPersp(tMat4& d, const tVec3& boxMin, const tVec3& boxMax);  |
599 | void 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.  |
603 | void tMakeProjPerspSymFovV(tMat4& d, float fovX, float aspect, float nearPlane, float farPlane);  |
604 | void 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.  |
610 | void tMakeProjPerspOffset  |
611 | (  |
612 | tMat4& d, float right, float top,  |
613 | float nearPlane, float farPlane,  |
614 | float offsetX, float offsetY  |
615 | );  |
616 | void tMakeProjPerspFovVOffset  |
617 | (  |
618 | tMat4& d, float fovX, float aspect,  |
619 | float nearPlane, float farPlane,  |
620 | float offsetX, float offsetY  |
621 | );  |
622 | void 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.  |
632 | void 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).  |
638 | void tMakeOrthoNormal(tMat4& m);  |
639 | void tMakeOrthoUniform(tMat4& m);  |
640 | void tMakeOrthoNonUniform(tMat4& m);  |
641 | inline 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.  |
646 | void 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.  |
654 | void   |
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.  |
661 | float tExtractProjectionNear(const tMat4&); // Returns near plane dist (assumes frustum is not oblique).  |
662 | float tExtractProjectionFar(const tMat4&); // Returns far plane dist (assumes frustum is not oblique).  |
663 | inline float (const tMat4& m) /* Returns aspect ratio, the width / height. */ { tAssert(m.a11 != 0.0f); return m.a22 / m.a11; }  |
664 | inline float (const tMat4& m) /* Returns offsetX, the horizontal oblique pan offset. */ { return -m.a13; }  |
665 | inline float (const tMat4& m) /* Returns offsetY, the vertical oblique pan offset. */ { return -m.a23; }  |
666 |   |
667 | // These are specific to perspective transforms.  |
668 | inline float (const tMat4& m) /* Returns FovX. */ { tAssert(m.a22 != 0.0f); return 2.0f * tArcTan(1.0f, m.a22); }  |
669 | inline float (const tMat4& m) /* Returns FovY. */ { tAssert(m.a11 != 0.0f); return 2.0f * tArcTan(1.0f, m.a11); }  |
670 | void tExtractPerspective(float& fovV, float& fovH, float& aspect, float& nearPlane, float& farPlane, const tMat4&);  |
671 | void 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?  |
706 | bool   |
707 | (  |
708 | tVec3& sol1, tVec3& sol2,  |
709 | const tMat4& rot,  |
710 | float gimbalZValue = 0.0f, tIntervalBias = tIntervalBias::Low  |
711 | );  |
712 |   |
713 | bool   |
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.  |
721 | bool 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].  |
724 | bool tApproachAngle(float& angle, float dest, float rate, float dt);  |
725 | bool 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.  |
729 | template <typename T> inline T tLinearScale(float t, T min, T max) { return min + (max - min)*t; }  |
730 | template <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.  |
734 | template <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.  |
738 | template <typename T> inline T tLinearLookup(float d, float d0, float d1, T r0, T r1) { return tLinearScale((d-d0)/(d1-d0), r0, r1); }  |
739 | template <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].  |
742 | template <typename T> inline T tLinearInterp(float d, float d0, float d1, T r0, T r1) { return tLinearScale(tSaturate((d-d0)/(d1-d0)), r0, r1); }  |
743 | template <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 |   |
752 | inline 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 |   |
768 | inline 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 |   |
784 | inline 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 |   |
808 | inline 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 |   |
833 | inline 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 |   |
844 | inline 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 |   |
869 | inline 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 |   |
894 | inline 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 |   |
919 | inline 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 |   |
931 | inline 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 |   |
940 | inline 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 |   |
950 | inline 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 |   |
960 | inline 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 |   |
969 | inline 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 |   |
979 | inline 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 |   |
989 | inline void tMath::tMul(tMat2& m, const tMat2& b)  |
990 | {  |
991 | tMat2 a;  |
992 | tSet(a, m);  |
993 | tMul(m, a, b);  |
994 | }  |
995 |   |
996 |   |
997 | inline 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 |   |
1006 | inline void tMath::tMul(tMat4& m, const tMat4& b)  |
1007 | {  |
1008 | tMat4 a;  |
1009 | tSet(a, m);  |
1010 | tMul(m, a, b);  |
1011 | }  |
1012 |   |
1013 |   |
1014 | inline 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 |   |
1031 | inline 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 |   |
1041 | inline 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 |   |
1062 | inline 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 |   |
1079 | inline bool tMath::tInvert(tMat2& m)  |
1080 | {  |
1081 | tMat2 s;  |
1082 | tSet(s, m);  |
1083 | return tInvert(m, s);  |
1084 | }  |
1085 |   |
1086 |   |
1087 | inline void tMath::tInvertAffine(tMat4& m)  |
1088 | {  |
1089 | tMat4 s;  |
1090 | tSet(s, m);  |
1091 | tInvertAffine(m, s);  |
1092 | }  |
1093 |   |
1094 |   |
1095 | inline 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 |   |
1104 | inline 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 |   |
1112 | inline 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 |   |
1121 | inline 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 |   |
1130 | inline 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 |   |
1143 | inline 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 |   |
1155 | inline 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 |   |
1167 | inline 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 |   |
1177 | inline void tMath::(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 |   |
1185 | inline float tMath::(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 |   |
1199 | inline float tMath::(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 |   |
1207 | inline void tMath::(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 |   |
1217 | inline void tMath::(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 |   |
1225 | inline 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 | |