v2 / vlib / gg / m4 / matrix.v
590 lines · 531 sloc · 14.92 KB · 0ffc33a5c9cf45653dba16290f7c9ebbdd116159
Raw
1/**********************************************************************
2*
3* Simply vector/matrix utility
4*
5* Copyright (c) 2021 Dario Deledda. All rights reserved.
6* Use of this source code is governed by an MIT license
7* that can be found in the LICENSE file.
8*
9* TODO:
10**********************************************************************/
11module m4
12
13import math
14
15pub union Mat4 {
16pub mut:
17 e [16]f32
18 f [4][4]f32
19}
20
21pub const precision = f32(10e-7)
22
23// default precision for the module
24
25/*********************************************************************
26*
27* Utility
28*
29*********************************************************************/
30// String representation of the matrix
31pub fn (x Mat4) str() string {
32 // vfmt off
33 return unsafe {
34 '|${x.e[0]: -6.3},${x.e[1]: -6.3},${x.e[2]: -6.3},${x.e[3]: -6.3}|\n' +
35 '|${x.e[4]: -6.3},${x.e[5]: -6.3},${x.e[6]: -6.3},${x.e[7]: -6.3}|\n' +
36 '|${x.e[8]: -6.3},${x.e[9]: -6.3},${x.e[10]:-6.3},${x.e[11]:-6.3}|\n' +
37 '|${x.e[12]:-6.3},${x.e[13]:-6.3},${x.e[14]:-6.3},${x.e[15]:-6.3}|'
38 }
39 // vfmt on
40}
41
42// Remove all the raw zeros
43@[direct_array_access]
44pub fn (a Mat4) clean() Mat4 {
45 unsafe {
46 x := Mat4{}
47 for c, value in a.e {
48 if f32_abs(value) < precision {
49 x.e[c] = 0
50 } else {
51 x.e[c] = value
52 }
53 }
54 return x
55 }
56 return zero_m4() // workaround -cstrict
57}
58
59// Sum all the elements of the matrix
60pub fn (x Mat4) sum_all() f32 {
61 mut res := f32(0)
62 for v in unsafe { x.e } {
63 res += v
64 }
65 return res
66}
67
68// Check if two matrix are equal using module precision
69@[direct_array_access]
70pub fn (x Mat4) is_equal(y Mat4) bool {
71 unsafe {
72 for c, value in x.e {
73 if f32_abs(value - y.e[c]) > precision {
74 return false
75 }
76 }
77 return true
78 }
79}
80
81//-------------------------------------
82// Set/Get values
83//-------------------------------------
84// Get an element of the matrix using [0..15] indexes, one dimension
85pub fn (x Mat4) get_e(elem_index int) f32 {
86 unsafe {
87 return x.e[elem_index]
88 }
89}
90
91// Get an element of the matrix using [0..3][0..3] indexes, two dimension
92pub fn (x Mat4) get_f(index_col int, index_row int) f32 {
93 unsafe {
94 return x.e[int(u32(index_row) << 2) + index_col]
95 }
96}
97
98// Set an element of the matrix using [0..15] indexes, one dimension
99pub fn (mut x Mat4) set_e(index int, value f32) {
100 unsafe {
101 x.e[index] = value
102 }
103}
104
105// Set an element of the matrix using [0..3][0..3] indexes, two dimension
106pub fn (mut x Mat4) set_f(index_col int, index_row int, value f32) {
107 unsafe {
108 x.e[int(u32(index_row) << 2) + index_col] = value
109 }
110}
111
112// Copy a matrix elements from another matrix
113pub fn (mut x Mat4) copy(y Mat4) {
114 unsafe {
115 x.e = [
116 // vfmt off
117 y.e[0 ], y.e[1 ], y.e[2 ], y.e[3 ],
118 y.e[4 ], y.e[5 ], y.e[6 ], y.e[7 ],
119 y.e[8 ], y.e[9 ], y.e[10], y.e[11],
120 y.e[12], y.e[13], y.e[14], y.e[15],
121 // vfmt on
122 ]!
123 }
124}
125
126// Set the trace of the matrix using a vec4
127pub fn (mut x Mat4) set_trace(v3 Vec4) {
128 unsafe {
129 // vfmt off
130 x.e[0 ] = v3.e[0]
131 x.e[5 ] = v3.e[1]
132 x.e[10] = v3.e[2]
133 x.e[15] = v3.e[3]
134 // vfmt on
135 }
136}
137
138// Get the trace of the matrix
139pub fn (x Mat4) get_trace() Vec4 {
140 unsafe {
141 // vfmt off
142 return Vec4{ e: [ x.e[0], x.e[5], x.e[10], x.e[15], ]! }
143 // vfmt on
144 }
145}
146
147// Set all the matrix elements to value
148pub fn (mut x Mat4) set_f32(value f32) {
149 unsafe {
150 // vfmt off
151 x.e = [
152 value, value, value, value,
153 value, value, value, value,
154 value, value, value, value,
155 value, value, value, value,
156 ]!
157 // vfmt on
158 }
159}
160
161//-------------------------------------
162// Rows/Column access
163//-------------------------------------
164// Set the row as the input vec4
165@[direct_array_access; unsafe]
166pub fn (mut x Mat4) set_row(row int, v3 Vec4) {
167 unsafe {
168 x.e[row * 4 + 0] = v3.e[0]
169 x.e[row * 4 + 1] = v3.e[1]
170 x.e[row * 4 + 2] = v3.e[2]
171 x.e[row * 4 + 3] = v3.e[3]
172 }
173}
174
175// Get a row from a matrix
176@[direct_array_access; unsafe]
177pub fn (x Mat4) get_row(row int) Vec4 {
178 unsafe {
179 // vfmt off
180 return Vec4{ e: [ x.e[row * 4], x.e[row * 4 + 1], x.e[row * 4 + 2], x.e[row * 4 + 3], ]! }
181 // vfmt on
182 }
183}
184
185// Set the column as the input vec4
186@[direct_array_access; unsafe]
187pub fn (mut x Mat4) set_col(col int, v3 Vec4) {
188 unsafe {
189 // vfmt off
190 x.e[col ] = v3.e[0]
191 x.e[col + 4 ] = v3.e[1]
192 x.e[col + 8 ] = v3.e[2]
193 x.e[col + 12] = v3.e[3]
194 // vfmt on
195 }
196}
197
198// Get a column from a matrix
199@[direct_array_access; unsafe]
200pub fn (x Mat4) get_col(col int) Vec4 {
201 unsafe {
202 // vfmt off
203 return Vec4{ e: [ x.e[col], x.e[col + 4 ], x.e[col + 8 ], x.e[col + 12], ]!}
204 // vfmt on
205 }
206}
207
208// Swap two columns in the matrix
209@[direct_array_access; unsafe]
210pub fn (mut x Mat4) swap_col(col1 int, col2 int) {
211 unsafe {
212 // vfmt off
213 v0 := x.e[col1 ]
214 v1 := x.e[col1 + 4 ]
215 v2 := x.e[col1 + 8 ]
216 v3 := x.e[col1 + 12]
217
218 x.e[col1 ] = x.e[col2 ]
219 x.e[col1 + 4 ] = x.e[col2 + 4 ]
220 x.e[col1 + 8 ] = x.e[col2 + 8 ]
221 x.e[col1 + 12] = x.e[col2 + 12]
222
223 x.e[col2 ] = v0
224 x.e[col2 + 4 ] = v1
225 x.e[col2 + 8 ] = v2
226 x.e[col2 + 12] = v3
227 // vfmt on
228 }
229}
230
231// Swap two rows in the matrix
232@[direct_array_access; unsafe]
233pub fn (mut x Mat4) swap_row(row1 int, row2 int) {
234 unsafe {
235 v0 := x.e[row1 * 4 + 0]
236 v1 := x.e[row1 * 4 + 1]
237 v2 := x.e[row1 * 4 + 2]
238 v3 := x.e[row1 * 4 + 3]
239
240 x.e[row1 * 4 + 0] = x.e[row2 * 4 + 0]
241 x.e[row1 * 4 + 1] = x.e[row2 * 4 + 1]
242 x.e[row1 * 4 + 2] = x.e[row2 * 4 + 2]
243 x.e[row1 * 4 + 3] = x.e[row2 * 4 + 3]
244
245 x.e[row2 * 4 + 0] = v0
246 x.e[row2 * 4 + 1] = v1
247 x.e[row2 * 4 + 2] = v2
248 x.e[row2 * 4 + 3] = v3
249 }
250}
251
252//-------------------------------------
253// Modify data
254//-------------------------------------
255// Transpose the matrix
256pub fn (x Mat4) transpose() Mat4 {
257 // vfmt off
258 return unsafe {
259 Mat4{ e: [
260 x.e[0 ], x.e[4 ], x.e[8 ], x.e[12],
261 x.e[1 ], x.e[5 ], x.e[9 ], x.e[13],
262 x.e[2 ], x.e[6 ], x.e[10], x.e[14],
263 x.e[3 ], x.e[7 ], x.e[11], x.e[15],
264 ]!}
265 }
266 // vfmt on
267}
268
269// Multiply the all the elements of the matrix by a scalar
270pub fn (x Mat4) mul_scalar(s f32) Mat4 {
271 // vfmt off
272 return unsafe {
273 Mat4{ e: [
274 x.e[0 ] * s, x.e[1 ] * s, x.e[2 ] * s, x.e[3 ] * s,
275 x.e[4 ] * s, x.e[5 ] * s, x.e[6 ] * s, x.e[7 ] * s,
276 x.e[8 ] * s, x.e[9 ] * s, x.e[10] * s, x.e[11] * s,
277 x.e[12] * s, x.e[13] * s, x.e[14] * s, x.e[15] * s,
278 ]!}
279 }
280 // vfmt on
281}
282
283/*********************************************************************
284*
285* Init/set
286*
287*********************************************************************/
288// Return a zero matrix
289pub fn zero_m4() Mat4 {
290 // vfmt off
291 return Mat4{ e: [
292 f32(0), 0, 0, 0,
293 0, 0, 0, 0,
294 0, 0, 0, 0,
295 0, 0, 0, 0,
296 ]!}
297 // vfmt on
298}
299
300// Return a unity matrix
301pub fn unit_m4() Mat4 {
302 // vfmt off
303 return Mat4{ e: [
304 f32(1), 0, 0, 0,
305 0, 1, 0, 0,
306 0, 0, 1, 0,
307 0, 0, 0, 1,
308 ]!}
309 // vfmt on
310}
311
312// Return a matrix initialized with value
313pub fn set_m4(value f32) Mat4 {
314 // vfmt off
315 return Mat4{ e: [
316 value, value, value, value,
317 value, value, value, value,
318 value, value, value, value,
319 value, value, value, value,
320 ]!}
321 // vfmt on
322}
323
324/*********************************************************************
325*
326* Math
327*
328*********************************************************************/
329
330// Sum of matrix, operator +
331pub fn (a Mat4) + (b Mat4) Mat4 {
332 // vfmt off
333 return unsafe {
334 Mat4{ e: [
335 a.e[0 ] + b.e[0 ], a.e[1 ] + b.e[1 ], a.e[2 ] + b.e[2 ], a.e[3 ] + b.e[3 ],
336 a.e[4 ] + b.e[4 ], a.e[5 ] + b.e[5 ], a.e[6 ] + b.e[6 ], a.e[7 ] + b.e[7 ],
337 a.e[8 ] + b.e[8 ], a.e[9 ] + b.e[9 ], a.e[10] + b.e[10], a.e[11] + b.e[11],
338 a.e[12] + b.e[12], a.e[13] + b.e[13], a.e[14] + b.e[14], a.e[15] + b.e[15],
339 ]!}
340 }
341 // vfmt on
342}
343
344// Subtraction of matrix, operator -
345pub fn (a Mat4) - (b Mat4) Mat4 {
346 // vfmt off
347 return unsafe {
348 Mat4{ e: [
349 a.e[0 ] - b.e[0 ], a.e[1 ] - b.e[1 ], a.e[2 ] - b.e[2 ], a.e[3 ] - b.e[3 ],
350 a.e[4 ] - b.e[4 ], a.e[5 ] - b.e[5 ], a.e[6 ] - b.e[6 ], a.e[7 ] - b.e[7 ],
351 a.e[8 ] - b.e[8 ], a.e[9 ] - b.e[9 ], a.e[10] - b.e[10], a.e[11] - b.e[11],
352 a.e[12] - b.e[12], a.e[13] - b.e[13], a.e[14] - b.e[14], a.e[15] - b.e[15],
353 ]!}
354 }
355 // vfmt on
356}
357
358// Multiplication of matrix, operator *
359pub fn (a Mat4) * (b Mat4) Mat4 {
360 // vfmt off
361 return unsafe {
362 Mat4{ e: [
363 a.f[0][0] * b.f[0][0] + a.f[0][1] * b.f[1][0] + a.f[0][2] * b.f[2][0] + a.f[0][3] * b.f[3][0], // [0][0]
364 a.f[0][0] * b.f[0][1] + a.f[0][1] * b.f[1][1] + a.f[0][2] * b.f[2][1] + a.f[0][3] * b.f[3][1], // [0][1]
365 a.f[0][0] * b.f[0][2] + a.f[0][1] * b.f[1][2] + a.f[0][2] * b.f[2][2] + a.f[0][3] * b.f[3][2], // [0][2]
366 a.f[0][0] * b.f[0][3] + a.f[0][1] * b.f[1][3] + a.f[0][2] * b.f[2][3] + a.f[0][3] * b.f[3][3], // [0][3]
367
368 a.f[1][0] * b.f[0][0] + a.f[1][1] * b.f[1][0] + a.f[1][2] * b.f[2][0] + a.f[1][3] * b.f[3][0], // [1][0]
369 a.f[1][0] * b.f[0][1] + a.f[1][1] * b.f[1][1] + a.f[1][2] * b.f[2][1] + a.f[1][3] * b.f[3][1], // [1][1]
370 a.f[1][0] * b.f[0][2] + a.f[1][1] * b.f[1][2] + a.f[1][2] * b.f[2][2] + a.f[1][3] * b.f[3][2], // [1][2]
371 a.f[1][0] * b.f[0][3] + a.f[1][1] * b.f[1][3] + a.f[1][2] * b.f[2][3] + a.f[1][3] * b.f[3][3], // [1][3]
372
373 a.f[2][0] * b.f[0][0] + a.f[2][1] * b.f[1][0] + a.f[2][2] * b.f[2][0] + a.f[2][3] * b.f[3][0], // [2][0]
374 a.f[2][0] * b.f[0][1] + a.f[2][1] * b.f[1][1] + a.f[2][2] * b.f[2][1] + a.f[2][3] * b.f[3][1], // [2][1]
375 a.f[2][0] * b.f[0][2] + a.f[2][1] * b.f[1][2] + a.f[2][2] * b.f[2][2] + a.f[2][3] * b.f[3][2], // [2][2]
376 a.f[2][0] * b.f[0][3] + a.f[2][1] * b.f[1][3] + a.f[2][2] * b.f[2][3] + a.f[2][3] * b.f[3][3], // [2][3]
377
378 a.f[3][0] * b.f[0][0] + a.f[3][1] * b.f[1][0] + a.f[3][2] * b.f[2][0] + a.f[3][3] * b.f[3][0], // [3][0]
379 a.f[3][0] * b.f[0][1] + a.f[3][1] * b.f[1][1] + a.f[3][2] * b.f[2][1] + a.f[3][3] * b.f[3][1], // [3][1]
380 a.f[3][0] * b.f[0][2] + a.f[3][1] * b.f[1][2] + a.f[3][2] * b.f[2][2] + a.f[3][3] * b.f[3][2], // [3][2]
381 a.f[3][0] * b.f[0][3] + a.f[3][1] * b.f[1][3] + a.f[3][2] * b.f[2][3] + a.f[3][3] * b.f[3][3], // [3][3]
382 ]!}
383 }
384 // vfmt on
385}
386
387// Sum of matrix function
388pub fn add(a Mat4, b Mat4) Mat4 {
389 return a + b
390}
391
392// Subtraction of matrix function
393pub fn sub(a Mat4, b Mat4) Mat4 {
394 return a - b
395}
396
397// Multiplication of matrix function
398pub fn mul(a Mat4, b Mat4) Mat4 {
399 return a * b
400}
401
402// Multiply a Matrix by a vector
403pub fn mul_vec(a Mat4, v Vec4) Vec4 {
404 // vfmt off
405 return unsafe {
406 Vec4{ e: [
407 a.e[0 ] * v.e[0] + a.e[1 ] * v.e[1] + a.e[2 ] * v.e[2] + a.e[3 ] * v.e[3],
408 a.e[4 ] * v.e[0] + a.e[5 ] * v.e[1] + a.e[6 ] * v.e[2] + a.e[7 ] * v.e[3],
409 a.e[8 ] * v.e[0] + a.e[9 ] * v.e[1] + a.e[10] * v.e[2] + a.e[11] * v.e[3],
410 a.e[12] * v.e[0] + a.e[13] * v.e[1] + a.e[14] * v.e[2] + a.e[15] * v.e[3],
411 ]!}
412 }
413 // vfmt on
414}
415
416// Calculate the determinant of the Matrix
417pub fn det(x Mat4) f32 {
418 unsafe {
419 mut t := [6]f32{}
420 x00 := x.f[0][0]
421 x10 := x.f[1][0]
422 x20 := x.f[2][0]
423 x30 := x.f[3][0]
424 x01 := x.f[0][1]
425 x11 := x.f[1][1]
426 x21 := x.f[2][1]
427 x31 := x.f[3][1]
428 x02 := x.f[0][2]
429 x12 := x.f[1][2]
430 x22 := x.f[2][2]
431 x32 := x.f[3][2]
432 x03 := x.f[0][3]
433 x13 := x.f[1][3]
434 x23 := x.f[2][3]
435 x33 := x.f[3][3]
436
437 t[0] = x22 * x33 - x23 * x32
438 t[1] = x12 * x33 - x13 * x32
439 t[2] = x12 * x23 - x13 * x22
440 t[3] = x02 * x33 - x03 * x32
441 t[4] = x02 * x23 - x03 * x22
442 t[5] = x02 * x13 - x03 * x12
443 // vfmt off
444 return
445 x00 * (x11 * t[0] - x21 * t[1] + x31 * t[2]) -
446 x10 * (x01 * t[0] - x21 * t[3] + x31 * t[4]) +
447 x20 * (x01 * t[1] - x11 * t[3] + x31 * t[5]) -
448 x30 * (x01 * t[2] - x11 * t[4] + x21 * t[5])
449 // vfmt on
450 }
451 return 0 // workaround -cstrict
452}
453
454// Calculate the inverse of the Matrix
455pub fn (x Mat4) inverse() Mat4 {
456 unsafe {
457 mut t := [6]f32{}
458 mut det := f32(0)
459
460 // vfmt off
461 a := x.f[0][0]
462 b := x.f[1][0]
463 c := x.f[2][0]
464 d := x.f[3][0]
465 e := x.f[0][1]
466 f := x.f[1][1]
467 g := x.f[2][1]
468 h := x.f[3][1]
469 i := x.f[0][2]
470 j := x.f[1][2]
471 k := x.f[2][2]
472 l := x.f[3][2]
473 m := x.f[0][3]
474 n := x.f[1][3]
475 o := x.f[2][3]
476 p := x.f[3][3]
477
478 t[0] = k * p - o * l
479 t[1] = j * p - n * l
480 t[2] = j * o - n * k
481 t[3] = i * p - m * l
482 t[4] = i * o - m * k
483 t[5] = i * n - m * j
484
485 mut dest := Mat4{}
486 dest.f[0][0] = f * t[0] - g * t[1] + h * t[2]
487 dest.f[0][1] = -(e * t[0] - g * t[3] + h * t[4])
488 dest.f[0][2] = e * t[1] - f * t[3] + h * t[5]
489 dest.f[0][3] = -(e * t[2] - f * t[4] + g * t[5])
490
491 dest.f[1][0] = -(b * t[0] - c * t[1] + d * t[2])
492 dest.f[1][1] = a * t[0] - c * t[3] + d * t[4]
493 dest.f[1][2] = -(a * t[1] - b * t[3] + d * t[5])
494 dest.f[1][3] = a * t[2] - b * t[4] + c * t[5]
495
496 t[0] = g * p - o * h
497 t[1] = f * p - n * h
498 t[2] = f * o - n * g
499 t[3] = e * p - m * h
500 t[4] = e * o - m * g
501 t[5] = e * n - m * f
502
503 dest.f[2][0] = b * t[0] - c * t[1] + d * t[2]
504 dest.f[2][1] = -(a * t[0] - c * t[3] + d * t[4])
505 dest.f[2][2] = a * t[1] - b * t[3] + d * t[5]
506 dest.f[2][3] = -(a * t[2] - b * t[4] + c * t[5])
507
508 t[0] = g * l - k * h
509 t[1] = f * l - j * h
510 t[2] = f * k - j * g
511 t[3] = e * l - i * h
512 t[4] = e * k - i * g
513 t[5] = e * j - i * f
514
515 dest.f[3][0] = -(b * t[0] - c * t[1] + d * t[2])
516 dest.f[3][1] = a * t[0] - c * t[3] + d * t[4]
517 dest.f[3][2] = -(a * t[1] - b * t[3] + d * t[5])
518 dest.f[3][3] = a * t[2] - b * t[4] + c * t[5]
519 // vfmt on
520
521 tmp := (a * dest.f[0][0] + b * dest.f[0][1] + c * dest.f[0][2] + d * dest.f[0][3])
522 if tmp != 0 {
523 det = f32(1.0) / tmp
524 }
525 return dest.mul_scalar(det)
526 }
527 return zero_m4()
528}
529
530/*********************************************************************
531*
532* Transformations
533*
534*********************************************************************/
535
536// Get a rotation matrix using w as rotation axis vector, the angle is in radians
537pub fn rotate(angle f32, w Vec4) Mat4 {
538 cs := f32(math.cos(angle))
539 sn := f32(math.sin(angle))
540 cv := f32(1.0) - cs
541 axis := w.normalize3()
542 unsafe {
543 ax := axis.e[0]
544 ay := axis.e[1]
545 az := axis.e[2]
546
547 // vfmt off
548 return Mat4{ e: [
549 (ax * ax * cv) + cs, (ax * ay * cv) + az * sn, (ax * az * cv) - ay * sn, 0,
550 (ay * ax * cv) - az * sn, (ay * ay * cv) + cs, (ay * az * cv) + ax * sn, 0,
551 (az * ax * cv) + ay * sn, (az * ay * cv) - ax * sn, (az * az * cv) + cs, 0,
552 0, 0, 0, 1,
553 ]!}
554 // vfmt on
555 }
556 return zero_m4()
557}
558
559/*********************************************************************
560*
561* Graphic
562*
563*********************************************************************/
564// Get a matrix translated by a vector w
565pub fn (x Mat4) translate(w Vec4) Mat4 {
566 // vfmt off
567 return unsafe {
568 Mat4{ e: [
569 x.e[0], x.e[1], x.e[2 ], x.e[3 ],
570 x.e[4], x.e[5], x.e[6 ], x.e[7 ],
571 x.e[8], x.e[9], x.e[10], x.e[11],
572 x.e[12] + w.e[0], x.e[13] + w.e[1], x.e[14] + w.e[2], x.e[15],
573 ]!}
574 }
575 // vfmt on
576}
577
578// Get a scale matrix, the scale vector is w, only xyz are evaluated.
579pub fn scale(w Vec4) Mat4 {
580 // vfmt off
581 return unsafe {
582 Mat4{ e: [
583 w.e[0], 0, 0, 0,
584 0, w.e[1], 0, 0,
585 0, 0, w.e[2], 0,
586 0, 0, 0, 1,
587 ]!}
588 }
589 // vfmt on
590}
591