-module(matrix@mat3f). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/matrix/mat3f.gleam"). -export([new/9, from_cols/3, from_diagonal/1, from_quaternion/1, from_axis_angle/2, from_rotation_x/1, from_rotation_y/1, from_rotation_z/1, from_translation/1, from_angle/1, from_scale_angle_translation/3, from_scale/1, transpose/1, determinant/1, mul_vec3/2, transform_point2/2, transform_vector2/2, look_to_rh/2, look_to_lh/2, look_at_lh/3, look_at_rh/3, mul_transpose_vec3/2, negate/1, absolute_value/1, add/2, subtract/2, multiply/2, scale/2, inverse/1, divide/2, scale_diagonal/2, reciprocal/1, sum/1, product/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC(" 3x3 matrices of floats\n"). -file("src/matrix/mat3f.gleam", 31). ?DOC( " Constructs a `Mat3f` from its components:\n" " ```text\n" " | a d g |\n" " | b e h |\n" " | c f i |\n" " ```\n" ). -spec new( float(), float(), float(), float(), float(), float(), float(), float(), float() ) -> vec@vec3:vec3(vec@vec3:vec3(float())). new(A, B, C, D, E, F, G, H, I) -> {vec3, {vec3, A, B, C}, {vec3, D, E, F}, {vec3, G, H, I}}. -file("src/matrix/mat3f.gleam", 51). ?DOC( " Constructs a `Mat3f` from its three columns.\n" " ```text\n" " | ax bx cx |\n" " | ay by cy |\n" " | az bz cz |\n" " ```\n" ). -spec from_cols( vec@vec3:vec3(float()), vec@vec3:vec3(float()), vec@vec3:vec3(float()) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_cols(A, B, C) -> {vec3, A, B, C}. -file("src/matrix/mat3f.gleam", 61). ?DOC( " Constructs a `Mat3f` with the given diagonal and all other entries set to 0.\n" " ```text\n" " | x 0.0 0.0 |\n" " | 0.0 y 0.0 |\n" " | 0.0 0.0 z |\n" " ```\n" ). -spec from_diagonal(vec@vec3:vec3(float())) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_diagonal(Diag) -> new( erlang:element(2, Diag), +0.0, +0.0, +0.0, erlang:element(3, Diag), +0.0, +0.0, +0.0, erlang:element(4, Diag) ). -file("src/matrix/mat3f.gleam", 66). ?DOC(" Constructs a 3D rotation matrix from the given quaternion, represented as a `vec4.Vec4(Float)`.\n"). -spec from_quaternion(vec@vec4:vec4(float())) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_quaternion(Q) -> Rotation = vec@vec4f:normalize(Q), X2 = erlang:element(2, Rotation) + erlang:element(2, Rotation), Y2 = erlang:element(3, Rotation) + erlang:element(3, Rotation), Z2 = erlang:element(4, Rotation) + erlang:element(4, Rotation), Xx = erlang:element(2, Rotation) * X2, Xy = erlang:element(2, Rotation) * Y2, Xz = erlang:element(2, Rotation) * Z2, Yy = erlang:element(3, Rotation) * Y2, Yz = erlang:element(3, Rotation) * Z2, Zz = erlang:element(4, Rotation) * Z2, Wx = erlang:element(5, Rotation) * X2, Wy = erlang:element(5, Rotation) * Y2, Wz = erlang:element(5, Rotation) * Z2, from_cols( {vec3, 1.0 - (Yy + Zz), Xy + Wz, Xz - Wy}, {vec3, Xy - Wz, 1.0 - (Xx + Zz), Yz + Wx}, {vec3, Xz + Wy, Yz - Wx, 1.0 - (Xx + Yy)} ). -file("src/matrix/mat3f.gleam", 90). ?DOC(" Creates a 3D rotation matrix from a normalized rotation `axis` and `angle` (in radians).\n"). -spec from_axis_angle(vec@vec3:vec3(float()), float()) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_axis_angle(Axis, Angle) -> Axis@1 = vec@vec3f:normalize(Axis), Sin_a = gleam_community@maths:sin(Angle), Cos_a = gleam_community@maths:cos(Angle), {vec3, X, Y, Z} = Axis@1, {vec3, Xsin, Ysin, Zsin} = vec@vec3f:scale(Axis@1, Sin_a), {vec3, X2, Y2, Z2} = vec@vec3f:multiply(Axis@1, Axis@1), Omc = 1.0 - Cos_a, Xyomc = (X * Y) * Omc, Xzomc = (X * Z) * Omc, Yzomc = (Y * Z) * Omc, from_cols( {vec3, (X2 * Omc) + Cos_a, Xyomc + Zsin, Yzomc - Ysin}, {vec3, Xyomc - Zsin, (Y2 * Omc) + Cos_a, Yzomc + Xsin}, {vec3, Xzomc + Ysin, Yzomc - Xsin, (Z2 * Omc) + Cos_a} ). -file("src/matrix/mat3f.gleam", 109). ?DOC(" Creates a 3D rotation matrix from `angle` in radians around the x axis.\n"). -spec from_rotation_x(float()) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_rotation_x(Angle) -> Sina = gleam_community@maths:sin(Angle), Cosa = gleam_community@maths:cos(Angle), from_cols( {vec3, 1.0, +0.0, +0.0}, {vec3, +0.0, Cosa, Sina}, {vec3, +0.0, +0.0 - Sina, Cosa} ). -file("src/matrix/mat3f.gleam", 116). ?DOC(" Creates a 3D rotation matrix from `angle` in radians around the y axis.\n"). -spec from_rotation_y(float()) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_rotation_y(Angle) -> Sina = gleam_community@maths:sin(Angle), Cosa = gleam_community@maths:cos(Angle), from_cols( {vec3, Cosa, +0.0, +0.0 - Sina}, {vec3, +0.0, 1.0, +0.0}, {vec3, Sina, +0.0, Cosa} ). -file("src/matrix/mat3f.gleam", 123). ?DOC(" Creates a 3D rotation matrix from `angle` in radians around the z axis.\n"). -spec from_rotation_z(float()) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_rotation_z(Angle) -> Sina = gleam_community@maths:sin(Angle), Cosa = gleam_community@maths:cos(Angle), from_cols( {vec3, Cosa, Sina, +0.0}, {vec3, +0.0 - Sina, Cosa, +0.0}, {vec3, +0.0, +0.0, 1.0} ). -file("src/matrix/mat3f.gleam", 132). ?DOC( " Creates an affine transformation matrix from the given 2D `translation`.\n" "\n" " The resulting matrix can be used to transform 2D points and vectors.\n" ). -spec from_translation(vec@vec2:vec2(float())) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_translation(Translation) -> from_cols( {vec3, 1.0, +0.0, +0.0}, {vec3, +0.0, 1.0, +0.0}, matrix@internal@projection:extend2(Translation, 1.0) ). -file("src/matrix/mat3f.gleam", 139). ?DOC( " Creates an affine transformation matrix from the given 2D rotation `angle` (in radians).\n" "\n" " The resulting matrix can be used to transform 2D points and vectors.\n" ). -spec from_angle(float()) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_angle(Angle) -> from_rotation_z(Angle). -file("src/matrix/mat3f.gleam", 146). ?DOC( " Creates an affine transformation matrix from the given 2D `scale`, rotation `angle` (in radians), and `translation`.\n" "\n" " The resulting matrix can be used to transform 2D points and vectors.\n" ). -spec from_scale_angle_translation( vec@vec2:vec2(float()), float(), vec@vec2:vec2(float()) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_scale_angle_translation(Scale, Angle, Translation) -> Sina = gleam_community@maths:sin(Angle), Cosa = gleam_community@maths:cos(Angle), from_cols( {vec3, Cosa * erlang:element(2, Scale), Sina * erlang:element(2, Scale), +0.0}, {vec3, gleam@float:negate(Sina) * erlang:element(3, Scale), Cosa * erlang:element(3, Scale), +0.0}, matrix@internal@projection:extend2(Translation, 1.0) ). -file("src/matrix/mat3f.gleam", 163). ?DOC( " Creates an affine transformation matrix from teh given non-uniform 2D `scale`.\n" "\n" " The resulting matrix can be used to transform 2D points and vectors.\n" ). -spec from_scale(vec@vec2:vec2(float())) -> vec@vec3:vec3(vec@vec3:vec3(float())). from_scale(Scale) -> from_diagonal(matrix@internal@projection:extend2(Scale, 1.0)). -file("src/matrix/mat3f.gleam", 168). ?DOC(" Transposes the `Mat3f` along the diagonal.\n"). -spec transpose(vec@vec3:vec3(vec@vec3:vec3(float()))) -> vec@vec3:vec3(vec@vec3:vec3(float())). transpose(Mat) -> new( erlang:element(2, erlang:element(2, Mat)), erlang:element(2, erlang:element(3, Mat)), erlang:element(2, erlang:element(4, Mat)), erlang:element(3, erlang:element(2, Mat)), erlang:element(3, erlang:element(3, Mat)), erlang:element(3, erlang:element(4, Mat)), erlang:element(4, erlang:element(2, Mat)), erlang:element(4, erlang:element(3, Mat)), erlang:element(4, erlang:element(4, Mat)) ). -file("src/matrix/mat3f.gleam", 183). ?DOC(" Returns the determinant for the `Mat3f`.\n"). -spec determinant(vec@vec3:vec3(vec@vec3:vec3(float()))) -> float(). determinant(Mat) -> {vec3, {vec3, A1, B1, C1}, {vec3, A2, B2, C2}, {vec3, A3, B3, C3}} = Mat, ((((((A1 * B2) * C3) - ((A1 * B3) * C2)) - ((A2 * B1) * C3)) + ((A2 * B3) * C1)) + ((A3 * B1) * C2)) - ((A3 * B2) * C1). -file("src/matrix/mat3f.gleam", 219). ?DOC(" Transforms a `Vec3f` by this `Mat3f`.\n"). -spec mul_vec3(vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(float())) -> vec@vec3:vec3(float()). mul_vec3(Mat, Rhs) -> _pipe = vec@vec3:map2(Mat, Rhs, fun vec@vec3f:scale/2), _pipe@1 = vec@vec3:to_list(_pipe), vec@vec3f:sum(_pipe@1). -file("src/matrix/mat3f.gleam", 230). ?DOC( " Transforms the given 2D vector as a point.\n" "\n" " This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `1`.\n" "\n" " This function assumes that `mat` contains a valid affine transform.\n" ). -spec transform_point2( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec2:vec2(float()) ) -> vec@vec2:vec2(float()). transform_point2(Mat, Rhs) -> _pipe = matrix@mat2f:from_cols( matrix@internal@projection:to_xy(erlang:element(2, Mat)), matrix@internal@projection:to_xy(erlang:element(3, Mat)) ), _pipe@1 = matrix@mat2f:mul_transpose_vec2(_pipe, Rhs), vec@vec2f:add( _pipe@1, matrix@internal@projection:to_xy(erlang:element(4, Mat)) ). -file("src/matrix/mat3f.gleam", 239). ?DOC( " Rotates the given 2D vector.\n" "\n" " This is the equivalent of multiplying `rhs` as a 3D vector where `z` is `0`.\n" ). -spec transform_vector2( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec2:vec2(float()) ) -> vec@vec2:vec2(float()). transform_vector2(Mat, Rhs) -> _pipe = matrix@mat2f:from_cols( matrix@internal@projection:to_xy(erlang:element(2, Mat)), matrix@internal@projection:to_xy(erlang:element(3, Mat)) ), matrix@mat2f:mul_transpose_vec2(_pipe, Rhs). -file("src/matrix/mat3f.gleam", 254). ?DOC( " Creates a right-handed view matrix using a facing direction and an up direction.\n" "\n" " For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.\n" ). -spec look_to_rh(vec@vec3:vec3(float()), vec@vec3:vec3(float())) -> vec@vec3:vec3(vec@vec3:vec3(float())). look_to_rh(Dir, Up) -> Up@1 = vec@vec3f:normalize(Up), F = vec@vec3f:normalize(Dir), S = begin _pipe = F, _pipe@1 = vec@vec3f:cross(_pipe, Up@1), vec@vec3f:normalize(_pipe@1) end, U = vec@vec3f:cross(S, F), Neg_f = vec@vec3f:negate(F), from_cols( {vec3, erlang:element(2, S), erlang:element(2, U), erlang:element(2, Neg_f)}, {vec3, erlang:element(3, S), erlang:element(3, U), erlang:element(3, Neg_f)}, {vec3, erlang:element(4, S), erlang:element(4, U), erlang:element(4, Neg_f)} ). -file("src/matrix/mat3f.gleam", 247). ?DOC( " Creates a left-handed view matrix using a facing direction and an up direction.\n" "\n" " For a view coordinate system with `+X=right`, `+Y=up`, and `+Z=forward`.\n" ). -spec look_to_lh(vec@vec3:vec3(float()), vec@vec3:vec3(float())) -> vec@vec3:vec3(vec@vec3:vec3(float())). look_to_lh(Dir, Up) -> look_to_rh(vec@vec3f:negate(Dir), Up). -file("src/matrix/mat3f.gleam", 272). ?DOC( " Creates a left-handed view matrix using a camera position, a focal point and an up\n" " direction.\n" "\n" " For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.\n" ). -spec look_at_lh( vec@vec3:vec3(float()), vec@vec3:vec3(float()), vec@vec3:vec3(float()) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). look_at_lh(Eye, Center, Up) -> look_to_lh(vec@vec3f:subtract(Center, Eye), Up). -file("src/matrix/mat3f.gleam", 280). ?DOC( " Creates a right-handed view matrix using a camera position, a focal point and an up\n" " direction.\n" "\n" " For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.\n" ). -spec look_at_rh( vec@vec3:vec3(float()), vec@vec3:vec3(float()), vec@vec3:vec3(float()) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). look_at_rh(Eye, Center, Up) -> look_to_rh(vec@vec3f:subtract(Center, Eye), Up). -file("src/matrix/mat3f.gleam", 285). ?DOC(" Transforms a `Vec3f` by the transpose of this `Mat3f`.\n"). -spec mul_transpose_vec3( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(float()) ) -> vec@vec3:vec3(float()). mul_transpose_vec3(Mat, Rhs) -> vec@vec3:map(Mat, fun(_capture) -> vec@vec3f:dot(_capture, Rhs) end). -file("src/matrix/mat3f.gleam", 290). ?DOC(" Negates all elements of the `Mat3f`\n"). -spec negate(vec@vec3:vec3(vec@vec3:vec3(float()))) -> vec@vec3:vec3(vec@vec3:vec3(float())). negate(Mat) -> vec@vec3:map(Mat, fun vec@vec3f:negate/1). -file("src/matrix/mat3f.gleam", 295). ?DOC(" Takes the absolute value of each element in the `Mat3f`.\n"). -spec absolute_value(vec@vec3:vec3(vec@vec3:vec3(float()))) -> vec@vec3:vec3(vec@vec3:vec3(float())). absolute_value(Mat) -> vec@vec3:map(Mat, fun vec@vec3f:absolute_value/1). -file("src/matrix/mat3f.gleam", 300). ?DOC(" Adds two `Mat3f` together.\n"). -spec add( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(vec@vec3:vec3(float())) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). add(A, B) -> vec@vec3:map2(A, B, fun vec@vec3f:add/2). -file("src/matrix/mat3f.gleam", 305). ?DOC(" Subtracts one `Mat3f` from the other.\n"). -spec subtract( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(vec@vec3:vec3(float())) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). subtract(A, B) -> vec@vec3:map2(A, B, fun vec@vec3f:subtract/2). -file("src/matrix/mat3f.gleam", 310). ?DOC(" Multiplies two `Mat3f` together.\n"). -spec multiply( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(vec@vec3:vec3(float())) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). multiply(A, B) -> vec@vec3:map(B, fun(_capture) -> mul_vec3(A, _capture) end). -file("src/matrix/mat3f.gleam", 321). ?DOC(" Scales the `Mat3f` by a `Float` factor.\n"). -spec scale(vec@vec3:vec3(vec@vec3:vec3(float())), float()) -> vec@vec3:vec3(vec@vec3:vec3(float())). scale(Mat, Scale) -> vec@vec3:map(Mat, fun(_capture) -> vec@vec3f:scale(_capture, Scale) end). -file("src/matrix/mat3f.gleam", 194). ?DOC(" Inverts the `Mat3f`, returning an error if the determinant is zero.\n"). -spec inverse(vec@vec3:vec3(vec@vec3:vec3(float()))) -> {ok, vec@vec3:vec3(vec@vec3:vec3(float()))} | {error, nil}. inverse(Mat) -> gleam@result:map( gleam@float:divide(1.0, determinant(Mat)), fun(Inv_det) -> Xx = begin _pipe = Mat, _pipe@1 = matrix@internal@projection:to_yz(_pipe), _pipe@2 = vec@vec2:map( _pipe@1, fun matrix@internal@projection:to_yz/1 ), matrix@mat2f:determinant(_pipe@2) end, Xy = begin _pipe@3 = Mat, _pipe@4 = matrix@internal@projection:to_xz(_pipe@3), _pipe@5 = vec@vec2:map( _pipe@4, fun matrix@internal@projection:to_yz/1 ), _pipe@6 = vec@vec2:swap(_pipe@5), matrix@mat2f:determinant(_pipe@6) end, Xz = begin _pipe@7 = Mat, _pipe@8 = matrix@internal@projection:to_xy(_pipe@7), _pipe@9 = vec@vec2:map( _pipe@8, fun matrix@internal@projection:to_yz/1 ), matrix@mat2f:determinant(_pipe@9) end, Yx = begin _pipe@10 = Mat, _pipe@11 = matrix@internal@projection:to_yz(_pipe@10), _pipe@12 = vec@vec2:map( _pipe@11, fun matrix@internal@projection:to_xz/1 ), _pipe@13 = vec@vec2:swap(_pipe@12), matrix@mat2f:determinant(_pipe@13) end, Yy = begin _pipe@14 = Mat, _pipe@15 = matrix@internal@projection:to_xz(_pipe@14), _pipe@16 = vec@vec2:map( _pipe@15, fun matrix@internal@projection:to_xz/1 ), matrix@mat2f:determinant(_pipe@16) end, Yz = begin _pipe@17 = Mat, _pipe@18 = matrix@internal@projection:to_xy(_pipe@17), _pipe@19 = vec@vec2:map( _pipe@18, fun matrix@internal@projection:to_xz/1 ), _pipe@20 = vec@vec2:swap(_pipe@19), matrix@mat2f:determinant(_pipe@20) end, Zx = begin _pipe@21 = Mat, _pipe@22 = matrix@internal@projection:to_yz(_pipe@21), _pipe@23 = vec@vec2:map( _pipe@22, fun matrix@internal@projection:to_xy/1 ), matrix@mat2f:determinant(_pipe@23) end, Zy = begin _pipe@24 = Mat, _pipe@25 = matrix@internal@projection:to_xz(_pipe@24), _pipe@26 = vec@vec2:map( _pipe@25, fun matrix@internal@projection:to_xy/1 ), _pipe@27 = vec@vec2:swap(_pipe@26), matrix@mat2f:determinant(_pipe@27) end, Zz = begin _pipe@28 = Mat, _pipe@29 = matrix@internal@projection:to_xy(_pipe@28), _pipe@30 = vec@vec2:map( _pipe@29, fun matrix@internal@projection:to_xy/1 ), matrix@mat2f:determinant(_pipe@30) end, scale(new(Xx, Xy, Xz, Yx, Yy, Yz, Zx, Zy, Zz), Inv_det) end ). -file("src/matrix/mat3f.gleam", 315). ?DOC(" Divides one `Mat3f` by another. Equivalent to multiplying the inverse of the second matrix.\n"). -spec divide( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(vec@vec3:vec3(float())) ) -> {ok, vec@vec3:vec3(vec@vec3:vec3(float()))} | {error, nil}. divide(A, B) -> gleam@result:map(inverse(B), fun(Inv_b) -> multiply(A, Inv_b) end). -file("src/matrix/mat3f.gleam", 328). ?DOC( " Scales the `Mat3f` by a `Vec3f`.\n" "\n" " This is faster than creating a diagonal scaling matrix and then multiplying that.\n" ). -spec scale_diagonal( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(float()) ) -> vec@vec3:vec3(vec@vec3:vec3(float())). scale_diagonal(Mat, Scale) -> vec@vec3:map2(Mat, Scale, fun vec@vec3f:scale/2). -file("src/matrix/mat3f.gleam", 335). ?DOC( " Returns a matrix containing the reciprocal of each element of the `Mat3f`.\n" "\n" " If any of the elements is zero, an error is returned.\n" ). -spec reciprocal(vec@vec3:vec3(vec@vec3:vec3(float()))) -> {ok, vec@vec3:vec3(vec@vec3:vec3(float()))} | {error, nil}. reciprocal(Mat) -> _pipe@2 = vec@vec3:map(Mat, fun(Column) -> _pipe = Column, _pipe@1 = vec@vec3:map( _pipe, fun(_capture) -> gleam@float:divide(1.0, _capture) end ), vec@vec3:result(_pipe@1) end), vec@vec3:result(_pipe@2). -file("src/matrix/mat3f.gleam", 345). ?DOC(" Sums a list of `Mat3f`s.\n"). -spec sum(list(vec@vec3:vec3(vec@vec3:vec3(float())))) -> vec@vec3:vec3(vec@vec3:vec3(float())). sum(Mats) -> gleam@list:fold( Mats, {vec3, {vec3, +0.0, +0.0, +0.0}, {vec3, +0.0, +0.0, +0.0}, {vec3, +0.0, +0.0, +0.0}}, fun add/2 ). -file("src/matrix/mat3f.gleam", 350). ?DOC(" Multiplies a list of `Mat3f`s.\n"). -spec product(list(vec@vec3:vec3(vec@vec3:vec3(float())))) -> vec@vec3:vec3(vec@vec3:vec3(float())). product(Mats) -> gleam@list:fold( Mats, {vec3, {vec3, 1.0, +0.0, +0.0}, {vec3, +0.0, 1.0, +0.0}, {vec3, +0.0, +0.0, 1.0}}, fun multiply/2 ).