Current section
Files
Jump to
Current section
Files
src/matrix/mat4f.gleam
//// 4x4 matrices of floats
import vec/vec4.{type Vec4, Vec4}
import vec/vec4f.{type Vec4f}
/// Mat4f is a 4x4 column-major matrix of `Float`s.
pub type Mat4f =
Vec4(Vec4f)
/// A 4x4 matrix filled with zeroes.
pub const zero: Mat4f = Vec4(vec4f.zero, vec4f.zero, vec4f.zero, vec4f.zero)
const x: Vec4f = Vec4(1.0, 0.0, 0.0, 0.0)
const y: Vec4f = Vec4(0.0, 1.0, 0.0, 0.0)
const z: Vec4f = Vec4(0.0, 0.0, 1.0, 0.0)
const w: Vec4f = Vec4(0.0, 0.0, 0.0, 1.0)
/// The 4x4 identity matrix
pub const identity: Mat4f = Vec4(x, y, z, w)
/// Constructs a `Mat4f` from its components.
/// ```text
/// | ax bx cx dx |
/// | ay by cy dy |
/// | az bz cz dz |
/// | aw bw cw dw |
/// ```
pub fn new(
ax: Float,
ay: Float,
az: Float,
aw: Float,
bx: Float,
by: Float,
bz: Float,
bw: Float,
cx: Float,
cy: Float,
cz: Float,
cw: Float,
dx: Float,
dy: Float,
dz: Float,
dw: Float,
) -> Mat4f {
Vec4(
Vec4(ax, ay, az, aw),
Vec4(bx, by, bz, bw),
Vec4(cx, cy, cz, cw),
Vec4(dx, dy, dz, dw),
)
}
/// Constructs a `Mat4f` from its four columns.
/// ```text
/// | a.x b.x c.x d.x |
/// | a.y b.y c.y d.y |
/// | a.z b.z c.z d.z |
/// | a.w b.w c.w d.w |
/// ```
pub fn from_cols(a: Vec4f, b: Vec4f, c: Vec4f, d: Vec4f) -> Mat4f {
Vec4(a, b, c, d)
}
/// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries are 0.
pub fn from_diagonal(diagonal: Vec4f) -> Mat4f {
from_cols(
Vec4(diagonal.x, 0.0, 0.0, 0.0),
Vec4(0.0, diagonal.y, 0.0, 0.0),
Vec4(0.0, 0.0, diagonal.z, 0.0),
Vec4(0.0, 0.0, 0.0, diagonal.w),
)
}
/// Transposes the `Mat4f` along the diagonal.
pub fn transpose(mat: Mat4f) -> Mat4f {
from_cols(
Vec4(mat.x.x, mat.y.x, mat.z.x, mat.w.x),
Vec4(mat.x.y, mat.y.y, mat.z.y, mat.w.y),
Vec4(mat.x.z, mat.y.z, mat.z.z, mat.w.z),
Vec4(mat.x.w, mat.y.w, mat.z.w, mat.w.w),
)
}
/// Extracts the diagonal of the `Mat4f`.
pub fn diagonal(mat: Mat4f) -> Vec4f {
Vec4(mat.x.x, mat.y.y, mat.z.z, mat.w.w)
}
/// Returns the determinant of the `Mat4f`.
pub fn determinant(mat: Mat4f) -> Float {
let Vec4(x: m00, y: m01, z: m02, w: m03) = mat.x
let Vec4(x: m10, y: m11, z: m12, w: m13) = mat.y
let Vec4(x: m20, y: m21, z: m22, w: m23) = mat.z
let Vec4(x: m30, y: m31, z: m32, w: m33) = mat.w
let a2323 = m22 *. m33 -. m23 *. m32
let a1323 = m21 *. m33 -. m23 *. m31
let a1223 = m21 *. m32 -. m22 *. m31
let a0323 = m20 *. m33 -. m23 *. m30
let a0223 = m20 *. m32 -. m22 *. m30
let a0123 = m20 *. m31 -. m21 *. m30
m00
*. { m11 *. a2323 -. m12 *. a1323 +. m13 *. a1223 }
-. m01
*. { m10 *. a2323 -. m12 *. a0323 +. m13 *. a0223 }
+. m02
*. { m10 *. a1323 -. m11 *. a0323 +. m13 *. a0123 }
-. m03
*. { m10 *. a1223 -. m11 *. a0223 +. m12 *. a0123 }
}
/// Transforms a 4D vector by this `Mat4f`.
pub fn mul_vec4(mat: Mat4f, rhs: Vec4f) -> Vec4f {
vec4.map2(mat, rhs, vec4f.scale)
|> vec4.to_list
|> vec4f.sum
}
/// Transforms a 4D vector by the transpose of the `Mat4f`.
///
/// Equivalent to matrix multiplication where the vector is on the left.
pub fn mul_transpose_vec4(mat: Mat4f, rhs: Vec4f) -> Vec4f {
vec4.map(mat, vec4f.dot(_, rhs))
}
/// Scales the `Mat4f` by a `Float`.
pub fn scale(mat: Mat4f, scale: Float) -> Mat4f {
vec4.map(mat, vec4f.scale(_, scale))
}
/// Adds two `Mat4f`s together
pub fn add(a: Mat4f, b: Mat4f) -> Mat4f {
vec4.map2(a, b, vec4f.add)
}
/// Subtracts `Mat4f` `b` from `a`
pub fn subtract(a: Mat4f, b: Mat4f) -> Mat4f {
vec4.map2(a, b, vec4f.subtract)
}