1 | // tLinearAlgebra.cpp  |
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 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 | #include "Math/tLinearAlgebra.h"  |
18 | #include "Math/tVector2.h"  |
19 | #include "Math/tVector3.h"  |
20 | #include "Math/tVector4.h"  |
21 | #include "Math/tQuaternion.h"  |
22 | #include "Math/tMatrix2.h"  |
23 | #include "Math/tMatrix4.h"  |
24 |   |
25 |   |
26 | const tMath::tVector2 tMath::tVector2::zero = { 0.0f, 0.0f };  |
27 | const tMath::tVector2 tMath::tVector2::i = { 1.0f, 0.0f };  |
28 | const tMath::tVector2 tMath::tVector2::j = { 0.0f, 1.0f };  |
29 | const tMath::tVector3 tMath::tVector3::zero = { 0.0f, 0.0f, 0.0f };  |
30 | const tMath::tVector3 tMath::tVector3::i = { 1.0f, 0.0f, 0.0f };  |
31 | const tMath::tVector3 tMath::tVector3::j = { 0.0f, 1.0f, 0.0f };  |
32 | const tMath::tVector3 tMath::tVector3::k = { 0.0f, 0.0f, 1.0f };  |
33 | const tMath::tVector4 tMath::tVector4::zero = { 0.0f, 0.0f, 0.0f, 0.0f };  |
34 | const tMath::tVector4 tMath::tVector4::i = { 1.0f, 0.0f, 0.0f, 1.0f };  |
35 | const tMath::tVector4 tMath::tVector4::j = { 0.0f, 1.0f, 0.0f, 1.0f };  |
36 | const tMath::tVector4 tMath::tVector4::k = { 0.0f, 0.0f, 1.0f, 1.0f };  |
37 | const tMath::tVector4 tMath::tVector4::origin = { 0.0f, 0.0f, 0.0f, 1.0f };  |
38 | const tMath::tQuaternion tMath::tQuaternion::zero = { 0.0f, 0.0f, 0.0f, 0.0f };  |
39 | const tMath::tQuaternion tMath::tQuaternion::unit = { 0.0f, 0.0f, 0.0f, 1.0f };  |
40 | const tMath::tMatrix2 tMath::tMatrix2::zero = { 0.0f, 0.0f, 0.0f, 0.0f };  |
41 | const tMath::tMatrix2 tMath::tMatrix2::identity = { 1.0f, 0.0f, 0.0f, 1.0f };  |
42 | const tMath::tMatrix4 tMath::tMatrix4::zero = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };  |
43 | const tMath::tMatrix4 tMath::tMatrix4::identity = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f };  |
44 |   |
45 |   |
46 | void tMath::tSet(tQuat& d, const tMat4& m)  |
47 | {  |
48 | float trace = m.E[0] + m.E[5] + m.E[10];  |
49 |   |
50 | // The 0.0 here implies a decision that when w < 0.5 we consider rounding errors to be a potential issue.  |
51 | if (trace > 0.0f)  |
52 | {  |
53 | // w >= 0.5. Negligible error.  |
54 | float s = tSqrt(trace + 1.0f);  |
55 | d.w = 0.5f * s;  |
56 | s = 0.5f / s;  |
57 | d.x = (m.E[6] - m.E[9]) * s;  |
58 | d.y = (m.E[8] - m.E[2]) * s;  |
59 | d.z = (m.E[1] - m.E[4]) * s;  |
60 | }  |
61 | else  |
62 | {  |
63 | // w < 0.5. Find the largest of the x, y, z components. The remaining components get computed from this  |
64 | // to avoid rounding errors.  |
65 | if ((m.E[0] > m.E[5]) && (m.E[0] > m.E[10]))  |
66 | {  |
67 | float s = tSqrt((m.E[0] - (m.E[5] + m.E[10])) + 1.0f);  |
68 | d.x = 0.5f * s;  |
69 | s = 0.5f / s;  |
70 | d.y = (m.E[4] + m.E[1]) * s;  |
71 | d.z = (m.E[2] + m.E[8]) * s;  |
72 | d.w = (m.E[6] - m.E[9]) * s;  |
73 | }  |
74 | else if (m.E[5] > m.E[10])  |
75 | {  |
76 | float s = tSqrt((m.E[5] - (m.E[10] + m.E[0])) + 1.0f);  |
77 | d.y = 0.5f * s;  |
78 | s = 0.5f / s;  |
79 | d.z = (m.E[9] + m.E[6]) * s;  |
80 | d.x = (m.E[4] + m.E[1]) * s;  |
81 | d.w = (m.E[8] - m.E[2]) * s;  |
82 | }  |
83 | else  |
84 | {  |
85 | float s = tSqrt((m.E[10] - (m.E[0] + m.E[5])) + 1.0f);  |
86 | d.z = 0.5f * s;  |
87 | s = 0.5f / s;  |
88 | d.x = (m.E[2] + m.E[8]) * s;  |
89 | d.y = (m.E[9] + m.E[6]) * s;  |
90 | d.w = (m.E[1] - m.E[4]) * s;  |
91 | }  |
92 | }  |
93 | }  |
94 |   |
95 |   |
96 | void tMath::tSet(tQuat& d, const tVec3& axis, float angle)  |
97 | {  |
98 | d.r = tCos(angle / 2.0f);  |
99 | float s = tSin(angle / 2.0f);  |
100 | tSet(d.v, axis.x * s, axis.y * s, axis.z * s);  |
101 | }  |
102 |   |
103 |   |
104 | void tMath::tSet(tMat4& d, const tQuat& s)  |
105 | {  |
106 | float yy = s.y * s.y;  |
107 | float xx = s.x * s.x;  |
108 | float zz = s.z * s.z;  |
109 | float xy = s.x * s.y;  |
110 | float yz = s.y * s.z;  |
111 | float wz = s.w * s.z;  |
112 | float xz = s.x * s.z;  |
113 | float wx = s.w * s.x;  |
114 | float wy = s.w * s.y;  |
115 |   |
116 | d.E[0] = 1.0f - 2.0f*(yy + zz);  |
117 | d.E[1] = 2.0f*(xy + wz);  |
118 | d.E[2] = 2.0f*(xz - wy);  |
119 | d.E[3] = 0.0f;  |
120 |   |
121 | d.E[4] = 2.0f*(xy - wz);  |
122 | d.E[5] = 1.0f - 2.0f*(xx + zz);  |
123 | d.E[6] = 2.0f*(yz + wx);  |
124 | d.E[7] = 0.0f;  |
125 |   |
126 | d.E[8] = 2.0f*(xz + wy);  |
127 | d.E[9] = 2.0f*(yz - wx);  |
128 | d.E[10] = 1.0f - 2.0f*(xx + yy);  |
129 | d.E[11] = 0.0f;  |
130 |   |
131 | d.E[12] = 0.0f;  |
132 | d.E[13] = 0.0f;  |
133 | d.E[14] = 0.0f;  |
134 | d.E[15] = 1.0f;  |
135 | }  |
136 |   |
137 |   |
138 | void tMath::tGet(tVec3& axis, float& angle, const tQuat& q)  |
139 | {  |
140 | angle = 2.0f * tArcCos(q.w); // Angle E [0, 2Pi]  |
141 | float s = tSqrt(1.0f - q.w*q.w); // Assumes normalised so Abs(w) < 1, w*w E [0,1], and 1-w*w > 0.  |
142 | if (s > 0.00001f) // Avoid infinity.   |
143 | tSet(axis, q.x/s, q.y/s, q.z/s);  |
144 | else  |
145 | tSet(axis, 1.0f, 0.0f, 0.0f); // The axis direction doesn't matter so (1,0,0) is fine.  |
146 |   |
147 | if (angle > Pi)  |
148 | {  |
149 | // To return an angle E [0,Pi] we may have to reverse the axis direction.  |
150 | tNeg(axis);  |
151 | angle = TwoPi - angle;  |
152 | }  |
153 | }  |
154 |   |
155 |   |
156 | void tMath::tMul(tVec3& d, const tMat4& a, const tVec3& b)  |
157 | {  |
158 | // It would be nice to have an intrinsics-based implementation instead of this inline assembly.  |
159 | // Unfortunately inline asm is not supported on architectures like x64.  |
160 | float x = b.x*a.a11 + b.y*a.a12 + b.z*a.a13 + a.a14;  |
161 | float y = b.x*a.a21 + b.y*a.a22 + b.z*a.a23 + a.a24;  |
162 | float z = b.x*a.a31 + b.y*a.a32 + b.z*a.a33 + a.a34;  |
163 | tSet(d, x, y, z);  |
164 | }  |
165 |   |
166 |   |
167 | void tMath::tMul(tVec4& d, const tMat4& a, const tVec4& b)  |
168 | {  |
169 | // @todo Optimize this using intrinsics or SSE.  |
170 | float x = b.x*a.a11 + b.y*a.a12 + b.z*a.a13 + b.w*a.a14;  |
171 | float y = b.x*a.a21 + b.y*a.a22 + b.z*a.a23 + b.w*a.a24;  |
172 | float z = b.x*a.a31 + b.y*a.a32 + b.z*a.a33 + b.w*a.a34;  |
173 | float w = b.x*a.a41 + b.y*a.a42 + b.z*a.a43 + b.w*a.a44;  |
174 |   |
175 | tSet(d, x, y, z, w);  |
176 | }  |
177 |   |
178 |   |
179 | void tMath::tMul(tMat4& d, const tMat4& a, const tMat4& b)  |
180 | {  |
181 | for (int i = 0; i < 4; ++i)  |
182 | {  |
183 | float a0i = a.A[0][i];  |
184 | float a1i = a.A[1][i];  |
185 | float a2i = a.A[2][i];  |
186 | float a3i = a.A[3][i];  |
187 |   |
188 | d.A[0][i] = (a0i * b.a11) + (a1i * b.a21) + (a2i * b.a31) + (a3i * b.a41);  |
189 | d.A[1][i] = (a0i * b.a12) + (a1i * b.a22) + (a2i * b.a32) + (a3i * b.a42);  |
190 | d.A[2][i] = (a0i * b.a13) + (a1i * b.a23) + (a2i * b.a33) + (a3i * b.a43);  |
191 | d.A[3][i] = (a0i * b.a14) + (a1i * b.a24) + (a2i * b.a34) + (a3i * b.a44);  |
192 | }  |
193 | }  |
194 |   |
195 |   |
196 | void tMath::tSlerp(tQuat& d, const tQuat& a, const tQuat& b, float t)  |
197 | {  |
198 | if (t >= 1.0f)  |
199 | {  |
200 | d = b;  |
201 | return;  |
202 | }  |
203 |   |
204 | if (t <= 0.0f)  |
205 | {  |
206 | d = a;  |
207 | return;  |
208 | }  |
209 |   |
210 | float cosTheta = tDot(a, b);  |
211 | if (cosTheta < 0.0f)  |
212 | {  |
213 | cosTheta = -cosTheta;  |
214 | tNeg(d, b);  |
215 | }  |
216 | else  |
217 | {  |
218 | d = b;  |
219 | }  |
220 |   |
221 | const float delta = 0.98f;  |
222 | float facA = 1.0f - t;  |
223 | float facB = t;  |
224 | if (cosTheta < delta)  |
225 | {  |
226 | float theta = tArcCos(cosTheta);  |
227 | float sinTheta = tSin(theta);  |
228 | float den = 1.0f / sinTheta;  |
229 |   |
230 | facA = den * tSin((1.0f - t) * theta);  |
231 | facB = den * tSin(t * theta);  |
232 | }  |
233 |   |
234 | d.x = facA*a.x + facB*d.x;  |
235 | d.y = facA*a.y + facB*d.y;  |
236 | d.z = facA*a.z + facB*d.z;  |
237 | d.w = facA*a.w + facB*d.w;  |
238 | }  |
239 |   |
240 |   |
241 | void tMath::tSlerp(tQuat& d, const tQuat& a, const tQuat& bb, float t, tOrientationPath path)  |
242 | {  |
243 | if (t >= 1.0f)  |
244 | {  |
245 | d = bb;  |
246 | return;  |
247 | }  |
248 |   |
249 | if (t <= 0.0f)  |
250 | {  |
251 | d = a;  |
252 | return;  |
253 | }  |
254 |   |
255 | tQuat b;  |
256 | tSet(b, bb);  |
257 | float cosTheta = tDot(a, b);  |
258 |   |
259 | if  |
260 | (  |
261 | ((path == tOrientationPath::Shortest) && (cosTheta < 0.0f)) || // Shortest spherical path.  |
262 | ((path == tOrientationPath::Longest) && (cosTheta > 0.0f)) || // Longest spherical path.  |
263 | ((path == tOrientationPath::Clockwise) && (a.w > b.w)) || // Clockwise spherical path.  |
264 | ((path == tOrientationPath::CounterClockwise) && (a.w < b.w)) // Counterclockwise spherical path.  |
265 | )  |
266 | {  |
267 | cosTheta = -cosTheta;  |
268 | tNeg(b);  |
269 | }  |
270 |   |
271 | // We need to separate out the top of the cos curve (where it's flat and the sin goes to 0).  |
272 | // In the same way that sin(x) ~= x for small x, cos(x) ~= 1 for small x.  |
273 | float thresh = 0.98f;  |
274 | float facA = 1.0f - t;  |
275 | float facB = t;  |
276 | if (cosTheta < thresh)  |
277 | {  |
278 | float theta = tArcCos(cosTheta);  |
279 | float sinTheta = tSin(theta);  |
280 | float inv = 1.0f / sinTheta;  |
281 | facA = inv * tSin((1.0f - t) * theta);  |
282 | facB = inv * tSin(t * theta);  |
283 | }  |
284 |   |
285 | d.x = facA*a.x + facB*b.x;  |
286 | d.y = facA*a.y + facB*b.y;  |
287 | d.z = facA*a.z + facB*b.z;  |
288 | d.w = facA*a.w + facB*b.w;  |
289 | }  |
290 |   |
291 |   |
292 | void tMath::tNlerp(tQuat& d, const tQuat& a, const tQuat& bb, float t, tOrientationPath path)  |
293 | {  |
294 | if (t >= 1.0f)  |
295 | {  |
296 | d = bb;  |
297 | return;  |
298 | }  |
299 |   |
300 | if (t <= 0.0f)  |
301 | {  |
302 | d = a;  |
303 | return;  |
304 | }  |
305 |   |
306 | tQuat b;  |
307 | tSet(b, bb);  |
308 | float cosTheta = tDot(a, b);  |
309 |   |
310 | if  |
311 | (  |
312 | ((path == tOrientationPath::Shortest) && (cosTheta < 0.0f)) || // Shortest linear path.  |
313 | ((path == tOrientationPath::Longest) && (cosTheta > 0.0f)) || // Longest linear path.  |
314 | ((path == tOrientationPath::Clockwise) && (a.w > b.w)) || // Clockwise path.  |
315 | ((path == tOrientationPath::CounterClockwise) && (a.w < b.w)) // Counterclockwise path.  |
316 | )  |
317 | {  |
318 | cosTheta = -cosTheta;  |
319 | tNeg(b);  |
320 | }  |
321 |   |
322 | float facA = 1.0f - t;  |
323 | float facB = t;  |
324 | d.x = facA*a.x + facB*b.x;  |
325 | d.y = facA*a.y + facB*b.y;  |
326 | d.z = facA*a.z + facB*b.z;  |
327 | d.w = facA*a.w + facB*b.w;  |
328 | tNormalize(d);  |
329 | }  |
330 |   |
331 |   |
332 | float tMath::tDeterminant(const tMat4& m)  |
333 | {  |
334 | return  |
335 | m.A[0][0] *  |
336 | (  |
337 | m.A[1][1] * (m.A[2][2] * m.A[3][3] - m.A[2][3] * m.A[3][2]) +  |
338 | m.A[2][1] * (m.A[1][3] * m.A[3][2] - m.A[1][2] * m.A[3][3]) +  |
339 | m.A[3][1] * (m.A[1][2] * m.A[2][3] - m.A[1][3] * m.A[2][2])  |
340 | ) -  |
341 | m.A[1][0] *  |
342 | (  |
343 | m.A[0][1] * (m.A[2][2] * m.A[3][3] - m.A[2][3] * m.A[3][2]) +  |
344 | m.A[2][1] * (m.A[0][3] * m.A[3][2] - m.A[0][2] * m.A[3][3]) +  |
345 | m.A[3][1] * (m.A[0][2] * m.A[2][3] - m.A[0][3] * m.A[2][2])  |
346 | ) +  |
347 | m.A[2][0] *  |
348 | (  |
349 | m.A[0][1] * (m.A[1][2] * m.A[3][3] - m.A[1][3] * m.A[3][2]) +  |
350 | m.A[1][1] * (m.A[0][3] * m.A[3][2] - m.A[0][2] * m.A[3][3]) +  |
351 | m.A[3][1] * (m.A[0][2] * m.A[1][3] - m.A[0][3] * m.A[1][2])  |
352 | ) -  |
353 | m.A[3][0] *  |
354 | (  |
355 | m.A[0][1] * (m.A[1][2] * m.A[2][3] - m.A[1][3] * m.A[2][2]) +  |
356 | m.A[1][1] * (m.A[0][3] * m.A[2][2] - m.A[0][2] * m.A[2][3]) +  |
357 | m.A[2][1] * (m.A[0][2] * m.A[1][3] - m.A[0][3] * m.A[1][2])  |
358 | );  |
359 | }  |
360 |   |
361 |   |
362 | bool tMath::tInvert(tMat4& m)  |
363 | {  |
364 | #if defined(PLATFORM_WINDOWS)  |
365 | if (tDeterminant(m) == 0.0f)  |
366 | return false;  |
367 |   |
368 | // Naming: m for minor. de for determinant. t0 for temporary. r for row.  |
369 | __m128 m1, m2, m3, m4, r1, r3, de;  |
370 | __m128 r2 = _mm_setzero_ps();  |
371 | __m128 r4 = _mm_setzero_ps();  |
372 | __m128 t0 = _mm_setzero_ps();  |
373 |   |
374 | // Cramer's rule used here (not Gaussian Elim).  |
375 | t0 = _mm_loadh_pi(_mm_loadl_pi(t0, (__m64*)(m.E+ 0)), (__m64*)(m.E+ 4));  |
376 | r2 = _mm_loadh_pi(_mm_loadl_pi(r2, (__m64*)(m.E+ 8)), (__m64*)(m.E+12));  |
377 | r1 = _mm_shuffle_ps(t0, r2, 0x88);  |
378 | r2 = _mm_shuffle_ps(r2, t0, 0xDD);  |
379 | t0 = _mm_loadh_pi(_mm_loadl_pi(t0, (__m64*)(m.E+ 2)), (__m64*)(m.E+ 6));  |
380 | r4 = _mm_loadh_pi(_mm_loadl_pi(r4, (__m64*)(m.E+10)), (__m64*)(m.E+14));  |
381 | r3 = _mm_shuffle_ps(t0, r4, 0x88);  |
382 | r4 = _mm_shuffle_ps(r4, t0, 0xDD);  |
383 | t0 = _mm_mul_ps(r3, r4);  |
384 | t0 = _mm_shuffle_ps(t0, t0, 0xB1);  |
385 | m1 = _mm_mul_ps(r2, t0);  |
386 | m2 = _mm_mul_ps(r1, t0);  |
387 | t0 = _mm_shuffle_ps(t0, t0, 0x4E);  |
388 | m1 = _mm_sub_ps(_mm_mul_ps(r2, t0), m1);  |
389 | m2 = _mm_sub_ps(_mm_mul_ps(r1, t0), m2);  |
390 | m2 = _mm_shuffle_ps(m2, m2, 0x4E);  |
391 | t0 = _mm_mul_ps(r2, r3);  |
392 | t0 = _mm_shuffle_ps(t0, t0, 0xB1);  |
393 | m1 = _mm_add_ps(_mm_mul_ps(r4, t0), m1);  |
394 | m4 = _mm_mul_ps(r1, t0);  |
395 | t0 = _mm_shuffle_ps(t0, t0, 0x4E);  |
396 | m1 = _mm_sub_ps(m1, _mm_mul_ps(r4, t0));  |
397 | m4 = _mm_sub_ps(_mm_mul_ps(r1, t0), m4);  |
398 | m4 = _mm_shuffle_ps(m4, m4, 0x4E);  |
399 | t0 = _mm_mul_ps(_mm_shuffle_ps(r2, r2, 0x4E), r4);  |
400 | t0 = _mm_shuffle_ps(t0, t0, 0xB1);  |
401 | r3 = _mm_shuffle_ps(r3, r3, 0x4E);  |
402 | m1 = _mm_add_ps(_mm_mul_ps(r3, t0), m1);  |
403 | m3 = _mm_mul_ps(r1, t0);  |
404 | t0 = _mm_shuffle_ps(t0, t0, 0x4E);  |
405 | m1 = _mm_sub_ps(m1, _mm_mul_ps(r3, t0));  |
406 | m3 = _mm_sub_ps(_mm_mul_ps(r1, t0), m3);  |
407 | m3 = _mm_shuffle_ps(m3, m3, 0x4E);  |
408 | t0 = _mm_mul_ps(r1, r2);  |
409 | t0 = _mm_shuffle_ps(t0, t0, 0xB1);  |
410 | m3 = _mm_add_ps(_mm_mul_ps(r4, t0), m3);  |
411 | m4 = _mm_sub_ps(_mm_mul_ps(r3, t0), m4);  |
412 | t0 = _mm_shuffle_ps(t0, t0, 0x4E);  |
413 | m3 = _mm_sub_ps(_mm_mul_ps(r4, t0), m3);  |
414 | m4 = _mm_sub_ps(m4, _mm_mul_ps(r3, t0));  |
415 | t0 = _mm_mul_ps(r1, r4);  |
416 | t0 = _mm_shuffle_ps(t0, t0, 0xB1);  |
417 | m2 = _mm_sub_ps(m2, _mm_mul_ps(r3, t0));  |
418 | m3 = _mm_add_ps(_mm_mul_ps(r2, t0), m3);  |
419 | t0 = _mm_shuffle_ps(t0, t0, 0x4E);  |
420 | m2 = _mm_add_ps(_mm_mul_ps(r3, t0), m2);  |
421 | m3 = _mm_sub_ps(m3, _mm_mul_ps(r2, t0));  |
422 | t0 = _mm_mul_ps(r1, r3);  |
423 | t0 = _mm_shuffle_ps(t0, t0, 0xB1);  |
424 | m2 = _mm_add_ps(_mm_mul_ps(r4, t0), m2);  |
425 | m4 = _mm_sub_ps(m4, _mm_mul_ps(r2, t0));  |
426 | t0 = _mm_shuffle_ps(t0, t0, 0x4E);  |
427 | m2 = _mm_sub_ps(m2, _mm_mul_ps(r4, t0));  |
428 | m4 = _mm_add_ps(_mm_mul_ps(r2, t0), m4);  |
429 | de = _mm_mul_ps(r1, m1);  |
430 | de = _mm_add_ps(_mm_shuffle_ps(de, de, 0x4E), de);  |
431 | de = _mm_add_ss(_mm_shuffle_ps(de, de, 0xB1), de);  |
432 | t0 = _mm_rcp_ss(de);  |
433 | de = _mm_sub_ss(_mm_add_ss(t0, t0), _mm_mul_ss(de, _mm_mul_ss(t0, t0)));  |
434 | de = _mm_shuffle_ps(de, de, 0x00);  |
435 | m1 = _mm_mul_ps(de, m1);  |
436 |   |
437 | // Assign the result.  |
438 | _mm_storel_pi((__m64*)(m.E+ 0), m1);  |
439 | _mm_storeh_pi((__m64*)(m.E+ 2), m1);  |
440 | m2 = _mm_mul_ps(de, m2);  |
441 | _mm_storel_pi((__m64*)(m.E+ 4), m2);  |
442 | _mm_storeh_pi((__m64*)(m.E+ 6), m2);  |
443 | m3 = _mm_mul_ps(de, m3);  |
444 | _mm_storel_pi((__m64*)(m.E+ 8), m3);  |
445 | _mm_storeh_pi((__m64*)(m.E+10), m3);  |
446 | m4 = _mm_mul_ps(de, m4);  |
447 | _mm_storel_pi((__m64*)(m.E+12), m4);  |
448 | _mm_storeh_pi((__m64*)(m.E+14), m4);  |
449 | return true;  |
450 |   |
451 | #else  |
452 | tMat4 s;  |
453 | tSet(s, m);  |
454 | return tInvert(m, s);  |
455 |   |
456 | #endif  |
457 | }  |
458 |   |
459 |   |
460 | bool tMath::tInvert(tMat4& d, const tMat4& s)  |
461 | {  |
462 | #if defined(PLATFORM_WINDOWS)  |
463 | tSet(d, s);  |
464 | return tInvert(d);  |
465 |   |
466 | #else  |
467 | tMat4 t;  |
468 | tTranspose(t, s);  |
469 | float prd[12];  |
470 |   |
471 | // Calculate intermediate products for the first set of 8 cofactors.  |
472 | prd[ 0] = t.E[10]*t.E[15]; prd[ 1] = t.E[11]*t.E[14]; prd[ 2] = t.E[ 9]*t.E[15]; prd[ 3] = t.E[11]*t.E[13];  |
473 | prd[ 4] = t.E[ 9]*t.E[14]; prd[ 5] = t.E[10]*t.E[13]; prd[ 6] = t.E[ 8]*t.E[15]; prd[ 7] = t.E[11]*t.E[12];  |
474 | prd[ 8] = t.E[ 8]*t.E[14]; prd[ 9] = t.E[10]*t.E[12]; prd[10] = t.E[ 8]*t.E[13]; prd[11] = t.E[ 9]*t.E[12];  |
475 |   |
476 | // Calculate first set of 8 cofactors.  |
477 | d.E[ 0] = (prd[ 0]*t.E[ 5] + prd[ 3]*t.E[ 6] + prd[ 4]*t.E[ 7]) - (prd[ 1]*t.E[ 5] + prd[ 2]*t.E[ 6] + prd[ 5]*t.E[ 7]);  |
478 | d.E[ 1] = (prd[ 1]*t.E[ 4] + prd[ 6]*t.E[ 6] + prd[ 9]*t.E[ 7]) - (prd[ 0]*t.E[ 4] + prd[ 7]*t.E[ 6] + prd[ 8]*t.E[ 7]);  |
479 | d.E[ 2] = (prd[ 2]*t.E[ 4] + prd[ 7]*t.E[ 5] + prd[10]*t.E[ 7]) - (prd[ 3]*t.E[ 4] + prd[ 6]*t.E[ 5] + prd[11]*t.E[ 7]);  |
480 | d.E[ 3] = (prd[ 5]*t.E[ 4] + prd[ 8]*t.E[ 5] + prd[11]*t.E[ 6]) - (prd[ 4]*t.E[ 4] + prd[ 9]*t.E[ 5] + prd[10]*t.E[ 6]);  |
481 | d.E[ 4] = (prd[ 1]*t.E[ 1] + prd[ 2]*t.E[ 2] + prd[ 5]*t.E[ 3]) - (prd[ 0]*t.E[ 1] + prd[ 3]*t.E[ 2] + prd[ 4]*t.E[ 3]);  |
482 | d.E[ 5] = (prd[ 0]*t.E[ 0] + prd[ 7]*t.E[ 2] + prd[ 8]*t.E[ 3]) - (prd[ 1]*t.E[ 0] + prd[ 6]*t.E[ 2] + prd[ 9]*t.E[ 3]);  |
483 | d.E[ 6] = (prd[ 3]*t.E[ 0] + prd[ 6]*t.E[ 1] + prd[11]*t.E[ 3]) - (prd[ 2]*t.E[ 0] + prd[ 7]*t.E[ 1] + prd[10]*t.E[ 3]);  |
484 | d.E[ 7] = (prd[ 4]*t.E[ 0] + prd[ 9]*t.E[ 1] + prd[10]*t.E[ 2]) - (prd[ 5]*t.E[ 0] + prd[ 8]*t.E[ 1] + prd[11]*t.E[ 2]);  |
485 |   |
486 | // Calculate intermediate products for the second set of 8 cofactors.  |
487 | prd[ 0] = t.E[ 2]*t.E[ 7]; prd[ 1] = t.E[ 3]*t.E[ 6]; prd[ 2] = t.E[ 1]*t.E[ 7]; prd[ 3] = t.E[ 3]*t.E[ 5];  |
488 | prd[ 4] = t.E[ 1]*t.E[ 6]; prd[ 5] = t.E[ 2]*t.E[ 5]; prd[ 6] = t.E[ 0]*t.E[ 7]; prd[ 7] = t.E[ 3]*t.E[ 4];  |
489 | prd[ 8] = t.E[ 0]*t.E[ 6]; prd[ 9] = t.E[ 2]*t.E[ 4]; prd[10] = t.E[ 0]*t.E[ 5]; prd[11] = t.E[ 1]*t.E[ 4];  |
490 |   |
491 | // Calculate second set of 8 cofactors.  |
492 | d.E[ 8] = (prd[ 0]*t.E[13] + prd[ 3]*t.E[14] + prd[ 4]*t.E[15]) - (prd[ 1]*t.E[13] + prd[ 2]*t.E[14] + prd[ 5]*t.E[15]);  |
493 | d.E[ 9] = (prd[ 1]*t.E[12] + prd[ 6]*t.E[14] + prd[ 9]*t.E[15]) - (prd[ 0]*t.E[12] + prd[ 7]*t.E[14] + prd[ 8]*t.E[15]);  |
494 | d.E[10] = (prd[ 2]*t.E[12] + prd[ 7]*t.E[13] + prd[10]*t.E[15]) - (prd[ 3]*t.E[12] + prd[ 6]*t.E[13] + prd[11]*t.E[15]);  |
495 | d.E[11] = (prd[ 5]*t.E[12] + prd[ 8]*t.E[13] + prd[11]*t.E[14]) - (prd[ 4]*t.E[12] + prd[ 9]*t.E[13] + prd[10]*t.E[14]);  |
496 | d.E[12] = (prd[ 2]*t.E[10] + prd[ 5]*t.E[11] + prd[ 1]*t.E[ 9]) - (prd[ 4]*t.E[11] + prd[ 0]*t.E[ 9] + prd[ 3]*t.E[10]);  |
497 | d.E[13] = (prd[ 8]*t.E[11] + prd[ 0]*t.E[ 8] + prd[ 7]*t.E[10]) - (prd[ 6]*t.E[10] + prd[ 9]*t.E[11] + prd[ 1]*t.E[ 8]);  |
498 | d.E[14] = (prd[ 6]*t.E[ 9] + prd[11]*t.E[11] + prd[ 3]*t.E[ 8]) - (prd[10]*t.E[11] + prd[ 2]*t.E[ 8] + prd[ 7]*t.E[ 9]);  |
499 | d.E[15] = (prd[10]*t.E[10] + prd[ 4]*t.E[ 8] + prd[ 9]*t.E[ 9]) - (prd[ 8]*t.E[ 9] + prd[11]*t.E[10] + prd[ 5]*t.E[ 8]);  |
500 |   |
501 | // Calculate determinant.  |
502 | float det = t.E[0]*d.E[0] + t.E[1]*d.E[1] + t.E[2]*d.E[2] + t.E[3]*d.E[3];  |
503 | if (det == 0.0f)  |
504 | return false;  |
505 |   |
506 | // Calculate inverse by multiplying by reciprocal of determinant.  |
507 | tDiv(d, det);  |
508 | #endif  |
509 |   |
510 | return true;  |
511 | }  |
512 |   |
513 |   |
514 | void tMath::tInvertAffine(tMat4& d, const tMat4& m)  |
515 | {  |
516 | // Let A be a 4x4 affine matrix where R is a 3x3 orthonormal matrix (the rotation part), T is the 3x1 translation,  |
517 | // and the row 4 of A is U, where U = [ 0 0 0 1 ].  |
518 | // A = [ R T ]  |
519 | // [ U ]  |
520 | //  |
521 | // then the inverse is given by  |
522 | // Inv(A) = [ Inv(R) -Inv(R)*T ]  |
523 | // [ U ]  |
524 | d.a11 = m.a11; d.a21 = m.a12; d.a31 = m.a13;  |
525 | d.a12 = m.a21; d.a22 = m.a22; d.a32 = m.a23;  |
526 | d.a13 = m.a31; d.a23 = m.a32; d.a33 = m.a33;  |
527 |   |
528 | d.C4.x = -m.C1.x*m.C4.x + -m.C1.y*m.C4.y + -m.C1.z*m.C4.z;  |
529 | d.C4.y = -m.C2.x*m.C4.x + -m.C2.y*m.C4.y + -m.C2.z*m.C4.z;  |
530 | d.C4.z = -m.C3.x*m.C4.x + -m.C3.y*m.C4.y + -m.C3.z*m.C4.z;  |
531 | }  |
532 |   |
533 |   |
534 | void tMath::tMakeLookAt(tMat4& d, const tVec3& eye, const tVec3& look, const tVec3& up)  |
535 | {  |
536 | tVec3 z;  |
537 | tSub(z, eye, look);  |
538 | tNormalize(z);  |
539 |   |
540 | tVec3 y(up);  |
541 | tVec3 x;  |
542 | tCross(x, y, z);  |
543 | tCross(y, z, x);  |
544 |   |
545 | tNormalize(x);  |
546 | tNormalize(y);  |
547 |   |
548 | tSet(d.C1, x.x, y.x, z.x, 0.0f);  |
549 | tSet(d.C2, x.y, y.y, z.y, 0.0f);  |
550 | tSet(d.C3, x.z, y.z, z.z, 0.0f);  |
551 | tSet(d.C4, 0.0f, 0.0f, 0.0f, 1.0f);  |
552 |   |
553 | tVec3 neg;  |
554 | tNeg(neg, eye);  |
555 | d.E[12] = d.E[0]*neg.x + d.E[4]*neg.y + d.E[ 8]*neg.z;  |
556 | d.E[13] = d.E[1]*neg.x + d.E[5]*neg.y + d.E[ 9]*neg.z;  |
557 | d.E[14] = d.E[2]*neg.x + d.E[6]*neg.y + d.E[10]*neg.z;  |
558 | }  |
559 |   |
560 |   |
561 | void tMath::tMakeRotate(tMat4& d, const tVec3& axis, float angle)  |
562 | {  |
563 | float t = tLengthSq(axis);  |
564 | if (t < 0.00001f)  |
565 | {  |
566 | tIdentity(d);  |
567 | return;  |
568 | }  |
569 |   |
570 | float x = axis.x;  |
571 | float y = axis.y;  |
572 | float z = axis.z;  |
573 | float s = tSin(angle);  |
574 | float c = tCos(angle);  |
575 |   |
576 | t = tRecipSqrtFast(t);  |
577 | x *= t; y *= t; z *= t;  |
578 | float xx = x*x; float yy = y*y; float zz = z*z;  |
579 | float xy = x*y; float yz = y*z; float zx = z*x;  |
580 | float xs = x*s; float ys = y*s; float zs = z*s;  |
581 | float rc = 1.0f - c;  |
582 |   |
583 | // Again, this is correct, even though at first it looks like the transpose.  |
584 | // It is being filled out in column major order for efficiency.  |
585 | d.a11 = rc*xx + c; d.a21 = rc*xy + zs; d.a31 = rc*zx - ys; d.a41 = 0.0f;  |
586 | d.a12 = rc*xy - zs; d.a22 = rc*yy + c; d.a32 = rc*yz + xs; d.a42 = 0.0f;  |
587 | d.a13 = rc*zx + ys; d.a23 = rc*yz - xs; d.a33 = rc*zz + c; d.a43 = 0.0f;  |
588 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
589 | }  |
590 |   |
591 |   |
592 | void tMath::tMakeRotate(tMat4& d, const tVec3& a, const tVec3& b)  |
593 | {  |
594 | // Based on "Efficiently building a matrix to rotate one vector to another vector", by Thomas Möller and John F.  |
595 | // Hughes, Journal of Graphics Tools, Vol 4, No 4, 1999. The method is also described in "Real-Time Rendering", by  |
596 | // Akenine-Möller and Haines, 2nd Edition, Section 3.3.2.  |
597 | float e = tDot(a, b);  |
598 | tVec3 v; tCross(v, a, b);  |
599 |   |
600 | if (tLength(v) < Epsilon) // Parallel?  |
601 | {  |
602 | if (e > 0.0f) // Aligned?  |
603 | {  |
604 | tIdentity(d);  |
605 | return;  |
606 | }  |
607 | else if (e < 0.0f)  |
608 | {  |
609 | // Rotate by Pi radians around an axis perpendicular to a.  |
610 | float smallest = tMin(a.x, a.y, a.z);  |
611 |   |
612 | // Make vector u perpendicular to a.  |
613 | tVec3 u;  |
614 | if (a.x == smallest)  |
615 | tSet(u, 0.0f, -a.z, a.y);  |
616 | else if (a.y == smallest)  |
617 | tSet(u, -a.z, 0.0f, a.x);  |
618 | else  |
619 | tSet(u, -a.y, a.z, 0.0f);  |
620 |   |
621 | tMakeRotate(d, u, Pi);  |
622 | }  |
623 | }  |
624 |   |
625 | // Not parallel to each other.  |
626 | float h = (1.0f - e) / tDot(v, v);  |
627 | d.a11 = e + h*v.x*v.x; d.a21 = h * v.x*v.y + v.z; d.a31 = h*v.x*v.z - v.y; d.a41 = 0.0f;  |
628 | d.a12 = h*v.x*v.y - v.z; d.a22 = e + h*v.y*v.y; d.a32 = h*v.y*v.z + v.x; d.a42 = 0.0f;  |
629 | d.a13 = h*v.x*v.z + v.y; d.a23 = h*v.y*v.z - v.x; d.a33 = e + h*v.z*v.z; d.a43 = 0.0f;  |
630 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
631 | }  |
632 |   |
633 |   |
634 | void tMath::tMakeRotateXYZ(tMat4& d, float a, float b, float c)  |
635 | {  |
636 | // An excellent reference can be found here: http://www.songho.ca/opengl/gl_anglestoaxes.html  |
637 | float ca = tCos(a); float sa = tSin(a);  |
638 | float cb = tCos(b); float sb = tSin(b);  |
639 | float cc = tCos(c); float sc = tSin(c);  |
640 |   |
641 | // For all these, cos is written before sin, and secondarily, a before b before c.  |
642 | d.a11 = cb*cc; d.a21 = cb*sc; d.a31 = -sb; d.a41 = 0.0f;  |
643 | d.a12 = cc*sa*sb - sc*ca; d.a22 = ca*cc + sa*sb*sc; d.a32 = cb*sa; d.a42 = 0.0f;  |
644 | d.a13 = sa*sc + ca*cc*sb; d.a23 = ca*sb*sc - cc*sa; d.a33 = ca*cb; d.a43 = 0.0f;  |
645 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
646 | }  |
647 |   |
648 |   |
649 | void tMath::tMakeRotateYZX(tMat4& d, float a, float b, float c)  |
650 | {  |
651 | float ca = tCos(a); float sa = tSin(a);  |
652 | float cb = tCos(b); float sb = tSin(b);  |
653 | float cc = tCos(c); float sc = tSin(c);  |
654 |   |
655 | d.a11 = cb*cc; d.a21 = ca*cb*sc + sa*sb; d.a31 = cb*sa*sc - ca*sb; d.a41 = 0.0f;  |
656 | d.a12 = -sc; d.a22 = ca*cc; d.a32 = cc*sa; d.a42 = 0.0f;  |
657 | d.a13 = cc*sb; d.a23 = ca*sb*sc - cb*sa; d.a33 = sa*sb*sc + ca*cb; d.a43 = 0.0f;  |
658 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
659 | }  |
660 |   |
661 |   |
662 | void tMath::tMakeRotateZXY(tMat4& d, float a, float b, float c)  |
663 | {  |
664 | float ca = tCos(a); float sa = tSin(a);  |
665 | float cb = tCos(b); float sb = tSin(b);  |
666 | float cc = tCos(c); float sc = tSin(c);  |
667 |   |
668 | d.a11 = cb*cc + sa*sb*sc; d.a21 = ca*sc; d.a31 = cb*sa*sc - cc*sb; d.a41 = 0.0f;  |
669 | d.a12 = cc*sa*sb - cb*sc; d.a22 = ca*cc; d.a32 = sb*sc + cb*cc*sa; d.a42 = 0.0f;  |
670 | d.a13 = ca*sb; d.a23 = -sa; d.a33 = ca*cb; d.a43 = 0.0f;  |
671 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
672 | }  |
673 |   |
674 |   |
675 | void tMath::tMakeRotateZYX(tMat4& d, float a, float b, float c)  |
676 | {  |
677 | float ca = tCos(a); float sa = tSin(a);  |
678 | float cb = tCos(b); float sb = tSin(b);  |
679 | float cc = tCos(c); float sc = tSin(c);  |
680 |   |
681 | d.a11 = cb*cc; d.a21 = cc*sa*sb + ca*sc; d.a31 = sa*sc - ca*cc*sb; d.a41 = 0.0f;  |
682 | d.a12 = -cb*sc; d.a22 = ca*cc - sa*sb*sc; d.a32 = ca*sb*sc + cc*sa; d.a42 = 0.0f;  |
683 | d.a13 = sb; d.a23 = -cb*sa; d.a33 = ca*cb; d.a43 = 0.0f;  |
684 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
685 | }  |
686 |   |
687 |   |
688 | void tMath::tMakeRotateXZY(tMat4& d, float a, float b, float c)  |
689 | {  |
690 | float ca = tCos(a); float sa = tSin(a);  |
691 | float cb = tCos(b); float sb = tSin(b);  |
692 | float cc = tCos(c); float sc = tSin(c);  |
693 |   |
694 | // Note there is (was?) a typo for a12 at the site: http://www.songho.ca/opengl/gl_anglestoaxes.html  |
695 | // I posted a correction. It may or may not have been updated. In any case, a12 is correct below.  |
696 | d.a11 = cb*cc; d.a21 = sc; d.a31 = -cc*sb; d.a41 = 0.0f;  |
697 | d.a12 = sa*sb - ca*cb*sc; d.a22 = ca*cc; d.a32 = ca*sb*sc + cb*sa; d.a42 = 0.0f;  |
698 | d.a13 = cb*sa*sc + ca*sb; d.a23 = -cc*sa; d.a33 = ca*cb - sa*sb*sc; d.a43 = 0.0f;  |
699 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
700 | }  |
701 |   |
702 |   |
703 | void tMath::tMakeRotateYXZ(tMat4& d, float a, float b, float c)  |
704 | {  |
705 | float ca = tCos(a); float sa = tSin(a);  |
706 | float cb = tCos(b); float sb = tSin(b);  |
707 | float cc = tCos(c); float sc = tSin(c);  |
708 |   |
709 | d.a11 = cb*cc - sa*sb*sc; d.a21 = cb*sc + cc*sa*sb; d.a31 = -ca*sb; d.a41 = 0.0f;  |
710 | d.a12 = -ca*sc; d.a22 = ca*cc; d.a32 = sa; d.a42 = 0.0f;  |
711 | d.a13 = cc*sb + cb*sa*sc; d.a23 = sb*sc - cb*cc*sa; d.a33 = ca*cb; d.a43 = 0.0f;  |
712 | d.a14 = 0.0f; d.a24 = 0.0f; d.a34 = 0.0f; d.a44 = 1.0f;  |
713 | }  |
714 |   |
715 |   |
716 | void tMath::tMakeProjPersp(tMat4& d, float left, float right, float bottom, float top, float near, float far)  |
717 | {  |
718 | // Generates: 2n/(r-l) 0 (r+l)/(r-l) 0   |
719 | // 0 2n/(t-b) (t+b)/(t-b) 0  |
720 | // 0 0 -(f+n)/(f-n) -2fn/(f-n)  |
721 | // 0 0 -1 0  |
722 | tZero(d);  |
723 | float lr = right-left; float bt = top-bottom;  |
724 | float nf = far-near; float n2 = 2.0f*near;  |
725 |   |
726 | d.a11 = n2 / lr;  |
727 | d.a22 = n2 / bt;  |
728 | d.a13 = (right+left) / lr;  |
729 | d.a23 = (top+bottom) / bt;  |
730 | d.a33 = -(far+near) / nf;  |
731 | d.a43 = -1.0f;  |
732 | d.a34 = -n2*far / nf;  |
733 | }  |
734 |   |
735 |   |
736 | void tMath::tMakeProjPersp(tMat4& d, const tVec3& boxMin, const tVec3& boxMax)  |
737 | {  |
738 | float left = boxMin.x;  |
739 | float right = boxMax.x;  |
740 | float bottom = boxMin.y;  |
741 | float top = boxMax.y;  |
742 | float nearPlane = -boxMax.z;  |
743 | float farPlane = -boxMin.z;  |
744 | tMakeProjPersp(d, left, right, bottom, top, nearPlane, farPlane);  |
745 | }  |
746 |   |
747 |   |
748 | void tMath::tMakeProjPerspSym(tMat4& d, float right, float top, float nearPlane, float farPlane)  |
749 | {  |
750 | // Symmetry allows a faster implementation since left = -right and bottom = -top.  |
751 | // Generates: n/r 0 0 0   |
752 | // 0 n/t 0 0  |
753 | // 0 0 -(f+n)/(f-n) -2fn/(f-n)  |
754 | // 0 0 -1 0  |
755 | tZero(d);  |
756 | d.a11 = nearPlane/right;  |
757 | d.a22 = nearPlane/top;  |
758 | d.a33 = -(farPlane+nearPlane)/(farPlane-nearPlane);  |
759 | d.a34 = -2.0f*farPlane*nearPlane/(farPlane-nearPlane);  |
760 | d.a43 = -1.0f;  |
761 | }  |
762 |   |
763 |   |
764 | void tMath::tMakeProjPerspSymFovV(tMat4& d, float fovX, float aspect, float nearPlane, float farPlane)  |
765 | {  |
766 | tAssert(aspect > 0.0f);  |
767 | float top = nearPlane*tTan(fovX/2.0f);  |
768 | float right = top*aspect;  |
769 | tMakeProjPerspSym(d, right, top, nearPlane, farPlane);  |
770 | }  |
771 |   |
772 |   |
773 | void tMath::tMakeProjPerspSymFovH(tMat4& d, float fovY, float aspect, float nearPlane, float farPlane)  |
774 | {  |
775 | tAssert(aspect > 0.0f);  |
776 | float right = nearPlane*tTan(fovY/2.0f);  |
777 | float top = right/aspect;  |
778 | tMakeProjPerspSym(d, right, top, nearPlane, farPlane);  |
779 | }  |
780 |   |
781 |   |
782 | void tMath::tMakeProjPerspOffset(tMat4& d, float right, float top, float nearPlane, float farPlane, float offsetX, float offsetY)  |
783 | {  |
784 | float offsetH = -offsetX*right;  |
785 | float offsetV = -offsetY*top;  |
786 | tMakeProjPersp(d, offsetH-right, offsetH+right, offsetV-top, offsetV+top, nearPlane, farPlane);  |
787 | }  |
788 |   |
789 |   |
790 | void tMath::tMakeProjPerspFovVOffset(tMat4& d, float fovX, float aspect, float nearPlane, float farPlane, float offsetX, float offsetY)  |
791 | {  |
792 | tAssert(aspect > 0.0f);  |
793 | float top = nearPlane*tTan(fovX/2.0f);  |
794 | float right = top*aspect;  |
795 |   |
796 | float offsetH = -offsetX*right;  |
797 | float offsetV = -offsetY*top;  |
798 | tMakeProjPersp(d, offsetH-right, offsetH+right, offsetV-top, offsetV+top, nearPlane, farPlane);  |
799 | }  |
800 |   |
801 |   |
802 | void tMath::tMakeProjPerspFovHOffset(tMat4& d, float fovY, float aspect, float nearPlane, float farPlane, float offsetX, float offsetY)  |
803 | {  |
804 | tAssert(aspect > 0.0f);  |
805 | float right = nearPlane*tTan(fovY/2.0f);  |
806 | float top = right/aspect;  |
807 |   |
808 | float offsetH = -offsetX*right;  |
809 | float offsetV = -offsetY*top;  |
810 | tMakeProjPersp(d, offsetH-right, offsetH+right, offsetV-top, offsetV+top, nearPlane, farPlane);  |
811 | }  |
812 |   |
813 |   |
814 | void tMath::tMakeProjParallel(tMat4& d, const tVec3& boxMin, const tVec3& boxMax)  |
815 | {  |
816 | tZero(d);  |
817 | d.a11 = 2.0f / (boxMax.x-boxMin.x);  |
818 | d.a14 = -(boxMax.x+boxMin.x) / (boxMax.x-boxMin.x);  |
819 | d.a22 = 2.0f / (boxMax.y-boxMin.y);  |
820 | d.a24 = -(boxMax.y+boxMin.y) / (boxMax.y-boxMin.y);  |
821 | d.a33 = -2.0f / (boxMax.z-boxMin.z);  |
822 | d.a34 = -(boxMax.z+boxMin.z) / (boxMax.z-boxMin.z);  |
823 | d.a44 = 1.0f;  |
824 | }  |
825 |   |
826 |   |
827 | void tMath::tMakeOrthoNormal(tMat4& m)  |
828 | {  |
829 | tVec3 c1;  |
830 | tSet(c1, m.C1);  |
831 | tNormalize(c1);  |
832 |   |
833 | tVec3 t2;  |
834 | tSet(t2, m.C2);  |
835 |   |
836 | tVec3 c3;  |
837 | tCross(c3, c1, t2);  |
838 | tNormalize(c3);  |
839 |   |
840 | tVec3 c2;  |
841 | tCross(c2, c3, c1);  |
842 |   |
843 | tSet(m.C1, c1);  |
844 | tSet(m.C2, c2);  |
845 | tSet(m.C3, c3);  |
846 |   |
847 | m.C1.w = m.C2.w = m.C3.w = 0.0f; m.C4.w = 1.0f;  |
848 | }  |
849 |   |
850 |   |
851 | void tMath::tMakeOrthoUniform(tMat4& m)  |
852 | {  |
853 | tVec3 c1;  |
854 | tSet(c1, m.C1);  |
855 | float scale = tLength(c1); // We use the length of the first column for all columns.  |
856 |   |
857 | tVec3 c2;  |
858 | tSet(c2, m.C2);  |
859 |   |
860 | tVec3 c3;  |
861 | tCross(c3, c1, c2);  |
862 | tNormalizeScale(c3, scale);  |
863 | tCross(c2, c3, c1);  |
864 | tNormalizeScale(c2, scale);  |
865 |   |
866 | tSet(m.C2, c2);  |
867 | tSet(m.C3, c3);  |
868 | m.C1.w = m.C2.w = m.C3.w = 0.0f; m.C4.w = 1.0f;  |
869 | }  |
870 |   |
871 |   |
872 | void tMath::tMakeOrthoNonUniform(tMat4& m)  |
873 | {  |
874 | tVec3 c1;  |
875 | tSet(c1, m.C1);  |
876 |   |
877 | tVec3 c2;  |
878 | tSet(c2, m.C2);  |
879 | float scale2 = tLength(c2);  |
880 |   |
881 | m.C3.w = 0.0f;  |
882 | float scale3 = tLength(m.C3);  |
883 |   |
884 | tVec3 c3;  |
885 | tCross(c3, c1, c2);  |
886 | tNormalizeScale(c3, scale3);  |
887 |   |
888 | tCross(c2, c3, c1);  |
889 | tNormalizeScale(c2, scale2);  |
890 |   |
891 | tSet(m.C2, c2);  |
892 | tSet(m.C3, c3);  |
893 | m.C1.w = m.C2.w = 0.0f; m.C4.w = 1.0f;  |
894 | }  |
895 |   |
896 |   |
897 | void tMath::(tVec4 planes[6], const tMat4& m, bool outwardNormals, bool normalizePlanes)  |
898 | {  |
899 | // Order is: Right, Left, Top, Bottom, Near, Far.  |
900 | tSet(planes[0], m.C1.d - m.C1.a, m.C2.d - m.C2.a, m.C3.d - m.C3.a, m.C4.d - m.C4.a );  |
901 | tSet(planes[1], m.C1.d + m.C1.a, m.C2.d + m.C2.a, m.C3.d + m.C3.a, m.C4.d + m.C4.a );  |
902 | tSet(planes[2], m.C1.d - m.C1.b, m.C2.d - m.C2.b, m.C3.d - m.C3.b, m.C4.d - m.C4.b );  |
903 | tSet(planes[3], m.C1.d + m.C1.b, m.C2.d + m.C2.b, m.C3.d + m.C3.b, m.C4.d + m.C4.b );  |
904 | tSet(planes[4], m.C1.d + m.C1.c, m.C2.d + m.C2.c, m.C3.d + m.C3.c, m.C4.d + m.C4.c );  |
905 | tSet(planes[5], m.C1.d - m.C1.c, m.C2.d - m.C2.c, m.C3.d - m.C3.c, m.C4.d - m.C4.c );  |
906 |   |
907 | if (outwardNormals)  |
908 | {  |
909 | for (int p = 0; p < 6; p++)  |
910 | tNeg(planes[p]);  |
911 | }  |
912 |   |
913 | if (normalizePlanes)  |
914 | {  |
915 | for (int p = 0; p < 6; p++)  |
916 | {  |
917 | tVec3 point;  |
918 | tSet(point, planes[p]);  |
919 | float length = tNormalizeGetLength(point);  |
920 | tDiv(planes[p], length);  |
921 | }  |
922 | }  |
923 | }  |
924 |   |
925 |   |
926 | bool tMath::  |
927 | (  |
928 | tVec3& sol1, tVec3& sol2, const tMat4& rot,  |
929 | float gimbalZ, tIntervalBias bias  |
930 | )  |
931 | {  |
932 | // Extraction based on http://staff.city.ac.uk/~sbbh653/publications/euler.pdf  |
933 | float gimbalEpsilon = 0.000001f;  |
934 | bool gimbalNeg = tApproxEqual(rot.a31, -1.0f, gimbalEpsilon);  |
935 | bool gimbalPos = tApproxEqual(rot.a31, 1.0f, gimbalEpsilon);  |
936 | if (!gimbalNeg && !gimbalPos)  |
937 | {  |
938 | sol1.y = -tArcSin(rot.a31); // [-Pi/2, Pi/2]  |
939 | sol2.y = tNormalizedAngle( Pi - sol1.y, bias );  |
940 |   |
941 | float ct1 = tCos(sol1.y); // Cos(theta1)  |
942 | float ct2 = tCos(sol2.y); // Cos(theta2)  |
943 | sol1.x = tNormalizedAngle( tArcTan(rot.a32/ct1, rot.a33/ct1), bias );  |
944 | sol2.x = tNormalizedAngle( tArcTan(rot.a32/ct2, rot.a33/ct2), bias );  |
945 | sol1.z = tNormalizedAngle( tArcTan(rot.a21/ct1, rot.a11/ct1), bias );  |
946 | sol2.z = tNormalizedAngle( tArcTan(rot.a21/ct2, rot.a11/ct2), bias );  |
947 | }  |
948 | else  |
949 | {  |
950 | // User choice of particular solution returned.  |
951 | sol1.z = gimbalZ;  |
952 | if (gimbalNeg)  |
953 | {  |
954 | sol1.y = PiOver2;  |
955 | sol1.x = tNormalizedAngle(sol1.z + tArcTan(rot.a12, rot.a13), bias);  |
956 | }  |
957 | else  |
958 | {  |
959 | sol1.y = -PiOver2;  |
960 | sol1.x = tNormalizedAngle(-sol1.z + tArcTan(-rot.a12, -rot.a13), bias);  |
961 | }  |
962 | sol2 = sol1;  |
963 | }  |
964 |   |
965 | return gimbalNeg || gimbalPos;  |
966 | }  |
967 |   |
968 |   |
969 | bool tMath::(tVec3& sol1, tVec3& sol2, const tMat4& affine, float gimbalZ, tIntervalBias bias)  |
970 | {  |
971 | tMat4 r; tSet(r, affine);  |
972 | tNormalize(r.C1);  |
973 | tNormalize(r.C2);  |
974 | tNormalize(r.C3);  |
975 | return tExtractRotationEulerXYZ(sol1, sol2, r, gimbalZ, bias);  |
976 | }  |
977 |   |
978 |   |
979 | bool tMath::tApproachAngle(float& angle, float dest, float rate, float dt)  |
980 | {  |
981 | float diff = dest - angle;  |
982 | while (diff > Pi)  |
983 | diff -= TwoPi;  |
984 |   |
985 | while (diff < -Pi)  |
986 | diff += TwoPi;  |
987 |   |
988 | float delta = rate*dt;  |
989 | if (tAbs(diff) <= delta)  |
990 | {  |
991 | angle = dest;  |
992 | return true;  |
993 | }  |
994 |   |
995 | angle += tSign(diff)*delta;  |
996 | return false;  |
997 | }  |
998 |   |
999 |   |
1000 | bool tMath::tApproachOrientation(tQuat& curr, const tQuat& dest, float rate, float dt)  |
1001 | {  |
1002 | // Here is the quaternion that will rotate from curr to dest. q' = q1^-1 * q2.  |
1003 | tQuat rot;  |
1004 | tConjugate(rot, curr);  |
1005 | tMul(rot, dest);  |
1006 |   |
1007 | // Angle is in [0,Pi]. It will be unit length.  |
1008 | float angle;  |
1009 | tVec3 axis;  |
1010 | tGet(axis, angle, rot);  |
1011 | if (angle <= (rate*dt))  |
1012 | {  |
1013 | curr = dest;  |
1014 | return true;  |
1015 | }  |
1016 |   |
1017 | tQuat diff;  |
1018 | tSet(diff, axis, rate*dt);  |
1019 | tMul(curr, diff);  |
1020 | tNormalize(curr);  |
1021 | return false;  |
1022 | }  |
1023 | |