./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
236 / 244
96.7%
Branches:
63 / 148
42.6%
Functions:
44 / 46
95.7%

libs/base/src/eu/base/mat4.cc
Line Branch Exec Source
1 #include "eu/base/mat4.h"
2
3 #include "eu/base/quat.h"
4
5 namespace eu
6 {
7 [[nodiscard]]
8 m4
9 13 m4::from_col_major
10 (
11 float t00, float t01, float t02, float t03,
12 float t10, float t11, float t12, float t13,
13 float t20, float t21, float t22, float t23,
14 float t30, float t31, float t32, float t33
15 )
16 {
17 return
18 {
19 t00, t01, t02, t03,
20 t10, t11, t12, t13,
21 t20, t21, t22, t23,
22 t30, t31, t32, t33
23 13 };
24 }
25
26 [[nodiscard]]
27 m4
28 1 m4::from_major(const v4& major)
29 {
30 1 const float zero = 0;
31 return from_row_major
32 1 (
33 1 major.x, zero, zero, zero,
34 1 zero, major.y, zero, zero,
35 1 zero, zero, major.z, zero,
36 1 zero, zero, zero, major.w
37 1 );
38 }
39
40 6 [[nodiscard]] m4 m4::from_basis(const n3& a, const n3& b, const n3& c)
41 {
42 return from_row_major
43 6 (
44 6 a.x, b.x, c.x, 0,
45 6 a.y, b.y, c.y, 0,
46 6 a.z, b.z, c.z, 0,
47 0, 0, 0, 1
48 6 );
49 }
50
51 ✗ [[nodiscard]] m4 m4::from_scale(const v3& s)
52 {
53
0/4
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 7 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 7 not taken.
✗ return from_major({s, 1.0f});
54 }
55
56 [[nodiscard]]
57 m4
58 6 m4::from_translation(const v3& v)
59 {
60 6 const float one = 1;
61 6 const float z = 0;
62 return from_row_major
63 6 (
64 6 one, z, z, v.x,
65 6 z, one, z, v.y,
66 6 z, z, one, v.z,
67 z, z, z, one
68 6 );
69 }
70
71 v4
72 17 m4::get_transformed(const v4& p) const
73 {
74 17 return *this * p;
75 }
76
77 v3
78 16 m4::get_transformed_point(const v3& p) const
79 {
80
3/6
✓ Branch 2 → 3 taken 16 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 16 times.
✗ Branch 3 → 8 not taken.
✓ Branch 4 → 5 taken 16 times.
✗ Branch 4 → 8 not taken.
16 return get_transformed(v4{p, 1.0f}).to_vec3_persp_div();
81 }
82
83 v3
84 ✗ m4::get_transformed(const Rui& rui) const
85 {
86
0/4
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 13 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 13 not taken.
✗ const auto right = get_transformed_vec(kk::right) * rui.right;
87
0/4
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 14 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 14 not taken.
✗ const auto up = get_transformed_vec(kk::up) * rui.up;
88
0/4
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 15 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 15 not taken.
✗ const auto in = get_transformed_vec(kk::in) * rui.in;
89
0/4
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 16 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 16 not taken.
✗ return right + up + in;
90 }
91
92 v3
93 1 m4::get_transformed_vec(const v3& p) const
94 {
95
3/6
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 8 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 8 not taken.
1 return get_transformed(v4{p, 0.0f}).to_vec3(0.0f);
96 }
97
98 n3
99 1 m4::get_transformed_vec(const n3& p) const
100 {
101
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 7 not taken.
1 return n3{ get_transformed_vec(static_cast<v3>(p))};
102 }
103
104 v3
105 1 m4::get_translation() const
106 {
107 1 return {get(0, 3), get(1, 3), get(2, 3)};
108 }
109
110 [[nodiscard]]
111 m4
112 2 m4::from_rot_x(const An& a)
113 {
114 2 const auto c = cos(a);
115 2 const auto s = sin(a);
116 return from_row_major
117 2 (
118 1, 0, 0, 0,
119 0, c, -s, 0,
120 0, s, c, 0,
121 0, 0, 0, 1
122 2 );
123 }
124
125 m4
126 1 m4::from_rot_y(const An& a)
127 {
128 1 const auto c = cos(a);
129 1 const auto s = sin(a);
130 return from_row_major
131 1 (
132 c, 0, s, 0,
133 0, 1, 0, 0,
134 -s, 0, c, 0,
135 0, 0, 0, 1
136 1 );
137 }
138
139 [[nodiscard]]
140 m4
141 1 m4::from_rot_z(const An& a)
142 {
143 1 const auto c = cos(a);
144 1 const auto s = sin(a);
145 return from_row_major
146 1 (
147 c, -s, 0, 0,
148 s, c, 0, 0,
149 0, 0, 1, 0,
150 0, 0, 0, 1
151 1 );
152 }
153
154 [[nodiscard]]
155 m4
156 6 m4::from(const AA& aa)
157 {
158 6 const float rcos = cos(aa.angle);
159 6 const float rsin = sin(aa.angle);
160
161 6 const auto u = aa.axis.x;
162 6 const auto v = aa.axis.y;
163 6 const auto w = aa.axis.z;
164
165 return m4::from_col_major
166 6 (
167 6 rcos + u * u * (1 - rcos),
168 6 w * rsin + v * u * (1 - rcos),
169 6 -v * rsin + w * u * (1 - rcos),
170 0,
171
172 6 -w * rsin + u * v * (1 - rcos),
173 6 rcos + v * v * (1 - rcos),
174 6 u * rsin + w * v * (1 - rcos),
175 0,
176
177 6 v * rsin + u * w * (1 - rcos),
178 6 -u * rsin + v * w * (1 - rcos),
179 6 rcos + w * w * (1 - rcos),
180 0,
181
182 0,
183 0,
184 0,
185 1
186 6 );
187 }
188
189
190 [[nodiscard]] m4
191 1 m4::from(const Q& q)
192 {
193
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 7 not taken.
1 const auto aa = AA::from(q);
194
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 7 not taken.
2 return m4::from(aa);
195 }
196
197
198 v4
199 2 m4::get_major() const
200 {
201
1/2
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 10 not taken.
2 return {get(0, 0), get(1, 1), get(2, 2), get(3, 3)};
202 }
203
204 n3
205 6 get_axis(const m4& m, int col)
206 {
207
3/6
✓ Branch 2 → 3 taken 6 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 8 not taken.
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 8 not taken.
6 return n3{m.get_column(col).to_vec3(0.0f)};
208 }
209
210 n3
211 2 m4::get_x_axis() const
212 {
213 2 return get_axis(*this, 0);
214 }
215
216 n3
217 2 m4::get_y_axis() const
218 {
219 2 return get_axis(*this, 1);
220 }
221
222 n3
223 2 m4::get_z_axis() const
224 {
225 2 return get_axis(*this, 2);
226 }
227
228 m4
229 2 m4::get_transposed() const
230 {
231 // https://www.j3d.org/matrix_faq/matrfaq_latest.html
232 return from_col_major
233 2 (
234 get(0, 0), get(0, 1), get(0, 2), get(0, 3),
235 get(1, 0), get(1, 1), get(1, 2), get(1, 3),
236 get(2, 0), get(2, 1), get(2, 2), get(2, 3),
237 get(3, 0), get(3, 1), get(3, 2), get(3, 3)
238 2 );
239 }
240
241 bool
242 2 m4::invert()
243 {
244 // from the glu source?
245 // https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
246
247 float inv[16];
248
249 2 float* m = data;
250
251 2 inv[0] =
252 2 m[5] * m[10] * m[15] - m[5] * m[11] * m[14] -
253 2 m[9] * m[6] * m[15] + m[9] * m[7] * m[14] +
254 2 m[13] * m[6] * m[11] - m[13] * m[7] * m[10]
255 ;
256
257 2 inv[4] =
258 2 -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] +
259 2 m[8] * m[6] * m[15] - m[8] * m[7] * m[14] -
260 2 m[12] * m[6] * m[11] + m[12] * m[7] * m[10]
261 ;
262
263 2 inv[8] =
264 2 m[4] * m[9] * m[15] - m[4] * m[11] * m[13] -
265 2 m[8] * m[5] * m[15] + m[8] * m[7] * m[13] +
266 2 m[12] * m[5] * m[11] - m[12] * m[7] * m[9]
267 ;
268
269 2 inv[12] =
270 2 -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] +
271 2 m[8] * m[5] * m[14] - m[8] * m[6] * m[13] -
272 2 m[12] * m[5] * m[10] + m[12] * m[6] * m[9]
273 ;
274
275 2 inv[1] =
276 2 -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] +
277 2 m[9] * m[2] * m[15] - m[9] * m[3] * m[14] -
278 2 m[13] * m[2] * m[11] + m[13] * m[3] * m[10]
279 ;
280
281 2 inv[5] =
282 2 m[0] * m[10] * m[15] - m[0] * m[11] * m[14] -
283 2 m[8] * m[2] * m[15] + m[8] * m[3] * m[14] +
284 2 m[12] * m[2] * m[11] - m[12] * m[3] * m[10]
285 ;
286
287 2 inv[9] =
288 2 -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] +
289 2 m[8] * m[1] * m[15] - m[8] * m[3] * m[13] -
290 2 m[12] * m[1] * m[11] + m[12] * m[3] * m[9]
291 ;
292
293 2 inv[13] =
294 2 m[0] * m[9] * m[14] - m[0] * m[10] * m[13] -
295 2 m[8] * m[1] * m[14] + m[8] * m[2] * m[13] +
296 2 m[12] * m[1] * m[10] - m[12] * m[2] * m[9]
297 ;
298
299 2 inv[2] =
300 2 m[1] * m[6] * m[15] - m[1] * m[7] * m[14] -
301 2 m[5] * m[2] * m[15] + m[5] * m[3] * m[14] +
302 2 m[13] * m[2] * m[7] - m[13] * m[3] * m[6]
303 ;
304
305 2 inv[6] =
306 2 -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] +
307 2 m[4] * m[2] * m[15] - m[4] * m[3] * m[14] -
308 2 m[12] * m[2] * m[7] + m[12] * m[3] * m[6]
309 ;
310
311 2 inv[10] =
312 2 m[0] * m[5] * m[15] - m[0] * m[7] * m[13] -
313 2 m[4] * m[1] * m[15] + m[4] * m[3] * m[13] +
314 2 m[12] * m[1] * m[7] - m[12] * m[3] * m[5]
315 ;
316
317 2 inv[14] =
318 2 -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] +
319 2 m[4] * m[1] * m[14] - m[4] * m[2] * m[13] -
320 2 m[12] * m[1] * m[6] + m[12] * m[2] * m[5]
321 ;
322
323 2 inv[3] =
324 2 -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] +
325 2 m[5] * m[2] * m[11] - m[5] * m[3] * m[10] -
326 2 m[9] * m[2] * m[7] + m[9] * m[3] * m[6]
327 ;
328
329 2 inv[7] =
330 2 m[0] * m[6] * m[11] - m[0] * m[7] * m[10] -
331 2 m[4] * m[2] * m[11] + m[4] * m[3] * m[10] +
332 2 m[8] * m[2] * m[7] - m[8] * m[3] * m[6]
333 ;
334
335 2 inv[11] =
336 2 -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] +
337 2 m[4] * m[1] * m[11] - m[4] * m[3] * m[9] -
338 2 m[8] * m[1] * m[7] + m[8] * m[3] * m[5]
339 ;
340
341 2 inv[15] =
342 2 m[0] * m[5] * m[10] - m[0] * m[6] * m[9] -
343 2 m[4] * m[1] * m[10] + m[4] * m[2] * m[9] +
344 2 m[8] * m[1] * m[6] - m[8] * m[2] * m[5]
345 ;
346
347 2 const auto inv_det =
348 2 m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] +
349 2 m[3] * inv[12];
350
351
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 if(inv_det == 0)
352 {
353 ✗ return false;
354 }
355
356 2 const auto det = 1.0f / inv_det;
357
358
2/2
✓ Branch 6 → 5 taken 32 times.
✓ Branch 6 → 7 taken 2 times.
34 for(int index = 0; index < 16; index += 1)
359 {
360 32 data[index] = inv[index] * det;
361 }
362
363 2 return true;
364 }
365
366 m4
367 1 m4::get_inverted() const
368 {
369 1 auto r = *this;
370 1 const auto was_inverted = r.invert();
371
1/6
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 10 taken 1 time.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 10 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 12 not taken.
1 ASSERT(was_inverted);
372 1 return r;
373 }
374
375 void
376 1 m4::operator+=(const m4& rhs)
377 {
378 #define OP(i) data[i] += rhs.data[i]
379 1 OP(0); OP(1); OP(2); OP(3);
380 1 OP(4); OP(5); OP(6); OP(7);
381 1 OP(8); OP(9); OP(10); OP(11);
382 1 OP(12); OP(13); OP(14); OP(15);
383 #undef OP
384 1 }
385
386 void
387 1 m4::operator-=(const m4& rhs)
388 {
389 #define OP(i) data[i] -= rhs.data[i]
390 1 OP(0); OP(1); OP(2); OP(3);
391 1 OP(4); OP(5); OP(6); OP(7);
392 1 OP(8); OP(9); OP(10); OP(11);
393 1 OP(12); OP(13); OP(14); OP(15);
394 #undef OP
395 1 }
396
397 [[nodiscard]]
398 m4
399 1 m4::create_ortho_lrud(float l, float r, float t, float b, float n, float f)
400 {
401 // http://www.songho.ca/opengl/gl_projectionmatrix.html
402 return from_row_major
403 1 (
404 1 2 / (r - l), 0, 0, -(r + l) / (r - l),
405 1 0, 2 / (t - b), 0, -(t + b) / (t - b),
406 1 0, 0, -2 / (f - n), -(f + n) / (f - n),
407 0, 0, 0, 1
408 1 );
409 }
410
411 [[nodiscard]]
412 m4
413 1 m4::create_perspective(const An& fov, float a, float near, float far)
414 {
415
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 7 not taken.
1 const float t = 1 / tan(fov / 2);
416 1 const float zm = far - near;
417 1 const float zp = far + near;
418 return from_row_major
419 1 (
420 t / a, 0, 0, 0,
421 0, t, 0, 0,
422 1 0, 0, -zp / zm, (-2 * far * near) / zm,
423 0, 0, -1, 0
424 1 );
425 }
426
427 m4
428 4 m4::get_translated(const v3& t) const
429 {
430
2/4
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 7 not taken.
4 return *this * from_translation(t);
431 }
432
433 m4
434 4 m4::get_rotated(const AA& aa) const
435 {
436
2/4
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 7 not taken.
4 return *this * from(aa);
437 }
438
439 const float*
440 1 m4::get_column_major_data_ptr() const
441 {
442 1 return data;
443 }
444
445 float*
446 1 m4::get_column_major_data_ptr()
447 {
448 1 return data;
449 }
450
451
452 float
453 1299 m4::get(int row, int col) const
454 {
455 1299 return data[col * 4 + row];
456 }
457
458 float
459 36 m4::get1(int row, int col) const
460 {
461 36 return data[(col-1) * 4 + (row-1)];
462 }
463
464 v4
465 182 m4::get_column(int col) const
466 {
467 182 const auto base = col * 4;
468 return
469 {
470 182 data[base + 0],
471 182 data[base + 1],
472 182 data[base + 2],
473 182 data[base + 3]
474
1/2
✓ Branch 2 → 3 taken 182 times.
✗ Branch 2 → 6 not taken.
182 };
475 }
476
477 v4
478 244 m4::get_row(int r) const
479 {
480
1/2
✓ Branch 6 → 7 taken 244 times.
✗ Branch 6 → 10 not taken.
244 return {get(r, 0), get(r, 1), get(r, 2), get(r, 3)};
481 }
482
483
484 2 std::string string_from(const m4& m)
485 {
486
1/2
✓ Branch 2 → 3 taken 8 times.
✗ Branch 2 → 5 not taken.
8 const auto s = [](const v4& v) { return fmt::format("{} {} {} {}", v.x, v.y, v.z, v.w); };
487
9/18
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 32 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 32 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 28 not taken.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 28 not taken.
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 24 not taken.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 24 not taken.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 20 not taken.
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 20 not taken.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 17 not taken.
2 return fmt::format("{}\n{}\n{}\n{}", s(m.get_row(0)), s(m.get_row(1)), s(m.get_row(2)), s(m.get_row(3)));
488 }
489
490
491 m4
492 1 operator+(const m4& lhs, const m4& rhs)
493 {
494 1 m4 t = lhs;
495 1 t += rhs;
496 1 return t;
497 }
498
499
500 m4
501 1 operator-(const m4& lhs, const m4& rhs)
502 {
503 1 m4 t = lhs;
504 1 t -= rhs;
505 1 return t;
506 }
507
508 float
509 232 get_component_multiply_sum(const v4& lhs, const v4& rhs)
510 {
511 232 const auto x = lhs.x * rhs.x;
512 232 const auto y = lhs.y * rhs.y;
513 232 const auto z = lhs.z * rhs.z;
514 232 const auto w = lhs.w* rhs.w;
515 232 return x + y + z + w;
516 }
517
518 10 m4 operator*(const m4& lhs, const m4& rhs)
519 {
520 160 const auto op = [&lhs, &rhs](int r, int c) -> float
521 {
522
2/4
✓ Branch 2 → 3 taken 160 times.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 160 times.
✗ Branch 3 → 7 not taken.
160 return get_component_multiply_sum(lhs.get_row(r), rhs.get_column(c));
523 10 };
524 return m4::from_row_major
525
17/34
✓ Branch 2 → 3 taken 10 times.
✗ Branch 2 → 22 not taken.
✓ Branch 3 → 4 taken 10 times.
✗ Branch 3 → 22 not taken.
✓ Branch 4 → 5 taken 10 times.
✗ Branch 4 → 22 not taken.
✓ Branch 5 → 6 taken 10 times.
✗ Branch 5 → 22 not taken.
✓ Branch 6 → 7 taken 10 times.
✗ Branch 6 → 22 not taken.
✓ Branch 7 → 8 taken 10 times.
✗ Branch 7 → 22 not taken.
✓ Branch 8 → 9 taken 10 times.
✗ Branch 8 → 22 not taken.
✓ Branch 9 → 10 taken 10 times.
✗ Branch 9 → 22 not taken.
✓ Branch 10 → 11 taken 10 times.
✗ Branch 10 → 22 not taken.
✓ Branch 11 → 12 taken 10 times.
✗ Branch 11 → 22 not taken.
✓ Branch 12 → 13 taken 10 times.
✗ Branch 12 → 22 not taken.
✓ Branch 13 → 14 taken 10 times.
✗ Branch 13 → 22 not taken.
✓ Branch 14 → 15 taken 10 times.
✗ Branch 14 → 22 not taken.
✓ Branch 15 → 16 taken 10 times.
✗ Branch 15 → 22 not taken.
✓ Branch 16 → 17 taken 10 times.
✗ Branch 16 → 22 not taken.
✓ Branch 17 → 18 taken 10 times.
✗ Branch 17 → 22 not taken.
✓ Branch 18 → 19 taken 10 times.
✗ Branch 18 → 22 not taken.
10 (
526 op(0, 0), op(0, 1), op(0, 2), op(0, 3),
527 op(1, 0), op(1, 1), op(1, 2), op(1, 3),
528 op(2, 0), op(2, 1), op(2, 2), op(2, 3),
529 op(3, 0), op(3, 1), op(3, 2), op(3, 3)
530 20 );
531 }
532
533
534 18 v4 operator*(const m4& lhs, const v4& rhs)
535 {
536 72 const auto op = [&lhs, &rhs](int r) -> float
537 {
538
1/2
✓ Branch 2 → 3 taken 72 times.
✗ Branch 2 → 6 not taken.
72 return get_component_multiply_sum(lhs.get_row(r), rhs);
539 18 };
540
541
5/10
✓ Branch 2 → 3 taken 18 times.
✗ Branch 2 → 10 not taken.
✓ Branch 3 → 4 taken 18 times.
✗ Branch 3 → 10 not taken.
✓ Branch 4 → 5 taken 18 times.
✗ Branch 4 → 10 not taken.
✓ Branch 5 → 6 taken 18 times.
✗ Branch 5 → 10 not taken.
✓ Branch 6 → 7 taken 18 times.
✗ Branch 6 → 10 not taken.
18 return {op(0), op(1), op(2), op(3)};
542 }
543
544
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 10 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 8 not taken.
1 ADD_CATCH_FORMATTER_IMPL(m4)
545 }
546