-module(matrix@mat4f). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/matrix/mat4f.gleam"). -export([new/16, from_cols/4, from_diagonal/1, transpose/1, diagonal/1, determinant/1, mul_vec4/2, mul_transpose_vec4/2, scale/2, add/2, subtract/2, from_mat3/1, from_mat3_translation/2, from_translation/1, from_axis_angle/2, from_rotation_x/1, from_rotation_y/1, from_rotation_z/1, from_scale/1, inverse/1, look_to_rh/3, look_to_lh/3, look_at_lh/3, look_at_rh/3, transform_point3/2, transform_vector3/2, from_scale_rotation_translation/3, from_rotation_translation/2, from_quaternion/1, to_scale_rotation_translation/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(" 4x4 matrices of floats\n"). -file("src/matrix/mat4f.gleam", 31). ?DOC( " Constructs a `Mat4f` from its components.\n" " ```text\n" " | ax bx cx dx |\n" " | ay by cy dy |\n" " | az bz cz dz |\n" " | aw bw cw dw |\n" " ```\n" ). -spec new( float(), float(), float(), float(), float(), float(), float(), float(), float(), float(), float(), float(), float(), float(), float(), float() ) -> vec@vec4:vec4(vec@vec4:vec4(float())). new(Ax, Ay, Az, Aw, Bx, By, Bz, Bw, Cx, Cy, Cz, Cw, Dx, Dy, Dz, Dw) -> {vec4, {vec4, Ax, Ay, Az, Aw}, {vec4, Bx, By, Bz, Bw}, {vec4, Cx, Cy, Cz, Cw}, {vec4, Dx, Dy, Dz, Dw}}. -file("src/matrix/mat4f.gleam", 64). ?DOC( " Constructs a `Mat4f` from its four columns.\n" " ```text\n" " | a.x b.x c.x d.x |\n" " | a.y b.y c.y d.y |\n" " | a.z b.z c.z d.z |\n" " | a.w b.w c.w d.w |\n" " ```\n" ). -spec from_cols( vec@vec4:vec4(float()), vec@vec4:vec4(float()), vec@vec4:vec4(float()), vec@vec4:vec4(float()) ) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_cols(A, B, C, D) -> {vec4, A, B, C, D}. -file("src/matrix/mat4f.gleam", 69). ?DOC(" Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries are 0.\n"). -spec from_diagonal(vec@vec4:vec4(float())) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_diagonal(Diagonal) -> from_cols( {vec4, erlang:element(2, Diagonal), +0.0, +0.0, +0.0}, {vec4, +0.0, erlang:element(3, Diagonal), +0.0, +0.0}, {vec4, +0.0, +0.0, erlang:element(4, Diagonal), +0.0}, {vec4, +0.0, +0.0, +0.0, erlang:element(5, Diagonal)} ). -file("src/matrix/mat4f.gleam", 79). ?DOC(" Transposes the `Mat4f` along the diagonal.\n"). -spec transpose(vec@vec4:vec4(vec@vec4:vec4(float()))) -> vec@vec4:vec4(vec@vec4:vec4(float())). transpose(Mat) -> from_cols( {vec4, erlang:element(2, erlang:element(2, Mat)), erlang:element(2, erlang:element(3, Mat)), erlang:element(2, erlang:element(4, Mat)), erlang:element(2, erlang:element(5, Mat))}, {vec4, erlang:element(3, erlang:element(2, Mat)), erlang:element(3, erlang:element(3, Mat)), erlang:element(3, erlang:element(4, Mat)), erlang:element(3, erlang:element(5, Mat))}, {vec4, erlang:element(4, erlang:element(2, Mat)), erlang:element(4, erlang:element(3, Mat)), erlang:element(4, erlang:element(4, Mat)), erlang:element(4, erlang:element(5, Mat))}, {vec4, erlang:element(5, erlang:element(2, Mat)), erlang:element(5, erlang:element(3, Mat)), erlang:element(5, erlang:element(4, Mat)), erlang:element(5, erlang:element(5, Mat))} ). -file("src/matrix/mat4f.gleam", 89). ?DOC(" Extracts the diagonal of the `Mat4f`.\n"). -spec diagonal(vec@vec4:vec4(vec@vec4:vec4(float()))) -> vec@vec4:vec4(float()). diagonal(Mat) -> {vec4, erlang:element(2, erlang:element(2, Mat)), erlang:element(3, erlang:element(3, Mat)), erlang:element(4, erlang:element(4, Mat)), erlang:element(5, erlang:element(5, Mat))}. -file("src/matrix/mat4f.gleam", 94). ?DOC(" Returns the determinant of the `Mat4f`.\n"). -spec determinant(vec@vec4:vec4(vec@vec4:vec4(float()))) -> float(). determinant(Mat) -> {vec4, M00, M01, M02, M03} = erlang:element(2, Mat), {vec4, M10, M11, M12, M13} = erlang:element(3, Mat), {vec4, M20, M21, M22, M23} = erlang:element(4, Mat), {vec4, M30, M31, M32, M33} = erlang:element(5, Mat), A2323 = (M22 * M33) - (M23 * M32), A1323 = (M21 * M33) - (M23 * M31), A1223 = (M21 * M32) - (M22 * M31), A0323 = (M20 * M33) - (M23 * M30), A0223 = (M20 * M32) - (M22 * M30), 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))). -file("src/matrix/mat4f.gleam", 118). ?DOC(" Transforms a 4D vector by this `Mat4f`.\n"). -spec mul_vec4(vec@vec4:vec4(vec@vec4:vec4(float())), vec@vec4:vec4(float())) -> vec@vec4:vec4(float()). mul_vec4(Mat, Rhs) -> _pipe = vec@vec4:map2(Mat, Rhs, fun vec@vec4f:scale/2), _pipe@1 = vec@vec4:to_list(_pipe), vec@vec4f:sum(_pipe@1). -file("src/matrix/mat4f.gleam", 127). ?DOC( " Transforms a 4D vector by the transpose of the `Mat4f`.\n" "\n" " Equivalent to matrix multiplication where the vector is on the left.\n" ). -spec mul_transpose_vec4( vec@vec4:vec4(vec@vec4:vec4(float())), vec@vec4:vec4(float()) ) -> vec@vec4:vec4(float()). mul_transpose_vec4(Mat, Rhs) -> vec@vec4:map(Mat, fun(_capture) -> vec@vec4f:dot(_capture, Rhs) end). -file("src/matrix/mat4f.gleam", 132). ?DOC(" Scales the `Mat4f` by a `Float`.\n"). -spec scale(vec@vec4:vec4(vec@vec4:vec4(float())), float()) -> vec@vec4:vec4(vec@vec4:vec4(float())). scale(Mat, Scale) -> vec@vec4:map(Mat, fun(_capture) -> vec@vec4f:scale(_capture, Scale) end). -file("src/matrix/mat4f.gleam", 137). ?DOC(" Adds two `Mat4f`s together\n"). -spec add( vec@vec4:vec4(vec@vec4:vec4(float())), vec@vec4:vec4(vec@vec4:vec4(float())) ) -> vec@vec4:vec4(vec@vec4:vec4(float())). add(A, B) -> vec@vec4:map2(A, B, fun vec@vec4f:add/2). -file("src/matrix/mat4f.gleam", 142). ?DOC(" Subtracts `Mat4f` `b` from `a`\n"). -spec subtract( vec@vec4:vec4(vec@vec4:vec4(float())), vec@vec4:vec4(vec@vec4:vec4(float())) ) -> vec@vec4:vec4(vec@vec4:vec4(float())). subtract(A, B) -> vec@vec4:map2(A, B, fun vec@vec4f:subtract/2). -file("src/matrix/mat4f.gleam", 219). ?DOC( " Creates an affine transformation matrix from the given 3x3 linear transformation\n" " matrix.\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_mat3(vec@vec3:vec3(vec@vec3:vec3(float()))) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_mat3(M) -> from_cols( matrix@internal@projection:extend3(erlang:element(2, M), +0.0), matrix@internal@projection:extend3(erlang:element(3, M), +0.0), matrix@internal@projection:extend3(erlang:element(4, M), +0.0), {vec4, +0.0, +0.0, +0.0, 1.0} ). -file("src/matrix/mat4f.gleam", 227). ?DOC( " Creates an affine transformation matrics from a 3x3 matrix (expressing scale, shear and\n" " rotation) and a translation vector.\n" "\n" " Equivalent to `multiply(from_translation(translation), from_mat3(mat3))`\n" ). -spec from_mat3_translation( vec@vec3:vec3(vec@vec3:vec3(float())), vec@vec3:vec3(float()) ) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_mat3_translation(Mat3, Translation) -> from_cols( matrix@internal@projection:extend3(erlang:element(2, Mat3), +0.0), matrix@internal@projection:extend3(erlang:element(3, Mat3), +0.0), matrix@internal@projection:extend3(erlang:element(4, Mat3), +0.0), matrix@internal@projection:extend3(Translation, 1.0) ). -file("src/matrix/mat4f.gleam", 239). ?DOC( " Creates an affine transformation matrix from the given 3D `translation`.\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_translation(vec@vec3:vec3(float())) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_translation(Translation) -> from_cols( {vec4, 1.0, +0.0, +0.0, +0.0}, {vec4, +0.0, 1.0, +0.0, +0.0}, {vec4, +0.0, +0.0, 1.0, +0.0}, matrix@internal@projection:extend3(Translation, 1.0) ). -file("src/matrix/mat4f.gleam", 247). ?DOC( " Creates an affine transformation matrix containing a 3D rotation around a normalized\n" " rotation `axis` of `angle` (in radians).\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_axis_angle(vec@vec3:vec3(float()), float()) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_axis_angle(Axis, Angle) -> Axis@1 = vec@vec3f:normalize(Axis), Sin = gleam_community@maths:sin(Angle), Cos = gleam_community@maths:cos(Angle), Axis_sin = vec@vec3f:scale(Axis@1, Sin), Axis_sq = vec@vec3f:multiply(Axis@1, Axis@1), Omc = 1.0 - Cos, Xyomc = (erlang:element(2, Axis@1) * erlang:element(3, Axis@1)) * Omc, Xzomc = (erlang:element(2, Axis@1) * erlang:element(4, Axis@1)) * Omc, Yzomc = (erlang:element(3, Axis@1) * erlang:element(4, Axis@1)) * Omc, from_cols( {vec4, (erlang:element(2, Axis_sq) * Omc) + Cos, Xyomc + erlang:element(4, Axis_sin), Xzomc - erlang:element(3, Axis_sin), +0.0}, {vec4, Xyomc - erlang:element(4, Axis_sin), (erlang:element(3, Axis_sq) * Omc) + Cos, Yzomc + erlang:element(2, Axis_sin), +0.0}, {vec4, Xzomc + erlang:element(3, Axis_sin), Yzomc - erlang:element(2, Axis_sin), (erlang:element(4, Axis_sq) * Omc) + Cos, +0.0}, {vec4, +0.0, +0.0, +0.0, 1.0} ). -file("src/matrix/mat4f.gleam", 269). ?DOC( " Creates an affine transformation matrix containing a 3D rotation around the x axis of\n" " `angle` (in radians).\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_rotation_x(float()) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_rotation_x(Angle) -> Sin = gleam_community@maths:sin(Angle), Cos = gleam_community@maths:cos(Angle), from_cols( {vec4, 1.0, +0.0, +0.0, +0.0}, {vec4, +0.0, Cos, Sin, +0.0}, {vec4, +0.0, +0.0 - Sin, Cos, +0.0}, {vec4, +0.0, +0.0, +0.0, 1.0} ). -file("src/matrix/mat4f.gleam", 284). ?DOC( " Creates an affine transformation matrix containing a 3D rotation around the y axis of\n" " `angle` (in radians).\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_rotation_y(float()) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_rotation_y(Angle) -> Sin = gleam_community@maths:sin(Angle), Cos = gleam_community@maths:cos(Angle), from_cols( {vec4, Cos, +0.0, +0.0 - Sin, +0.0}, {vec4, +0.0, 1.0, +0.0, +0.0}, {vec4, Sin, +0.0, Cos, +0.0}, {vec4, +0.0, +0.0, +0.0, 1.0} ). -file("src/matrix/mat4f.gleam", 299). ?DOC( " Creates an affine transformation matrix containing a 3D rotation around the z axis of\n" " `angle` (in radians).\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_rotation_z(float()) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_rotation_z(Angle) -> Sin = gleam_community@maths:sin(Angle), Cos = gleam_community@maths:cos(Angle), from_cols( {vec4, Cos, Sin, +0.0, +0.0}, {vec4, +0.0 - Sin, Cos, +0.0, +0.0}, {vec4, +0.0, +0.0, 1.0, +0.0}, {vec4, +0.0, +0.0, +0.0, 1.0} ). -file("src/matrix/mat4f.gleam", 313). ?DOC( " Creates an affine transformation matrix containing the given 3D non-uniform `scale`.\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_scale(vec@vec3:vec3(float())) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_scale(Scale) -> from_diagonal(matrix@internal@projection:extend3(Scale, 1.0)). -file("src/matrix/mat4f.gleam", 318). ?DOC(" Inverts the `Mat4f`, returning an error if the matrix is not invertible.\n"). -spec inverse(vec@vec4:vec4(vec@vec4:vec4(float()))) -> {ok, vec@vec4:vec4(vec@vec4:vec4(float()))} | {error, nil}. inverse(Mat) -> {vec4, {vec4, M00, M01, M02, M03}, {vec4, M10, M11, M12, M13}, {vec4, M20, M21, M22, M23}, {vec4, M30, M31, M32, M33}} = Mat, Coef00 = (M22 * M33) - (M32 * M23), Coef02 = (M12 * M33) - (M32 * M13), Coef03 = (M12 * M23) - (M22 * M13), Coef04 = (M21 * M33) - (M31 * M23), Coef06 = (M11 * M33) - (M31 * M13), Coef07 = (M11 * M23) - (M21 * M13), Coef08 = (M21 * M32) - (M31 * M22), Coef10 = (M11 * M32) - (M31 * M12), Coef11 = (M11 * M22) - (M21 * M12), Coef12 = (M20 * M33) - (M30 * M23), Coef14 = (M10 * M33) - (M30 * M13), Coef15 = (M10 * M23) - (M20 * M13), Coef16 = (M20 * M32) - (M30 * M22), Coef18 = (M10 * M32) - (M30 * M12), Coef19 = (M10 * M22) - (M20 * M12), Coef20 = (M20 * M31) - (M30 * M21), Coef22 = (M10 * M31) - (M30 * M11), Coef23 = (M10 * M21) - (M20 * M11), Fac0 = {vec4, Coef00, Coef00, Coef02, Coef03}, Fac1 = {vec4, Coef04, Coef04, Coef06, Coef07}, Fac2 = {vec4, Coef08, Coef08, Coef10, Coef11}, Fac3 = {vec4, Coef12, Coef12, Coef14, Coef15}, Fac4 = {vec4, Coef16, Coef16, Coef18, Coef19}, Fac5 = {vec4, Coef20, Coef20, Coef22, Coef23}, Vec0 = {vec4, M10, M00, M00, M00}, Vec1 = {vec4, M11, M01, M01, M01}, Vec2 = {vec4, M12, M02, M02, M02}, Vec3 = {vec4, M13, M03, M03, M03}, Inv0 = begin _pipe = Vec1, _pipe@1 = vec@vec4f:multiply(_pipe, Fac0), _pipe@3 = vec@vec4f:subtract( _pipe@1, begin _pipe@2 = Vec2, vec@vec4f:multiply(_pipe@2, Fac1) end ), vec@vec4f:add( _pipe@3, begin _pipe@4 = Vec3, vec@vec4f:multiply(_pipe@4, Fac2) end ) end, Inv1 = begin _pipe@5 = Vec0, _pipe@6 = vec@vec4f:multiply(_pipe@5, Fac0), _pipe@8 = vec@vec4f:subtract( _pipe@6, begin _pipe@7 = Vec2, vec@vec4f:multiply(_pipe@7, Fac3) end ), vec@vec4f:add( _pipe@8, begin _pipe@9 = Vec3, vec@vec4f:multiply(_pipe@9, Fac4) end ) end, Inv2 = begin _pipe@10 = Vec0, _pipe@11 = vec@vec4f:multiply(_pipe@10, Fac1), _pipe@13 = vec@vec4f:subtract( _pipe@11, begin _pipe@12 = Vec1, vec@vec4f:multiply(_pipe@12, Fac3) end ), vec@vec4f:add( _pipe@13, begin _pipe@14 = Vec3, vec@vec4f:multiply(_pipe@14, Fac5) end ) end, Inv3 = begin _pipe@15 = Vec0, _pipe@16 = vec@vec4f:multiply(_pipe@15, Fac2), _pipe@18 = vec@vec4f:subtract( _pipe@16, begin _pipe@17 = Vec1, vec@vec4f:multiply(_pipe@17, Fac4) end ), vec@vec4f:add( _pipe@18, begin _pipe@19 = Vec2, vec@vec4f:multiply(_pipe@19, Fac5) end ) end, Sign_a = {vec4, 1.0, -1.0, 1.0, -1.0}, Sign_b = {vec4, -1.0, 1.0, -1.0, 1.0}, Inverse = from_cols( begin _pipe@20 = Inv0, vec@vec4f:multiply(_pipe@20, Sign_a) end, begin _pipe@21 = Inv1, vec@vec4f:multiply(_pipe@21, Sign_b) end, begin _pipe@22 = Inv2, vec@vec4f:multiply(_pipe@22, Sign_a) end, begin _pipe@23 = Inv3, vec@vec4f:multiply(_pipe@23, Sign_b) end ), Col0 = {vec4, erlang:element(2, erlang:element(2, Inverse)), erlang:element(2, erlang:element(3, Inverse)), erlang:element(2, erlang:element(4, Inverse)), erlang:element(2, erlang:element(5, Inverse))}, Dot0 = begin _pipe@24 = erlang:element(2, Mat), vec@vec4f:multiply(_pipe@24, Col0) end, Dot1 = ((erlang:element(2, Dot0) + erlang:element(3, Dot0)) + erlang:element( 4, Dot0 )) + erlang:element(5, Dot0), gleam@result:map( gleam@float:divide(1.0, Dot1), fun(_capture) -> scale(Inverse, _capture) end ). -file("src/matrix/mat4f.gleam", 409). ?DOC( " Creates a right-handed view matrix using a camera position, a facing direction, and an up\n" " 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(float()) ) -> vec@vec4:vec4(vec@vec4:vec4(float())). look_to_rh(Eye, Dir, Up) -> F = Dir, S = begin _pipe = vec@vec3f:cross(F, Up), vec@vec3f:normalize(_pipe) end, U = vec@vec3f:cross(S, F), Neg_f = vec@vec3f:negate(F), Neg_dot_s = gleam@float:negate(vec@vec3f:dot(Eye, S)), Neg_dot_u = gleam@float:negate(vec@vec3f:dot(Eye, U)), Dot_f = vec@vec3f:dot(Eye, F), from_cols( {vec4, erlang:element(2, S), erlang:element(2, U), erlang:element(2, Neg_f), +0.0}, {vec4, erlang:element(3, S), erlang:element(3, U), erlang:element(3, Neg_f), +0.0}, {vec4, erlang:element(4, S), erlang:element(4, U), erlang:element(4, Neg_f), +0.0}, {vec4, Neg_dot_s, Neg_dot_u, Dot_f, 1.0} ). -file("src/matrix/mat4f.gleam", 401). ?DOC( " Creates a left-handed view matrix using a camera position, a facing direction and an up\n" " 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(float()) ) -> vec@vec4:vec4(vec@vec4:vec4(float())). look_to_lh(Eye, Dir, Up) -> look_to_rh(Eye, vec@vec3f:negate(Dir), Up). -file("src/matrix/mat4f.gleam", 430). ?DOC( " Creates a left-handed view matrix using a camera position, a focal points 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@vec4:vec4(vec@vec4:vec4(float())). look_at_lh(Eye, Center, Up) -> look_to_lh( Eye, begin _pipe = Center, _pipe@1 = vec@vec3f:subtract(_pipe, Eye), vec@vec3f:normalize(_pipe@1) end, Up ). -file("src/matrix/mat4f.gleam", 438). ?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@vec4:vec4(vec@vec4:vec4(float())). look_at_rh(Eye, Center, Up) -> look_to_rh( Eye, begin _pipe = Center, _pipe@1 = vec@vec3f:subtract(_pipe, Eye), vec@vec3f:normalize(_pipe@1) end, Up ). -file("src/matrix/mat4f.gleam", 448). ?DOC( " Transforms the given 3D vector as a point.\n" "\n" " This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is\n" " `1.0`.\n" "\n" " This function assumes that `mat` contains a valid affine transform.\n" ). -spec transform_point3( vec@vec4:vec4(vec@vec4:vec4(float())), vec@vec3:vec3(float()) ) -> vec@vec3:vec3(float()). transform_point3(Mat, Rhs) -> _pipe = vec@vec4f:scale(erlang:element(2, Mat), erlang:element(2, Rhs)), _pipe@1 = vec@vec4f:add( _pipe, vec@vec4f:scale(erlang:element(3, Mat), erlang:element(3, Rhs)) ), _pipe@2 = vec@vec4f:add( _pipe@1, vec@vec4f:scale(erlang:element(4, Mat), erlang:element(4, Rhs)) ), _pipe@3 = vec@vec4f:add(_pipe@2, erlang:element(5, Mat)), matrix@internal@projection:to_xyz(_pipe@3). -file("src/matrix/mat4f.gleam", 462). ?DOC( " Transforms the given 3D vector as a direction.\n" "\n" " This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is\n" " `0.0`.\n" "\n" " This method assumes that `mat` contains a valid affine transform.\n" ). -spec transform_vector3( vec@vec4:vec4(vec@vec4:vec4(float())), vec@vec3:vec3(float()) ) -> vec@vec3:vec3(float()). transform_vector3(Mat, Rhs) -> _pipe = vec@vec4f:scale(erlang:element(2, Mat), erlang:element(2, Rhs)), _pipe@1 = vec@vec4f:add( _pipe, vec@vec4f:scale(erlang:element(3, Mat), erlang:element(3, Rhs)) ), _pipe@2 = vec@vec4f:add( _pipe@1, vec@vec4f:scale(erlang:element(4, Mat), erlang:element(4, Rhs)) ), matrix@internal@projection:to_xyz(_pipe@2). -file("src/matrix/mat4f.gleam", 471). -spec quat_to_axes(vec@vec4:vec4(float())) -> vec@vec3:vec3(vec@vec4:vec4(float())). quat_to_axes(Rotation) -> {vec4, X, Y, Z, W} = vec@vec4f:normalize(Rotation), X2 = X + X, Y2 = Y + Y, Z2 = Z + Z, Xx = X * X2, Xy = X * Y2, Xz = X * Z2, Yy = Y * Y2, Yz = Y * Z2, Zz = Z * Z2, Wx = W * X2, Wy = Y * Y2, Wz = W * Z2, X_axis = {vec4, 1.0 - (Yy + Zz), Xy + Wz, Xz - Wy, +0.0}, Y_axis = {vec4, Xy - Wz, 1.0 - (Xx + Zz), Yz + Wx, +0.0}, Z_axis = {vec4, Xz + Wy, Yz - Wx, 1.0 - (Xx + Yy), +0.0}, {vec3, X_axis, Y_axis, Z_axis}. -file("src/matrix/mat4f.gleam", 150). ?DOC( " Creates an affine transformation matrix from the given 3D `scale`, `rotation` and\n" " `translation`.\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_scale_rotation_translation( vec@vec3:vec3(float()), vec@vec4:vec4(float()), vec@vec3:vec3(float()) ) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_scale_rotation_translation(Scale, Rotation, Translation) -> Axes = begin _pipe = Rotation, _pipe@1 = quat_to_axes(_pipe), vec@vec3:map2(_pipe@1, Scale, fun vec@vec4f:scale/2) end, from_cols( erlang:element(2, Axes), erlang:element(3, Axes), erlang:element(4, Axes), matrix@internal@projection:extend3(Translation, 1.0) ). -file("src/matrix/mat4f.gleam", 166). ?DOC( " Creates an affine transformation matrix from the given 3D `translation`.\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_rotation_translation(vec@vec4:vec4(float()), vec@vec3:vec3(float())) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_rotation_translation(Rotation, Translation) -> from_scale_rotation_translation( {vec3, 1.0, 1.0, 1.0}, Rotation, Translation ). -file("src/matrix/mat4f.gleam", 210). ?DOC( " Creates an affine transformation matrix from the given `rotation` quaternion.\n" "\n" " The resulting matrix can be used to transform 3D points and vectors.\n" ). -spec from_quaternion(vec@vec4:vec4(float())) -> vec@vec4:vec4(vec@vec4:vec4(float())). from_quaternion(Q) -> Rotation = quat_to_axes(Q), from_cols( erlang:element(2, Rotation), erlang:element(3, Rotation), erlang:element(4, Rotation), {vec4, +0.0, +0.0, +0.0, 1.0} ). -file("src/matrix/mat4f.gleam", 493). -spec quat_from_rotation_axes( vec@vec3:vec3(float()), vec@vec3:vec3(float()), vec@vec3:vec3(float()) ) -> vec@vec4:vec4(float()). quat_from_rotation_axes(X_axis, Y_axis, Z_axis) -> {vec3, M00, M01, M02} = X_axis, {vec3, M10, M11, M12} = Y_axis, {vec3, M20, M21, M22} = Z_axis, case M22 =< +0.0 of true -> Dif10 = M11 - M00, Omm22 = 1.0 - M22, case Dif10 =< +0.0 of true -> Four_xsq = Omm22 - Dif10, Inv4x = begin Four_x@1 = case gleam@float:square_root(Four_xsq) of {ok, Four_x} -> Four_x; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"matrix/mat4f"/utf8>>, function => <<"quat_from_rotation_axes"/utf8>>, line => 512, value => _assert_fail, start => 15383, 'end' => 15434, pattern_start => 15394, pattern_end => 15404}) end, case Four_x@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator -> 0.5 / Gleam@denominator end end, {vec4, Four_xsq * Inv4x, (M01 + M10) * Inv4x, (M02 + M20) * Inv4x, (M12 - M21) * Inv4x}; false -> Four_ysq = Omm22 + Dif10, Inv4y = begin Four_y@1 = case gleam@float:square_root(Four_ysq) of {ok, Four_y} -> Four_y; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"matrix/mat4f"/utf8>>, function => <<"quat_from_rotation_axes"/utf8>>, line => 526, value => _assert_fail@1, start => 15772, 'end' => 15823, pattern_start => 15783, pattern_end => 15793}) end, case Four_y@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator@1 -> 0.5 / Gleam@denominator@1 end end, {vec4, (M01 + M10) * Inv4y, Four_ysq * Inv4y, (M12 + M21) * Inv4y, (M20 - M02) * Inv4y} end; false -> Sum10 = M11 + M00, Opm22 = 1.0 + M22, case Sum10 =< +0.0 of true -> Four_zsq = Opm22 - Sum10, Inv4z = begin Four_z@1 = case gleam@float:square_root(Four_zsq) of {ok, Four_z} -> Four_z; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"matrix/mat4f"/utf8>>, function => <<"quat_from_rotation_axes"/utf8>>, line => 547, value => _assert_fail@2, start => 16306, 'end' => 16357, pattern_start => 16317, pattern_end => 16327}) end, case Four_z@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator@2 -> 0.5 / Gleam@denominator@2 end end, {vec4, (M02 + M20) * Inv4z, (M12 + M21) * Inv4z, Four_zsq * Inv4z, (M01 - M10) * Inv4z}; false -> Four_wsq = Opm22 + Sum10, Inv4w = begin Four_w@1 = case gleam@float:square_root(Four_wsq) of {ok, Four_w} -> Four_w; _assert_fail@3 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"matrix/mat4f"/utf8>>, function => <<"quat_from_rotation_axes"/utf8>>, line => 561, value => _assert_fail@3, start => 16695, 'end' => 16746, pattern_start => 16706, pattern_end => 16716}) end, case Four_w@1 of +0.0 -> +0.0; -0.0 -> -0.0; Gleam@denominator@3 -> 0.5 / Gleam@denominator@3 end end, {vec4, (M12 - M21) * Inv4w, (M20 - M02) * Inv4w, (M01 - M10) * Inv4w, Four_wsq * Inv4w} end end. -file("src/matrix/mat4f.gleam", 175). ?DOC( " Extracts `scale`, `rotation` and `translation` from `mat`. The input matrix is\n" " expected to be a 3D affine transformation matrix otherwise the output will be invalid.\n" "\n" " Will return `Error(Nil)` if the determinant of `mat` is zero or if the resulting scale vector\n" " contains any zero elements.\n" ). -spec to_scale_rotation_translation(vec@vec4:vec4(vec@vec4:vec4(float()))) -> {ok, {vec@vec3:vec3(float()), vec@vec4:vec4(float()), vec@vec3:vec3(float())}} | {error, nil}. to_scale_rotation_translation(Mat) -> Det = determinant(Mat), gleam@result:'try'( gleam@float:divide(Det, gleam@float:absolute_value(Det)), fun(Signum) -> Scale = {vec3, vec@vec4f:length(erlang:element(2, Mat)) * Signum, vec@vec4f:length(erlang:element(3, Mat)), vec@vec4f:length(erlang:element(4, Mat))}, gleam@bool:guard( not vec@vec3f:loosely_equals( Scale, {vec3, +0.0, +0.0, +0.0}, 0.0000001 ), {error, nil}, fun() -> gleam@result:map( begin _pipe = Scale, _pipe@1 = vec@vec3:map( _pipe, fun(_capture) -> gleam@float:divide(1.0, _capture) end ), vec@vec3:result(_pipe@1) end, fun(Inv_scale) -> Rotation = quat_from_rotation_axes( begin _pipe@2 = erlang:element(2, Mat), _pipe@3 = vec@vec4f:scale( _pipe@2, erlang:element(2, Inv_scale) ), matrix@internal@projection:to_xyz(_pipe@3) end, begin _pipe@4 = erlang:element(3, Mat), _pipe@5 = vec@vec4f:scale( _pipe@4, erlang:element(3, Inv_scale) ), matrix@internal@projection:to_xyz(_pipe@5) end, begin _pipe@6 = erlang:element(4, Mat), _pipe@7 = vec@vec4f:scale( _pipe@6, erlang:element(4, Inv_scale) ), matrix@internal@projection:to_xyz(_pipe@7) end ), {Scale, Rotation, matrix@internal@projection:to_xyz( erlang:element(5, Mat) )} end ) end ) end ).