Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+102
View File
@@ -0,0 +1,102 @@
module m4
/**********************************************************************
* Simple vector/matrix graphic utility
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
**********************************************************************/
import math
// Translate degrees to radians
@[inline]
pub fn rad(deg f32) f32 {
return (math.pi / 180.0) * deg
}
// Translate radians to degrees
@[inline]
pub fn deg(grad f32) f32 {
return (180.0 / math.pi) * grad
}
// calculate the Orthographic projection matrix
pub fn ortho(left f32, right f32, bottom f32, top f32, z_near f32, z_far f32) Mat4 {
rml := right - left
rpl := right + left
tmb := top - bottom
tpb := top + bottom
fmn := z_far - z_near
fpn := z_far + z_near
// vfmt off
if fmn != 0 {
return Mat4{
e: [
2 / rml, 0, 0, -(rpl / rml),
0 , 2 / tmb, 0, -(tpb / tmb),
0 , 0, 2 / fmn, -(fpn / fmn),
0 , 0, 0, 1,
]!
}
}
return Mat4{
e: [
2 / rml, 0, 0, -(rpl / rml),
0, 2 / tmb, 0, -(tpb / tmb),
0, 0, 0, 0,
0, 0, 0, 1,
]!
}
// vfmt on
}
// Calculate the perspective matrix using (fov:fov, ar:aspect_ratio ,n:near_pane, f:far_plane) as parameters
pub fn perspective(fov f32, ar f32, n f32, f f32) Mat4 {
ctan := f32(1.0 / math.tan(fov * (f32(math.pi) / 360.0))) // for the FOV we use 360 instead 180
// vfmt off
return Mat4{
e: [
ctan / ar, 0, 0, 0,
0, ctan, 0, 0,
0, 0, (n + f) / (n - f), -1.0,
0, 0, (2.0 * n * f) / (n - f), 0,
]!
}
// vfmt on
}
// Calculate the look-at matrix
pub fn look_at(eye Vec4, center Vec4, up Vec4) Mat4 {
f := (center - eye).normalize3()
s := (f % up).normalize3()
u := (s % f)
// vfmt off
return Mat4{e: [
s.e[0], u.e[0], -f.e[0], 0,
s.e[1], u.e[1], -f.e[1], 0,
s.e[2], u.e[2], -f.e[2], 0,
-(s * eye), -(u * eye), f * eye, 1,
]!}
// vfmt on
}
// Get the complete transformation matrix for GLSL demos
pub fn calc_tr_matrices(w f32, h f32, rx f32, ry f32, in_scale f32) Mat4 {
proj := perspective(60, w / h, 0.01, 10.0)
// vfmt off
view := look_at(
Vec4{ e: [f32(0.0), 1.5, 6, 0]! },
Vec4{ e: [f32(0), 0, 0, 0]!},
Vec4{ e: [f32(0), 1.0, 0, 0]!}
)
view_proj := view * proj
rxm := rotate(rad(rx), Vec4{ e: [f32(1), 0, 0, 0]! })
rym := rotate(rad(ry), Vec4{ e: [f32(0), 1, 0, 0]! })
scale_m := scale(Vec4{ e: [in_scale, in_scale, in_scale, 1]! })
// vfmt on
model := rym * rxm
res := (scale_m * model) * view_proj
return res
}
+237
View File
@@ -0,0 +1,237 @@
import gg.m4
// vfmt off
pub fn test_m4() {
unsafe {
// Test Mat4
mut a := m4.Mat4{ e: [
f32(0), 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
]!
}
mut b := m4.Mat4{}
mut c := m4.Mat4{}
// equal test
assert a.e == [
f32(0), 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
]!
// copy test
b.copy(a)
assert a.e == b.e
// test: transpose, scale
assert b.transpose().mul_scalar(2.0).mul_scalar(0.5).transpose().e == a.e
assert b.sum_all() == 120.0
// test rows/columns set/get
for i in 0 .. 4 {
b = m4.zero_m4()
b.set_row(i, m4.Vec4{ e: [f32(1.0), 2, 3, 4]! })
assert b.get_f(0, i) == 1.0
assert b.get_f(1, i) == 2.0
assert b.get_f(2, i) == 3.0
assert b.get_f(3, i) == 4.0
// println(b)
c = m4.zero_m4()
c.set_col(i, m4.Vec4{ e: [f32(1.0), 2, 3, 4]! })
assert c.get_f(i, 0) == 1.0
assert c.get_f(i, 1) == 2.0
assert c.get_f(i, 2) == 3.0
assert c.get_f(i, 3) == 4.0
// println(c)
}
}
}
fn test_swap_col_row() {
unsafe {
// swap_col / swap_row
b := m4.Mat4{ e: [
f32(1), 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
]!
}
b.swap_col(0, 2)
assert b.e == [
f32(3), 2, 1, 4,
7, 6, 5, 8,
11, 10, 9, 12,
15, 14, 13, 16,
]!
b = m4.Mat4{ e: [
f32(1), 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
]!
}
b.swap_row(0, 2)
assert b.e == [
f32(9), 10, 11, 12,
5, 6, 7, 8,
1, 2, 3, 4,
13, 14, 15, 16,
]!
}
}
fn test_sum_sub() {
unsafe {
// test sum/sub
b := m4.unit_m4()
c := m4.unit_m4()
assert m4.sub(m4.add(b, c), b).e == m4.unit_m4().e
assert (b + c - b).e == m4.unit_m4().e
}
}
fn test_transpose() {
unsafe {
b := m4.Mat4{ e: [
f32(0), 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
]!
}
assert b.transpose().transpose().e == b.e
}
}
fn test_multiplication() {
unsafe {
b := m4.Mat4{ e: [
f32(1), 0, 0, 0,
0, 2, 0, 0,
0, 0, 3, 0,
0, 0, 0, 4,
]!
}
c := m4.Mat4{ e: [
f32(1), 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
]!
}
assert (c * c).e == [
f32(90),100,110,120,
202,228,254,280,
314,356,398,440,
426,484,542,600,
]!
assert m4.mul(c, c).e == [
f32(90),100,110,120,
202,228,254,280,
314,356,398,440,
426,484,542,600,
]!
assert m4.mul(b, c).e == [
f32(1), 2, 3, 4,
10, 12, 14, 16,
27, 30, 33, 36,
52, 56, 60, 64,
]!
assert (b * c).e == [
f32(1), 2, 3, 4,
10, 12, 14, 16,
27, 30, 33, 36,
52, 56, 60, 64,
]!
assert m4.det(b) == 24
}
}
fn test_det() {
unsafe {
b := m4.Mat4{ e: [
f32(5), 6, 6, 8,
2, 2, 2, 8,
6, 6, 2, 8,
2, 3, 6, 7,
]!
}
assert m4.det(b) == -8
c := m4.Mat4{ e: [
f32(1), 8, 2, 3,
8, 2, 3, 1,
2, 3, 3, 2,
3, 1, 2, 4,
]!
}
// println("*** INVERSE ****")
// println(m4.mul(b.inverse(),b))
// println(m4.clean_small(m4.mul(c.inverse(),c)))
// println("****************")
assert m4.mul(b.inverse(), b).e == m4.unit_m4().e
assert m4.mul(c.inverse(), c).is_equal(m4.unit_m4())
}
}
fn test_vec4() {
// Test Vec4
// println("*** Vector4 ****")
assert m4.vec3(1,2,3) == m4.Vec4{[f32(1), 2, 3, 1]!}
mut v := m4.Vec4{[f32(1), 2, 3, 4]!}
assert v * v.inv() == 4
assert v.mul_scalar(1.0 / v.mod()).mod() == 1
assert v + m4.Vec4{ e: [f32(5), 6, 7, 8]! } == m4.Vec4{ e: [f32(6), 8, 10, 12]! }
assert v - m4.Vec4{ e: [f32(1), 2, 3, 4]! } == m4.Vec4{ e: [f32(0), 0, 0, 0]! }
assert v.mul_vec4(m4.Vec4{ e: [f32(2), 2, 2, 2]! }) == m4.Vec4{ e: [f32(2), 4, 6, 8]! }
assert f32_abs(v.normalize().mod() - 1) < m4.precision
v = m4.Vec4{[f32(1), 2, 3, 0]!}
assert f32_abs(v.normalize3().mod3() - 1) < m4.precision
assert f32_abs(v.normalize3().mod() - 1) < m4.precision
// cross product
// x y z
// 1 2 3 ==> -3 6 -3 0
// 4 5 6
// println(m4.Vec4{[f32(1),2,3,2]!} % m4.Vec4{[f32(4),5,6,2]!})
assert m4.Vec4{[f32(1), 2, 3, 0]!} % m4.Vec4{[f32(4), 5, 6, 0 ]!} == m4.Vec4{[ f32(-3), 6, -3, 0, ]!}
assert m4.Vec4{[f32(1), 2, 3, 13]!} % m4.Vec4{[f32(4), 5, 6, 11]!} == m4.Vec4{[ f32(-3), 6, -3, 0, ]!}
// matrix * vector
a := m4.Mat4{ e: [
f32(1), 2, 3, 4
5, 6, 7, 8
9, 10, 11, 12
13, 14, 15, 16
]!
}
assert m4.mul_vec(a, m4.Vec4{[f32(1), 2, 3, 4]!}) == m4.Vec4{[ f32(30), 70, 110,150, ]!}
// Rotation
// println("*** Rotation ****")
rotx := m4.rotate(m4.rad(-90), m4.Vec4{ e: [f32(1.0), 0, 0, 0]! }).clean()
roty := m4.rotate(m4.rad(-90), m4.Vec4{ e: [f32(0), 1.0, 0, 0]! }).clean()
rotz := m4.rotate(m4.rad(-90), m4.Vec4{ e: [f32(0), 0, 1, 0]! }).clean()
// println( rotx )
// println( roty )
// println( rotz )
// println( m4.mul_vec(rotx, m4.Vec4{e:[f32(0),0,1,0]!}).clean())
assert m4.mul_vec(roty, m4.Vec4{ e: [f32(1.0), 0.0, 0, 0]! }).clean() == m4.Vec4{ e: [f32(0), 0.0, -1, 0]! }
assert m4.mul_vec(rotz, m4.Vec4{ e: [f32(1.0), 0.0, 0, 0]! }).clean() == m4.Vec4{ e: [f32(0), 1, 0, 0]! }
assert m4.mul_vec(rotx, m4.Vec4{ e: [f32(0), 0, 1, 0]! }).clean() == m4.Vec4{ e: [f32(0), -1, 0, 0]! }
// println("****************")
}
fn test_proj() {
ort := m4.ortho(0,300,0,200,0,0)
assert m4.mul_vec(ort, m4.Vec4{[ f32(150), 100, 0, 1]!}).is_equal(m4.Vec4{[ f32(0), 0, 0, 1]!})
assert m4.mul_vec(ort, m4.Vec4{[ f32(0), 0, 0, 1]!}).is_equal(m4.Vec4{[ f32(-1), -1, 0, 1]!})
assert m4.mul_vec(ort, m4.Vec4{[ f32(300), 200, 0, 1]!}).is_equal(m4.Vec4{[ f32(1), 1, 0, 1]!})
}
// vfmt on
+590
View File
@@ -0,0 +1,590 @@
/**********************************************************************
*
* Simply vector/matrix utility
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* TODO:
**********************************************************************/
module m4
import math
pub union Mat4 {
pub mut:
e [16]f32
f [4][4]f32
}
pub const precision = f32(10e-7)
// default precision for the module
/*********************************************************************
*
* Utility
*
*********************************************************************/
// String representation of the matrix
pub fn (x Mat4) str() string {
// vfmt off
return unsafe {
'|${x.e[0]: -6.3},${x.e[1]: -6.3},${x.e[2]: -6.3},${x.e[3]: -6.3}|\n' +
'|${x.e[4]: -6.3},${x.e[5]: -6.3},${x.e[6]: -6.3},${x.e[7]: -6.3}|\n' +
'|${x.e[8]: -6.3},${x.e[9]: -6.3},${x.e[10]:-6.3},${x.e[11]:-6.3}|\n' +
'|${x.e[12]:-6.3},${x.e[13]:-6.3},${x.e[14]:-6.3},${x.e[15]:-6.3}|'
}
// vfmt on
}
// Remove all the raw zeros
@[direct_array_access]
pub fn (a Mat4) clean() Mat4 {
unsafe {
x := Mat4{}
for c, value in a.e {
if f32_abs(value) < precision {
x.e[c] = 0
} else {
x.e[c] = value
}
}
return x
}
return zero_m4() // workaround -cstrict
}
// Sum all the elements of the matrix
pub fn (x Mat4) sum_all() f32 {
mut res := f32(0)
for v in unsafe { x.e } {
res += v
}
return res
}
// Check if two matrix are equal using module precision
@[direct_array_access]
pub fn (x Mat4) is_equal(y Mat4) bool {
unsafe {
for c, value in x.e {
if f32_abs(value - y.e[c]) > precision {
return false
}
}
return true
}
}
//-------------------------------------
// Set/Get values
//-------------------------------------
// Get an element of the matrix using [0..15] indexes, one dimension
pub fn (x Mat4) get_e(elem_index int) f32 {
unsafe {
return x.e[elem_index]
}
}
// Get an element of the matrix using [0..3][0..3] indexes, two dimension
pub fn (x Mat4) get_f(index_col int, index_row int) f32 {
unsafe {
return x.e[int(u32(index_row) << 2) + index_col]
}
}
// Set an element of the matrix using [0..15] indexes, one dimension
pub fn (mut x Mat4) set_e(index int, value f32) {
unsafe {
x.e[index] = value
}
}
// Set an element of the matrix using [0..3][0..3] indexes, two dimension
pub fn (mut x Mat4) set_f(index_col int, index_row int, value f32) {
unsafe {
x.e[int(u32(index_row) << 2) + index_col] = value
}
}
// Copy a matrix elements from another matrix
pub fn (mut x Mat4) copy(y Mat4) {
unsafe {
x.e = [
// vfmt off
y.e[0 ], y.e[1 ], y.e[2 ], y.e[3 ],
y.e[4 ], y.e[5 ], y.e[6 ], y.e[7 ],
y.e[8 ], y.e[9 ], y.e[10], y.e[11],
y.e[12], y.e[13], y.e[14], y.e[15],
// vfmt on
]!
}
}
// Set the trace of the matrix using a vec4
pub fn (mut x Mat4) set_trace(v3 Vec4) {
unsafe {
// vfmt off
x.e[0 ] = v3.e[0]
x.e[5 ] = v3.e[1]
x.e[10] = v3.e[2]
x.e[15] = v3.e[3]
// vfmt on
}
}
// Get the trace of the matrix
pub fn (x Mat4) get_trace() Vec4 {
unsafe {
// vfmt off
return Vec4{ e: [ x.e[0], x.e[5], x.e[10], x.e[15], ]! }
// vfmt on
}
}
// Set all the matrix elements to value
pub fn (mut x Mat4) set_f32(value f32) {
unsafe {
// vfmt off
x.e = [
value, value, value, value,
value, value, value, value,
value, value, value, value,
value, value, value, value,
]!
// vfmt on
}
}
//-------------------------------------
// Rows/Column access
//-------------------------------------
// Set the row as the input vec4
@[direct_array_access; unsafe]
pub fn (mut x Mat4) set_row(row int, v3 Vec4) {
unsafe {
x.e[row * 4 + 0] = v3.e[0]
x.e[row * 4 + 1] = v3.e[1]
x.e[row * 4 + 2] = v3.e[2]
x.e[row * 4 + 3] = v3.e[3]
}
}
// Get a row from a matrix
@[direct_array_access; unsafe]
pub fn (x Mat4) get_row(row int) Vec4 {
unsafe {
// vfmt off
return Vec4{ e: [ x.e[row * 4], x.e[row * 4 + 1], x.e[row * 4 + 2], x.e[row * 4 + 3], ]! }
// vfmt on
}
}
// Set the column as the input vec4
@[direct_array_access; unsafe]
pub fn (mut x Mat4) set_col(col int, v3 Vec4) {
unsafe {
// vfmt off
x.e[col ] = v3.e[0]
x.e[col + 4 ] = v3.e[1]
x.e[col + 8 ] = v3.e[2]
x.e[col + 12] = v3.e[3]
// vfmt on
}
}
// Get a column from a matrix
@[direct_array_access; unsafe]
pub fn (x Mat4) get_col(col int) Vec4 {
unsafe {
// vfmt off
return Vec4{ e: [ x.e[col], x.e[col + 4 ], x.e[col + 8 ], x.e[col + 12], ]!}
// vfmt on
}
}
// Swap two columns in the matrix
@[direct_array_access; unsafe]
pub fn (mut x Mat4) swap_col(col1 int, col2 int) {
unsafe {
// vfmt off
v0 := x.e[col1 ]
v1 := x.e[col1 + 4 ]
v2 := x.e[col1 + 8 ]
v3 := x.e[col1 + 12]
x.e[col1 ] = x.e[col2 ]
x.e[col1 + 4 ] = x.e[col2 + 4 ]
x.e[col1 + 8 ] = x.e[col2 + 8 ]
x.e[col1 + 12] = x.e[col2 + 12]
x.e[col2 ] = v0
x.e[col2 + 4 ] = v1
x.e[col2 + 8 ] = v2
x.e[col2 + 12] = v3
// vfmt on
}
}
// Swap two rows in the matrix
@[direct_array_access; unsafe]
pub fn (mut x Mat4) swap_row(row1 int, row2 int) {
unsafe {
v0 := x.e[row1 * 4 + 0]
v1 := x.e[row1 * 4 + 1]
v2 := x.e[row1 * 4 + 2]
v3 := x.e[row1 * 4 + 3]
x.e[row1 * 4 + 0] = x.e[row2 * 4 + 0]
x.e[row1 * 4 + 1] = x.e[row2 * 4 + 1]
x.e[row1 * 4 + 2] = x.e[row2 * 4 + 2]
x.e[row1 * 4 + 3] = x.e[row2 * 4 + 3]
x.e[row2 * 4 + 0] = v0
x.e[row2 * 4 + 1] = v1
x.e[row2 * 4 + 2] = v2
x.e[row2 * 4 + 3] = v3
}
}
//-------------------------------------
// Modify data
//-------------------------------------
// Transpose the matrix
pub fn (x Mat4) transpose() Mat4 {
// vfmt off
return unsafe {
Mat4{ e: [
x.e[0 ], x.e[4 ], x.e[8 ], x.e[12],
x.e[1 ], x.e[5 ], x.e[9 ], x.e[13],
x.e[2 ], x.e[6 ], x.e[10], x.e[14],
x.e[3 ], x.e[7 ], x.e[11], x.e[15],
]!}
}
// vfmt on
}
// Multiply the all the elements of the matrix by a scalar
pub fn (x Mat4) mul_scalar(s f32) Mat4 {
// vfmt off
return unsafe {
Mat4{ e: [
x.e[0 ] * s, x.e[1 ] * s, x.e[2 ] * s, x.e[3 ] * s,
x.e[4 ] * s, x.e[5 ] * s, x.e[6 ] * s, x.e[7 ] * s,
x.e[8 ] * s, x.e[9 ] * s, x.e[10] * s, x.e[11] * s,
x.e[12] * s, x.e[13] * s, x.e[14] * s, x.e[15] * s,
]!}
}
// vfmt on
}
/*********************************************************************
*
* Init/set
*
*********************************************************************/
// Return a zero matrix
pub fn zero_m4() Mat4 {
// vfmt off
return Mat4{ e: [
f32(0), 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
]!}
// vfmt on
}
// Return a unity matrix
pub fn unit_m4() Mat4 {
// vfmt off
return Mat4{ e: [
f32(1), 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]!}
// vfmt on
}
// Return a matrix initialized with value
pub fn set_m4(value f32) Mat4 {
// vfmt off
return Mat4{ e: [
value, value, value, value,
value, value, value, value,
value, value, value, value,
value, value, value, value,
]!}
// vfmt on
}
/*********************************************************************
*
* Math
*
*********************************************************************/
// Sum of matrix, operator +
pub fn (a Mat4) + (b Mat4) Mat4 {
// vfmt off
return unsafe {
Mat4{ e: [
a.e[0 ] + b.e[0 ], a.e[1 ] + b.e[1 ], a.e[2 ] + b.e[2 ], a.e[3 ] + b.e[3 ],
a.e[4 ] + b.e[4 ], a.e[5 ] + b.e[5 ], a.e[6 ] + b.e[6 ], a.e[7 ] + b.e[7 ],
a.e[8 ] + b.e[8 ], a.e[9 ] + b.e[9 ], a.e[10] + b.e[10], a.e[11] + b.e[11],
a.e[12] + b.e[12], a.e[13] + b.e[13], a.e[14] + b.e[14], a.e[15] + b.e[15],
]!}
}
// vfmt on
}
// Subtraction of matrix, operator -
pub fn (a Mat4) - (b Mat4) Mat4 {
// vfmt off
return unsafe {
Mat4{ e: [
a.e[0 ] - b.e[0 ], a.e[1 ] - b.e[1 ], a.e[2 ] - b.e[2 ], a.e[3 ] - b.e[3 ],
a.e[4 ] - b.e[4 ], a.e[5 ] - b.e[5 ], a.e[6 ] - b.e[6 ], a.e[7 ] - b.e[7 ],
a.e[8 ] - b.e[8 ], a.e[9 ] - b.e[9 ], a.e[10] - b.e[10], a.e[11] - b.e[11],
a.e[12] - b.e[12], a.e[13] - b.e[13], a.e[14] - b.e[14], a.e[15] - b.e[15],
]!}
}
// vfmt on
}
// Multiplication of matrix, operator *
pub fn (a Mat4) * (b Mat4) Mat4 {
// vfmt off
return unsafe {
Mat4{ e: [
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
]!}
}
// vfmt on
}
// Sum of matrix function
pub fn add(a Mat4, b Mat4) Mat4 {
return a + b
}
// Subtraction of matrix function
pub fn sub(a Mat4, b Mat4) Mat4 {
return a - b
}
// Multiplication of matrix function
pub fn mul(a Mat4, b Mat4) Mat4 {
return a * b
}
// Multiply a Matrix by a vector
pub fn mul_vec(a Mat4, v Vec4) Vec4 {
// vfmt off
return unsafe {
Vec4{ e: [
a.e[0 ] * v.e[0] + a.e[1 ] * v.e[1] + a.e[2 ] * v.e[2] + a.e[3 ] * v.e[3],
a.e[4 ] * v.e[0] + a.e[5 ] * v.e[1] + a.e[6 ] * v.e[2] + a.e[7 ] * v.e[3],
a.e[8 ] * v.e[0] + a.e[9 ] * v.e[1] + a.e[10] * v.e[2] + a.e[11] * v.e[3],
a.e[12] * v.e[0] + a.e[13] * v.e[1] + a.e[14] * v.e[2] + a.e[15] * v.e[3],
]!}
}
// vfmt on
}
// Calculate the determinant of the Matrix
pub fn det(x Mat4) f32 {
unsafe {
mut t := [6]f32{}
x00 := x.f[0][0]
x10 := x.f[1][0]
x20 := x.f[2][0]
x30 := x.f[3][0]
x01 := x.f[0][1]
x11 := x.f[1][1]
x21 := x.f[2][1]
x31 := x.f[3][1]
x02 := x.f[0][2]
x12 := x.f[1][2]
x22 := x.f[2][2]
x32 := x.f[3][2]
x03 := x.f[0][3]
x13 := x.f[1][3]
x23 := x.f[2][3]
x33 := x.f[3][3]
t[0] = x22 * x33 - x23 * x32
t[1] = x12 * x33 - x13 * x32
t[2] = x12 * x23 - x13 * x22
t[3] = x02 * x33 - x03 * x32
t[4] = x02 * x23 - x03 * x22
t[5] = x02 * x13 - x03 * x12
// vfmt off
return
x00 * (x11 * t[0] - x21 * t[1] + x31 * t[2]) -
x10 * (x01 * t[0] - x21 * t[3] + x31 * t[4]) +
x20 * (x01 * t[1] - x11 * t[3] + x31 * t[5]) -
x30 * (x01 * t[2] - x11 * t[4] + x21 * t[5])
// vfmt on
}
return 0 // workaround -cstrict
}
// Calculate the inverse of the Matrix
pub fn (x Mat4) inverse() Mat4 {
unsafe {
mut t := [6]f32{}
mut inv_det := f32(0)
// vfmt off
a := x.f[0][0]
b := x.f[1][0]
c := x.f[2][0]
d := x.f[3][0]
e := x.f[0][1]
f := x.f[1][1]
g := x.f[2][1]
h := x.f[3][1]
i := x.f[0][2]
j := x.f[1][2]
k := x.f[2][2]
l := x.f[3][2]
m := x.f[0][3]
n := x.f[1][3]
o := x.f[2][3]
p := x.f[3][3]
t[0] = k * p - o * l
t[1] = j * p - n * l
t[2] = j * o - n * k
t[3] = i * p - m * l
t[4] = i * o - m * k
t[5] = i * n - m * j
mut dest := Mat4{}
dest.f[0][0] = f * t[0] - g * t[1] + h * t[2]
dest.f[0][1] = -(e * t[0] - g * t[3] + h * t[4])
dest.f[0][2] = e * t[1] - f * t[3] + h * t[5]
dest.f[0][3] = -(e * t[2] - f * t[4] + g * t[5])
dest.f[1][0] = -(b * t[0] - c * t[1] + d * t[2])
dest.f[1][1] = a * t[0] - c * t[3] + d * t[4]
dest.f[1][2] = -(a * t[1] - b * t[3] + d * t[5])
dest.f[1][3] = a * t[2] - b * t[4] + c * t[5]
t[0] = g * p - o * h
t[1] = f * p - n * h
t[2] = f * o - n * g
t[3] = e * p - m * h
t[4] = e * o - m * g
t[5] = e * n - m * f
dest.f[2][0] = b * t[0] - c * t[1] + d * t[2]
dest.f[2][1] = -(a * t[0] - c * t[3] + d * t[4])
dest.f[2][2] = a * t[1] - b * t[3] + d * t[5]
dest.f[2][3] = -(a * t[2] - b * t[4] + c * t[5])
t[0] = g * l - k * h
t[1] = f * l - j * h
t[2] = f * k - j * g
t[3] = e * l - i * h
t[4] = e * k - i * g
t[5] = e * j - i * f
dest.f[3][0] = -(b * t[0] - c * t[1] + d * t[2])
dest.f[3][1] = a * t[0] - c * t[3] + d * t[4]
dest.f[3][2] = -(a * t[1] - b * t[3] + d * t[5])
dest.f[3][3] = a * t[2] - b * t[4] + c * t[5]
// vfmt on
tmp := (a * dest.f[0][0] + b * dest.f[0][1] + c * dest.f[0][2] + d * dest.f[0][3])
if tmp != 0 {
inv_det = f32(1.0) / tmp
}
return dest.mul_scalar(inv_det)
}
return zero_m4()
}
/*********************************************************************
*
* Transformations
*
*********************************************************************/
// Get a rotation matrix using w as rotation axis vector, the angle is in radians
pub fn rotate(angle f32, w Vec4) Mat4 {
cs := f32(math.cos(angle))
sn := f32(math.sin(angle))
cv := f32(1.0) - cs
axis := w.normalize3()
unsafe {
ax := axis.e[0]
ay := axis.e[1]
az := axis.e[2]
// vfmt off
return Mat4{ e: [
(ax * ax * cv) + cs, (ax * ay * cv) + az * sn, (ax * az * cv) - ay * sn, 0,
(ay * ax * cv) - az * sn, (ay * ay * cv) + cs, (ay * az * cv) + ax * sn, 0,
(az * ax * cv) + ay * sn, (az * ay * cv) - ax * sn, (az * az * cv) + cs, 0,
0, 0, 0, 1,
]!}
// vfmt on
}
return zero_m4()
}
/*********************************************************************
*
* Graphic
*
*********************************************************************/
// Get a matrix translated by a vector w
pub fn (x Mat4) translate(w Vec4) Mat4 {
// vfmt off
return unsafe {
Mat4{ e: [
x.e[0], x.e[1], x.e[2 ], x.e[3 ],
x.e[4], x.e[5], x.e[6 ], x.e[7 ],
x.e[8], x.e[9], x.e[10], x.e[11],
x.e[12] + w.e[0], x.e[13] + w.e[1], x.e[14] + w.e[2], x.e[15],
]!}
}
// vfmt on
}
// Get a scale matrix, the scale vector is w, only xyz are evaluated.
pub fn scale(w Vec4) Mat4 {
// vfmt off
return unsafe {
Mat4{ e: [
w.e[0], 0, 0, 0,
0, w.e[1], 0, 0,
0, 0, w.e[2], 0,
0, 0, 0, 1,
]!}
}
// vfmt on
}
+250
View File
@@ -0,0 +1,250 @@
/**********************************************************************
* Simple vector/matrix utility
* Copyright (c) 2024 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
**********************************************************************/
module m4
import math
pub struct Vec4 {
pub mut:
e [4]f32
}
// str returns a `string` representation of `Vec4`.
pub fn (x Vec4) str() string {
return '|${x.e[0]:-6.3},${x.e[1]:-6.3},${x.e[2]:-6.3},${x.e[3]:-6.3}|'
}
// vec3 creates a Vec4 value, passing x,y,z as parameters. The w element is set to 1
@[inline]
pub fn vec3(x f32, y f32, z f32) Vec4 {
return Vec4{
e: [x, y, z, 1]!
}
}
// vec4 creates a Vec4 value, based on the x,y,z,w parameters
@[inline]
pub fn vec4(x f32, y f32, z f32, w f32) Vec4 {
return Vec4{
e: [x, y, z, w]!
}
}
// is_equal checks if two vector are equal using the module precision (10e-7)
@[direct_array_access]
pub fn (x Vec4) is_equal(y Vec4) bool {
unsafe {
for c, value in x.e {
if f32_abs(value - y.e[c]) > precision {
return false
}
}
return true
}
}
// clean returns a new vector, based on `x`, but with all the values < precision, set to 0
@[direct_array_access]
pub fn (x Vec4) clean() Vec4 {
mut n := x
for c, value in x.e {
if f32_abs(value) < precision {
n.e[c] = 0
}
}
return n
}
// copy sets all elements of `x` to `value`
pub fn (mut x Vec4) copy(value f32) {
x.e = [value, value, value, value]!
}
// mul_scalar returns the result of multiplying the vector `x`, by the scalar `value`
@[inline]
pub fn (x Vec4) mul_scalar(value f32) Vec4 {
return Vec4{
e: [x.e[0] * value, x.e[1] * value, x.e[2] * value, x.e[3] * value]!
}
}
// inv returns the reciprocal of the vector `x`
pub fn (x Vec4) inv() Vec4 {
return Vec4{
e: [
if x.e[0] != 0 { 1.0 / x.e[0] } else { 0 },
if x.e[1] != 0 { 1.0 / x.e[1] } else { 0 },
if x.e[2] != 0 { 1.0 / x.e[2] } else { 0 },
if x.e[3] != 0 { 1.0 / x.e[3] } else { 0 },
]!
}
}
// normalize returns a normalized form of the vector `x`
pub fn (x Vec4) normalize() Vec4 {
m := x.mod()
if m == 0 {
return zero_v4()
}
return Vec4{
e: [
x.e[0] * (1 / m),
x.e[1] * (1 / m),
x.e[2] * (1 / m),
x.e[3] * (1 / m),
]!
}
}
// normalize3 returns a normalized form of the vector `x`, where the w element is set to 0
pub fn (x Vec4) normalize3() Vec4 {
m := x.mod3()
if m == 0 {
return zero_v4()
}
return Vec4{
e: [
x.e[0] * (1 / m),
x.e[1] * (1 / m),
x.e[2] * (1 / m),
0,
]!
}
}
// mod returns a module of the vector `x`
@[inline]
pub fn (x Vec4) mod() f32 {
return math.sqrtf(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2] + x.e[3] * x.e[3])
}
// mod3 returns a module of the 3d vector `x`, ignoring the value of its w element
@[inline]
pub fn (x Vec4) mod3() f32 {
return math.sqrtf(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2])
}
/*********************************************************************
* Math
*********************************************************************/
// zero_v4 returns a zero vector (all elements set to 0)
@[inline]
pub fn zero_v4() Vec4 {
return Vec4{
e: [
f32(0),
0,
0,
0,
]!
}
}
// one_v4 returns a vector, where all elements are set to 1
@[inline]
pub fn one_v4() Vec4 {
return Vec4{
e: [
f32(1),
1,
1,
1,
]!
}
}
// blank_v4 returns a vector, where all elements are set to 0, except `w`, which is set to 1
pub fn blank_v4() Vec4 {
return Vec4{
e: [
f32(0),
0,
0,
1,
]!
}
}
// set_v4 returns a vector, where all elements are set to `value`
@[inline]
pub fn set_v4(value f32) Vec4 {
return Vec4{
e: [
value,
value,
value,
value,
]!
}
}
// sum returns a sum of all the elements
@[inline]
pub fn (x Vec4) sum() f32 {
return x.e[0] + x.e[1] + x.e[2] + x.e[3]
}
/*********************************************************************
* Operators
*********************************************************************/
// + returns `a` + `b` (corresponding elements are added)
@[inline]
pub fn (a Vec4) + (b Vec4) Vec4 {
return Vec4{
e: [
a.e[0] + b.e[0],
a.e[1] + b.e[1],
a.e[2] + b.e[2],
a.e[3] + b.e[3],
]!
}
}
// - returns `a` + `b` (corresponding elements are subtracted)
@[inline]
pub fn (a Vec4) - (b Vec4) Vec4 {
return Vec4{
e: [
a.e[0] - b.e[0],
a.e[1] - b.e[1],
a.e[2] - b.e[2],
a.e[3] - b.e[3],
]!
}
}
// * returns `a` * `b` (corresponding elements are multiplied, then summed), i.e. a dot product
@[inline]
pub fn (a Vec4) * (b Vec4) f32 {
return a.e[0] * b.e[0] + a.e[1] * b.e[1] + a.e[2] * b.e[2] + a.e[3] * b.e[3]
}
// % returns a cross product of the vectors `a` and `b`
@[inline]
pub fn (a Vec4) % (b Vec4) Vec4 {
return Vec4{
e: [
(a.e[1] * b.e[2]) - (a.e[2] * b.e[1]),
(a.e[2] * b.e[0]) - (a.e[0] * b.e[2]),
(a.e[0] * b.e[1]) - (a.e[1] * b.e[0]),
0,
]!
}
}
// mul_vec4 returns a vector, where the corresponding `x` and `y` elements are multiplied
@[inline]
pub fn (x Vec4) mul_vec4(y Vec4) Vec4 {
return Vec4{
e: [
x.e[0] * y.e[0],
x.e[1] * y.e[1],
x.e[2] * y.e[2],
x.e[3] * y.e[3],
]!
}
}