Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOMatrix.m
Go to the documentation of this file.
1/*
2
3OOMatrix.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25
26#include "OOMaths.h"
27#if OOMATHS_OPENGL_INTEGRATION
29#endif
30
31const OOMatrix kIdentityMatrix =
32 { .m = {
33 {1.0f, 0.0f, 0.0f, 0.0f},
34 {0.0f, 1.0f, 0.0f, 0.0f},
35 {0.0f, 0.0f, 1.0f, 0.0f},
36 {0.0f, 0.0f, 0.0f, 1.0f}
37 }};
38const OOMatrix kZeroMatrix = { .m = {
39 {0.0f, 0.0f, 0.0f, 0.0f},
40 {0.0f, 0.0f, 0.0f, 0.0f},
41 {0.0f, 0.0f, 0.0f, 0.0f},
42 {0.0f, 0.0f, 0.0f, 0.0f},
43 }};
44
45
46OOMatrix OOMatrixForRotation(Vector axis, OOScalar angle)
47{
48 axis = vector_normal(axis);
49
50 OOScalar x = axis.x, y = axis.y, z = axis.z;
51 OOScalar s = sin(angle), c = cos(angle);
52 OOScalar t = 1.0f - c;
53
54 // Lots of opportunity for common subexpression elimintation here, but I'll leave it to the compiler for now.
55 return OOMatrixConstruct
56 (
57 t * x * x + c, t * x * y + s * z, t * x * z - s * y, 0.0f,
58 t * x * y - s * z, t * y * y + c, t * y * z + s * x, 0.0f,
59 t * x * y + s * y, t * y * z - s * x, t * z * z + c, 0.0f,
60 0.0f, 0.0f, 0.0f, 1.0f
61 );
62}
63
64
65OOMatrix OOMatrixForQuaternionRotation(Quaternion orientation)
66{
67 OOScalar w, wz, wy, wx;
68 OOScalar x, xz, xy, xx;
69 OOScalar y, yz, yy;
70 OOScalar z, zz;
71
72 Quaternion q = orientation;
73 quaternion_normalize(&q);
74
75 w = q.w;
76 z = q.z;
77 y = q.y;
78 x = q.x;
79
80 xx = 2.0f * x; yy = 2.0f * y; zz = 2.0f * z;
81 wx = w * xx; wy = w * yy; wz = w * zz;
82 xx = x * xx; xy = x * yy; xz = x * zz;
83 yy = y * yy; yz = y * zz;
84 zz = z * zz;
85
86 return OOMatrixConstruct
87 (
88 1.0f - yy - zz, xy - wz, xz + wy, 0.0f,
89 xy + wz, 1.0f - xx - zz, yz - wx, 0.0f,
90 xz - wy, yz + wx, 1.0f - xx - yy, 0.0f,
91 0.0f, 0.0f, 0.0f, 1.0f
92 );
93}
94
95
96bool OOMatrixEqual(OOMatrix a, OOMatrix b)
97{
98 OOScalar *ma = &a.m[0][0];
99 OOScalar *mb = &b.m[0][0];
100
101 unsigned i;
102 for (i = 0; i < 16; i++)
103 {
104 if (*ma++ != *mb++) return false;
105 }
106
107 return true;
108}
109
110
111OOMatrix OOMatrixMultiply(OOMatrix a, OOMatrix b)
112{
113 unsigned i = 0;
114 OOMatrix r;
115
116 // This is amenable to significant optimization with Altivec, and presumably also SSE.
117 for (i = 0; i != 4; ++i)
118 {
119 r.m[i][0] = a.m[i][0] * b.m[0][0] + a.m[i][1] * b.m[1][0] + a.m[i][2] * b.m[2][0] + a.m[i][3] * b.m[3][0];
120 r.m[i][1] = a.m[i][0] * b.m[0][1] + a.m[i][1] * b.m[1][1] + a.m[i][2] * b.m[2][1] + a.m[i][3] * b.m[3][1];
121 r.m[i][2] = a.m[i][0] * b.m[0][2] + a.m[i][1] * b.m[1][2] + a.m[i][2] * b.m[2][2] + a.m[i][3] * b.m[3][2];
122 r.m[i][3] = a.m[i][0] * b.m[0][3] + a.m[i][1] * b.m[1][3] + a.m[i][2] * b.m[2][3] + a.m[i][3] * b.m[3][3];
123 }
124
125 return r;
126}
127
128
129Vector OOVectorMultiplyMatrix(Vector v, OOMatrix m)
130{
131 OOScalar x, y, z, w;
132
133 x = m.m[0][0] * v.x + m.m[1][0] * v.y + m.m[2][0] * v.z + m.m[3][0];
134 y = m.m[0][1] * v.x + m.m[1][1] * v.y + m.m[2][1] * v.z + m.m[3][1];
135 z = m.m[0][2] * v.x + m.m[1][2] * v.y + m.m[2][2] * v.z + m.m[3][2];
136 w = m.m[0][3] * v.x + m.m[1][3] * v.y + m.m[2][3] * v.z + m.m[3][3];
137
138 w = 1.0f/w;
139 return make_vector(x * w, y * w, z * w);
140}
141
142// HPVect: this loses precision because the matrix is single-precision
143// Best used for rotation matrices only - use HPvector_add for
144// translations of vectors if possible
145HPVector OOHPVectorMultiplyMatrix(HPVector v, OOMatrix m)
146{
147 OOScalar x, y, z, w;
148
149 x = m.m[0][0] * v.x + m.m[1][0] * v.y + m.m[2][0] * v.z + m.m[3][0];
150 y = m.m[0][1] * v.x + m.m[1][1] * v.y + m.m[2][1] * v.z + m.m[3][1];
151 z = m.m[0][2] * v.x + m.m[1][2] * v.y + m.m[2][2] * v.z + m.m[3][2];
152 w = m.m[0][3] * v.x + m.m[1][3] * v.y + m.m[2][3] * v.z + m.m[3][3];
153
154 w = 1.0f/w;
155 return make_HPvector(x * w, y * w, z * w);
156}
157
158
159OOMatrix OOMatrixOrthogonalize(OOMatrix m)
160{
161 // Simple orthogonalization: make everything orthogonal to everything else.
162
163 Vector i;// = { m.m[0][0], m.m[1][0], m.m[2][0] }; // Overwritten without being used
164 Vector j = { m.m[0][1], m.m[1][1], m.m[2][1] };
165 Vector k = { m.m[0][2], m.m[1][2], m.m[2][2] };
166
167 k = vector_normal(k);
168 i = vector_normal(cross_product(j, k));
169 j = cross_product(k, i);
170
171 m.m[0][0] = i.x; m.m[1][0] = i.y; m.m[2][0] = i.z;
172 m.m[0][1] = j.x; m.m[1][1] = j.y; m.m[2][1] = j.z;
173 m.m[0][2] = k.x; m.m[1][2] = k.y; m.m[2][2] = k.z;
174
175 return m;
176}
177
178
179#if __OBJC__
180NSString *OOMatrixDescription(OOMatrix matrix)
181{
182 return [NSString stringWithFormat:@"{{%g, %g, %g, %g}, {%g, %g, %g, %g}, {%g, %g, %g, %g}, {%g, %g, %g, %g}}",
183 matrix.m[0][0], matrix.m[0][1], matrix.m[0][2], matrix.m[0][3],
184 matrix.m[1][0], matrix.m[1][1], matrix.m[1][2], matrix.m[1][3],
185 matrix.m[2][0], matrix.m[2][1], matrix.m[2][2], matrix.m[2][3],
186 matrix.m[3][0], matrix.m[3][1], matrix.m[3][2], matrix.m[3][3]];
187}
188#endif
189
190
191OOMatrix OOMatrixForBillboard(HPVector bbPos, HPVector eyePos)
192{
193 Vector v0, v1, v2, arbv;
194
195 v0 = HPVectorToVector(HPvector_subtract(bbPos, eyePos));
196 // once the subtraction is done safe to lose precision since
197 // we're now dealing with relatively small vectors
198 v0 = vector_normal_or_fallback(v0, kBasisZVector);
199
200 // arbitrary axis - not aligned with v0
201 if (EXPECT_NOT(v0.x == 0.0 && v0.y == 0.0)) arbv = kBasisXVector;
202 else arbv = kBasisZVector;
203
204 v1 = cross_product(v0, arbv); // 90 degrees to (v0 x arb1)
205 v2 = cross_product(v0, v1); // 90 degrees to (v0 x v1)
206
207 return OOMatrixFromBasisVectors(v1, v2, v0);
208}
209
210
211void OOMatrixRowSwap(OOMatrix *M, int row1, int row2)
212{
213 if (row1<0 || row1 >= 4 || row2 < 0 || row2 >= 4 || row1 == row2 )
214 {
215 return;
216 }
217 float x;
218 int i;
219 for (i = 0; i < 4; i++)
220 {
221 x = M->m[row1][i];
222 M->m[row1][i] = M->m[row2][i];
223 M->m[row2][i] = x;
224 }
225 return;
226}
227
228void OOMatrixRowScale(OOMatrix *M, int row, OOScalar factor)
229{
230 if (row < 0 || row >= 4)
231 {
232 return;
233 }
234 int i;
235 for (i = 0; i < 4; i++)
236 {
237 M->m[row][i] *= factor;
238 }
239 return;
240}
241
242void OOMatrixRowOperation(OOMatrix *M, int row1, OOScalar factor1, int row2, OOScalar factor2)
243{
244 if (row1 < 0 || row1 >= 4 || row2 < 0 || row2 >= 4)
245 {
246 return;
247 }
248 int i;
249 for (i = 0; i < 4; i++)
250 {
251 M->m[row1][i] = factor1 * M->m[row1][i] + factor2 * M->m[row2][i];
252 }
253 return;
254}
255
256void OOMatrixColumnSwap(OOMatrix *M, int column1, int column2)
257{
258 if (column1<0 || column1 >= 4 || column2 < 0 || column2 >= 4 || column1 == column2 )
259 {
260 return;
261 }
262 float x;
263 int i;
264 for (i = 0; i < 4; i++)
265 {
266 x = M->m[i][column1];
267 M->m[i][column1] = M->m[i][column2];
268 M->m[i][column2] = x;
269 }
270 return;
271}
272
273void OOMatrixColumnScale(OOMatrix *M, int column, OOScalar factor)
274{
275 if (column < 0 || column >= 4)
276 {
277 return;
278 }
279 int i;
280 for (i = 0; i < 4; i++)
281 {
282 M->m[i][column] *= factor;
283 }
284 return;
285}
286
287void OOMatrixColumnOperation(OOMatrix *M, int column1, OOScalar factor1, int column2, OOScalar factor2)
288{
289 if (column1 < 0 || column1 >= 4 || column2 < 0 || column2 >= 4)
290 {
291 return;
292 }
293 int i;
294 for (i = 0; i < 4; i++)
295 {
296 M->m[i][column1] = factor1 * M->m[i][column1] + factor2 * M->m[i][column2];
297 }
298 return;
299}
300
301OOMatrix OOMatrixLeftTransform(OOMatrix A, OOMatrix B)
302{
303 int i, j;
304 bool found;
305 for (i = 0; i < 4; i++)
306 {
307 if (A.m[i][i] == 0.0)
308 {
309 found = false;
310 for (j = i+1; j < 4; j++)
311 {
312 if (A.m[j][i] != 0.0)
313 {
314 found = true;
315 OOMatrixColumnSwap(&A,i,j);
316 OOMatrixColumnSwap(&B,i,j);
317 break;
318 }
319 }
320 if (!found)
321 {
322 return kZeroMatrix;
323 }
324 }
325 OOMatrixColumnScale(&B, i, 1/A.m[i][i]);
326 OOMatrixColumnScale(&A, i, 1/A.m[i][i]);
327 for (j = i+1; j < 4; j++)
328 {
329 OOMatrixColumnOperation(&B, j, 1, i, -A.m[i][j]);
330 OOMatrixColumnOperation(&A, j, 1, i, -A.m[i][j]);
331 }
332 }
333 for (i = 3; i > 0; i--)
334 {
335 for (j = 0; j < i; j++)
336 {
337 OOMatrixColumnOperation(&B, j, 1, i, -A.m[i][j]);
338 OOMatrixColumnOperation(&A, j, 1, i, -A.m[i][j]);
339 }
340 }
341 return B;
342}
343
344OOMatrix OOMatrixRightTransform(OOMatrix A, OOMatrix B)
345{
346 int i, j;
347 bool found;
348 for (i = 0; i < 4; i++)
349 {
350 if (A.m[i][i] == 0.0)
351 {
352 found = false;
353 for (j = i+1; j < 4; j++)
354 {
355 if (A.m[j][i] != 0.0)
356 {
357 found = true;
358 OOMatrixRowSwap(&A,i,j);
359 OOMatrixRowSwap(&B,i,j);
360 break;
361 }
362 }
363 if (!found)
364 {
365 return kZeroMatrix;
366 }
367 }
368 OOMatrixRowScale(&B, i, 1/A.m[i][i]);
369 OOMatrixRowScale(&A, i, 1/A.m[i][i]);
370 for (j = i+1; j < 4; j++)
371 {
372 if (A.m[j][i] != 0.0)
373 {
374 OOMatrixRowOperation(&B, j, 1, i, -A.m[j][i]);
375 OOMatrixRowOperation(&A, j, 1, i, -A.m[j][i]);
376 }
377 }
378 }
379 for (i = 3; i > 0; i--)
380 {
381 for (j = 0; j < i; j++)
382 {
383 if (A.m[j][i] != 0.0)
384 {
385 OOMatrixRowOperation(&B, j, 1, i, -A.m[j][i]);
386 OOMatrixRowOperation(&A, j, 1, i, -A.m[j][i]);
387 }
388 }
389 }
390 return B;
391}
392
393OOMatrix OOMatrixInverse(OOMatrix M)
394{
396}
397
399{
400 int i, j;
401 OOMatrix B = kIdentityMatrix;
402 int best_row;
403 float max_value;
404
405 *d = 1.0;
406 for (i = 0; i < 4; i++)
407 {
408 max_value = fabsf(M.m[i][i]);
409 best_row = i;
410 for (j = i+1; j < 4; j++)
411 {
412 if (fabs(M.m[j][i]) > max_value)
413 {
414 best_row = j;
415 max_value = fabs(M.m[j][i]);
416 }
417 }
418 if (max_value == 0.0)
419 {
420 *d = 0.0;
421 return kZeroMatrix;
422 }
423 if (best_row != i)
424 {
425 OOMatrixRowSwap(&M,i,best_row);
426 OOMatrixRowSwap(&B,i,best_row);
427 *d *= -1;
428 }
429 *d /= M.m[i][i];
430 OOMatrixRowScale(&B, i, 1/M.m[i][i]);
431 OOMatrixRowScale(&M, i, 1/M.m[i][i]);
432 for (j = i+1; j < 4; j++)
433 {
434 if (M.m[j][i] != 0.0)
435 {
436 OOMatrixRowOperation(&B, j, 1, i, -M.m[j][i]);
437 OOMatrixRowOperation(&M, j, 1, i, -M.m[j][i]);
438 }
439 }
440 }
441 for (i = 3; i > 0; i--)
442 {
443 for (j = 0; j < i; j++)
444 {
445 if (M.m[j][i] != 0.0)
446 {
447 OOMatrixRowOperation(&B, j, 1, i, -M.m[j][i]);
448 OOMatrixRowOperation(&M, j, 1, i, -M.m[j][i]);
449 }
450 }
451 }
452 return B;
453}
454
455#if OOMATHS_OPENGL_INTEGRATION
456
457void GLUniformMatrix3(int location, OOMatrix M)
458{
459 OOScalar m[9];
460 m[0] = M.m[0][0];
461 m[1] = M.m[0][1];
462 m[2] = M.m[0][2];
463 m[3] = M.m[1][0];
464 m[4] = M.m[1][1];
465 m[5] = M.m[1][2];
466 m[6] = M.m[2][0];
467 m[7] = M.m[2][1];
468 m[8] = M.m[2][2];
469 OOGL(glUniformMatrix3fvARB(location, 1, NO, m));
470}
471
472#endif
473
#define EXPECT_NOT(x)
GLfloat OOScalar
Definition OOMaths.h:64
HPVector OOHPVectorMultiplyMatrix(HPVector v, OOMatrix m)
Definition OOMatrix.m:145
void OOMatrixColumnSwap(OOMatrix *M, int column1, int column2)
Definition OOMatrix.m:256
OOMatrix OOMatrixMultiply(OOMatrix a, OOMatrix b)
Definition OOMatrix.m:111
bool OOMatrixEqual(OOMatrix a, OOMatrix b)
Definition OOMatrix.m:96
OOMatrix OOMatrixForBillboard(HPVector bbPos, HPVector eyePos)
Definition OOMatrix.m:191
OOMatrix OOMatrixLeftTransform(OOMatrix A, OOMatrix B)
Definition OOMatrix.m:301
void GLUniformMatrix3(int location, OOMatrix M)
Definition OOMatrix.m:457
void OOMatrixColumnOperation(OOMatrix *M, int column1, OOScalar factor1, int column2, OOScalar factor2)
Definition OOMatrix.m:287
void OOMatrixColumnScale(OOMatrix *M, int column, OOScalar factor)
Definition OOMatrix.m:273
OOMatrix OOMatrixRightTransform(OOMatrix A, OOMatrix B)
Definition OOMatrix.m:344
OOMatrix OOMatrixForRotation(Vector axis, OOScalar angle)
Definition OOMatrix.m:46
OOMatrix OOMatrixOrthogonalize(OOMatrix m)
Definition OOMatrix.m:159
OOMatrix OOMatrixInverseWithDeterminant(OOMatrix M, OOScalar *d)
Definition OOMatrix.m:398
void OOMatrixRowSwap(OOMatrix *M, int row1, int row2)
Definition OOMatrix.m:211
const OOMatrix kIdentityMatrix
Definition OOMatrix.m:31
void OOMatrixRowScale(OOMatrix *M, int row, OOScalar factor)
Definition OOMatrix.m:228
Vector OOVectorMultiplyMatrix(Vector v, OOMatrix m)
Definition OOMatrix.m:129
const OOMatrix kZeroMatrix
Definition OOMatrix.m:38
OOMatrix OOMatrixInverse(OOMatrix M)
Definition OOMatrix.m:393
void OOMatrixRowOperation(OOMatrix *M, int row1, OOScalar factor1, int row2, OOScalar factor2)
Definition OOMatrix.m:242
OOMatrix OOMatrixForQuaternionRotation(Quaternion orientation)
Definition OOMatrix.m:65
#define OOGL(statement)
Definition OOOpenGL.h:251
float y
float x
const Vector kBasisZVector
Definition OOVector.m:31
const Vector kBasisXVector
Definition OOVector.m:29